* [PATCH v2 1/2] iio: gyro: mpu3050: Split data ready trigger enable/disable into helpers
2026-11-01 9:23 ` [PATCH v2 0/2] " laixiangwu
@ 2026-11-01 9:23 ` laixiangwu
2026-11-01 9:23 ` [PATCH v2 2/2] iio: gyro: mpu3050: Fix runtime PM refcount leak in trigger enable path laixiangwu
1 sibling, 0 replies; 6+ messages in thread
From: laixiangwu @ 2026-11-01 9:23 UTC (permalink / raw)
To: jic23, linusw, linux-iio
Cc: linux-kernel, andy, dlechner, nuno.sa, laixiangwu
mpu3050_drdy_trigger_set_state() implements both the enable and the
disable path of the data ready trigger in the two legs of a large
if/else statement.
Split the two legs out into separate mpu3050_drdy_trigger_enable()
and mpu3050_drdy_trigger_disable() helpers and reduce
mpu3050_drdy_trigger_set_state() to dispatching to the appropriate
one. This is a pure code move with no functional change, done to make
the error handling of the enable path easier to read.
Signed-off-by: laixiangwu <laixiangwu@cmss.chinamobile.com>
---
drivers/iio/gyro/mpu3050-core.c | 173 ++++++++++++++++++--------------
1 file changed, 99 insertions(+), 74 deletions(-)
diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c
index 07c0f9011..d966911ab 100644
--- a/drivers/iio/gyro/mpu3050-core.c
+++ b/drivers/iio/gyro/mpu3050-core.c
@@ -946,103 +946,128 @@ static irqreturn_t mpu3050_irq_thread(int irq, void *p)
}
/**
- * mpu3050_drdy_trigger_set_state() - set data ready interrupt state
- * @trig: trigger instance
- * @enable: true if trigger should be enabled, false to disable
+ * mpu3050_drdy_trigger_enable() - enable the data ready trigger
+ * @mpu3050: device to configure
+ *
+ * Power up the device, enable the FIFO and configure the data ready
+ * interrupt.
*/
-static int mpu3050_drdy_trigger_set_state(struct iio_trigger *trig,
- bool enable)
+static int mpu3050_drdy_trigger_enable(struct mpu3050 *mpu3050)
{
- struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
- struct mpu3050 *mpu3050 = iio_priv(indio_dev);
unsigned int val;
int ret;
- /* Disabling trigger: disable interrupt and return */
- if (!enable) {
- /* Disable all interrupts */
- ret = regmap_write(mpu3050->map,
- MPU3050_INT_CFG,
- 0);
- if (ret)
- dev_err(mpu3050->dev, "error disabling IRQ\n");
+ pm_runtime_get_sync(mpu3050->dev);
+ mpu3050->hw_irq_trigger = true;
- /* Clear IRQ flag */
- ret = regmap_read(mpu3050->map, MPU3050_INT_STATUS, &val);
- if (ret)
- dev_err(mpu3050->dev, "error clearing IRQ status\n");
+ /* Disable all things in the FIFO */
+ ret = regmap_write(mpu3050->map, MPU3050_FIFO_EN, 0);
+ if (ret)
+ return ret;
- /* Disable all things in the FIFO and reset it */
- ret = regmap_write(mpu3050->map, MPU3050_FIFO_EN, 0);
- if (ret)
- dev_err(mpu3050->dev, "error disabling FIFO\n");
+ /* Reset and enable the FIFO */
+ ret = regmap_set_bits(mpu3050->map, MPU3050_USR_CTRL,
+ MPU3050_USR_CTRL_FIFO_EN |
+ MPU3050_USR_CTRL_FIFO_RST);
+ if (ret)
+ return ret;
- ret = regmap_write(mpu3050->map, MPU3050_USR_CTRL,
- MPU3050_USR_CTRL_FIFO_RST);
- if (ret)
- dev_err(mpu3050->dev, "error resetting FIFO\n");
+ mpu3050->pending_fifo_footer = false;
- pm_runtime_put_autosuspend(mpu3050->dev);
- mpu3050->hw_irq_trigger = false;
+ /* Turn on the FIFO for temp+X+Y+Z */
+ ret = regmap_write(mpu3050->map, MPU3050_FIFO_EN,
+ MPU3050_FIFO_EN_TEMP_OUT |
+ MPU3050_FIFO_EN_GYRO_XOUT |
+ MPU3050_FIFO_EN_GYRO_YOUT |
+ MPU3050_FIFO_EN_GYRO_ZOUT |
+ MPU3050_FIFO_EN_FOOTER);
+ if (ret)
+ return ret;
- return 0;
- } else {
- /* Else we're enabling the trigger from this point */
- pm_runtime_get_sync(mpu3050->dev);
- mpu3050->hw_irq_trigger = true;
+ /* Configure the sample engine */
+ ret = mpu3050_start_sampling(mpu3050);
+ if (ret)
+ return ret;
- /* Disable all things in the FIFO */
- ret = regmap_write(mpu3050->map, MPU3050_FIFO_EN, 0);
- if (ret)
- return ret;
+ /* Clear IRQ flag */
+ ret = regmap_read(mpu3050->map, MPU3050_INT_STATUS, &val);
+ if (ret)
+ dev_err(mpu3050->dev, "error clearing IRQ status\n");
- /* Reset and enable the FIFO */
- ret = regmap_set_bits(mpu3050->map, MPU3050_USR_CTRL,
- MPU3050_USR_CTRL_FIFO_EN |
- MPU3050_USR_CTRL_FIFO_RST);
- if (ret)
- return ret;
+ /* Give us interrupts whenever there is new data ready */
+ val = MPU3050_INT_RAW_RDY_EN;
- mpu3050->pending_fifo_footer = false;
+ if (mpu3050->irq_actl)
+ val |= MPU3050_INT_ACTL;
+ if (mpu3050->irq_latch)
+ val |= MPU3050_INT_LATCH_EN;
+ if (mpu3050->irq_opendrain)
+ val |= MPU3050_INT_OPEN;
- /* Turn on the FIFO for temp+X+Y+Z */
- ret = regmap_write(mpu3050->map, MPU3050_FIFO_EN,
- MPU3050_FIFO_EN_TEMP_OUT |
- MPU3050_FIFO_EN_GYRO_XOUT |
- MPU3050_FIFO_EN_GYRO_YOUT |
- MPU3050_FIFO_EN_GYRO_ZOUT |
- MPU3050_FIFO_EN_FOOTER);
- if (ret)
- return ret;
+ ret = regmap_write(mpu3050->map, MPU3050_INT_CFG, val);
+ if (ret)
+ return ret;
- /* Configure the sample engine */
- ret = mpu3050_start_sampling(mpu3050);
- if (ret)
- return ret;
+ return 0;
+}
- /* Clear IRQ flag */
- ret = regmap_read(mpu3050->map, MPU3050_INT_STATUS, &val);
- if (ret)
- dev_err(mpu3050->dev, "error clearing IRQ status\n");
+/**
+ * mpu3050_drdy_trigger_disable() - disable the data ready trigger
+ * @mpu3050: device to configure
+ *
+ * Disable the data ready interrupt, flush the FIFO and drop the
+ * runtime PM reference taken in mpu3050_drdy_trigger_enable().
+ */
+static int mpu3050_drdy_trigger_disable(struct mpu3050 *mpu3050)
+{
+ unsigned int val;
+ int ret;
- /* Give us interrupts whenever there is new data ready */
- val = MPU3050_INT_RAW_RDY_EN;
+ /* Disable all interrupts */
+ ret = regmap_write(mpu3050->map,
+ MPU3050_INT_CFG,
+ 0);
+ if (ret)
+ dev_err(mpu3050->dev, "error disabling IRQ\n");
- if (mpu3050->irq_actl)
- val |= MPU3050_INT_ACTL;
- if (mpu3050->irq_latch)
- val |= MPU3050_INT_LATCH_EN;
- if (mpu3050->irq_opendrain)
- val |= MPU3050_INT_OPEN;
+ /* Clear IRQ flag */
+ ret = regmap_read(mpu3050->map, MPU3050_INT_STATUS, &val);
+ if (ret)
+ dev_err(mpu3050->dev, "error clearing IRQ status\n");
- ret = regmap_write(mpu3050->map, MPU3050_INT_CFG, val);
- if (ret)
- return ret;
- }
+ /* Disable all things in the FIFO and reset it */
+ ret = regmap_write(mpu3050->map, MPU3050_FIFO_EN, 0);
+ if (ret)
+ dev_err(mpu3050->dev, "error disabling FIFO\n");
+
+ ret = regmap_write(mpu3050->map, MPU3050_USR_CTRL,
+ MPU3050_USR_CTRL_FIFO_RST);
+ if (ret)
+ dev_err(mpu3050->dev, "error resetting FIFO\n");
+
+ pm_runtime_put_autosuspend(mpu3050->dev);
+ mpu3050->hw_irq_trigger = false;
return 0;
}
+/**
+ * mpu3050_drdy_trigger_set_state() - set data ready interrupt state
+ * @trig: trigger instance
+ * @enable: true if trigger should be enabled, false to disable
+ */
+static int mpu3050_drdy_trigger_set_state(struct iio_trigger *trig,
+ bool enable)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct mpu3050 *mpu3050 = iio_priv(indio_dev);
+
+ if (enable)
+ return mpu3050_drdy_trigger_enable(mpu3050);
+
+ return mpu3050_drdy_trigger_disable(mpu3050);
+}
+
static const struct iio_trigger_ops mpu3050_trigger_ops = {
.set_trigger_state = mpu3050_drdy_trigger_set_state,
};
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 2/2] iio: gyro: mpu3050: Fix runtime PM refcount leak in trigger enable path
2026-11-01 9:23 ` [PATCH v2 0/2] " laixiangwu
2026-11-01 9:23 ` [PATCH v2 1/2] iio: gyro: mpu3050: Split data ready trigger enable/disable into helpers laixiangwu
@ 2026-11-01 9:23 ` laixiangwu
1 sibling, 0 replies; 6+ messages in thread
From: laixiangwu @ 2026-11-01 9:23 UTC (permalink / raw)
To: jic23, linusw, linux-iio
Cc: linux-kernel, andy, dlechner, nuno.sa, laixiangwu
mpu3050_drdy_trigger_enable() calls pm_runtime_get_sync() when
enabling the data ready trigger, but all five error returns in the
enable path return directly without the matching
pm_runtime_put_autosuspend(). The disable path, in contrast, drops
the reference correctly.
As a result, a failed trigger enable leaves the runtime PM usage
counter incremented and the sensor can never runtime suspend. It also
leaves hw_irq_trigger set to true, claiming the hardware IRQ is in
use when it is not.
Use pm_runtime_resume_and_get(), which does not leave the usage
counter incremented when resume fails, and add an error label that
drops the runtime PM reference and clears hw_irq_trigger so that a
failed enable returns with the device in the same state as before
the attempt.
Fixes: 3904b28efb2c ("iio: gyro: Add driver for the MPU-3050 gyroscope")
Signed-off-by: laixiangwu <laixiangwu@cmss.chinamobile.com>
---
Changes in v2:
- Rebase the fix on a new precursor patch that splits the enable and
disable paths of mpu3050_drdy_trigger_set_state() into separate
helpers, as suggested by the reviewer, so the error label only
applies to the enable path.
- Use pm_runtime_resume_and_get() instead of pm_runtime_get_sync(),
as suggested by the reviewer; it also keeps the usage counter
balanced when the resume fails, so no manual
pm_runtime_put_noidle() is needed in the caller.
Link: https://lore.kernel.org/r/20261030084305.1660-1-laixiangwu@cmss.chinamobile.com
drivers/iio/gyro/mpu3050-core.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c
index d966911ab..fc305564d 100644
--- a/drivers/iio/gyro/mpu3050-core.c
+++ b/drivers/iio/gyro/mpu3050-core.c
@@ -957,20 +957,23 @@ static int mpu3050_drdy_trigger_enable(struct mpu3050 *mpu3050)
unsigned int val;
int ret;
- pm_runtime_get_sync(mpu3050->dev);
+ ret = pm_runtime_resume_and_get(mpu3050->dev);
+ if (ret)
+ return ret;
+
mpu3050->hw_irq_trigger = true;
/* Disable all things in the FIFO */
ret = regmap_write(mpu3050->map, MPU3050_FIFO_EN, 0);
if (ret)
- return ret;
+ goto err_put_pm;
/* Reset and enable the FIFO */
ret = regmap_set_bits(mpu3050->map, MPU3050_USR_CTRL,
MPU3050_USR_CTRL_FIFO_EN |
MPU3050_USR_CTRL_FIFO_RST);
if (ret)
- return ret;
+ goto err_put_pm;
mpu3050->pending_fifo_footer = false;
@@ -982,12 +985,12 @@ static int mpu3050_drdy_trigger_enable(struct mpu3050 *mpu3050)
MPU3050_FIFO_EN_GYRO_ZOUT |
MPU3050_FIFO_EN_FOOTER);
if (ret)
- return ret;
+ goto err_put_pm;
/* Configure the sample engine */
ret = mpu3050_start_sampling(mpu3050);
if (ret)
- return ret;
+ goto err_put_pm;
/* Clear IRQ flag */
ret = regmap_read(mpu3050->map, MPU3050_INT_STATUS, &val);
@@ -1006,9 +1009,15 @@ static int mpu3050_drdy_trigger_enable(struct mpu3050 *mpu3050)
ret = regmap_write(mpu3050->map, MPU3050_INT_CFG, val);
if (ret)
- return ret;
+ goto err_put_pm;
return 0;
+
+err_put_pm:
+ pm_runtime_put_autosuspend(mpu3050->dev);
+ mpu3050->hw_irq_trigger = false;
+
+ return ret;
}
/**
^ permalink raw reply [flat|nested] 6+ messages in thread