1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Integrator/AP timer driver
4 * Copyright (C) 2000-2003 Deep Blue Solutions Ltd
5 * Copyright (c) 2014, Linaro Limited
9 #include <linux/clocksource.h>
10 #include <linux/of_irq.h>
11 #include <linux/of_address.h>
12 #include <linux/of_platform.h>
13 #include <linux/clockchips.h>
14 #include <linux/interrupt.h>
15 #include <linux/sched_clock.h>
19 static void __iomem
* sched_clk_base
;
21 static u64 notrace
integrator_read_sched_clock(void)
23 return -readl(sched_clk_base
+ TIMER_VALUE
);
26 static int __init
integrator_clocksource_init(unsigned long inrate
,
29 u32 ctrl
= TIMER_CTRL_ENABLE
| TIMER_CTRL_PERIODIC
;
30 unsigned long rate
= inrate
;
33 if (rate
>= 1500000) {
35 ctrl
|= TIMER_CTRL_DIV16
;
38 writel(0xffff, base
+ TIMER_LOAD
);
39 writel(ctrl
, base
+ TIMER_CTRL
);
41 ret
= clocksource_mmio_init(base
+ TIMER_VALUE
, "timer2",
42 rate
, 200, 16, clocksource_mmio_readl_down
);
46 sched_clk_base
= base
;
47 sched_clock_register(integrator_read_sched_clock
, 16, rate
);
52 static unsigned long timer_reload
;
53 static void __iomem
* clkevt_base
;
56 * IRQ handler for the timer
58 static irqreturn_t
integrator_timer_interrupt(int irq
, void *dev_id
)
60 struct clock_event_device
*evt
= dev_id
;
62 /* clear the interrupt */
63 writel(1, clkevt_base
+ TIMER_INTCLR
);
65 evt
->event_handler(evt
);
70 static int clkevt_shutdown(struct clock_event_device
*evt
)
72 u32 ctrl
= readl(clkevt_base
+ TIMER_CTRL
) & ~TIMER_CTRL_ENABLE
;
75 writel(ctrl
, clkevt_base
+ TIMER_CTRL
);
79 static int clkevt_set_oneshot(struct clock_event_device
*evt
)
81 u32 ctrl
= readl(clkevt_base
+ TIMER_CTRL
) &
82 ~(TIMER_CTRL_ENABLE
| TIMER_CTRL_PERIODIC
);
84 /* Leave the timer disabled, .set_next_event will enable it */
85 writel(ctrl
, clkevt_base
+ TIMER_CTRL
);
89 static int clkevt_set_periodic(struct clock_event_device
*evt
)
91 u32 ctrl
= readl(clkevt_base
+ TIMER_CTRL
) & ~TIMER_CTRL_ENABLE
;
94 writel(ctrl
, clkevt_base
+ TIMER_CTRL
);
96 /* Enable the timer and start the periodic tick */
97 writel(timer_reload
, clkevt_base
+ TIMER_LOAD
);
98 ctrl
|= TIMER_CTRL_PERIODIC
| TIMER_CTRL_ENABLE
;
99 writel(ctrl
, clkevt_base
+ TIMER_CTRL
);
103 static int clkevt_set_next_event(unsigned long next
, struct clock_event_device
*evt
)
105 unsigned long ctrl
= readl(clkevt_base
+ TIMER_CTRL
);
107 writel(ctrl
& ~TIMER_CTRL_ENABLE
, clkevt_base
+ TIMER_CTRL
);
108 writel(next
, clkevt_base
+ TIMER_LOAD
);
109 writel(ctrl
| TIMER_CTRL_ENABLE
, clkevt_base
+ TIMER_CTRL
);
114 static struct clock_event_device integrator_clockevent
= {
116 .features
= CLOCK_EVT_FEAT_PERIODIC
|
117 CLOCK_EVT_FEAT_ONESHOT
,
118 .set_state_shutdown
= clkevt_shutdown
,
119 .set_state_periodic
= clkevt_set_periodic
,
120 .set_state_oneshot
= clkevt_set_oneshot
,
121 .tick_resume
= clkevt_shutdown
,
122 .set_next_event
= clkevt_set_next_event
,
126 static int integrator_clockevent_init(unsigned long inrate
,
127 void __iomem
*base
, int irq
)
129 unsigned long rate
= inrate
;
130 unsigned int ctrl
= 0;
134 /* Calculate and program a divisor */
135 if (rate
> 0x100000 * HZ
) {
137 ctrl
|= TIMER_CTRL_DIV256
;
138 } else if (rate
> 0x10000 * HZ
) {
140 ctrl
|= TIMER_CTRL_DIV16
;
142 timer_reload
= rate
/ HZ
;
143 writel(ctrl
, clkevt_base
+ TIMER_CTRL
);
145 ret
= request_irq(irq
, integrator_timer_interrupt
,
146 IRQF_TIMER
| IRQF_IRQPOLL
, "timer",
147 &integrator_clockevent
);
151 clockevents_config_and_register(&integrator_clockevent
,
158 static int __init
integrator_ap_timer_init_of(struct device_node
*node
)
166 struct device_node
*alias_node
;
168 base
= of_io_request_and_map(node
, 0, "integrator-timer");
170 return PTR_ERR(base
);
172 clk
= of_clk_get(node
, 0);
174 pr_err("No clock for %pOFn\n", node
);
177 clk_prepare_enable(clk
);
178 rate
= clk_get_rate(clk
);
179 writel(0, base
+ TIMER_CTRL
);
181 err
= of_property_read_string(of_aliases
,
182 "arm,timer-primary", &path
);
184 pr_warn("Failed to read property\n");
188 alias_node
= of_find_node_by_path(path
);
191 * The pointer is used as an identifier not as a pointer, we
192 * can drop the refcount on the of__node immediately after
195 of_node_put(alias_node
);
197 if (node
== alias_node
)
198 /* The primary timer lacks IRQ, use as clocksource */
199 return integrator_clocksource_init(rate
, base
);
201 err
= of_property_read_string(of_aliases
,
202 "arm,timer-secondary", &path
);
204 pr_warn("Failed to read property\n");
208 alias_node
= of_find_node_by_path(path
);
210 of_node_put(alias_node
);
212 if (node
== alias_node
) {
213 /* The secondary timer will drive the clock event */
214 irq
= irq_of_parse_and_map(node
, 0);
215 return integrator_clockevent_init(rate
, base
, irq
);
218 pr_info("Timer @%p unused\n", base
);
219 clk_disable_unprepare(clk
);
224 TIMER_OF_DECLARE(integrator_ap_timer
, "arm,integrator-timer",
225 integrator_ap_timer_init_of
);