1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Clocksource driver for NXP LPC32xx/18xx/43xx timer |
4 | * |
5 | * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> |
6 | * |
7 | * Based on: |
8 | * time-efm32 Copyright (C) 2013 Pengutronix |
9 | * mach-lpc32xx/timer.c Copyright (C) 2009 - 2010 NXP Semiconductors |
10 | */ |
11 | |
12 | #define pr_fmt(fmt) "%s: " fmt, __func__ |
13 | |
14 | #include <linux/clk.h> |
15 | #include <linux/clockchips.h> |
16 | #include <linux/clocksource.h> |
17 | #include <linux/delay.h> |
18 | #include <linux/interrupt.h> |
19 | #include <linux/irq.h> |
20 | #include <linux/kernel.h> |
21 | #include <linux/of.h> |
22 | #include <linux/of_address.h> |
23 | #include <linux/of_irq.h> |
24 | #include <linux/sched_clock.h> |
25 | |
26 | #define LPC32XX_TIMER_IR 0x000 |
27 | #define LPC32XX_TIMER_IR_MR0INT BIT(0) |
28 | #define LPC32XX_TIMER_TCR 0x004 |
29 | #define LPC32XX_TIMER_TCR_CEN BIT(0) |
30 | #define LPC32XX_TIMER_TCR_CRST BIT(1) |
31 | #define LPC32XX_TIMER_TC 0x008 |
32 | #define LPC32XX_TIMER_PR 0x00c |
33 | #define LPC32XX_TIMER_MCR 0x014 |
34 | #define LPC32XX_TIMER_MCR_MR0I BIT(0) |
35 | #define LPC32XX_TIMER_MCR_MR0R BIT(1) |
36 | #define LPC32XX_TIMER_MCR_MR0S BIT(2) |
37 | #define LPC32XX_TIMER_MR0 0x018 |
38 | #define LPC32XX_TIMER_CTCR 0x070 |
39 | |
40 | struct lpc32xx_clock_event_ddata { |
41 | struct clock_event_device evtdev; |
42 | void __iomem *base; |
43 | u32 ticks_per_jiffy; |
44 | }; |
45 | |
46 | /* Needed for the sched clock */ |
47 | static void __iomem *clocksource_timer_counter; |
48 | |
49 | static u64 notrace lpc32xx_read_sched_clock(void) |
50 | { |
51 | return readl(addr: clocksource_timer_counter); |
52 | } |
53 | |
54 | static unsigned long lpc32xx_delay_timer_read(void) |
55 | { |
56 | return readl(addr: clocksource_timer_counter); |
57 | } |
58 | |
59 | static struct delay_timer lpc32xx_delay_timer = { |
60 | .read_current_timer = lpc32xx_delay_timer_read, |
61 | }; |
62 | |
63 | static int lpc32xx_clkevt_next_event(unsigned long delta, |
64 | struct clock_event_device *evtdev) |
65 | { |
66 | struct lpc32xx_clock_event_ddata *ddata = |
67 | container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev); |
68 | |
69 | /* |
70 | * Place timer in reset and program the delta in the match |
71 | * channel 0 (MR0). When the timer counter matches the value |
72 | * in MR0 register the match will trigger an interrupt. |
73 | * After setup the timer is released from reset and enabled. |
74 | */ |
75 | writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR); |
76 | writel_relaxed(delta, ddata->base + LPC32XX_TIMER_MR0); |
77 | writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR); |
78 | |
79 | return 0; |
80 | } |
81 | |
82 | static int lpc32xx_clkevt_shutdown(struct clock_event_device *evtdev) |
83 | { |
84 | struct lpc32xx_clock_event_ddata *ddata = |
85 | container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev); |
86 | |
87 | /* Disable the timer */ |
88 | writel_relaxed(0, ddata->base + LPC32XX_TIMER_TCR); |
89 | |
90 | return 0; |
91 | } |
92 | |
93 | static int lpc32xx_clkevt_oneshot(struct clock_event_device *evtdev) |
94 | { |
95 | struct lpc32xx_clock_event_ddata *ddata = |
96 | container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev); |
97 | |
98 | /* |
99 | * When using oneshot, we must also disable the timer |
100 | * to wait for the first call to set_next_event(). |
101 | */ |
102 | writel_relaxed(0, ddata->base + LPC32XX_TIMER_TCR); |
103 | |
104 | /* Enable interrupt, reset on match and stop on match (MCR). */ |
105 | writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R | |
106 | LPC32XX_TIMER_MCR_MR0S, ddata->base + LPC32XX_TIMER_MCR); |
107 | return 0; |
108 | } |
109 | |
110 | static int lpc32xx_clkevt_periodic(struct clock_event_device *evtdev) |
111 | { |
112 | struct lpc32xx_clock_event_ddata *ddata = |
113 | container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev); |
114 | |
115 | /* Enable interrupt and reset on match. */ |
116 | writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R, |
117 | ddata->base + LPC32XX_TIMER_MCR); |
118 | |
119 | /* |
120 | * Place timer in reset and program the delta in the match |
121 | * channel 0 (MR0). |
122 | */ |
123 | writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR); |
124 | writel_relaxed(ddata->ticks_per_jiffy, ddata->base + LPC32XX_TIMER_MR0); |
125 | writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR); |
126 | |
127 | return 0; |
128 | } |
129 | |
130 | static irqreturn_t lpc32xx_clock_event_handler(int irq, void *dev_id) |
131 | { |
132 | struct lpc32xx_clock_event_ddata *ddata = dev_id; |
133 | |
134 | /* Clear match on channel 0 */ |
135 | writel_relaxed(LPC32XX_TIMER_IR_MR0INT, ddata->base + LPC32XX_TIMER_IR); |
136 | |
137 | ddata->evtdev.event_handler(&ddata->evtdev); |
138 | |
139 | return IRQ_HANDLED; |
140 | } |
141 | |
142 | static struct lpc32xx_clock_event_ddata lpc32xx_clk_event_ddata = { |
143 | .evtdev = { |
144 | .name = "lpc3220 clockevent" , |
145 | .features = CLOCK_EVT_FEAT_ONESHOT | |
146 | CLOCK_EVT_FEAT_PERIODIC, |
147 | .rating = 300, |
148 | .set_next_event = lpc32xx_clkevt_next_event, |
149 | .set_state_shutdown = lpc32xx_clkevt_shutdown, |
150 | .set_state_oneshot = lpc32xx_clkevt_oneshot, |
151 | .set_state_periodic = lpc32xx_clkevt_periodic, |
152 | }, |
153 | }; |
154 | |
155 | static int __init lpc32xx_clocksource_init(struct device_node *np) |
156 | { |
157 | void __iomem *base; |
158 | unsigned long rate; |
159 | struct clk *clk; |
160 | int ret; |
161 | |
162 | clk = of_clk_get_by_name(np, name: "timerclk" ); |
163 | if (IS_ERR(ptr: clk)) { |
164 | pr_err("clock get failed (%ld)\n" , PTR_ERR(clk)); |
165 | return PTR_ERR(ptr: clk); |
166 | } |
167 | |
168 | ret = clk_prepare_enable(clk); |
169 | if (ret) { |
170 | pr_err("clock enable failed (%d)\n" , ret); |
171 | goto err_clk_enable; |
172 | } |
173 | |
174 | base = of_iomap(node: np, index: 0); |
175 | if (!base) { |
176 | pr_err("unable to map registers\n" ); |
177 | ret = -EADDRNOTAVAIL; |
178 | goto err_iomap; |
179 | } |
180 | |
181 | /* |
182 | * Disable and reset timer then set it to free running timer |
183 | * mode (CTCR) with no prescaler (PR) or match operations (MCR). |
184 | * After setup the timer is released from reset and enabled. |
185 | */ |
186 | writel_relaxed(LPC32XX_TIMER_TCR_CRST, base + LPC32XX_TIMER_TCR); |
187 | writel_relaxed(0, base + LPC32XX_TIMER_PR); |
188 | writel_relaxed(0, base + LPC32XX_TIMER_MCR); |
189 | writel_relaxed(0, base + LPC32XX_TIMER_CTCR); |
190 | writel_relaxed(LPC32XX_TIMER_TCR_CEN, base + LPC32XX_TIMER_TCR); |
191 | |
192 | rate = clk_get_rate(clk); |
193 | ret = clocksource_mmio_init(base + LPC32XX_TIMER_TC, "lpc3220 timer" , |
194 | rate, 300, 32, clocksource_mmio_readl_up); |
195 | if (ret) { |
196 | pr_err("failed to init clocksource (%d)\n" , ret); |
197 | goto err_clocksource_init; |
198 | } |
199 | |
200 | clocksource_timer_counter = base + LPC32XX_TIMER_TC; |
201 | lpc32xx_delay_timer.freq = rate; |
202 | register_current_timer_delay(&lpc32xx_delay_timer); |
203 | sched_clock_register(read: lpc32xx_read_sched_clock, bits: 32, rate); |
204 | |
205 | return 0; |
206 | |
207 | err_clocksource_init: |
208 | iounmap(addr: base); |
209 | err_iomap: |
210 | clk_disable_unprepare(clk); |
211 | err_clk_enable: |
212 | clk_put(clk); |
213 | return ret; |
214 | } |
215 | |
216 | static int __init lpc32xx_clockevent_init(struct device_node *np) |
217 | { |
218 | void __iomem *base; |
219 | unsigned long rate; |
220 | struct clk *clk; |
221 | int ret, irq; |
222 | |
223 | clk = of_clk_get_by_name(np, name: "timerclk" ); |
224 | if (IS_ERR(ptr: clk)) { |
225 | pr_err("clock get failed (%ld)\n" , PTR_ERR(clk)); |
226 | return PTR_ERR(ptr: clk); |
227 | } |
228 | |
229 | ret = clk_prepare_enable(clk); |
230 | if (ret) { |
231 | pr_err("clock enable failed (%d)\n" , ret); |
232 | goto err_clk_enable; |
233 | } |
234 | |
235 | base = of_iomap(node: np, index: 0); |
236 | if (!base) { |
237 | pr_err("unable to map registers\n" ); |
238 | ret = -EADDRNOTAVAIL; |
239 | goto err_iomap; |
240 | } |
241 | |
242 | irq = irq_of_parse_and_map(node: np, index: 0); |
243 | if (!irq) { |
244 | pr_err("get irq failed\n" ); |
245 | ret = -ENOENT; |
246 | goto err_irq; |
247 | } |
248 | |
249 | /* |
250 | * Disable timer and clear any pending interrupt (IR) on match |
251 | * channel 0 (MR0). Clear the prescaler as it's not used. |
252 | */ |
253 | writel_relaxed(0, base + LPC32XX_TIMER_TCR); |
254 | writel_relaxed(0, base + LPC32XX_TIMER_PR); |
255 | writel_relaxed(0, base + LPC32XX_TIMER_CTCR); |
256 | writel_relaxed(LPC32XX_TIMER_IR_MR0INT, base + LPC32XX_TIMER_IR); |
257 | |
258 | rate = clk_get_rate(clk); |
259 | lpc32xx_clk_event_ddata.base = base; |
260 | lpc32xx_clk_event_ddata.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ); |
261 | clockevents_config_and_register(dev: &lpc32xx_clk_event_ddata.evtdev, |
262 | freq: rate, min_delta: 1, max_delta: -1); |
263 | |
264 | ret = request_irq(irq, handler: lpc32xx_clock_event_handler, |
265 | IRQF_TIMER | IRQF_IRQPOLL, name: "lpc3220 clockevent" , |
266 | dev: &lpc32xx_clk_event_ddata); |
267 | if (ret) { |
268 | pr_err("request irq failed\n" ); |
269 | goto err_irq; |
270 | } |
271 | |
272 | return 0; |
273 | |
274 | err_irq: |
275 | iounmap(addr: base); |
276 | err_iomap: |
277 | clk_disable_unprepare(clk); |
278 | err_clk_enable: |
279 | clk_put(clk); |
280 | return ret; |
281 | } |
282 | |
283 | /* |
284 | * This function asserts that we have exactly one clocksource and one |
285 | * clock_event_device in the end. |
286 | */ |
287 | static int __init lpc32xx_timer_init(struct device_node *np) |
288 | { |
289 | static int has_clocksource, has_clockevent; |
290 | int ret = 0; |
291 | |
292 | if (!has_clocksource) { |
293 | ret = lpc32xx_clocksource_init(np); |
294 | if (!ret) { |
295 | has_clocksource = 1; |
296 | return 0; |
297 | } |
298 | } |
299 | |
300 | if (!has_clockevent) { |
301 | ret = lpc32xx_clockevent_init(np); |
302 | if (!ret) { |
303 | has_clockevent = 1; |
304 | return 0; |
305 | } |
306 | } |
307 | |
308 | return ret; |
309 | } |
310 | TIMER_OF_DECLARE(lpc32xx_timer, "nxp,lpc3220-timer" , lpc32xx_timer_init); |
311 | |