linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] Convert WM8350 to genirq
@ 2010-01-05 13:57 Mark Brown
  2010-01-05 13:59 ` [PATCH 1/4] mfd: WM8350 off by one bug Mark Brown
  0 siblings, 1 reply; 8+ messages in thread
From: Mark Brown @ 2010-01-05 13:57 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-kernel, Alessandro Zummo, rtc-linux

The following patch series converts the WM8350 driver to use genirq for
the interrupt controller on the chip.  It also includes a patch for the
RTC driver to handle the fact that genirq nests enables and disables.
Ideally this patch would go in via the MFD tree to avoid merge issues.

Since this collides with (and removes the need for) Dan Carpenter's
bounds checking change I've also included that in the series.

Dan Carpenter (1):
      mfd: WM8350 off by one bug

Mark Brown (3):
      mfd: Add a data argument to the WM8350 IRQ free function
      rtc: Suppress duplicate enable/disable of WM8350 update interrupt
      mfd: Convert WM8350 to genirq

 drivers/mfd/wm8350-irq.c             |  155 +++++++++++++++++++---------------
 drivers/power/wm8350_power.c         |   24 +++---
 drivers/regulator/wm8350-regulator.c |    2 +-
 drivers/rtc/rtc-wm8350.c             |   11 ++-
 include/linux/mfd/wm8350/core.h      |   45 +++++++---
 include/linux/mfd/wm8350/rtc.h       |    1 +
 sound/soc/codecs/wm8350.c            |    4 +-
 7 files changed, 144 insertions(+), 98 deletions(-)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/4] mfd: WM8350 off by one bug
  2010-01-05 13:57 [PATCH 0/4] Convert WM8350 to genirq Mark Brown
@ 2010-01-05 13:59 ` Mark Brown
  2010-01-05 13:59   ` [PATCH 2/4] mfd: Add a data argument to the WM8350 IRQ free function Mark Brown
  0 siblings, 1 reply; 8+ messages in thread
From: Mark Brown @ 2010-01-05 13:59 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-kernel, Dan Carpenter, Mark Brown

From: Dan Carpenter <error27@gmail.com>

If irq == WM8350_NUM_IRQ that would put us past the end of the array.

Signed-off-by: Dan Carpenter <error27@gmail.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/mfd/wm8350-irq.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c
index c8df547..9025f29 100644
--- a/drivers/mfd/wm8350-irq.c
+++ b/drivers/mfd/wm8350-irq.c
@@ -434,7 +434,7 @@ int wm8350_register_irq(struct wm8350 *wm8350, int irq,
 			irq_handler_t handler, unsigned long flags,
 			const char *name, void *data)
 {
-	if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
+	if (irq < 0 || irq >= WM8350_NUM_IRQ || !handler)
 		return -EINVAL;
 
 	if (wm8350->irq[irq].handler)
@@ -453,7 +453,7 @@ EXPORT_SYMBOL_GPL(wm8350_register_irq);
 
 int wm8350_free_irq(struct wm8350 *wm8350, int irq)
 {
-	if (irq < 0 || irq > WM8350_NUM_IRQ)
+	if (irq < 0 || irq >= WM8350_NUM_IRQ)
 		return -EINVAL;
 
 	wm8350_mask_irq(wm8350, irq);
-- 
1.6.5.7


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/4] mfd: Add a data argument to the WM8350 IRQ free function
  2010-01-05 13:59 ` [PATCH 1/4] mfd: WM8350 off by one bug Mark Brown
@ 2010-01-05 13:59   ` Mark Brown
  2010-01-05 13:59     ` [PATCH 3/4] rtc: Suppress duplicate enable/disable of WM8350 update interrupt Mark Brown
  0 siblings, 1 reply; 8+ messages in thread
From: Mark Brown @ 2010-01-05 13:59 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-kernel, Mark Brown

To better match genirq.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/mfd/wm8350-irq.c             |    2 +-
 drivers/power/wm8350_power.c         |   24 ++++++++++++------------
 drivers/regulator/wm8350-regulator.c |    2 +-
 drivers/rtc/rtc-wm8350.c             |    4 ++--
 include/linux/mfd/wm8350/core.h      |    3 ++-
 sound/soc/codecs/wm8350.c            |    4 ++--
 6 files changed, 20 insertions(+), 19 deletions(-)

diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c
index 9025f29..655836b 100644
--- a/drivers/mfd/wm8350-irq.c
+++ b/drivers/mfd/wm8350-irq.c
@@ -451,7 +451,7 @@ int wm8350_register_irq(struct wm8350 *wm8350, int irq,
 }
 EXPORT_SYMBOL_GPL(wm8350_register_irq);
 
-int wm8350_free_irq(struct wm8350 *wm8350, int irq)
+int wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data)
 {
 	if (irq < 0 || irq >= WM8350_NUM_IRQ)
 		return -EINVAL;
diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c
index ad4f071..3839a5e 100644
--- a/drivers/power/wm8350_power.c
+++ b/drivers/power/wm8350_power.c
@@ -428,18 +428,18 @@ static void wm8350_init_charger(struct wm8350 *wm8350)
 
 static void free_charger_irq(struct wm8350 *wm8350)
 {
-	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
-	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
-	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
-	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO);
-	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END);
-	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START);
-	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
-	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
-	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
-	wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
-	wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
-	wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350);
+	wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350);
+	wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350);
+	wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, wm8350);
 }
 
 static __devinit int wm8350_power_probe(struct platform_device *pdev)
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index 1bbff09..0764a0b 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -1407,7 +1407,7 @@ static int wm8350_regulator_remove(struct platform_device *pdev)
 	struct regulator_dev *rdev = platform_get_drvdata(pdev);
 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
 
-	wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq);
+	wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq, rdev);
 
 	regulator_unregister(rdev);
 
diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c
index f164866..a427491 100644
--- a/drivers/rtc/rtc-wm8350.c
+++ b/drivers/rtc/rtc-wm8350.c
@@ -476,8 +476,8 @@ static int __devexit wm8350_rtc_remove(struct platform_device *pdev)
 	struct wm8350 *wm8350 = platform_get_drvdata(pdev);
 	struct wm8350_rtc *wm_rtc = &wm8350->rtc;
 
-	wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC);
-	wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM);
+	wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC, wm8350);
+	wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM, wm8350);
 
 	rtc_device_unregister(wm_rtc->rtc);
 
diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h
index e115560..cfccb4a 100644
--- a/include/linux/mfd/wm8350/core.h
+++ b/include/linux/mfd/wm8350/core.h
@@ -682,7 +682,8 @@ int wm8350_block_write(struct wm8350 *wm8350, int reg, int size, u16 *src);
 int wm8350_register_irq(struct wm8350 *wm8350, int irq,
 			irq_handler_t handler, unsigned long flags,
 			const char *name, void *data);
-int wm8350_free_irq(struct wm8350 *wm8350, int irq);
+int wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data);
+
 int wm8350_mask_irq(struct wm8350 *wm8350, int irq);
 int wm8350_unmask_irq(struct wm8350 *wm8350, int irq);
 int wm8350_irq_init(struct wm8350 *wm8350, int irq,
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index ebbf11b..f45845a 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -1521,8 +1521,8 @@ static int wm8350_remove(struct platform_device *pdev)
 			  WM8350_JDL_ENA | WM8350_JDR_ENA);
 	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
 
-	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L);
-	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv);
 
 	priv->hpl.jack = NULL;
 	priv->hpr.jack = NULL;
-- 
1.6.5.7


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/4] rtc: Suppress duplicate enable/disable of WM8350 update interrupt
  2010-01-05 13:59   ` [PATCH 2/4] mfd: Add a data argument to the WM8350 IRQ free function Mark Brown
@ 2010-01-05 13:59     ` Mark Brown
  2010-01-05 13:59       ` [PATCH 4/4] mfd: Convert WM8350 to genirq Mark Brown
  2010-01-05 15:04       ` [PATCH 3/4] rtc: Suppress duplicate enable/disable of WM8350 update interrupt Alessandro Zummo
  0 siblings, 2 replies; 8+ messages in thread
From: Mark Brown @ 2010-01-05 13:59 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-kernel, Mark Brown, Alessandro Zummo, rtc-linux

Unlike the wm8350-custom code genirq nests enable and disable calls
so we can't just unconditionally mask or unmask the interrupt,
we need to remember the state we set and only mask or unmask when
there is a real change.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: rtc-linux@googlegroups.com
---
 drivers/rtc/rtc-wm8350.c       |    7 +++++++
 include/linux/mfd/wm8350/rtc.h |    1 +
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c
index a427491..ef376d7 100644
--- a/drivers/rtc/rtc-wm8350.c
+++ b/drivers/rtc/rtc-wm8350.c
@@ -307,11 +307,18 @@ static int wm8350_rtc_update_irq_enable(struct device *dev,
 {
 	struct wm8350 *wm8350 = dev_get_drvdata(dev);
 
+	/* Suppress duplicate changes since genirq nests enable and
+	 * disable calls. */
+	if (enabled == wm8350->rtc.update_enabled)
+		return 0;
+
 	if (enabled)
 		wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_SEC);
 	else
 		wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
 
+	wm8350->rtc.update_enabled = enabled;
+
 	return 0;
 }
 
diff --git a/include/linux/mfd/wm8350/rtc.h b/include/linux/mfd/wm8350/rtc.h
index 24add2b..ebd72ff 100644
--- a/include/linux/mfd/wm8350/rtc.h
+++ b/include/linux/mfd/wm8350/rtc.h
@@ -263,6 +263,7 @@ struct wm8350_rtc {
 	struct platform_device *pdev;
 	struct rtc_device *rtc;
 	int alarm_enabled;      /* used over suspend/resume */
+	int update_enabled;
 };
 
 #endif
-- 
1.6.5.7


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/4] mfd: Convert WM8350 to genirq
  2010-01-05 13:59     ` [PATCH 3/4] rtc: Suppress duplicate enable/disable of WM8350 update interrupt Mark Brown
@ 2010-01-05 13:59       ` Mark Brown
  2010-01-05 20:40         ` [PATCH 5/4] mfd: Don't allow WM8350 to be built modular Mark Brown
  2010-01-05 15:04       ` [PATCH 3/4] rtc: Suppress duplicate enable/disable of WM8350 update interrupt Alessandro Zummo
  1 sibling, 1 reply; 8+ messages in thread
From: Mark Brown @ 2010-01-05 13:59 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-kernel, Mark Brown

This gives us use of the diagnostic facilities genirq provides and
will allow implementation of interrupt support for the WM8350 GPIOs.
Stub functions are provided to ease the transition of the individual
drivers, probably after additional work to pass the IRQ numbers via
the struct devices.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/mfd/wm8350-irq.c        |  155 ++++++++++++++++++++++-----------------
 include/linux/mfd/wm8350/core.h |   44 ++++++++---
 2 files changed, 118 insertions(+), 81 deletions(-)

diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c
index 655836b..f56c9ad 100644
--- a/drivers/mfd/wm8350-irq.c
+++ b/drivers/mfd/wm8350-irq.c
@@ -18,7 +18,7 @@
 #include <linux/bug.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
-#include <linux/workqueue.h>
+#include <linux/irq.h>
 
 #include <linux/mfd/wm8350/core.h>
 #include <linux/mfd/wm8350/audio.h>
@@ -29,8 +29,6 @@
 #include <linux/mfd/wm8350/supply.h>
 #include <linux/mfd/wm8350/wdt.h>
 
-#define WM8350_NUM_IRQ_REGS 7
-
 #define WM8350_INT_OFFSET_1                     0
 #define WM8350_INT_OFFSET_2                     1
 #define WM8350_POWER_UP_INT_OFFSET              2
@@ -366,19 +364,10 @@ static struct wm8350_irq_data wm8350_irqs[] = {
 	},
 };
 
-static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
+static inline struct wm8350_irq_data *irq_to_wm8350_irq(struct wm8350 *wm8350,
+							int irq)
 {
-	mutex_lock(&wm8350->irq_mutex);
-
-	if (wm8350->irq[irq].handler)
-		wm8350->irq[irq].handler(irq, wm8350->irq[irq].data);
-	else {
-		dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n",
-			irq);
-		wm8350_mask_irq(wm8350, irq);
-	}
-
-	mutex_unlock(&wm8350->irq_mutex);
+	return &wm8350_irqs[irq - wm8350->irq_base];
 }
 
 /*
@@ -386,7 +375,9 @@ static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
  * interrupts are clear on read the IRQ line will be reasserted and
  * the physical IRQ will be handled again if another interrupt is
  * asserted while we run - in the normal course of events this is a
- * rare occurrence so we save I2C/SPI reads.
+ * rare occurrence so we save I2C/SPI reads.  We're also assuming that
+ * it's rare to get lots of interrupts firing simultaneously so try to
+ * minimise I/O.
  */
 static irqreturn_t wm8350_irq(int irq, void *irq_data)
 {
@@ -397,7 +388,6 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data)
 	struct wm8350_irq_data *data;
 	int i;
 
-	/* TODO: Use block reads to improve performance? */
 	level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
 		& ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
 
@@ -416,93 +406,101 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data)
 			sub_reg[data->reg] =
 				wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 +
 						data->reg);
-			sub_reg[data->reg] &=
-				~wm8350_reg_read(wm8350,
-						 WM8350_INT_STATUS_1_MASK +
-						 data->reg);
+			sub_reg[data->reg] &= ~wm8350->irq_masks[data->reg];
 			read_done[data->reg] = 1;
 		}
 
 		if (sub_reg[data->reg] & data->mask)
-			wm8350_irq_call_handler(wm8350, i);
+			handle_nested_irq(wm8350->irq_base + i);
 	}
 
 	return IRQ_HANDLED;
 }
 
-int wm8350_register_irq(struct wm8350 *wm8350, int irq,
-			irq_handler_t handler, unsigned long flags,
-			const char *name, void *data)
+static void wm8350_irq_lock(unsigned int irq)
 {
-	if (irq < 0 || irq >= WM8350_NUM_IRQ || !handler)
-		return -EINVAL;
-
-	if (wm8350->irq[irq].handler)
-		return -EBUSY;
-
-	mutex_lock(&wm8350->irq_mutex);
-	wm8350->irq[irq].handler = handler;
-	wm8350->irq[irq].data = data;
-	mutex_unlock(&wm8350->irq_mutex);
-
-	wm8350_unmask_irq(wm8350, irq);
+	struct wm8350 *wm8350 = get_irq_chip_data(irq);
 
-	return 0;
+	mutex_lock(&wm8350->irq_lock);
 }
-EXPORT_SYMBOL_GPL(wm8350_register_irq);
 
-int wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data)
+static void wm8350_irq_sync_unlock(unsigned int irq)
 {
-	if (irq < 0 || irq >= WM8350_NUM_IRQ)
-		return -EINVAL;
+	struct wm8350 *wm8350 = get_irq_chip_data(irq);
+	int i;
 
-	wm8350_mask_irq(wm8350, irq);
+	for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
+		/* If there's been a change in the mask write it back
+		 * to the hardware. */
+		if (wm8350->irq_masks[i] !=
+		    wm8350->reg_cache[WM8350_INT_STATUS_1_MASK + i])
+			WARN_ON(wm8350_reg_write(wm8350,
+					 WM8350_INT_STATUS_1_MASK + i,
+						 wm8350->irq_masks[i]));
+	}
 
-	mutex_lock(&wm8350->irq_mutex);
-	wm8350->irq[irq].handler = NULL;
-	mutex_unlock(&wm8350->irq_mutex);
-	return 0;
+	mutex_unlock(&wm8350->irq_lock);
 }
-EXPORT_SYMBOL_GPL(wm8350_free_irq);
 
-int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
+static void wm8350_irq_enable(unsigned int irq)
 {
-	return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK +
-			       wm8350_irqs[irq].reg,
-			       wm8350_irqs[irq].mask);
+	struct wm8350 *wm8350 = get_irq_chip_data(irq);
+	struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
+
+	wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask;
 }
-EXPORT_SYMBOL_GPL(wm8350_mask_irq);
 
-int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
+static void wm8350_irq_disable(unsigned int irq)
 {
-	return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK +
-				 wm8350_irqs[irq].reg,
-				 wm8350_irqs[irq].mask);
+	struct wm8350 *wm8350 = get_irq_chip_data(irq);
+	struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
+
+	wm8350->irq_masks[irq_data->reg] |= irq_data->mask;
 }
-EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
+
+static struct irq_chip wm8350_irq_chip = {
+	.name = "wm8350",
+	.bus_lock = wm8350_irq_lock,
+	.bus_sync_unlock = wm8350_irq_sync_unlock,
+	.disable = wm8350_irq_disable,
+	.enable = wm8350_irq_enable,
+};
 
 int wm8350_irq_init(struct wm8350 *wm8350, int irq,
 		    struct wm8350_platform_data *pdata)
 {
-	int ret;
+	int ret, cur_irq, i;
 	int flags = IRQF_ONESHOT;
 
 	if (!irq) {
-		dev_err(wm8350->dev, "No IRQ configured\n");
-		return -EINVAL;
+		dev_warn(wm8350->dev, "No interrupt support, no core IRQ\n");
+		return 0;
+	}
+
+	if (!pdata || !pdata->irq_base) {
+		dev_warn(wm8350->dev, "No interrupt support, no IRQ base\n");
+		return 0;
 	}
 
+	/* Mask top level interrupts */
 	wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
-	wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF);
-	wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF);
-	wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF);
-	wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF);
-	wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF);
 
-	mutex_init(&wm8350->irq_mutex);
+	/* Mask all individual interrupts by default and cache the
+	 * masks.  We read the masks back since there are unwritable
+	 * bits in the mask registers. */
+	for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
+		wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK + i,
+				 0xFFFF);
+		wm8350->irq_masks[i] =
+			wm8350_reg_read(wm8350,
+					WM8350_INT_STATUS_1_MASK + i);
+	}
+
+	mutex_init(&wm8350->irq_lock);
 	wm8350->chip_irq = irq;
+	wm8350->irq_base = pdata->irq_base;
 
-	if (pdata && pdata->irq_high) {
+	if (pdata->irq_high) {
 		flags |= IRQF_TRIGGER_HIGH;
 
 		wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
@@ -514,11 +512,32 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq,
 				  WM8350_IRQ_POL);
 	}
 
+	/* Register with genirq */
+	for (cur_irq = wm8350->irq_base;
+	     cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base;
+	     cur_irq++) {
+		set_irq_chip_data(cur_irq, wm8350);
+		set_irq_chip_and_handler(cur_irq, &wm8350_irq_chip,
+					 handle_edge_irq);
+		set_irq_nested_thread(cur_irq, 1);
+
+		/* ARM needs us to explicitly flag the IRQ as valid
+		 * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+		set_irq_flags(cur_irq, IRQF_VALID);
+#else
+		set_irq_noprobe(cur_irq);
+#endif
+	}
+
 	ret = request_threaded_irq(irq, NULL, wm8350_irq, flags,
 				   "wm8350", wm8350);
 	if (ret != 0)
 		dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret);
 
+	/* Allow interrupts to fire */
+	wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0);
+
 	return ret;
 }
 
diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h
index cfccb4a..fae08aa 100644
--- a/include/linux/mfd/wm8350/core.h
+++ b/include/linux/mfd/wm8350/core.h
@@ -579,6 +579,8 @@
 
 #define WM8350_NUM_IRQ				63
 
+#define WM8350_NUM_IRQ_REGS 7
+
 struct wm8350_reg_access {
 	u16 readable;		/* Mask of readable bits */
 	u16 writable;		/* Mask of writable bits */
@@ -600,11 +602,6 @@ extern const u16 wm8352_mode3_defaults[];
 
 struct wm8350;
 
-struct wm8350_irq {
-	irq_handler_t handler;
-	void *data;
-};
-
 struct wm8350_hwmon {
 	struct platform_device *pdev;
 	struct device *classdev;
@@ -626,9 +623,10 @@ struct wm8350 {
 	struct mutex auxadc_mutex;
 
 	/* Interrupt handling */
-	struct mutex irq_mutex; /* IRQ table mutex */
-	struct wm8350_irq irq[WM8350_NUM_IRQ];
+	struct mutex irq_lock;
 	int chip_irq;
+	int irq_base;
+	u16 irq_masks[WM8350_NUM_IRQ_REGS];
 
 	/* Client devices */
 	struct wm8350_codec codec;
@@ -679,13 +677,33 @@ int wm8350_block_write(struct wm8350 *wm8350, int reg, int size, u16 *src);
 /*
  * WM8350 internal interrupts
  */
-int wm8350_register_irq(struct wm8350 *wm8350, int irq,
-			irq_handler_t handler, unsigned long flags,
-			const char *name, void *data);
-int wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data);
+static inline int wm8350_register_irq(struct wm8350 *wm8350, int irq,
+				      irq_handler_t handler,
+				      unsigned long flags,
+				      const char *name, void *data)
+{
+	if (!wm8350->irq_base)
+		return -ENODEV;
+
+	return request_threaded_irq(irq + wm8350->irq_base, NULL,
+				    handler, flags, name, data);
+}
+
+static inline void wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data)
+{
+	free_irq(irq + wm8350->irq_base, data);
+}
+
+static inline void wm8350_mask_irq(struct wm8350 *wm8350, int irq)
+{
+	disable_irq(irq + wm8350->irq_base);
+}
+
+static inline void wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
+{
+	enable_irq(irq + wm8350->irq_base);
+}
 
-int wm8350_mask_irq(struct wm8350 *wm8350, int irq);
-int wm8350_unmask_irq(struct wm8350 *wm8350, int irq);
 int wm8350_irq_init(struct wm8350 *wm8350, int irq,
 		    struct wm8350_platform_data *pdata);
 int wm8350_irq_exit(struct wm8350 *wm8350);
-- 
1.6.5.7


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/4] rtc: Suppress duplicate enable/disable of WM8350 update interrupt
  2010-01-05 13:59     ` [PATCH 3/4] rtc: Suppress duplicate enable/disable of WM8350 update interrupt Mark Brown
  2010-01-05 13:59       ` [PATCH 4/4] mfd: Convert WM8350 to genirq Mark Brown
@ 2010-01-05 15:04       ` Alessandro Zummo
  1 sibling, 0 replies; 8+ messages in thread
From: Alessandro Zummo @ 2010-01-05 15:04 UTC (permalink / raw)
  To: Mark Brown; +Cc: Samuel Ortiz, linux-kernel, Mark Brown, rtc-linux, akpm

On Tue,  5 Jan 2010 13:59:08 +0000
Mark Brown <broonie@opensource.wolfsonmicro.com> wrote:

> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> Cc: Alessandro Zummo <a.zummo@towertech.it>
> Cc: rtc-linux@googlegroups.com


 Acked-by: Alessandro Zummo <a.zummo@towertech.it>

-- 

 Best regards,

 Alessandro Zummo,
  Tower Technologies - Torino, Italy

  http://www.towertech.it


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 5/4] mfd: Don't allow WM8350 to be built modular
  2010-01-05 13:59       ` [PATCH 4/4] mfd: Convert WM8350 to genirq Mark Brown
@ 2010-01-05 20:40         ` Mark Brown
  2010-01-06  8:56           ` Samuel Ortiz
  0 siblings, 1 reply; 8+ messages in thread
From: Mark Brown @ 2010-01-05 20:40 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-kernel, Mark Brown

The genirq implementation does not allow modules to implement irq_chips
so the conversion of WM8350 to genirq means we can no longer allow the
driver to be built as a module.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---

Sorry, I thought I'd sent a patch for this earlier but I appear to be
imagining things.

 drivers/mfd/Kconfig |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 8782978..1414cec 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -205,7 +205,7 @@ config MFD_WM831X
 	  functionality of the device.
 
 config MFD_WM8350
-	tristate
+	bool
 
 config MFD_WM8350_CONFIG_MODE_0
 	bool
@@ -256,9 +256,9 @@ config MFD_WM8352_CONFIG_MODE_3
 	depends on MFD_WM8350
 
 config MFD_WM8350_I2C
-	tristate "Support Wolfson Microelectronics WM8350 with I2C"
+	bool "Support Wolfson Microelectronics WM8350 with I2C"
 	select MFD_WM8350
-	depends on I2C
+	depends on I2C=y
 	help
 	  The WM8350 is an integrated audio and power management
 	  subsystem with watchdog and RTC functionality for embedded
-- 
1.6.5.7


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 5/4] mfd: Don't allow WM8350 to be built modular
  2010-01-05 20:40         ` [PATCH 5/4] mfd: Don't allow WM8350 to be built modular Mark Brown
@ 2010-01-06  8:56           ` Samuel Ortiz
  0 siblings, 0 replies; 8+ messages in thread
From: Samuel Ortiz @ 2010-01-06  8:56 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-kernel

Hi Mark,

On Tue, Jan 05, 2010 at 08:40:47PM +0000, Mark Brown wrote:
> The genirq implementation does not allow modules to implement irq_chips
> so the conversion of WM8350 to genirq means we can no longer allow the
> driver to be built as a module.
> 
> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> ---
> 
> Sorry, I thought I'd sent a patch for this earlier but I appear to be
> imagining things.
No problem, patch applied.

Cheers,
Samuel.

>  drivers/mfd/Kconfig |    6 +++---
>  1 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 8782978..1414cec 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -205,7 +205,7 @@ config MFD_WM831X
>  	  functionality of the device.
>  
>  config MFD_WM8350
> -	tristate
> +	bool
>  
>  config MFD_WM8350_CONFIG_MODE_0
>  	bool
> @@ -256,9 +256,9 @@ config MFD_WM8352_CONFIG_MODE_3
>  	depends on MFD_WM8350
>  
>  config MFD_WM8350_I2C
> -	tristate "Support Wolfson Microelectronics WM8350 with I2C"
> +	bool "Support Wolfson Microelectronics WM8350 with I2C"
>  	select MFD_WM8350
> -	depends on I2C
> +	depends on I2C=y
>  	help
>  	  The WM8350 is an integrated audio and power management
>  	  subsystem with watchdog and RTC functionality for embedded
> -- 
> 1.6.5.7
> 

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2010-01-06  8:54 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-01-05 13:57 [PATCH 0/4] Convert WM8350 to genirq Mark Brown
2010-01-05 13:59 ` [PATCH 1/4] mfd: WM8350 off by one bug Mark Brown
2010-01-05 13:59   ` [PATCH 2/4] mfd: Add a data argument to the WM8350 IRQ free function Mark Brown
2010-01-05 13:59     ` [PATCH 3/4] rtc: Suppress duplicate enable/disable of WM8350 update interrupt Mark Brown
2010-01-05 13:59       ` [PATCH 4/4] mfd: Convert WM8350 to genirq Mark Brown
2010-01-05 20:40         ` [PATCH 5/4] mfd: Don't allow WM8350 to be built modular Mark Brown
2010-01-06  8:56           ` Samuel Ortiz
2010-01-05 15:04       ` [PATCH 3/4] rtc: Suppress duplicate enable/disable of WM8350 update interrupt Alessandro Zummo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).