diff options
Diffstat (limited to 'drivers/clocksource/timer-imx-gpt.c')
-rw-r--r-- | drivers/clocksource/timer-imx-gpt.c | 540 |
1 files changed, 540 insertions, 0 deletions
diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c new file mode 100644 index 000000000000..879c78423546 --- /dev/null +++ b/drivers/clocksource/timer-imx-gpt.c | |||
@@ -0,0 +1,540 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/plat-mxc/time.c | ||
3 | * | ||
4 | * Copyright (C) 2000-2001 Deep Blue Solutions | ||
5 | * Copyright (C) 2002 Shane Nay (shane@minirl.com) | ||
6 | * Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com) | ||
7 | * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version 2 | ||
12 | * of the License, or (at your option) any later version. | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
21 | * MA 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/clockchips.h> | ||
27 | #include <linux/clk.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/err.h> | ||
30 | #include <linux/sched_clock.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/of.h> | ||
33 | #include <linux/of_address.h> | ||
34 | #include <linux/of_irq.h> | ||
35 | #include <soc/imx/timer.h> | ||
36 | |||
37 | /* | ||
38 | * There are 4 versions of the timer hardware on Freescale MXC hardware. | ||
39 | * - MX1/MXL | ||
40 | * - MX21, MX27. | ||
41 | * - MX25, MX31, MX35, MX37, MX51, MX6Q(rev1.0) | ||
42 | * - MX6DL, MX6SX, MX6Q(rev1.1+) | ||
43 | */ | ||
44 | |||
45 | /* defines common for all i.MX */ | ||
46 | #define MXC_TCTL 0x00 | ||
47 | #define MXC_TCTL_TEN (1 << 0) /* Enable module */ | ||
48 | #define MXC_TPRER 0x04 | ||
49 | |||
50 | /* MX1, MX21, MX27 */ | ||
51 | #define MX1_2_TCTL_CLK_PCLK1 (1 << 1) | ||
52 | #define MX1_2_TCTL_IRQEN (1 << 4) | ||
53 | #define MX1_2_TCTL_FRR (1 << 8) | ||
54 | #define MX1_2_TCMP 0x08 | ||
55 | #define MX1_2_TCN 0x10 | ||
56 | #define MX1_2_TSTAT 0x14 | ||
57 | |||
58 | /* MX21, MX27 */ | ||
59 | #define MX2_TSTAT_CAPT (1 << 1) | ||
60 | #define MX2_TSTAT_COMP (1 << 0) | ||
61 | |||
62 | /* MX31, MX35, MX25, MX5, MX6 */ | ||
63 | #define V2_TCTL_WAITEN (1 << 3) /* Wait enable mode */ | ||
64 | #define V2_TCTL_CLK_IPG (1 << 6) | ||
65 | #define V2_TCTL_CLK_PER (2 << 6) | ||
66 | #define V2_TCTL_CLK_OSC_DIV8 (5 << 6) | ||
67 | #define V2_TCTL_FRR (1 << 9) | ||
68 | #define V2_TCTL_24MEN (1 << 10) | ||
69 | #define V2_TPRER_PRE24M 12 | ||
70 | #define V2_IR 0x0c | ||
71 | #define V2_TSTAT 0x08 | ||
72 | #define V2_TSTAT_OF1 (1 << 0) | ||
73 | #define V2_TCN 0x24 | ||
74 | #define V2_TCMP 0x10 | ||
75 | |||
76 | #define V2_TIMER_RATE_OSC_DIV8 3000000 | ||
77 | |||
78 | struct imx_timer { | ||
79 | enum imx_gpt_type type; | ||
80 | void __iomem *base; | ||
81 | int irq; | ||
82 | struct clk *clk_per; | ||
83 | struct clk *clk_ipg; | ||
84 | const struct imx_gpt_data *gpt; | ||
85 | struct clock_event_device ced; | ||
86 | enum clock_event_mode cem; | ||
87 | struct irqaction act; | ||
88 | }; | ||
89 | |||
90 | struct imx_gpt_data { | ||
91 | int reg_tstat; | ||
92 | int reg_tcn; | ||
93 | int reg_tcmp; | ||
94 | void (*gpt_setup_tctl)(struct imx_timer *imxtm); | ||
95 | void (*gpt_irq_enable)(struct imx_timer *imxtm); | ||
96 | void (*gpt_irq_disable)(struct imx_timer *imxtm); | ||
97 | void (*gpt_irq_acknowledge)(struct imx_timer *imxtm); | ||
98 | int (*set_next_event)(unsigned long evt, | ||
99 | struct clock_event_device *ced); | ||
100 | }; | ||
101 | |||
102 | static inline struct imx_timer *to_imx_timer(struct clock_event_device *ced) | ||
103 | { | ||
104 | return container_of(ced, struct imx_timer, ced); | ||
105 | } | ||
106 | |||
107 | static void imx1_gpt_irq_disable(struct imx_timer *imxtm) | ||
108 | { | ||
109 | unsigned int tmp; | ||
110 | |||
111 | tmp = readl_relaxed(imxtm->base + MXC_TCTL); | ||
112 | writel_relaxed(tmp & ~MX1_2_TCTL_IRQEN, imxtm->base + MXC_TCTL); | ||
113 | } | ||
114 | #define imx21_gpt_irq_disable imx1_gpt_irq_disable | ||
115 | |||
116 | static void imx31_gpt_irq_disable(struct imx_timer *imxtm) | ||
117 | { | ||
118 | writel_relaxed(0, imxtm->base + V2_IR); | ||
119 | } | ||
120 | #define imx6dl_gpt_irq_disable imx31_gpt_irq_disable | ||
121 | |||
122 | static void imx1_gpt_irq_enable(struct imx_timer *imxtm) | ||
123 | { | ||
124 | unsigned int tmp; | ||
125 | |||
126 | tmp = readl_relaxed(imxtm->base + MXC_TCTL); | ||
127 | writel_relaxed(tmp | MX1_2_TCTL_IRQEN, imxtm->base + MXC_TCTL); | ||
128 | } | ||
129 | #define imx21_gpt_irq_enable imx1_gpt_irq_enable | ||
130 | |||
131 | static void imx31_gpt_irq_enable(struct imx_timer *imxtm) | ||
132 | { | ||
133 | writel_relaxed(1<<0, imxtm->base + V2_IR); | ||
134 | } | ||
135 | #define imx6dl_gpt_irq_enable imx31_gpt_irq_enable | ||
136 | |||
137 | static void imx1_gpt_irq_acknowledge(struct imx_timer *imxtm) | ||
138 | { | ||
139 | writel_relaxed(0, imxtm->base + MX1_2_TSTAT); | ||
140 | } | ||
141 | |||
142 | static void imx21_gpt_irq_acknowledge(struct imx_timer *imxtm) | ||
143 | { | ||
144 | writel_relaxed(MX2_TSTAT_CAPT | MX2_TSTAT_COMP, | ||
145 | imxtm->base + MX1_2_TSTAT); | ||
146 | } | ||
147 | |||
148 | static void imx31_gpt_irq_acknowledge(struct imx_timer *imxtm) | ||
149 | { | ||
150 | writel_relaxed(V2_TSTAT_OF1, imxtm->base + V2_TSTAT); | ||
151 | } | ||
152 | #define imx6dl_gpt_irq_acknowledge imx31_gpt_irq_acknowledge | ||
153 | |||
154 | static void __iomem *sched_clock_reg; | ||
155 | |||
156 | static u64 notrace mxc_read_sched_clock(void) | ||
157 | { | ||
158 | return sched_clock_reg ? readl_relaxed(sched_clock_reg) : 0; | ||
159 | } | ||
160 | |||
161 | static struct delay_timer imx_delay_timer; | ||
162 | |||
163 | static unsigned long imx_read_current_timer(void) | ||
164 | { | ||
165 | return readl_relaxed(sched_clock_reg); | ||
166 | } | ||
167 | |||
168 | static int __init mxc_clocksource_init(struct imx_timer *imxtm) | ||
169 | { | ||
170 | unsigned int c = clk_get_rate(imxtm->clk_per); | ||
171 | void __iomem *reg = imxtm->base + imxtm->gpt->reg_tcn; | ||
172 | |||
173 | imx_delay_timer.read_current_timer = &imx_read_current_timer; | ||
174 | imx_delay_timer.freq = c; | ||
175 | register_current_timer_delay(&imx_delay_timer); | ||
176 | |||
177 | sched_clock_reg = reg; | ||
178 | |||
179 | sched_clock_register(mxc_read_sched_clock, 32, c); | ||
180 | return clocksource_mmio_init(reg, "mxc_timer1", c, 200, 32, | ||
181 | clocksource_mmio_readl_up); | ||
182 | } | ||
183 | |||
184 | /* clock event */ | ||
185 | |||
186 | static int mx1_2_set_next_event(unsigned long evt, | ||
187 | struct clock_event_device *ced) | ||
188 | { | ||
189 | struct imx_timer *imxtm = to_imx_timer(ced); | ||
190 | unsigned long tcmp; | ||
191 | |||
192 | tcmp = readl_relaxed(imxtm->base + MX1_2_TCN) + evt; | ||
193 | |||
194 | writel_relaxed(tcmp, imxtm->base + MX1_2_TCMP); | ||
195 | |||
196 | return (int)(tcmp - readl_relaxed(imxtm->base + MX1_2_TCN)) < 0 ? | ||
197 | -ETIME : 0; | ||
198 | } | ||
199 | |||
200 | static int v2_set_next_event(unsigned long evt, | ||
201 | struct clock_event_device *ced) | ||
202 | { | ||
203 | struct imx_timer *imxtm = to_imx_timer(ced); | ||
204 | unsigned long tcmp; | ||
205 | |||
206 | tcmp = readl_relaxed(imxtm->base + V2_TCN) + evt; | ||
207 | |||
208 | writel_relaxed(tcmp, imxtm->base + V2_TCMP); | ||
209 | |||
210 | return evt < 0x7fffffff && | ||
211 | (int)(tcmp - readl_relaxed(imxtm->base + V2_TCN)) < 0 ? | ||
212 | -ETIME : 0; | ||
213 | } | ||
214 | |||
215 | #ifdef DEBUG | ||
216 | static const char *clock_event_mode_label[] = { | ||
217 | [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC", | ||
218 | [CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT", | ||
219 | [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN", | ||
220 | [CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED", | ||
221 | [CLOCK_EVT_MODE_RESUME] = "CLOCK_EVT_MODE_RESUME", | ||
222 | }; | ||
223 | #endif /* DEBUG */ | ||
224 | |||
225 | static void mxc_set_mode(enum clock_event_mode mode, | ||
226 | struct clock_event_device *ced) | ||
227 | { | ||
228 | struct imx_timer *imxtm = to_imx_timer(ced); | ||
229 | unsigned long flags; | ||
230 | |||
231 | /* | ||
232 | * The timer interrupt generation is disabled at least | ||
233 | * for enough time to call mxc_set_next_event() | ||
234 | */ | ||
235 | local_irq_save(flags); | ||
236 | |||
237 | /* Disable interrupt in GPT module */ | ||
238 | imxtm->gpt->gpt_irq_disable(imxtm); | ||
239 | |||
240 | if (mode != imxtm->cem) { | ||
241 | u32 tcn = readl_relaxed(imxtm->base + imxtm->gpt->reg_tcn); | ||
242 | /* Set event time into far-far future */ | ||
243 | writel_relaxed(tcn - 3, imxtm->base + imxtm->gpt->reg_tcmp); | ||
244 | |||
245 | /* Clear pending interrupt */ | ||
246 | imxtm->gpt->gpt_irq_acknowledge(imxtm); | ||
247 | } | ||
248 | |||
249 | #ifdef DEBUG | ||
250 | printk(KERN_INFO "mxc_set_mode: changing mode from %s to %s\n", | ||
251 | clock_event_mode_label[imxtm->cem], | ||
252 | clock_event_mode_label[mode]); | ||
253 | #endif /* DEBUG */ | ||
254 | |||
255 | /* Remember timer mode */ | ||
256 | imxtm->cem = mode; | ||
257 | local_irq_restore(flags); | ||
258 | |||
259 | switch (mode) { | ||
260 | case CLOCK_EVT_MODE_PERIODIC: | ||
261 | printk(KERN_ERR"mxc_set_mode: Periodic mode is not " | ||
262 | "supported for i.MX\n"); | ||
263 | break; | ||
264 | case CLOCK_EVT_MODE_ONESHOT: | ||
265 | /* | ||
266 | * Do not put overhead of interrupt enable/disable into | ||
267 | * mxc_set_next_event(), the core has about 4 minutes | ||
268 | * to call mxc_set_next_event() or shutdown clock after | ||
269 | * mode switching | ||
270 | */ | ||
271 | local_irq_save(flags); | ||
272 | imxtm->gpt->gpt_irq_enable(imxtm); | ||
273 | local_irq_restore(flags); | ||
274 | break; | ||
275 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
276 | case CLOCK_EVT_MODE_UNUSED: | ||
277 | case CLOCK_EVT_MODE_RESUME: | ||
278 | /* Left event sources disabled, no more interrupts appear */ | ||
279 | break; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * IRQ handler for the timer | ||
285 | */ | ||
286 | static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id) | ||
287 | { | ||
288 | struct clock_event_device *ced = dev_id; | ||
289 | struct imx_timer *imxtm = to_imx_timer(ced); | ||
290 | uint32_t tstat; | ||
291 | |||
292 | tstat = readl_relaxed(imxtm->base + imxtm->gpt->reg_tstat); | ||
293 | |||
294 | imxtm->gpt->gpt_irq_acknowledge(imxtm); | ||
295 | |||
296 | ced->event_handler(ced); | ||
297 | |||
298 | return IRQ_HANDLED; | ||
299 | } | ||
300 | |||
301 | static int __init mxc_clockevent_init(struct imx_timer *imxtm) | ||
302 | { | ||
303 | struct clock_event_device *ced = &imxtm->ced; | ||
304 | struct irqaction *act = &imxtm->act; | ||
305 | |||
306 | imxtm->cem = CLOCK_EVT_MODE_UNUSED; | ||
307 | |||
308 | ced->name = "mxc_timer1"; | ||
309 | ced->features = CLOCK_EVT_FEAT_ONESHOT; | ||
310 | ced->set_mode = mxc_set_mode; | ||
311 | ced->set_next_event = imxtm->gpt->set_next_event; | ||
312 | ced->rating = 200; | ||
313 | ced->cpumask = cpumask_of(0); | ||
314 | clockevents_config_and_register(ced, clk_get_rate(imxtm->clk_per), | ||
315 | 0xff, 0xfffffffe); | ||
316 | |||
317 | act->name = "i.MX Timer Tick"; | ||
318 | act->flags = IRQF_TIMER | IRQF_IRQPOLL; | ||
319 | act->handler = mxc_timer_interrupt; | ||
320 | act->dev_id = ced; | ||
321 | |||
322 | return setup_irq(imxtm->irq, act); | ||
323 | } | ||
324 | |||
325 | static void imx1_gpt_setup_tctl(struct imx_timer *imxtm) | ||
326 | { | ||
327 | u32 tctl_val; | ||
328 | |||
329 | tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN; | ||
330 | writel_relaxed(tctl_val, imxtm->base + MXC_TCTL); | ||
331 | } | ||
332 | #define imx21_gpt_setup_tctl imx1_gpt_setup_tctl | ||
333 | |||
334 | static void imx31_gpt_setup_tctl(struct imx_timer *imxtm) | ||
335 | { | ||
336 | u32 tctl_val; | ||
337 | |||
338 | tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN; | ||
339 | if (clk_get_rate(imxtm->clk_per) == V2_TIMER_RATE_OSC_DIV8) | ||
340 | tctl_val |= V2_TCTL_CLK_OSC_DIV8; | ||
341 | else | ||
342 | tctl_val |= V2_TCTL_CLK_PER; | ||
343 | |||
344 | writel_relaxed(tctl_val, imxtm->base + MXC_TCTL); | ||
345 | } | ||
346 | |||
347 | static void imx6dl_gpt_setup_tctl(struct imx_timer *imxtm) | ||
348 | { | ||
349 | u32 tctl_val; | ||
350 | |||
351 | tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN; | ||
352 | if (clk_get_rate(imxtm->clk_per) == V2_TIMER_RATE_OSC_DIV8) { | ||
353 | tctl_val |= V2_TCTL_CLK_OSC_DIV8; | ||
354 | /* 24 / 8 = 3 MHz */ | ||
355 | writel_relaxed(7 << V2_TPRER_PRE24M, imxtm->base + MXC_TPRER); | ||
356 | tctl_val |= V2_TCTL_24MEN; | ||
357 | } else { | ||
358 | tctl_val |= V2_TCTL_CLK_PER; | ||
359 | } | ||
360 | |||
361 | writel_relaxed(tctl_val, imxtm->base + MXC_TCTL); | ||
362 | } | ||
363 | |||
364 | static const struct imx_gpt_data imx1_gpt_data = { | ||
365 | .reg_tstat = MX1_2_TSTAT, | ||
366 | .reg_tcn = MX1_2_TCN, | ||
367 | .reg_tcmp = MX1_2_TCMP, | ||
368 | .gpt_irq_enable = imx1_gpt_irq_enable, | ||
369 | .gpt_irq_disable = imx1_gpt_irq_disable, | ||
370 | .gpt_irq_acknowledge = imx1_gpt_irq_acknowledge, | ||
371 | .gpt_setup_tctl = imx1_gpt_setup_tctl, | ||
372 | .set_next_event = mx1_2_set_next_event, | ||
373 | }; | ||
374 | |||
375 | static const struct imx_gpt_data imx21_gpt_data = { | ||
376 | .reg_tstat = MX1_2_TSTAT, | ||
377 | .reg_tcn = MX1_2_TCN, | ||
378 | .reg_tcmp = MX1_2_TCMP, | ||
379 | .gpt_irq_enable = imx21_gpt_irq_enable, | ||
380 | .gpt_irq_disable = imx21_gpt_irq_disable, | ||
381 | .gpt_irq_acknowledge = imx21_gpt_irq_acknowledge, | ||
382 | .gpt_setup_tctl = imx21_gpt_setup_tctl, | ||
383 | .set_next_event = mx1_2_set_next_event, | ||
384 | }; | ||
385 | |||
386 | static const struct imx_gpt_data imx31_gpt_data = { | ||
387 | .reg_tstat = V2_TSTAT, | ||
388 | .reg_tcn = V2_TCN, | ||
389 | .reg_tcmp = V2_TCMP, | ||
390 | .gpt_irq_enable = imx31_gpt_irq_enable, | ||
391 | .gpt_irq_disable = imx31_gpt_irq_disable, | ||
392 | .gpt_irq_acknowledge = imx31_gpt_irq_acknowledge, | ||
393 | .gpt_setup_tctl = imx31_gpt_setup_tctl, | ||
394 | .set_next_event = v2_set_next_event, | ||
395 | }; | ||
396 | |||
397 | static const struct imx_gpt_data imx6dl_gpt_data = { | ||
398 | .reg_tstat = V2_TSTAT, | ||
399 | .reg_tcn = V2_TCN, | ||
400 | .reg_tcmp = V2_TCMP, | ||
401 | .gpt_irq_enable = imx6dl_gpt_irq_enable, | ||
402 | .gpt_irq_disable = imx6dl_gpt_irq_disable, | ||
403 | .gpt_irq_acknowledge = imx6dl_gpt_irq_acknowledge, | ||
404 | .gpt_setup_tctl = imx6dl_gpt_setup_tctl, | ||
405 | .set_next_event = v2_set_next_event, | ||
406 | }; | ||
407 | |||
408 | static void __init _mxc_timer_init(struct imx_timer *imxtm) | ||
409 | { | ||
410 | switch (imxtm->type) { | ||
411 | case GPT_TYPE_IMX1: | ||
412 | imxtm->gpt = &imx1_gpt_data; | ||
413 | break; | ||
414 | case GPT_TYPE_IMX21: | ||
415 | imxtm->gpt = &imx21_gpt_data; | ||
416 | break; | ||
417 | case GPT_TYPE_IMX31: | ||
418 | imxtm->gpt = &imx31_gpt_data; | ||
419 | break; | ||
420 | case GPT_TYPE_IMX6DL: | ||
421 | imxtm->gpt = &imx6dl_gpt_data; | ||
422 | break; | ||
423 | default: | ||
424 | BUG(); | ||
425 | } | ||
426 | |||
427 | if (IS_ERR(imxtm->clk_per)) { | ||
428 | pr_err("i.MX timer: unable to get clk\n"); | ||
429 | return; | ||
430 | } | ||
431 | |||
432 | if (!IS_ERR(imxtm->clk_ipg)) | ||
433 | clk_prepare_enable(imxtm->clk_ipg); | ||
434 | |||
435 | clk_prepare_enable(imxtm->clk_per); | ||
436 | |||
437 | /* | ||
438 | * Initialise to a known state (all timers off, and timing reset) | ||
439 | */ | ||
440 | |||
441 | writel_relaxed(0, imxtm->base + MXC_TCTL); | ||
442 | writel_relaxed(0, imxtm->base + MXC_TPRER); /* see datasheet note */ | ||
443 | |||
444 | imxtm->gpt->gpt_setup_tctl(imxtm); | ||
445 | |||
446 | /* init and register the timer to the framework */ | ||
447 | mxc_clocksource_init(imxtm); | ||
448 | mxc_clockevent_init(imxtm); | ||
449 | } | ||
450 | |||
451 | void __init mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type type) | ||
452 | { | ||
453 | struct imx_timer *imxtm; | ||
454 | |||
455 | imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL); | ||
456 | BUG_ON(!imxtm); | ||
457 | |||
458 | imxtm->clk_per = clk_get_sys("imx-gpt.0", "per"); | ||
459 | imxtm->clk_ipg = clk_get_sys("imx-gpt.0", "ipg"); | ||
460 | |||
461 | imxtm->base = ioremap(pbase, SZ_4K); | ||
462 | BUG_ON(!imxtm->base); | ||
463 | |||
464 | imxtm->type = type; | ||
465 | |||
466 | _mxc_timer_init(imxtm); | ||
467 | } | ||
468 | |||
469 | static void __init mxc_timer_init_dt(struct device_node *np, enum imx_gpt_type type) | ||
470 | { | ||
471 | struct imx_timer *imxtm; | ||
472 | static int initialized; | ||
473 | |||
474 | /* Support one instance only */ | ||
475 | if (initialized) | ||
476 | return; | ||
477 | |||
478 | imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL); | ||
479 | BUG_ON(!imxtm); | ||
480 | |||
481 | imxtm->base = of_iomap(np, 0); | ||
482 | WARN_ON(!imxtm->base); | ||
483 | imxtm->irq = irq_of_parse_and_map(np, 0); | ||
484 | |||
485 | imxtm->clk_ipg = of_clk_get_by_name(np, "ipg"); | ||
486 | |||
487 | /* Try osc_per first, and fall back to per otherwise */ | ||
488 | imxtm->clk_per = of_clk_get_by_name(np, "osc_per"); | ||
489 | if (IS_ERR(imxtm->clk_per)) | ||
490 | imxtm->clk_per = of_clk_get_by_name(np, "per"); | ||
491 | |||
492 | imxtm->type = type; | ||
493 | |||
494 | _mxc_timer_init(imxtm); | ||
495 | |||
496 | initialized = 1; | ||
497 | } | ||
498 | |||
499 | static void __init imx1_timer_init_dt(struct device_node *np) | ||
500 | { | ||
501 | mxc_timer_init_dt(np, GPT_TYPE_IMX1); | ||
502 | } | ||
503 | |||
504 | static void __init imx21_timer_init_dt(struct device_node *np) | ||
505 | { | ||
506 | mxc_timer_init_dt(np, GPT_TYPE_IMX21); | ||
507 | } | ||
508 | |||
509 | static void __init imx31_timer_init_dt(struct device_node *np) | ||
510 | { | ||
511 | enum imx_gpt_type type = GPT_TYPE_IMX31; | ||
512 | |||
513 | /* | ||
514 | * We were using the same compatible string for i.MX6Q/D and i.MX6DL/S | ||
515 | * GPT device, while they actually have different programming model. | ||
516 | * This is a workaround to keep the existing i.MX6DL/S DTBs continue | ||
517 | * working with the new kernel. | ||
518 | */ | ||
519 | if (of_machine_is_compatible("fsl,imx6dl")) | ||
520 | type = GPT_TYPE_IMX6DL; | ||
521 | |||
522 | mxc_timer_init_dt(np, type); | ||
523 | } | ||
524 | |||
525 | static void __init imx6dl_timer_init_dt(struct device_node *np) | ||
526 | { | ||
527 | mxc_timer_init_dt(np, GPT_TYPE_IMX6DL); | ||
528 | } | ||
529 | |||
530 | CLOCKSOURCE_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt); | ||
531 | CLOCKSOURCE_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt); | ||
532 | CLOCKSOURCE_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt); | ||
533 | CLOCKSOURCE_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt); | ||
534 | CLOCKSOURCE_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt); | ||
535 | CLOCKSOURCE_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt); | ||
536 | CLOCKSOURCE_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt); | ||
537 | CLOCKSOURCE_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt); | ||
538 | CLOCKSOURCE_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt); | ||
539 | CLOCKSOURCE_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt); | ||
540 | CLOCKSOURCE_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt); | ||