]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
i2c: imx-lpi2c: mark I2C adapter when hardware is powered down
authorCarlos Song <carlos.song@nxp.com>
Mon, 25 May 2026 03:14:50 +0000 (11:14 +0800)
committerAndi Shyti <andi.shyti@kernel.org>
Wed, 17 Jun 2026 09:07:50 +0000 (11:07 +0200)
On some i.MX platforms, certain I2C client drivers keep a periodic
workqueue which continues to trigger I2C transfers.

During system suspend/resume, there exists a time window between:
  - suspend_noirq and the system entering suspend
  - the system starting to resume and resume_noirq

In this window, the I2C controller resources such as clock and pinctrl
may already be disabled or not yet restored.

If a workqueue triggers an I2C transfer in this period, the driver
attempts to access I2C registers while the hardware resources are
unavailable, which may lead to system hang.

Mark the I2C adapter as suspended during noirq suspend and block new
transfers until resume, ensuring that I2C transfers are only issued
when hardware resources are available.

Fixes: 1ee867e465c1 ("i2c: imx-lpi2c: add target mode support")
Signed-off-by: Carlos Song <carlos.song@nxp.com>
Cc: <stable@vger.kernel.org> # v6.14+
Acked-by: Mukesh Savaliya <mukesh.savaliya@oss.qualcomm.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
Link: https://lore.kernel.org/r/20260525031450.3183421-1-carlos.song@oss.nxp.com
drivers/i2c/busses/i2c-imx-lpi2c.c

index cd4da50c4dd96ab112c5cb9ea1e7abd8b8a61b07..e6c24a9d934d7cae398a1a01736b66482060cb6a 100644 (file)
@@ -1646,7 +1646,18 @@ static int __maybe_unused lpi2c_runtime_resume(struct device *dev)
 
 static int __maybe_unused lpi2c_suspend_noirq(struct device *dev)
 {
-       return pm_runtime_force_suspend(dev);
+       struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
+       int ret;
+
+       i2c_mark_adapter_suspended(&lpi2c_imx->adapter);
+
+       ret = pm_runtime_force_suspend(dev);
+       if (ret) {
+               i2c_mark_adapter_resumed(&lpi2c_imx->adapter);
+               return ret;
+       }
+
+       return 0;
 }
 
 static int __maybe_unused lpi2c_resume_noirq(struct device *dev)
@@ -1666,6 +1677,8 @@ static int __maybe_unused lpi2c_resume_noirq(struct device *dev)
        if (lpi2c_imx->target)
                lpi2c_imx_target_init(lpi2c_imx);
 
+       i2c_mark_adapter_resumed(&lpi2c_imx->adapter);
+
        return 0;
 }