regmap: irq: Enable devices for runtime PM while handling interrupts
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Tue, 24 Jul 2012 14:41:19 +0000 (15:41 +0100)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Tue, 7 Aug 2012 19:29:45 +0000 (20:29 +0100)
Some devices need to have a runtime PM reference while handling interrupts
to ensure that the register I/O is available. Support this with a flag in
the chip.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
drivers/base/regmap/regmap-irq.c
include/linux/regmap.h

index 6f8f0c1..bb5e103 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/irqdomain.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
 #include "internal.h"
@@ -62,6 +63,13 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
        int i, ret;
        u32 reg;
 
+       if (d->chip->runtime_pm) {
+               ret = pm_runtime_get_sync(map->dev);
+               if (ret < 0)
+                       dev_err(map->dev, "IRQ sync failed to resume: %d\n",
+                               ret);
+       }
+
        /*
         * If there's been a change in the mask write it back to the
         * hardware.  We rely on the use of the regmap core cache to
@@ -77,6 +85,9 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                                reg);
        }
 
+       if (d->chip->runtime_pm)
+               pm_runtime_put(map->dev);
+
        /* If we've changed our wakeup count propagate it to the parent */
        if (d->wake_count < 0)
                for (i = d->wake_count; i < 0; i++)
@@ -147,6 +158,15 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
        bool handled = false;
        u32 reg;
 
+       if (chip->runtime_pm) {
+               ret = pm_runtime_get_sync(map->dev);
+               if (ret < 0) {
+                       dev_err(map->dev, "IRQ thread failed to resume: %d\n",
+                               ret);
+                       return IRQ_NONE;
+               }
+       }
+
        /*
         * Ignore masked IRQs and ack if we need to; we ack early so
         * there is no race between handling and acknowleding the
@@ -162,6 +182,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                if (ret != 0) {
                        dev_err(map->dev, "Failed to read IRQ status: %d\n",
                                        ret);
+                       if (chip->runtime_pm)
+                               pm_runtime_put(map->dev);
                        return IRQ_NONE;
                }
 
@@ -185,6 +207,9 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                }
        }
 
+       if (chip->runtime_pm)
+               pm_runtime_put(map->dev);
+
        if (handled)
                return IRQ_HANDLED;
        else
index 7f7e00d..9c4c9c6 100644 (file)
@@ -285,6 +285,7 @@ struct regmap_irq {
  * @ack_base:    Base ack address.  If zero then the chip is clear on read.
  * @wake_base:   Base address for wake enables.  If zero unsupported.
  * @irq_reg_stride:  Stride to use for chips where registers are not contiguous.
+ * @runtime_pm:  Hold a runtime PM lock on the device when accessing it.
  *
  * @num_regs:    Number of registers in each control bank.
  * @irqs:        Descriptors for individual IRQs.  Interrupt numbers are
@@ -299,6 +300,7 @@ struct regmap_irq_chip {
        unsigned int ack_base;
        unsigned int wake_base;
        unsigned int irq_reg_stride;
+       bool runtime_pm;
 
        int num_regs;