* [PATCH v10 01/10] dt-bindings: iio: accel: mma8452: Add drive-open-drain
2026-09-28 8:26 [PATCH v10 00/10] io: accel: mma8452: Allow open drain interrupt pin configuration Esben Haabendal
@ 2026-09-28 8:26 ` Esben Haabendal
2026-09-28 8:26 ` [PATCH v10 02/10] iio: accel: mma8452: Fix use-after-free bug in error error path Esben Haabendal
` (8 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Esben Haabendal @ 2026-09-28 8:26 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner
Cc: Esben Haabendal, linux-iio, devicetree, linux-kernel
Add new boolean to configure selected interrupt pin to open drain instead
of the default push-pull mode.
Acked-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
Documentation/devicetree/bindings/iio/accel/fsl,mma8452.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/accel/fsl,mma8452.yaml b/Documentation/devicetree/bindings/iio/accel/fsl,mma8452.yaml
index b0dd2b4e116a..20701aa725d0 100644
--- a/Documentation/devicetree/bindings/iio/accel/fsl,mma8452.yaml
+++ b/Documentation/devicetree/bindings/iio/accel/fsl,mma8452.yaml
@@ -39,6 +39,12 @@ properties:
minItems: 1
maxItems: 2
+ drive-open-drain:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: the interrupt line will be configured as open drain, which is
+ useful if several sensors share the same interrupt line. (This binding is
+ taken from pinctrl.)
+
vdd-supply: true
vddio-supply: true
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v10 02/10] iio: accel: mma8452: Fix use-after-free bug in error error path
2026-09-28 8:26 [PATCH v10 00/10] io: accel: mma8452: Allow open drain interrupt pin configuration Esben Haabendal
2026-09-28 8:26 ` [PATCH v10 01/10] dt-bindings: iio: accel: mma8452: Add drive-open-drain Esben Haabendal
@ 2026-09-28 8:26 ` Esben Haabendal
2026-09-28 8:26 ` [PATCH v10 03/10] iio: accel: mma8452: Fix runtime PM bugs in mma8452_read() Esben Haabendal
` (7 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Esben Haabendal @ 2026-09-28 8:26 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner
Cc: Esben Haabendal, linux-iio, devicetree, linux-kernel, stable,
Joshua Crofts
If mma8452_probe() fails in iio_device_register() or later, we could end up
with runtime suspend callback being called with a now freed device pointer.
Fixes: 96c0cb2bbfe0 ("iio: mma8452: add support for runtime power management")
Cc: stable@vger.kernel.org
Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
drivers/iio/accel/mma8452.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index fe62a903f0e2..a937cbd84f30 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -1681,7 +1681,7 @@ static int mma8452_probe(struct i2c_client *client)
ret = iio_device_register(indio_dev);
if (ret < 0)
- goto free_irq;
+ goto runtime_suspend;
ret = mma8452_set_freefall_mode(data, false);
if (ret < 0)
@@ -1692,6 +1692,10 @@ static int mma8452_probe(struct i2c_client *client)
unregister_device:
iio_device_unregister(indio_dev);
+runtime_suspend:
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+
free_irq:
if (client->irq)
free_irq(client->irq, indio_dev);
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v10 03/10] iio: accel: mma8452: Fix runtime PM bugs in mma8452_read()
2026-09-28 8:26 [PATCH v10 00/10] io: accel: mma8452: Allow open drain interrupt pin configuration Esben Haabendal
2026-09-28 8:26 ` [PATCH v10 01/10] dt-bindings: iio: accel: mma8452: Add drive-open-drain Esben Haabendal
2026-09-28 8:26 ` [PATCH v10 02/10] iio: accel: mma8452: Fix use-after-free bug in error error path Esben Haabendal
@ 2026-09-28 8:26 ` Esben Haabendal
2026-09-28 8:26 ` [PATCH v10 04/10] iio: accel: mma8452: Optimize struct mma8452_data member orders Esben Haabendal
` (6 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Esben Haabendal @ 2026-09-28 8:26 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner
Cc: Esben Haabendal, linux-iio, devicetree, linux-kernel, stable
When runtime PM support was added [1], the implementation in mma8452_read()
was done incorrectly, as it calls mma8452_drdy() before ensuring runtime pm
has set the device active, so it can cause read from STATUS register while
device is suspended/off. At the same time, the return value from
i2c_smbus_read_i2c_block_data() was discarded, and the function would
return the value returned from pm_runtime_put_autosuspend() instead.
When the latter bug described above was fixed [2], another bug was
introduced, as mma8452_read() would now leak the runtime PM reference
counter when i2c_smbus_read_i2c_block_data() failed.
This commit corrects this mess.
[1] commit 96c0cb2bbfe0 ("iio: mma8452: add support for runtime power management")
[2] commit 5bdff291d20c ("iio: accel: mma8452: handle I2C read error(s) in mma8452_read()")
Fixes: 96c0cb2bbfe0 ("iio: mma8452: add support for runtime power management")
Cc: stable@vger.kernel.org
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
drivers/iio/accel/mma8452.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index a937cbd84f30..a77c4b88b61d 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -242,21 +242,25 @@ static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on)
static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
{
- int ret = mma8452_drdy(data);
-
- if (ret < 0)
- return ret;
+ int ret;
ret = mma8452_set_runtime_pm_state(data->client, true);
if (ret)
return ret;
+ ret = mma8452_drdy(data);
+ if (ret < 0)
+ goto out_runtime_put;
+
ret = i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
3 * sizeof(__be16), (u8 *)buf);
if (ret < 0)
- return ret;
+ goto out_runtime_put;
+
+ return mma8452_set_runtime_pm_state(data->client, false);
- ret = mma8452_set_runtime_pm_state(data->client, false);
+out_runtime_put:
+ mma8452_set_runtime_pm_state(data->client, false);
return ret;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v10 04/10] iio: accel: mma8452: Optimize struct mma8452_data member orders
2026-09-28 8:26 [PATCH v10 00/10] io: accel: mma8452: Allow open drain interrupt pin configuration Esben Haabendal
` (2 preceding siblings ...)
2026-09-28 8:26 ` [PATCH v10 03/10] iio: accel: mma8452: Fix runtime PM bugs in mma8452_read() Esben Haabendal
@ 2026-09-28 8:26 ` Esben Haabendal
2026-09-28 8:26 ` [PATCH v10 05/10] iio: accel: mma8452: Only apply trigger type when not set by firmware Esben Haabendal
` (5 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Esben Haabendal @ 2026-09-28 8:26 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner
Cc: Esben Haabendal, linux-iio, devicetree, linux-kernel,
Joshua Crofts, Andy Shevchenko
Reorder struct mma8452_data members to avoid holes.
Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
drivers/iio/accel/mma8452.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index a77c4b88b61d..8d70fe89110c 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -108,10 +108,7 @@ struct mma8452_data {
struct i2c_client *client;
struct mutex lock;
struct iio_mount_matrix orientation;
- u8 ctrl_reg1;
- u8 data_cfg;
const struct mma_chip_info *chip_info;
- int sleep_val;
struct regulator_bulk_data regs[2];
/* Ensure correct alignment of time stamp when present */
@@ -119,6 +116,10 @@ struct mma8452_data {
__be16 channels[3];
aligned_s64 ts;
} buffer;
+
+ int sleep_val;
+ u8 ctrl_reg1;
+ u8 data_cfg;
};
/**
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v10 05/10] iio: accel: mma8452: Only apply trigger type when not set by firmware
2026-09-28 8:26 [PATCH v10 00/10] io: accel: mma8452: Allow open drain interrupt pin configuration Esben Haabendal
` (3 preceding siblings ...)
2026-09-28 8:26 ` [PATCH v10 04/10] iio: accel: mma8452: Optimize struct mma8452_data member orders Esben Haabendal
@ 2026-09-28 8:26 ` Esben Haabendal
2026-09-28 8:36 ` sashiko-bot
2026-09-28 8:26 ` [PATCH v10 06/10] iio: accel: mma8452: Fix unintended comment indent Esben Haabendal
` (4 subsequent siblings)
9 siblings, 1 reply; 17+ messages in thread
From: Esben Haabendal @ 2026-09-28 8:26 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner
Cc: Esben Haabendal, linux-iio, devicetree, linux-kernel,
Andy Shevchenko
Instead of unconditionally overriding the trigger type, it is better to
only apply a default when no trigger type is set by firmware. This should
be reasonably backward compatible, and should only potentially cause
problems if systems exist where firmware specifies an incorrect trigger
type. With a bit of luck, there are no such systems.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
drivers/iio/accel/mma8452.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 8d70fe89110c..72b4ab32775a 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -1669,9 +1669,16 @@ static int mma8452_probe(struct i2c_client *client)
goto trigger_cleanup;
if (client->irq) {
+ unsigned long irq_flags;
+
+ irq_flags = irq_get_trigger_type(client->irq);
+ if (irq_flags == IRQ_TYPE_NONE) {
+ dev_info(dev, "invalid irq type, setting default active low\n");
+ irq_flags = IRQF_TRIGGER_LOW;
+ }
+ irq_flags |= IRQF_ONESHOT;
ret = request_threaded_irq(client->irq, NULL, mma8452_interrupt,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- client->name, indio_dev);
+ irq_flags, client->name, indio_dev);
if (ret)
goto buffer_cleanup;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH v10 05/10] iio: accel: mma8452: Only apply trigger type when not set by firmware
2026-09-28 8:26 ` [PATCH v10 05/10] iio: accel: mma8452: Only apply trigger type when not set by firmware Esben Haabendal
@ 2026-09-28 8:36 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-09-28 8:36 UTC (permalink / raw)
To: Esben Haabendal; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] iio: accel: mma8452: IRQ storm due to unconfigured hardware interrupt polarity
--
commit 24f5b1347bb4e1832201e80435a781ee363c54e3
Author: Esben Haabendal <esben@geanix.com>
iio: accel: mma8452: Only apply trigger type when not set by firmware
This commit changes the mma8452 probe function to read the IRQ trigger type
from the firmware instead of unconditionally forcing it to active-low. It
falls back to active-low if the firmware does not specify a type.
> diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
> index 8d70fe89110cd..72b4ab32775a6 100644
> --- a/drivers/iio/accel/mma8452.c
> +++ b/drivers/iio/accel/mma8452.c
> @@ -1669,9 +1669,16 @@ static int mma8452_probe(struct i2c_client *client)
> goto trigger_cleanup;
>
> if (client->irq) {
> + unsigned long irq_flags;
> +
> + irq_flags = irq_get_trigger_type(client->irq);
> + if (irq_flags == IRQ_TYPE_NONE) {
> + dev_info(dev, "invalid irq type, setting default active low\n");
> + irq_flags = IRQF_TRIGGER_LOW;
> + }
> + irq_flags |= IRQF_ONESHOT;
> ret = request_threaded_irq(client->irq, NULL, mma8452_interrupt,
> - IRQF_TRIGGER_LOW | IRQF_ONESHOT,
> - client->name, indio_dev);
> + irq_flags, client->name, indio_dev);
[Severity: High]
Does this risk an IRQ storm if the firmware specifies an active-high trigger?
By dynamically applying the firmware's IRQ trigger type to the host interrupt
controller, the host configuration might no longer match the hardware default.
If the firmware requests an active-high interrupt, the host interrupt
controller will be configured for it here. However, the driver does not appear
to write to the MMA8452 sensor's CTRL_REG3 register to set the IPOL bit. This
leaves the sensor's physical output polarity at its active-low default.
For a level-triggered interrupt, this mismatch would cause the interrupt line
to constantly fire. Since the interrupt handler returns IRQ_NONE when no events
are pending, could this result in an infinite loop?
> if (ret)
> goto buffer_cleanup;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260928-mma8452-open-drain-v10-0-b906fb408386@geanix.com?part=5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v10 06/10] iio: accel: mma8452: Fix unintended comment indent
2026-09-28 8:26 [PATCH v10 00/10] io: accel: mma8452: Allow open drain interrupt pin configuration Esben Haabendal
` (4 preceding siblings ...)
2026-09-28 8:26 ` [PATCH v10 05/10] iio: accel: mma8452: Only apply trigger type when not set by firmware Esben Haabendal
@ 2026-09-28 8:26 ` Esben Haabendal
2026-09-28 8:26 ` [PATCH v10 07/10] iio: accel: mma8452: Add comment block for struct mma8452_data Esben Haabendal
` (3 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Esben Haabendal @ 2026-09-28 8:26 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner
Cc: Esben Haabendal, linux-iio, devicetree, linux-kernel,
Joshua Crofts
The extra space this block was indented with looks quite untraditional, and
does not align with the common style used in the kernel.
Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
drivers/iio/accel/mma8452.c | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 72b4ab32775a..b70bc8638128 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -122,21 +122,21 @@ struct mma8452_data {
u8 data_cfg;
};
- /**
- * struct mma8452_event_regs - chip specific data related to events
- * @ev_cfg: event config register address
- * @ev_cfg_ele: latch bit in event config register
- * @ev_cfg_chan_shift: number of the bit to enable events in X
- * direction; in event config register
- * @ev_src: event source register address
- * @ev_ths: event threshold register address
- * @ev_ths_mask: mask for the threshold value
- * @ev_count: event count (period) register address
- *
- * Since not all chips supported by the driver support comparing high pass
- * filtered data for events (interrupts), different interrupt sources are
- * used for different chips and the relevant registers are included here.
- */
+/**
+ * struct mma8452_event_regs - chip specific data related to events
+ * @ev_cfg: event config register address
+ * @ev_cfg_ele: latch bit in event config register
+ * @ev_cfg_chan_shift: number of the bit to enable events in X
+ * direction; in event config register
+ * @ev_src: event source register address
+ * @ev_ths: event threshold register address
+ * @ev_ths_mask: mask for the threshold value
+ * @ev_count: event count (period) register address
+ *
+ * Since not all chips supported by the driver support comparing high pass
+ * filtered data for events (interrupts), different interrupt sources are
+ * used for different chips and the relevant registers are included here.
+ */
struct mma8452_event_regs {
u8 ev_cfg;
u8 ev_cfg_ele;
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v10 07/10] iio: accel: mma8452: Add comment block for struct mma8452_data
2026-09-28 8:26 [PATCH v10 00/10] io: accel: mma8452: Allow open drain interrupt pin configuration Esben Haabendal
` (5 preceding siblings ...)
2026-09-28 8:26 ` [PATCH v10 06/10] iio: accel: mma8452: Fix unintended comment indent Esben Haabendal
@ 2026-09-28 8:26 ` Esben Haabendal
2026-09-28 8:26 ` [PATCH v10 08/10] iio: accel: mma8452: Allow open drain interrupt pin configuration Esben Haabendal
` (2 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Esben Haabendal @ 2026-09-28 8:26 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner
Cc: Esben Haabendal, linux-iio, devicetree, linux-kernel,
Joshua Crofts
The struct mma8452_data is central for this driver, and it makes sense to
have a description of the fields in it to make it easier to work with the
driver.
Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
drivers/iio/accel/mma8452.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index b70bc8638128..0c6ca6640f72 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -104,6 +104,21 @@
#define MMA8452_AUTO_SUSPEND_DELAY_MS 2000
+/**
+ * struct mma8452_data - IIO device private data structure
+ * @client: the I2C client object
+ * @lock: mutex for synchronization of register
+ * read-modify-write sequences and holding chip in
+ * STANDBY mode while writing to registers
+ * @orientation: mounting matrix, flipped axis etc.
+ * @chip_info: chip specific data
+ * @regs: reference to voltage regulators
+ * @buffer: triggered buffer
+ * @sleep_val: time in ms to sleep while waiting for drdy
+ * @ctrl_reg1: CTRL_REG1 register shadow value
+ * @data_cfg: DATA_CFG register shadow value
+ * @open_drain: true for irq pin in open-drain mode
+ */
struct mma8452_data {
struct i2c_client *client;
struct mutex lock;
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v10 08/10] iio: accel: mma8452: Allow open drain interrupt pin configuration
2026-09-28 8:26 [PATCH v10 00/10] io: accel: mma8452: Allow open drain interrupt pin configuration Esben Haabendal
` (6 preceding siblings ...)
2026-09-28 8:26 ` [PATCH v10 07/10] iio: accel: mma8452: Add comment block for struct mma8452_data Esben Haabendal
@ 2026-09-28 8:26 ` Esben Haabendal
2026-09-28 8:26 ` [PATCH v10 09/10] iio: accel: mma8452: Use proper error code when missing device model Esben Haabendal
2026-09-28 8:26 ` [PATCH v10 10/10] iio: accel: mma8452: Support interrupt sharing Esben Haabendal
9 siblings, 0 replies; 17+ messages in thread
From: Esben Haabendal @ 2026-09-28 8:26 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner
Cc: Esben Haabendal, linux-iio, devicetree, linux-kernel,
Andy Shevchenko
When designing systems sharing the interrupt for mma8452 chips, it is
helpful to be able to configure the irq pin in open-drain mode (default is
push-pull).
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
drivers/iio/accel/mma8452.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 0c6ca6640f72..0b48aded2230 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -83,6 +83,8 @@
#define MMA8452_CTRL_REG2_RST BIT(6)
#define MMA8452_CTRL_REG2_MODS_SHIFT 3
#define MMA8452_CTRL_REG2_MODS_MASK 0x1b
+#define MMA8452_CTRL_REG3 0x2c
+#define MMA8452_CTRL_REG3_PP_OD BIT(0)
#define MMA8452_CTRL_REG4 0x2d
#define MMA8452_CTRL_REG5 0x2e
#define MMA8452_OFF_X 0x2f
@@ -135,6 +137,7 @@ struct mma8452_data {
int sleep_val;
u8 ctrl_reg1;
u8 data_cfg;
+ bool open_drain;
};
/**
@@ -662,6 +665,22 @@ static int mma8452_set_power_mode(struct mma8452_data *data, u8 mode)
return mma8452_change_config(data, MMA8452_CTRL_REG2, reg);
}
+static int mma8452_set_interrupt_pin_mode(struct mma8452_data *data)
+{
+ int reg;
+
+ reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG3);
+ if (reg < 0)
+ return reg;
+
+ if (data->open_drain)
+ reg |= MMA8452_CTRL_REG3_PP_OD;
+ else
+ reg &= ~MMA8452_CTRL_REG3_PP_OD;
+
+ return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG3, reg);
+}
+
/* returns >0 if in freefall mode, 0 if not or <0 if an error occurred */
static int mma8452_freefall_mode_enabled(struct mma8452_data *data)
{
@@ -1668,6 +1687,11 @@ static int mma8452_probe(struct i2c_client *client)
goto disable_regulators;
}
+ data->open_drain = device_property_read_bool(dev, "drive-open-drain");
+ ret = mma8452_set_interrupt_pin_mode(data);
+ if (ret)
+ goto trigger_cleanup;
+
data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
@@ -1795,6 +1819,10 @@ static int mma8452_runtime_resume(struct device *dev)
return ret;
}
+ ret = mma8452_set_interrupt_pin_mode(data);
+ if (ret)
+ goto runtime_resume_failed;
+
ret = mma8452_active(data);
if (ret < 0)
goto runtime_resume_failed;
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v10 09/10] iio: accel: mma8452: Use proper error code when missing device model
2026-09-28 8:26 [PATCH v10 00/10] io: accel: mma8452: Allow open drain interrupt pin configuration Esben Haabendal
` (7 preceding siblings ...)
2026-09-28 8:26 ` [PATCH v10 08/10] iio: accel: mma8452: Allow open drain interrupt pin configuration Esben Haabendal
@ 2026-09-28 8:26 ` Esben Haabendal
2026-09-28 8:26 ` [PATCH v10 10/10] iio: accel: mma8452: Support interrupt sharing Esben Haabendal
9 siblings, 0 replies; 17+ messages in thread
From: Esben Haabendal @ 2026-09-28 8:26 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner
Cc: Esben Haabendal, linux-iio, devicetree, linux-kernel,
Joshua Crofts, Andy Shevchenko
Switch -ENODEV error on i2c_get_match_data() failure to -ENODATA to
satisfy the IIO coding style.
Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
drivers/iio/accel/mma8452.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 0b48aded2230..dc8031e14c29 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -1594,7 +1594,7 @@ static int mma8452_probe(struct i2c_client *client)
data->chip_info = i2c_get_match_data(client);
if (!data->chip_info)
- return dev_err_probe(dev, -ENODEV, "unknown device model\n");
+ return dev_err_probe(dev, -ENODATA, "unknown device model\n");
ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v10 10/10] iio: accel: mma8452: Support interrupt sharing
2026-09-28 8:26 [PATCH v10 00/10] io: accel: mma8452: Allow open drain interrupt pin configuration Esben Haabendal
` (8 preceding siblings ...)
2026-09-28 8:26 ` [PATCH v10 09/10] iio: accel: mma8452: Use proper error code when missing device model Esben Haabendal
@ 2026-09-28 8:26 ` Esben Haabendal
2026-09-28 8:43 ` sashiko-bot
2026-09-28 9:26 ` Andy Shevchenko
9 siblings, 2 replies; 17+ messages in thread
From: Esben Haabendal @ 2026-09-28 8:26 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner
Cc: Esben Haabendal, linux-iio, devicetree, linux-kernel
Adding support for sharing interrupt line with other device requires the
interrupt handler to handle runtime PM suspension properly, ignoring the
irq if the device is suspended (maybe even off). And while at it, we use
the PM reference to ensure we do not get suspended while processing an irq.
In order to prevent the chip from raising irq while suspended (that is when
using fixed regulator, where suspend just means setting the device in
STANDBY mode), we disable all interrupt sources by clearing CTRL_REG4, and
then restores the value again when resuming.
The scoped_guard in mma8452_runtime_suspend() is changed to a plain
mutex_lock() instead, both to prevent mixing guards and goto, but also to
ensure that we stay in STANDBY mode while writing to CTRL_REG4 and all the
way up to disabling the device as much as possible.
With that in place, it is safe to add the IRQF_SHARED flag.
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.
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
drivers/iio/accel/mma8452.c | 120 ++++++++++++++++++++++++++++++++++----------
1 file changed, 93 insertions(+), 27 deletions(-)
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index dc8031e14c29..f05dd936b7f3 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -119,6 +119,7 @@
* @sleep_val: time in ms to sleep while waiting for drdy
* @ctrl_reg1: CTRL_REG1 register shadow value
* @data_cfg: DATA_CFG register shadow value
+ * @ctrl_reg4: CTRL_REG4 register value to restore on resume
* @open_drain: true for irq pin in open-drain mode
*/
struct mma8452_data {
@@ -137,6 +138,7 @@ struct mma8452_data {
int sleep_val;
u8 ctrl_reg1;
u8 data_cfg;
+ u8 ctrl_reg4;
bool open_drain;
};
@@ -1086,15 +1088,32 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
{
struct iio_dev *indio_dev = p;
struct mma8452_data *data = iio_priv(indio_dev);
+ struct device *dev = &data->client->dev;
irqreturn_t ret = IRQ_NONE;
+ int pm_status;
int src;
+ pm_status = pm_runtime_get_if_active(dev);
+ if (pm_status == 0)
+ /* device is powered down */
+ return IRQ_NONE;
+ if (IS_ENABLED(CONFIG_PM) && pm_status < 0)
+ /* runtime PM was disabled, possibly suspending */
+ return IRQ_HANDLED;
+
+ /*
+ * pm_status is now 1 or -EINVAL (with CONFIG_PM not enabled). If
+ * pm_status==1, runtime PM is enabled and device is RPM_ACTIVE. If
+ * pm_status==-EINVAL, runtime PM is build-time disabled (i.e. CONFIG_PM
+ * not enabled), and we can/must assume device is active.
+ */
+
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);
@@ -1120,6 +1139,10 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
ret = IRQ_HANDLED;
}
+out_runtime_put:
+ if (pm_status > 0)
+ pm_runtime_put_autosuspend(dev);
+
return ret;
}
@@ -1707,6 +1730,14 @@ static int mma8452_probe(struct i2c_client *client)
if (ret < 0)
goto trigger_cleanup;
+ ret = pm_runtime_set_active(dev);
+ if (ret < 0)
+ goto buffer_cleanup;
+
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, MMA8452_AUTO_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
+
if (client->irq) {
unsigned long irq_flags;
@@ -1715,24 +1746,16 @@ 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)
- goto buffer_cleanup;
+ goto runtime_suspend;
}
- ret = pm_runtime_set_active(dev);
- if (ret < 0)
- goto free_irq;
-
- pm_runtime_enable(dev);
- pm_runtime_set_autosuspend_delay(dev, MMA8452_AUTO_SUSPEND_DELAY_MS);
- pm_runtime_use_autosuspend(dev);
-
ret = iio_device_register(indio_dev);
if (ret < 0)
- goto runtime_suspend;
+ goto free_irq;
ret = mma8452_set_freefall_mode(data, false);
if (ret < 0)
@@ -1743,14 +1766,14 @@ static int mma8452_probe(struct i2c_client *client)
unregister_device:
iio_device_unregister(indio_dev);
-runtime_suspend:
- pm_runtime_disable(dev);
- pm_runtime_set_suspended(dev);
-
free_irq:
if (client->irq)
free_irq(client->irq, indio_dev);
+runtime_suspend:
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+
buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
@@ -1771,11 +1794,12 @@ static void mma8452_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
- pm_runtime_disable(dev);
- pm_runtime_set_suspended(dev);
-
if (client->irq)
free_irq(client->irq, indio_dev);
+ /* No irq will fire beyond this point */
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
iio_triggered_buffer_cleanup(indio_dev);
mma8452_trigger_cleanup(indio_dev);
@@ -1787,29 +1811,67 @@ static void mma8452_remove(struct i2c_client *client)
#ifdef CONFIG_PM
static int mma8452_runtime_suspend(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct i2c_client *client = to_i2c_client(dev);
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct mma8452_data *data = iio_priv(indio_dev);
int ret;
- scoped_guard(mutex, &data->lock)
- ret = mma8452_standby(data);
+ mutex_lock(&data->lock);
+
+ ret = mma8452_standby(data);
+ if (ret < 0) {
+ dev_err(dev, "transition to STANDBY mode failed\n");
+ ret = -EAGAIN;
+ goto out_unlock;
+ }
+
+ ret = i2c_smbus_read_byte_data(client, MMA8452_CTRL_REG4);
if (ret < 0) {
- dev_err(dev, "powering off device failed\n");
- return -EAGAIN;
+ dev_warn(dev, "backing up CTRL_REG4 failed\n");
+ ret = -EAGAIN;
+ goto out_active;
+ } else
+ data->ctrl_reg4 = ret;
+
+ ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG4, 0);
+ if (ret) {
+ dev_warn(dev, "disabling interrupt sources (CTRL_REG4) failed\n");
+ ret = -EAGAIN;
+ goto out_active;
}
+ /*
+ * Interrupt line should be deasserted now, so we just need ensure any
+ * mid-flight irq is completed (will return IRQ_NONE due to
+ * pm_status==0).
+ */
+ if (client->irq)
+ synchronize_irq(client->irq);
+
ret = regulator_bulk_disable(ARRAY_SIZE(data->regs), data->regs);
if (ret) {
dev_err(dev, "failed to disable regulators\n");
- return ret;
+ goto out_restore_ctrl_reg4;
}
+ mutex_unlock(&data->lock);
return 0;
+
+out_restore_ctrl_reg4:
+ if (i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG4, data->ctrl_reg4))
+ dev_warn(dev, "restoring CTRL_REG4 failed\n");
+out_active:
+ if (mma8452_active(data))
+ dev_warn(dev, "failed to switch back to ACTIVE mode\n");
+out_unlock:
+ mutex_unlock(&data->lock);
+ return ret;
}
static int mma8452_runtime_resume(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct i2c_client *client = to_i2c_client(dev);
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct mma8452_data *data = iio_priv(indio_dev);
int ret, sleep_val;
@@ -1823,6 +1885,10 @@ static int mma8452_runtime_resume(struct device *dev)
if (ret)
goto runtime_resume_failed;
+ ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG4, data->ctrl_reg4);
+ if (ret)
+ goto runtime_resume_failed;
+
ret = mma8452_active(data);
if (ret < 0)
goto runtime_resume_failed;
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH v10 10/10] iio: accel: mma8452: Support interrupt sharing
2026-09-28 8:26 ` [PATCH v10 10/10] iio: accel: mma8452: Support interrupt sharing Esben Haabendal
@ 2026-09-28 8:43 ` sashiko-bot
2026-09-28 9:26 ` Andy Shevchenko
1 sibling, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-09-28 8:43 UTC (permalink / raw)
To: Esben Haabendal; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] iio: mma8452: interrupt storm during runtime resume and suspend
- [Medium] iio: mma8452: unbalanced regulator disable on removal when runtime suspended
--
commit f941a16ef4ad24cff1f76a14b03513af5d8ea4cd
Author: Esben Haabendal <esben@geanix.com>
iio: accel: mma8452: Support interrupt sharing
Adding support for sharing interrupt line with other device requires the
interrupt handler to handle runtime PM suspension properly, ignoring the
irq if the device is suspended (maybe even off).
> diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
> index dc8031e14c292..f05dd936b7f37 100644
> --- a/drivers/iio/accel/mma8452.c
> +++ b/drivers/iio/accel/mma8452.c
> @@ -1086,15 +1088,32 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
> {
> struct iio_dev *indio_dev = p;
> struct mma8452_data *data = iio_priv(indio_dev);
> + struct device *dev = &data->client->dev;
> irqreturn_t ret = IRQ_NONE;
> + int pm_status;
> int src;
>
> + pm_status = pm_runtime_get_if_active(dev);
> + if (pm_status == 0)
> + /* device is powered down */
> + return IRQ_NONE;
> + if (IS_ENABLED(CONFIG_PM) && pm_status < 0)
> + /* runtime PM was disabled, possibly suspending */
> + return IRQ_HANDLED;
[Severity: High]
Does returning IRQ_NONE here without clearing the hardware interrupt source
risk causing an interrupt storm?
The driver registers a threaded IRQ handler with IRQF_ONESHOT | IRQF_SHARED.
If an interrupt fires while pm_status is 0, returning IRQ_NONE without
clearing the interrupt means the core will unmask the still-asserted line,
causing an immediate refire and potentially an infinite interrupt storm that
hangs the CPU.
Additionally, doesn't returning IRQ_HANDLED when pm_status < 0 incorrectly
claim shared interrupts raised by other devices, hiding them from the
spurious interrupt detector?
[ ... ]
> @@ -1787,29 +1811,67 @@ static void mma8452_remove(struct i2c_client *client)
> #ifdef CONFIG_PM
> static int mma8452_runtime_suspend(struct device *dev)
> {
[ ... ]
> + ret = regulator_bulk_disable(ARRAY_SIZE(data->regs), data->regs);
> if (ret) {
> dev_err(dev, "failed to disable regulators\n");
> - return ret;
> + goto out_restore_ctrl_reg4;
> }
[Severity: Medium]
Since regulator_bulk_disable() is now called here during runtime suspend,
does this cause unbalanced regulator disables in mma8452_remove()?
In mma8452_remove(), the driver unconditionally calls mma8452_standby() and
regulator_bulk_disable() without checking the runtime PM state or waking up
the device (e.g. via pm_runtime_get_sync()).
If the device was already runtime suspended on removal, its regulators are
off. Calling mma8452_standby() performs an I2C write to an unpowered chip,
resulting in an I2C error, and calling regulator_bulk_disable() a second time
drops the regulator usage count below zero, triggering a kernel warning.
[ ... ]
> @@ -1823,6 +1885,10 @@ static int mma8452_runtime_resume(struct device *dev)
> if (ret)
> goto runtime_resume_failed;
>
> + ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG4, data->ctrl_reg4);
> + if (ret)
> + goto runtime_resume_failed;
> +
> ret = mma8452_active(data);
> if (ret < 0)
> goto runtime_resume_failed;
[Severity: High]
Does re-enabling hardware interrupts here risk an interrupt storm?
During mma8452_runtime_resume(), the device state is RPM_RESUMING, so
pm_runtime_get_if_active() inside mma8452_interrupt() will return 0.
If an interrupt fires after writing to MMA8452_CTRL_REG4 and before the
resume completes (for example, during the sleep later in this function), the
interrupt handler will return IRQ_NONE without clearing it. As mentioned
above, this can lead to an infinite interrupt storm.
A similar issue appears to exist during mma8452_runtime_suspend() before
CTRL_REG4 is disabled, since the state is RPM_SUSPENDING.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260928-mma8452-open-drain-v10-0-b906fb408386@geanix.com?part=10
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v10 10/10] iio: accel: mma8452: Support interrupt sharing
2026-09-28 8:26 ` [PATCH v10 10/10] iio: accel: mma8452: Support interrupt sharing Esben Haabendal
2026-09-28 8:43 ` sashiko-bot
@ 2026-09-28 9:26 ` Andy Shevchenko
2026-09-28 10:15 ` Esben Haabendal
2026-09-28 10:27 ` Joshua Crofts
1 sibling, 2 replies; 17+ messages in thread
From: Andy Shevchenko @ 2026-09-28 9:26 UTC (permalink / raw)
To: Esben Haabendal
Cc: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner, linux-iio, devicetree,
linux-kernel
On Mon, Sep 28, 2026 at 10:26:26AM +0200, Esben Haabendal wrote:
> Adding support for sharing interrupt line with other device requires the
> interrupt handler to handle runtime PM suspension properly, ignoring the
> irq if the device is suspended (maybe even off). And while at it, we use
> the PM reference to ensure we do not get suspended while processing an irq.
>
> In order to prevent the chip from raising irq while suspended (that is when
> using fixed regulator, where suspend just means setting the device in
> STANDBY mode), we disable all interrupt sources by clearing CTRL_REG4, and
> then restores the value again when resuming.
>
> The scoped_guard in mma8452_runtime_suspend() is changed to a plain
> mutex_lock() instead, both to prevent mixing guards and goto, but also to
> ensure that we stay in STANDBY mode while writing to CTRL_REG4 and all the
> way up to disabling the device as much as possible.
>
> With that in place, it is safe to add the IRQF_SHARED flag.
>
> 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.
...
> + pm_status = pm_runtime_get_if_active(dev);
> + if (pm_status == 0)
> + /* device is powered down */
> + return IRQ_NONE;
> + if (IS_ENABLED(CONFIG_PM) && pm_status < 0)
> + /* runtime PM was disabled, possibly suspending */
> + return IRQ_HANDLED;
This is very interesting part. I bet this will be the first driver using this.
A big question "why?"
> + /*
> + * pm_status is now 1 or -EINVAL (with CONFIG_PM not enabled). If
> + * pm_status==1, runtime PM is enabled and device is RPM_ACTIVE. If
> + * pm_status==-EINVAL, runtime PM is build-time disabled (i.e. CONFIG_PM
> + * not enabled), and we can/must assume device is active.
> + */
> +
> 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);
> @@ -1120,6 +1139,10 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
> ret = IRQ_HANDLED;
> }
>
> +out_runtime_put:
> + if (pm_status > 0)
> + pm_runtime_put_autosuspend(dev);
> +
> return ret;
> }
...
> + pm_runtime_enable(dev);
> + pm_runtime_set_autosuspend_delay(dev, MMA8452_AUTO_SUSPEND_DELAY_MS);
> + pm_runtime_use_autosuspend(dev);
I don't see the respective _dont_use_autosuspend() call anywhere.
...
I am wondering how many of the above possible scenarios you were able to test.
...
P.S. I bet you can now make a presentation "PM runtime in Linux and
why it is so hard."
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v10 10/10] iio: accel: mma8452: Support interrupt sharing
2026-09-28 9:26 ` Andy Shevchenko
@ 2026-09-28 10:15 ` Esben Haabendal
2026-09-28 10:17 ` Esben Haabendal
2026-09-28 10:27 ` Joshua Crofts
1 sibling, 1 reply; 17+ messages in thread
From: Esben Haabendal @ 2026-09-28 10:15 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner, linux-iio, devicetree,
linux-kernel
"Andy Shevchenko" <andriy.shevchenko@intel.com> writes:
> On Mon, Sep 28, 2026 at 10:26:26AM +0200, Esben Haabendal wrote:
>> Adding support for sharing interrupt line with other device requires the
>> interrupt handler to handle runtime PM suspension properly, ignoring the
>> irq if the device is suspended (maybe even off). And while at it, we use
>> the PM reference to ensure we do not get suspended while processing an irq.
>>
>> In order to prevent the chip from raising irq while suspended (that is when
>> using fixed regulator, where suspend just means setting the device in
>> STANDBY mode), we disable all interrupt sources by clearing CTRL_REG4, and
>> then restores the value again when resuming.
>>
>> The scoped_guard in mma8452_runtime_suspend() is changed to a plain
>> mutex_lock() instead, both to prevent mixing guards and goto, but also to
>> ensure that we stay in STANDBY mode while writing to CTRL_REG4 and all the
>> way up to disabling the device as much as possible.
>>
>> With that in place, it is safe to add the IRQF_SHARED flag.
>>
>> 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.
>
> ...
>
>> + pm_status = pm_runtime_get_if_active(dev);
>> + if (pm_status == 0)
>> + /* device is powered down */
>> + return IRQ_NONE;
>
>> + if (IS_ENABLED(CONFIG_PM) && pm_status < 0)
>> + /* runtime PM was disabled, possibly suspending */
>> + return IRQ_HANDLED;
>
> This is very interesting part. I bet this will be the first driver using this.
> A big question "why?"
Because as I understood it, I needed to add this for the patch to be
accepted [1]. It is definitely possible that I have misunderstood that.
The technical reason I believe is that during system suspend,
pm_runtime_force_suspend() disabled runtime PM, and if a shared
interrupt durings this, pm_runtime_get_if_active returns -EINVAL, and we
could therefore end up doing I2C reads on unpowered hardware.
Per that reasoning, we probably should be doing this in other drivers as
well.
>> + /*
>> + * pm_status is now 1 or -EINVAL (with CONFIG_PM not enabled). If
>> + * pm_status==1, runtime PM is enabled and device is RPM_ACTIVE. If
>> + * pm_status==-EINVAL, runtime PM is build-time disabled (i.e. CONFIG_PM
>> + * not enabled), and we can/must assume device is active.
>> + */
>> +
>> 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);
>> @@ -1120,6 +1139,10 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
>> ret = IRQ_HANDLED;
>> }
>>
>> +out_runtime_put:
>> + if (pm_status > 0)
>> + pm_runtime_put_autosuspend(dev);
>> +
>> return ret;
>> }
>
> ...
>
>> + pm_runtime_enable(dev);
>> + pm_runtime_set_autosuspend_delay(dev, MMA8452_AUTO_SUSPEND_DELAY_MS);
>> + pm_runtime_use_autosuspend(dev);
>
> I don't see the respective _dont_use_autosuspend() call anywhere.
Ah. I was not aware it was attached to a usage counter as well. I will
add a pm_runtime_dont_use_autosuspend() to the runtime_suspend: error handling.
> ...
>
> I am wondering how many of the above possible scenarios you were able
> to test.
Not enough. I haven't done any additional instrumentation to cause all
the various error conditions that is handled here in _probe().
> ...
>
> P.S. I bet you can now make a presentation "PM runtime in Linux and
> why it is so hard."
LOL. I am getting there, yes. I have definitely learned a lot about how
runtime PM works. Especially since I was mostly starting from scratch on
that.
But i fear it would easily end up being quite a chaotic presentation :)
/Esben
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v10 10/10] iio: accel: mma8452: Support interrupt sharing
2026-09-28 10:15 ` Esben Haabendal
@ 2026-09-28 10:17 ` Esben Haabendal
0 siblings, 0 replies; 17+ messages in thread
From: Esben Haabendal @ 2026-09-28 10:17 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner, linux-iio, devicetree,
linux-kernel
"Esben Haabendal" <esben@geanix.com> writes:
> "Andy Shevchenko" <andriy.shevchenko@intel.com> writes:
>
>> On Mon, Sep 28, 2026 at 10:26:26AM +0200, Esben Haabendal wrote:
>>> Adding support for sharing interrupt line with other device requires the
>>> interrupt handler to handle runtime PM suspension properly, ignoring the
>>> irq if the device is suspended (maybe even off). And while at it, we use
>>> the PM reference to ensure we do not get suspended while processing an irq.
>>>
>>> In order to prevent the chip from raising irq while suspended (that is when
>>> using fixed regulator, where suspend just means setting the device in
>>> STANDBY mode), we disable all interrupt sources by clearing CTRL_REG4, and
>>> then restores the value again when resuming.
>>>
>>> The scoped_guard in mma8452_runtime_suspend() is changed to a plain
>>> mutex_lock() instead, both to prevent mixing guards and goto, but also to
>>> ensure that we stay in STANDBY mode while writing to CTRL_REG4 and all the
>>> way up to disabling the device as much as possible.
>>>
>>> With that in place, it is safe to add the IRQF_SHARED flag.
>>>
>>> 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.
>>
>> ...
>>
>>> + pm_status = pm_runtime_get_if_active(dev);
>>> + if (pm_status == 0)
>>> + /* device is powered down */
>>> + return IRQ_NONE;
>>
>>> + if (IS_ENABLED(CONFIG_PM) && pm_status < 0)
>>> + /* runtime PM was disabled, possibly suspending */
>>> + return IRQ_HANDLED;
>>
>> This is very interesting part. I bet this will be the first driver using this.
>> A big question "why?"
>
> Because as I understood it, I needed to add this for the patch to be
> accepted [1]. It is definitely possible that I have misunderstood that.
Sorry, forgot to add the reference.
[1] https://lore.kernel.org/all/20260921015115.4c7d79f3@jic23-hlaptop/
>
> The technical reason I believe is that during system suspend,
> pm_runtime_force_suspend() disabled runtime PM, and if a shared
> interrupt durings this, pm_runtime_get_if_active returns -EINVAL, and we
> could therefore end up doing I2C reads on unpowered hardware.
>
> Per that reasoning, we probably should be doing this in other drivers as
> well.
>
>>> + /*
>>> + * pm_status is now 1 or -EINVAL (with CONFIG_PM not enabled). If
>>> + * pm_status==1, runtime PM is enabled and device is RPM_ACTIVE. If
>>> + * pm_status==-EINVAL, runtime PM is build-time disabled (i.e. CONFIG_PM
>>> + * not enabled), and we can/must assume device is active.
>>> + */
>>> +
>>> 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);
>>> @@ -1120,6 +1139,10 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
>>> ret = IRQ_HANDLED;
>>> }
>>>
>>> +out_runtime_put:
>>> + if (pm_status > 0)
>>> + pm_runtime_put_autosuspend(dev);
>>> +
>>> return ret;
>>> }
>>
>> ...
>>
>>> + pm_runtime_enable(dev);
>>> + pm_runtime_set_autosuspend_delay(dev, MMA8452_AUTO_SUSPEND_DELAY_MS);
>>> + pm_runtime_use_autosuspend(dev);
>>
>> I don't see the respective _dont_use_autosuspend() call anywhere.
>
> Ah. I was not aware it was attached to a usage counter as well. I will
> add a pm_runtime_dont_use_autosuspend() to the runtime_suspend: error handling.
>
>> ...
>>
>> I am wondering how many of the above possible scenarios you were able
>> to test.
>
> Not enough. I haven't done any additional instrumentation to cause all
> the various error conditions that is handled here in _probe().
>
>> ...
>>
>> P.S. I bet you can now make a presentation "PM runtime in Linux and
>> why it is so hard."
>
> LOL. I am getting there, yes. I have definitely learned a lot about how
> runtime PM works. Especially since I was mostly starting from scratch on
> that.
>
> But i fear it would easily end up being quite a chaotic presentation :)
>
> /Esben
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v10 10/10] iio: accel: mma8452: Support interrupt sharing
2026-09-28 9:26 ` Andy Shevchenko
2026-09-28 10:15 ` Esben Haabendal
@ 2026-09-28 10:27 ` Joshua Crofts
1 sibling, 0 replies; 17+ messages in thread
From: Joshua Crofts @ 2026-09-28 10:27 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Esben Haabendal, Jonathan Cameron, Lars-Peter Clausen,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Martin Kepplinger,
Sean Nyekjaer, David Lechner, Nuno Sá, Andy Shevchenko,
Martin Kepplinger, Christoph Muellner, linux-iio, devicetree,
linux-kernel
On Mon, 28 Sep 2026 12:26:12 +0300
Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> On Mon, Sep 28, 2026 at 10:26:26AM +0200, Esben Haabendal wrote:
> > Adding support for sharing interrupt line with other device requires the
> > interrupt handler to handle runtime PM suspension properly, ignoring the
> > irq if the device is suspended (maybe even off). And while at it, we use
> > the PM reference to ensure we do not get suspended while processing an irq.
> >
> > In order to prevent the chip from raising irq while suspended (that is when
> > using fixed regulator, where suspend just means setting the device in
> > STANDBY mode), we disable all interrupt sources by clearing CTRL_REG4, and
> > then restores the value again when resuming.
> >
> > The scoped_guard in mma8452_runtime_suspend() is changed to a plain
> > mutex_lock() instead, both to prevent mixing guards and goto, but also to
> > ensure that we stay in STANDBY mode while writing to CTRL_REG4 and all the
> > way up to disabling the device as much as possible.
> >
> > With that in place, it is safe to add the IRQF_SHARED flag.
> >
> > 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.
>
> ...
>
> > + pm_status = pm_runtime_get_if_active(dev);
> > + if (pm_status == 0)
> > + /* device is powered down */
> > + return IRQ_NONE;
>
> > + if (IS_ENABLED(CONFIG_PM) && pm_status < 0)
> > + /* runtime PM was disabled, possibly suspending */
> > + return IRQ_HANDLED;
>
> This is very interesting part. I bet this will be the first driver using this.
> A big question "why?"
>
> > + /*
> > + * pm_status is now 1 or -EINVAL (with CONFIG_PM not enabled). If
> > + * pm_status==1, runtime PM is enabled and device is RPM_ACTIVE. If
> > + * pm_status==-EINVAL, runtime PM is build-time disabled (i.e. CONFIG_PM
> > + * not enabled), and we can/must assume device is active.
> > + */
> > +
> > 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);
> > @@ -1120,6 +1139,10 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
> > ret = IRQ_HANDLED;
> > }
> >
> > +out_runtime_put:
> > + if (pm_status > 0)
> > + pm_runtime_put_autosuspend(dev);
> > +
> > return ret;
> > }
>
> ...
>
> > + pm_runtime_enable(dev);
> > + pm_runtime_set_autosuspend_delay(dev, MMA8452_AUTO_SUSPEND_DELAY_MS);
> > + pm_runtime_use_autosuspend(dev);
>
> I don't see the respective _dont_use_autosuspend() call anywhere.
FWIW, starting Linux 7.4 you won't need to add _dont_use_autosuspend()
calls, driver core will just handle it on unbind [1].
If anyone would like to join me in purging the kernel of redundant
dont_use_autosuspend() calls once the patch hits mainline, feel free
to do so :)
[1] https://lore.kernel.org/all/20260919-move-dont-use-autosuspend-v1-1-f6e2d1315c23@gmail.com/
--
Kind regards,
Joshua Crofts
^ permalink raw reply [flat|nested] 17+ messages in thread