| From: Benedikt Spranger <b.spranger@linutronix.de> |
| Date: Sat, 6 Mar 2010 17:47:10 +0100 |
| Subject: ARM: AT91: PIT: Remove irq handler when clock event is unused |
| |
| Setup and remove the interrupt handler in clock event mode selection. |
| This avoids calling the (shared) interrupt handler when the device is |
| not used. |
| |
| Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| [bigeasy: redo the patch with NR_IRQS_LEGACY which is probably required since |
| commit 8fe82a55 ("ARM: at91: sparse irq support") which is included since v3.6. |
| Patch based on what Sami Pietikรคinen <Sami.Pietikainen@wapice.com> suggested]. |
| Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| --- |
| drivers/clocksource/timer-atmel-pit.c | 18 +++++++++--------- |
| drivers/clocksource/timer-atmel-st.c | 34 ++++++++++++++++++++++------------ |
| 2 files changed, 31 insertions(+), 21 deletions(-) |
| |
| --- a/drivers/clocksource/timer-atmel-pit.c |
| +++ b/drivers/clocksource/timer-atmel-pit.c |
| @@ -96,15 +96,24 @@ static int pit_clkevt_shutdown(struct cl |
| |
| /* disable irq, leaving the clocksource active */ |
| pit_write(data->base, AT91_PIT_MR, (data->cycle - 1) | AT91_PIT_PITEN); |
| + free_irq(data->irq, data); |
| return 0; |
| } |
| |
| +static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id); |
| /* |
| * Clockevent device: interrupts every 1/HZ (== pit_cycles * MCK/16) |
| */ |
| static int pit_clkevt_set_periodic(struct clock_event_device *dev) |
| { |
| struct pit_data *data = clkevt_to_pit_data(dev); |
| + int ret; |
| + |
| + ret = request_irq(data->irq, at91sam926x_pit_interrupt, |
| + IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL, |
| + "at91_tick", data); |
| + if (ret) |
| + panic(pr_fmt("Unable to setup IRQ\n")); |
| |
| /* update clocksource counter */ |
| data->cnt += data->cycle * PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR)); |
| @@ -230,15 +239,6 @@ static int __init at91sam926x_pit_dt_ini |
| return ret; |
| } |
| |
| - /* Set up irq handler */ |
| - ret = request_irq(data->irq, at91sam926x_pit_interrupt, |
| - IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL, |
| - "at91_tick", data); |
| - if (ret) { |
| - pr_err("Unable to setup IRQ\n"); |
| - return ret; |
| - } |
| - |
| /* Set up and register clockevents */ |
| data->clkevt.name = "pit"; |
| data->clkevt.features = CLOCK_EVT_FEAT_PERIODIC; |
| --- a/drivers/clocksource/timer-atmel-st.c |
| +++ b/drivers/clocksource/timer-atmel-st.c |
| @@ -115,18 +115,29 @@ static void clkdev32k_disable_and_flush_ |
| last_crtr = read_CRTR(); |
| } |
| |
| +static int atmel_st_irq; |
| + |
| static int clkevt32k_shutdown(struct clock_event_device *evt) |
| { |
| clkdev32k_disable_and_flush_irq(); |
| irqmask = 0; |
| regmap_write(regmap_st, AT91_ST_IER, irqmask); |
| + free_irq(atmel_st_irq, regmap_st); |
| return 0; |
| } |
| |
| static int clkevt32k_set_oneshot(struct clock_event_device *dev) |
| { |
| + int ret; |
| + |
| clkdev32k_disable_and_flush_irq(); |
| |
| + ret = request_irq(atmel_st_irq, at91rm9200_timer_interrupt, |
| + IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL, |
| + "at91_tick", regmap_st); |
| + if (ret) |
| + panic(pr_fmt("Unable to setup IRQ\n")); |
| + |
| /* |
| * ALM for oneshot irqs, set by next_event() |
| * before 32 seconds have passed. |
| @@ -139,8 +150,16 @@ static int clkevt32k_set_oneshot(struct |
| |
| static int clkevt32k_set_periodic(struct clock_event_device *dev) |
| { |
| + int ret; |
| + |
| clkdev32k_disable_and_flush_irq(); |
| |
| + ret = request_irq(atmel_st_irq, at91rm9200_timer_interrupt, |
| + IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL, |
| + "at91_tick", regmap_st); |
| + if (ret) |
| + panic(pr_fmt("Unable to setup IRQ\n")); |
| + |
| /* PIT for periodic irqs; fixed rate of 1/HZ */ |
| irqmask = AT91_ST_PITS; |
| regmap_write(regmap_st, AT91_ST_PIMR, timer_latch); |
| @@ -198,7 +217,7 @@ static int __init atmel_st_timer_init(st |
| { |
| struct clk *sclk; |
| unsigned int sclk_rate, val; |
| - int irq, ret; |
| + int ret; |
| |
| regmap_st = syscon_node_to_regmap(node); |
| if (IS_ERR(regmap_st)) { |
| @@ -212,21 +231,12 @@ static int __init atmel_st_timer_init(st |
| regmap_read(regmap_st, AT91_ST_SR, &val); |
| |
| /* Get the interrupts property */ |
| - irq = irq_of_parse_and_map(node, 0); |
| - if (!irq) { |
| + atmel_st_irq = irq_of_parse_and_map(node, 0); |
| + if (!atmel_st_irq) { |
| pr_err("Unable to get IRQ from DT\n"); |
| return -EINVAL; |
| } |
| |
| - /* Make IRQs happen for the system timer */ |
| - ret = request_irq(irq, at91rm9200_timer_interrupt, |
| - IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL, |
| - "at91_tick", regmap_st); |
| - if (ret) { |
| - pr_err("Unable to setup IRQ\n"); |
| - return ret; |
| - } |
| - |
| sclk = of_clk_get(node, 0); |
| if (IS_ERR(sclk)) { |
| pr_err("Unable to get slow clock\n"); |