diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2012-01-10 23:15:45 +0100 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2012-03-13 14:27:51 +0100 |
commit | d8e0364364d333feb4564bb7d7d983182b34427e (patch) | |
tree | d79b09cf76a2a0852086b5b11e6f824d158f4cce /arch/arm/kernel/smp_twd.c | |
parent | ARM: smp_twd: add runtime registration support (diff) | |
download | linux-d8e0364364d333feb4564bb7d7d983182b34427e.tar.xz linux-d8e0364364d333feb4564bb7d7d983182b34427e.zip |
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/smp_twd.c')
-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 @@ #include <linux/clockchips.h> #include <linux/irq.h> #include <linux/io.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> #include <asm/smp_twd.h> #include <asm/localtimer.h> @@ -284,37 +286,86 @@ static struct local_timer_ops twd_lt_ops __cpuinitdata = { .stop = twd_timer_stop, }; -int __init twd_local_timer_register(struct twd_local_timer *tlt) +static int __init twd_local_timer_common_register(void) { int err; - if (twd_base || twd_evt) - return -EBUSY; - - twd_ppi = tlt->res[1].start; - twd_evt = alloc_percpu(struct clock_event_device *); - twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0])); - if (!twd_base || !twd_evt) { + if (!twd_evt) { err = -ENOMEM; - goto out; + goto out_free; } err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt); if (err) { pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err); - goto out; + goto out_free; } err = local_timer_register(&twd_lt_ops); if (err) - goto out; + goto out_irq; return 0; -out: +out_irq: + free_percpu_irq(twd_ppi, twd_evt); +out_free: iounmap(twd_base); + twd_base = NULL; free_percpu(twd_evt); - twd_base = twd_evt = NULL; + return err; } + +int __init twd_local_timer_register(struct twd_local_timer *tlt) +{ + if (twd_base || twd_evt) + return -EBUSY; + + twd_ppi = tlt->res[1].start; + + twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0])); + if (!twd_base) + return -ENOMEM; + + return twd_local_timer_common_register(); +} + +#ifdef CONFIG_OF +const static struct of_device_id twd_of_match[] __initconst = { + { .compatible = "arm,cortex-a9-twd-timer", }, + { .compatible = "arm,cortex-a5-twd-timer", }, + { .compatible = "arm,arm11mp-twd-timer", }, + { }, +}; + +void __init twd_local_timer_of_register(void) +{ + struct device_node *np; + int err; + + np = of_find_matching_node(NULL, twd_of_match); + if (!np) { + err = -ENODEV; + goto out; + } + + twd_ppi = irq_of_parse_and_map(np, 0); + if (!twd_ppi) { + err = -EINVAL; + goto out; + } + + twd_base = of_iomap(np, 0); + if (!twd_base) { + err = -ENOMEM; + goto out; + } + + err = twd_local_timer_common_register(); + +out: + WARN(err, "twd_local_timer_of_register failed (%d)\n", err); +} +#endif |