[PATCH RESEND v5 4/6] iio: accel: mma8452: Support interrupt sharing
From: Esben Haabendal
Date: Wed Aug 19 2026 - 04:16:51 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 | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 1fb43c5b0b72..25bb2dd69381 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,19 @@ 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 || READ_ONCE(data->suspended))
+ return IRQ_NONE; /* device is powered down or being removed */
+
src = i2c_smbus_read_byte_data(data->client, MMA8452_INT_SRC);
if (src < 0)
- return IRQ_NONE;
+ goto out;
if (!(src & (data->chip_info->enabled_events | MMA8452_INT_DRDY)))
- return IRQ_NONE;
+ goto out;
if (src & MMA8452_INT_DRDY) {
iio_trigger_poll_nested(indio_dev->trig);
@@ -1089,6 +1095,10 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
ret = IRQ_HANDLED;
}
+out:
+ if (pm_status > 0)
+ pm_runtime_put_autosuspend(&data->client->dev);
+
return ret;
}
@@ -1690,7 +1700,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)
@@ -1768,12 +1778,15 @@ static int mma8452_runtime_suspend(struct device *dev)
mutex_lock(&data->lock);
ret = mma8452_standby(data);
+ WRITE_ONCE(data->suspended, true);
mutex_unlock(&data->lock);
if (ret < 0) {
dev_err(&data->client->dev, "powering off device failed\n");
return -EAGAIN;
}
+ synchronize_irq(client->irq);
+
ret = regulator_disable(data->vddio_reg);
if (ret) {
dev_err(dev, "failed to disable VDDIO regulator\n");
@@ -1808,6 +1821,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 +1837,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