diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-07-24 15:41:19 +0100 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-08-07 20:29:45 +0100 |
commit | 0c00c50b41a9a6ee83eb16fb5c6c22e5115391b8 (patch) | |
tree | 12a30d730032a46fac0793fea2ba30ef900b4d4f | |
parent | 40052ca0c243d101cfadd65936f60ef81df10b02 (diff) | |
download | linux-0c00c50b41a9a6ee83eb16fb5c6c22e5115391b8.tar.bz2 |
regmap: irq: Enable devices for runtime PM while handling interrupts
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>
-rw-r--r-- | drivers/base/regmap/regmap-irq.c | 25 | ||||
-rw-r--r-- | include/linux/regmap.h | 2 |
2 files changed, 27 insertions, 0 deletions
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 6f8f0c1e550f..bb5e10305197 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -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 diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 7f7e00df3adf..9c4c9c673f38 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -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; |