diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2012-01-10 17:15:45 -0500 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2012-03-13 09:27:51 -0400 |
commit | d8e0364364d333feb4564bb7d7d983182b34427e (patch) | |
tree | d79b09cf76a2a0852086b5b11e6f824d158f4cce /arch/arm/kernel | |
parent | 81e46f7b6dcec485bcb1f988ba4dc5b20189573c (diff) |
ARM: smp_twd: add device tree support
Add bindings to support DT discovery of the ARM Timer Watchdog
(aka TWD). Only the timer side is converted by this patch.
Acked-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/smp_twd.c | 77 |
1 files changed, 64 insertions, 13 deletions
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 18c55f1e4e48..761826c628b1 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/clockchips.h> | 20 | #include <linux/clockchips.h> |
21 | #include <linux/irq.h> | 21 | #include <linux/irq.h> |
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/of_irq.h> | ||
24 | #include <linux/of_address.h> | ||
23 | 25 | ||
24 | #include <asm/smp_twd.h> | 26 | #include <asm/smp_twd.h> |
25 | #include <asm/localtimer.h> | 27 | #include <asm/localtimer.h> |
@@ -284,37 +286,86 @@ static struct local_timer_ops twd_lt_ops __cpuinitdata = { | |||
284 | .stop = twd_timer_stop, | 286 | .stop = twd_timer_stop, |
285 | }; | 287 | }; |
286 | 288 | ||
287 | int __init twd_local_timer_register(struct twd_local_timer *tlt) | 289 | static int __init twd_local_timer_common_register(void) |
288 | { | 290 | { |
289 | int err; | 291 | int err; |
290 | 292 | ||
291 | if (twd_base || twd_evt) | ||
292 | return -EBUSY; | ||
293 | |||
294 | twd_ppi = tlt->res[1].start; | ||
295 | |||
296 | twd_evt = alloc_percpu(struct clock_event_device *); | 293 | twd_evt = alloc_percpu(struct clock_event_device *); |
297 | twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0])); | 294 | if (!twd_evt) { |
298 | if (!twd_base || !twd_evt) { | ||
299 | err = -ENOMEM; | 295 | err = -ENOMEM; |
300 | goto out; | 296 | goto out_free; |
301 | } | 297 | } |
302 | 298 | ||
303 | err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt); | 299 | err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt); |
304 | if (err) { | 300 | if (err) { |
305 | pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err); | 301 | pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err); |
306 | goto out; | 302 | goto out_free; |
307 | } | 303 | } |
308 | 304 | ||
309 | err = local_timer_register(&twd_lt_ops); | 305 | err = local_timer_register(&twd_lt_ops); |
310 | if (err) | 306 | if (err) |
311 | goto out; | 307 | goto out_irq; |
312 | 308 | ||
313 | return 0; | 309 | return 0; |
314 | 310 | ||
315 | out: | 311 | out_irq: |
312 | free_percpu_irq(twd_ppi, twd_evt); | ||
313 | out_free: | ||
316 | iounmap(twd_base); | 314 | iounmap(twd_base); |
315 | twd_base = NULL; | ||
317 | free_percpu(twd_evt); | 316 | free_percpu(twd_evt); |
318 | twd_base = twd_evt = NULL; | 317 | |
319 | return err; | 318 | return err; |
320 | } | 319 | } |
320 | |||
321 | int __init twd_local_timer_register(struct twd_local_timer *tlt) | ||
322 | { | ||
323 | if (twd_base || twd_evt) | ||
324 | return -EBUSY; | ||
325 | |||
326 | twd_ppi = tlt->res[1].start; | ||
327 | |||
328 | twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0])); | ||
329 | if (!twd_base) | ||
330 | return -ENOMEM; | ||
331 | |||
332 | return twd_local_timer_common_register(); | ||
333 | } | ||
334 | |||
335 | #ifdef CONFIG_OF | ||
336 | const static struct of_device_id twd_of_match[] __initconst = { | ||
337 | { .compatible = "arm,cortex-a9-twd-timer", }, | ||
338 | { .compatible = "arm,cortex-a5-twd-timer", }, | ||
339 | { .compatible = "arm,arm11mp-twd-timer", }, | ||
340 | { }, | ||
341 | }; | ||
342 | |||
343 | void __init twd_local_timer_of_register(void) | ||
344 | { | ||
345 | struct device_node *np; | ||
346 | int err; | ||
347 | |||
348 | np = of_find_matching_node(NULL, twd_of_match); | ||
349 | if (!np) { | ||
350 | err = -ENODEV; | ||
351 | goto out; | ||
352 | } | ||
353 | |||
354 | twd_ppi = irq_of_parse_and_map(np, 0); | ||
355 | if (!twd_ppi) { | ||
356 | err = -EINVAL; | ||
357 | goto out; | ||
358 | } | ||
359 | |||
360 | twd_base = of_iomap(np, 0); | ||
361 | if (!twd_base) { | ||
362 | err = -ENOMEM; | ||
363 | goto out; | ||
364 | } | ||
365 | |||
366 | err = twd_local_timer_common_register(); | ||
367 | |||
368 | out: | ||
369 | WARN(err, "twd_local_timer_of_register failed (%d)\n", err); | ||
370 | } | ||
371 | #endif | ||