From 53820fd33815c343c219b8404119f8dc156894fc Mon Sep 17 00:00:00 2001
From: Benedikt Spranger <b.spranger@linutronix.de>
Date: Sat, 6 Mar 2010 17:47:10 +0100
Subject: [PATCH 126/518] ARM: AT91: PIT: Remove irq handler when clock event
 is unused
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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 | 19 +++++++--------
 drivers/clocksource/timer-atmel-st.c  | 34 +++++++++++++++++----------
 2 files changed, 31 insertions(+), 22 deletions(-)

diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c
index 2fab18fae4fcb..68c530354512d 100644
--- a/drivers/clocksource/timer-atmel-pit.c
+++ b/drivers/clocksource/timer-atmel-pit.c
@@ -96,15 +96,24 @@ static int pit_clkevt_shutdown(struct clock_event_device *dev)
 
 	/* 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));
@@ -233,16 +242,6 @@ static int __init at91sam926x_pit_dt_init(struct device_node *node)
 		goto exit;
 	}
 
-	/* 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");
-		clocksource_unregister(&data->clksrc);
-		goto exit;
-	}
-
 	/* Set up and register clockevents */
 	data->clkevt.name = "pit";
 	data->clkevt.features = CLOCK_EVT_FEAT_PERIODIC;
diff --git a/drivers/clocksource/timer-atmel-st.c b/drivers/clocksource/timer-atmel-st.c
index d2e660f475af6..c63b96cfc23ec 100644
--- a/drivers/clocksource/timer-atmel-st.c
+++ b/drivers/clocksource/timer-atmel-st.c
@@ -115,18 +115,29 @@ static void clkdev32k_disable_and_flush_irq(void)
 	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 clock_event_device *dev)
 
 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(struct device_node *node)
 {
 	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(struct device_node *node)
 	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");
-- 
2.41.0

