Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0c00c50b authored by Mark Brown's avatar Mark Brown
Browse files

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: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent 40052ca0
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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;