[PATCH v6 4/9] iio: accel: mma8452: Support interrupt sharing
From: Esben Haabendal
Date: Tue Aug 25 2026 - 04:48:00 EST
Adding handling of rutnime PM suspension in the interrupt handler allows
sharing interrupt with other devices.
Keep in mind that the device by default is using push-pull for the irq pin,
which might require additional hardware design to allow interrupt sharing.
The suspended flag is added together with synchronize_irq() in order to
protect against race conditions when doing runtime suspend and device
removal. This way we ensure that interrupt handler does not try to access
the device while regulators are disabled.
Signed-off-by: Esben Haabendal <esben@xxxxxxxxxx>
---
drivers/iio/accel/mma8452.c | 28 +++++++++++++++++++++++++---
1 file changed, 25 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 1fb43c5b0b72..8eb97e6793d6 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -119,6 +119,7 @@ struct mma8452_data {
int sleep_val;
u8 ctrl_reg1;
u8 data_cfg;
+ bool suspended;
};
/**
@@ -1056,14 +1057,24 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
struct iio_dev *indio_dev = p;
struct mma8452_data *data = iio_priv(indio_dev);
irqreturn_t ret = IRQ_NONE;
+ int pm_status;
int src;
+ pm_status = pm_runtime_get_if_active(&data->client->dev);
+ if (pm_status == 0)
+ return IRQ_NONE; /* device is powered down */
+ if (READ_ONCE(data->suspended)) {
+ /* device is being removed */
+ ret = IRQ_NONE;
+ goto out_runtime_put;
+ }
+
src = i2c_smbus_read_byte_data(data->client, MMA8452_INT_SRC);
if (src < 0)
- return IRQ_NONE;
+ goto out_runtime_put;
if (!(src & (data->chip_info->enabled_events | MMA8452_INT_DRDY)))
- return IRQ_NONE;
+ goto out_runtime_put;
if (src & MMA8452_INT_DRDY) {
iio_trigger_poll_nested(indio_dev->trig);
@@ -1089,6 +1100,10 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
ret = IRQ_HANDLED;
}
+out_runtime_put:
+ if (pm_status > 0)
+ pm_runtime_put_autosuspend(&data->client->dev);
+
return ret;
}
@@ -1690,7 +1705,7 @@ static int mma8452_probe(struct i2c_client *client)
dev_info(dev, "invalid irq type, setting default active low\n");
irq_flags = IRQF_TRIGGER_LOW;
}
- irq_flags |= IRQF_ONESHOT;
+ irq_flags |= IRQF_ONESHOT | IRQF_SHARED;
ret = request_threaded_irq(client->irq, NULL, mma8452_interrupt,
irq_flags, client->name, indio_dev);
if (ret)
@@ -1774,6 +1789,10 @@ static int mma8452_runtime_suspend(struct device *dev)
return -EAGAIN;
}
+ WRITE_ONCE(data->suspended, true);
+
+ synchronize_irq(client->irq);
+
ret = regulator_disable(data->vddio_reg);
if (ret) {
dev_err(dev, "failed to disable VDDIO regulator\n");
@@ -1808,6 +1827,8 @@ static int mma8452_runtime_resume(struct device *dev)
return ret;
}
+ WRITE_ONCE(data->suspended, false);
+
ret = mma8452_active(data);
if (ret < 0)
goto runtime_resume_failed;
@@ -1822,6 +1843,7 @@ static int mma8452_runtime_resume(struct device *dev)
return 0;
runtime_resume_failed:
+ WRITE_ONCE(data->suspended, true);
regulator_disable(data->vddio_reg);
regulator_disable(data->vdd_reg);
--
2.55.0