Linux Audio

Check our new training course

Linux BSP development engineering services

Need help to port Linux and bootloaders to your hardware?
Loading...
Note: File does not exist in v6.8.
  1/*
  2 * Actions Semi Owl timer
  3 *
  4 * Copyright 2012 Actions Semi Inc.
  5 * Author: Actions Semi, Inc.
  6 *
  7 * Copyright (c) 2017 SUSE Linux GmbH
  8 * Author: Andreas Färber
  9 *
 10 * This program is free software; you can redistribute  it and/or modify it
 11 * under  the terms of  the GNU General  Public License as published by the
 12 * Free Software Foundation;  either version 2 of the  License, or (at your
 13 * option) any later version.
 14 */
 15
 16#include <linux/clk.h>
 17#include <linux/clockchips.h>
 18#include <linux/interrupt.h>
 19#include <linux/irq.h>
 20#include <linux/irqreturn.h>
 21#include <linux/sched_clock.h>
 22#include <linux/of.h>
 23#include <linux/of_address.h>
 24#include <linux/of_irq.h>
 25
 26#define OWL_Tx_CTL		0x0
 27#define OWL_Tx_CMP		0x4
 28#define OWL_Tx_VAL		0x8
 29
 30#define OWL_Tx_CTL_PD		BIT(0)
 31#define OWL_Tx_CTL_INTEN	BIT(1)
 32#define OWL_Tx_CTL_EN		BIT(2)
 33
 34static void __iomem *owl_timer_base;
 35static void __iomem *owl_clksrc_base;
 36static void __iomem *owl_clkevt_base;
 37
 38static inline void owl_timer_reset(void __iomem *base)
 39{
 40	writel(0, base + OWL_Tx_CTL);
 41	writel(0, base + OWL_Tx_VAL);
 42	writel(0, base + OWL_Tx_CMP);
 43}
 44
 45static inline void owl_timer_set_enabled(void __iomem *base, bool enabled)
 46{
 47	u32 ctl = readl(base + OWL_Tx_CTL);
 48
 49	/* PD bit is cleared when set */
 50	ctl &= ~OWL_Tx_CTL_PD;
 51
 52	if (enabled)
 53		ctl |= OWL_Tx_CTL_EN;
 54	else
 55		ctl &= ~OWL_Tx_CTL_EN;
 56
 57	writel(ctl, base + OWL_Tx_CTL);
 58}
 59
 60static u64 notrace owl_timer_sched_read(void)
 61{
 62	return (u64)readl(owl_clksrc_base + OWL_Tx_VAL);
 63}
 64
 65static int owl_timer_set_state_shutdown(struct clock_event_device *evt)
 66{
 67	owl_timer_set_enabled(owl_clkevt_base, false);
 68
 69	return 0;
 70}
 71
 72static int owl_timer_set_state_oneshot(struct clock_event_device *evt)
 73{
 74	owl_timer_reset(owl_clkevt_base);
 75
 76	return 0;
 77}
 78
 79static int owl_timer_tick_resume(struct clock_event_device *evt)
 80{
 81	return 0;
 82}
 83
 84static int owl_timer_set_next_event(unsigned long evt,
 85				    struct clock_event_device *ev)
 86{
 87	void __iomem *base = owl_clkevt_base;
 88
 89	owl_timer_set_enabled(base, false);
 90	writel(OWL_Tx_CTL_INTEN, base + OWL_Tx_CTL);
 91	writel(0, base + OWL_Tx_VAL);
 92	writel(evt, base + OWL_Tx_CMP);
 93	owl_timer_set_enabled(base, true);
 94
 95	return 0;
 96}
 97
 98static struct clock_event_device owl_clockevent = {
 99	.name			= "owl_tick",
100	.rating			= 200,
101	.features		= CLOCK_EVT_FEAT_ONESHOT |
102				  CLOCK_EVT_FEAT_DYNIRQ,
103	.set_state_shutdown	= owl_timer_set_state_shutdown,
104	.set_state_oneshot	= owl_timer_set_state_oneshot,
105	.tick_resume		= owl_timer_tick_resume,
106	.set_next_event		= owl_timer_set_next_event,
107};
108
109static irqreturn_t owl_timer1_interrupt(int irq, void *dev_id)
110{
111	struct clock_event_device *evt = (struct clock_event_device *)dev_id;
112
113	writel(OWL_Tx_CTL_PD, owl_clkevt_base + OWL_Tx_CTL);
114
115	evt->event_handler(evt);
116
117	return IRQ_HANDLED;
118}
119
120static int __init owl_timer_init(struct device_node *node)
121{
122	struct clk *clk;
123	unsigned long rate;
124	int timer1_irq, ret;
125
126	owl_timer_base = of_io_request_and_map(node, 0, "owl-timer");
127	if (IS_ERR(owl_timer_base)) {
128		pr_err("Can't map timer registers\n");
129		return PTR_ERR(owl_timer_base);
130	}
131
132	owl_clksrc_base = owl_timer_base + 0x08;
133	owl_clkevt_base = owl_timer_base + 0x14;
134
135	timer1_irq = of_irq_get_byname(node, "timer1");
136	if (timer1_irq <= 0) {
137		pr_err("Can't parse timer1 IRQ\n");
138		return -EINVAL;
139	}
140
141	clk = of_clk_get(node, 0);
142	if (IS_ERR(clk))
143		return PTR_ERR(clk);
144
145	rate = clk_get_rate(clk);
146
147	owl_timer_reset(owl_clksrc_base);
148	owl_timer_set_enabled(owl_clksrc_base, true);
149
150	sched_clock_register(owl_timer_sched_read, 32, rate);
151	clocksource_mmio_init(owl_clksrc_base + OWL_Tx_VAL, node->name,
152			      rate, 200, 32, clocksource_mmio_readl_up);
153
154	owl_timer_reset(owl_clkevt_base);
155
156	ret = request_irq(timer1_irq, owl_timer1_interrupt, IRQF_TIMER,
157			  "owl-timer", &owl_clockevent);
158	if (ret) {
159		pr_err("failed to request irq %d\n", timer1_irq);
160		return ret;
161	}
162
163	owl_clockevent.cpumask = cpumask_of(0);
164	owl_clockevent.irq = timer1_irq;
165
166	clockevents_config_and_register(&owl_clockevent, rate,
167					0xf, 0xffffffff);
168
169	return 0;
170}
171TIMER_OF_DECLARE(owl_s500, "actions,s500-timer", owl_timer_init);
172TIMER_OF_DECLARE(owl_s700, "actions,s700-timer", owl_timer_init);
173TIMER_OF_DECLARE(owl_s900, "actions,s900-timer", owl_timer_init);