diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2012-01-10 20:39:26 +0100 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2012-03-13 14:27:50 +0100 |
commit | 81e46f7b6dcec485bcb1f988ba4dc5b20189573c (patch) | |
tree | 13e8da9addc2c1428ae3ac308e5a9223efc29a8a /arch/arm/kernel/smp_twd.c | |
parent | ARM: local timers: introduce a new registration interface (diff) | |
download | linux-81e46f7b6dcec485bcb1f988ba4dc5b20189573c.tar.xz linux-81e46f7b6dcec485bcb1f988ba4dc5b20189573c.zip |
ARM: smp_twd: add runtime registration support
Add support for the new registration interface to smp_twd.
Platforms can populate a struct twd_local_timer with MMIO
and IRQ resources, and then call twd_local_timer_register()
to have the timer registered with the core.
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 | 51 |
1 files changed, 48 insertions, 3 deletions
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index b39916ad31c2..18c55f1e4e48 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -32,6 +32,7 @@ static struct clk *twd_clk; static unsigned long twd_timer_rate; static struct clock_event_device __percpu **twd_evt; +static int twd_ppi; static void twd_set_mode(enum clock_event_mode mode, struct clock_event_device *clk) @@ -227,7 +228,7 @@ static struct clk *twd_get_clock(void) /* * Setup the local clock events for a CPU. */ -void __cpuinit twd_timer_setup(struct clock_event_device *clk) +int __cpuinit twd_timer_setup(struct clock_event_device *clk) { struct clock_event_device **this_cpu_clk; @@ -237,7 +238,7 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) twd_evt = alloc_percpu(struct clock_event_device *); if (!twd_evt) { pr_err("twd: can't allocate memory\n"); - return; + return -ENOMEM; } err = request_percpu_irq(clk->irq, twd_handler, @@ -245,7 +246,7 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) if (err) { pr_err("twd: can't register interrupt %d (%d)\n", clk->irq, err); - return; + return err; } } @@ -265,6 +266,8 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) clk->rating = 350; clk->set_mode = twd_set_mode; clk->set_next_event = twd_set_next_event; + if (!clk->irq) + clk->irq = twd_ppi; this_cpu_clk = __this_cpu_ptr(twd_evt); *this_cpu_clk = clk; @@ -272,4 +275,46 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) clockevents_config_and_register(clk, twd_timer_rate, 0xf, 0xffffffff); enable_percpu_irq(clk->irq, 0); + + return 0; +} + +static struct local_timer_ops twd_lt_ops __cpuinitdata = { + .setup = twd_timer_setup, + .stop = twd_timer_stop, +}; + +int __init twd_local_timer_register(struct twd_local_timer *tlt) +{ + 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) { + err = -ENOMEM; + goto out; + } + + 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; + } + + err = local_timer_register(&twd_lt_ops); + if (err) + goto out; + + return 0; + +out: + iounmap(twd_base); + free_percpu(twd_evt); + twd_base = twd_evt = NULL; + return err; } |