aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2012-01-10 17:15:45 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2012-03-13 09:27:51 -0400
commitd8e0364364d333feb4564bb7d7d983182b34427e (patch)
treed79b09cf76a2a0852086b5b11e6f824d158f4cce /arch
parent81e46f7b6dcec485bcb1f988ba4dc5b20189573c (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')
-rw-r--r--arch/arm/include/asm/smp_twd.h8
-rw-r--r--arch/arm/kernel/smp_twd.c77
2 files changed, 72 insertions, 13 deletions
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
index 16c89b793f9..8047e6e580b 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -40,4 +40,12 @@ struct twd_local_timer name __initdata = { \
40 40
41int twd_local_timer_register(struct twd_local_timer *); 41int twd_local_timer_register(struct twd_local_timer *);
42 42
43#ifdef CONFIG_HAVE_ARM_TWD
44void twd_local_timer_of_register(void);
45#else
46static inline void twd_local_timer_of_register(void)
47{
48}
49#endif
50
43#endif 51#endif
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 18c55f1e4e4..761826c628b 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
287int __init twd_local_timer_register(struct twd_local_timer *tlt) 289static 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
315out: 311out_irq:
312 free_percpu_irq(twd_ppi, twd_evt);
313out_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
321int __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
336const 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
343void __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
368out:
369 WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
370}
371#endif