Skip to content

Commit 7638826

Browse files
committed
i2c: imx: make controller available until system suspend_noirq() and from resume_noirq()
JIRA: https://issues.redhat.com/browse/RHEL-116101 commit 358025a Author: Carlos Song <carlos.song@nxp.com> Date: Mon Nov 25 22:21:08 2024 +0800 i2c: imx: make controller available until system suspend_noirq() and from resume_noirq() Put runtime PM to resume state between suspend() and suspend_noirq(), resume_noirq() and resume(), because some I2C devices need the controller on to perform communication during this period. The controller can't be woken up once runtime pm is disabled and in runtime autosuspended state. The problem can be easily reproduced on the I.MX8MQ platform: the PMIC needs to be used to enable regulator when the system resumes. When the PMIC uses the I2C controller, I2C runtime pm has not been enabled, so in i2c xfer(), pm_runtime_resume_and_get() will return an error, which causes data transfer to fail. Therefore, regulators cannot be enabled and system resume hangs. Here is resume error log: [ 53.888902] galcore 38000000.gpu3d: PM: calling genpd_resume_noirq @ 529, parent: platform [ 53.897203] i2c_imx_xfer, pm_runtime_resume_and_get is -13 [ 53.902713] imx-pgc imx-pgc-domain.5: failed to enable regulator: -EACCES [ 53.909518] galcore 38000000.gpu3d: PM: genpd_resume_noirq returned 0 after 12331 usecs [ 53.917545] mxc_hantro 38300000.vpu: PM: calling genpd_resume_noirq @ 529, parent: soc@0 [ 53.925659] i2c_imx_xfer, pm_runtime_resume_and_get is -13 [ 53.931157] imx-pgc imx-pgc-domain.6: failed to enable regulator: -EACCES I.MX8MQ system resume normally after applying the fix. Here is resume log: [ 71.068807] galcore 38000000.gpu3d: PM: calling genpd_resume_noirq @ 530, parent: platform [ 71.077103] i2c_imx_xfer, pm_runtime_resume_and_get is 0 [ 71.083578] galcore 38000000.gpu3d: PM: genpd_resume_noirq returned 0 after 6490 usecs [ 71.091526] mxc_hantro 38300000.vpu: PM: calling genpd_resume_noirq @ 530, parent: soc@0 [ 71.099638] i2c_imx_xfer, pm_runtime_resume_and_get is 0 [ 71.106091] mxc_hantro 38300000.vpu: PM: genpd_resume_noirq returned 0 after 6458 usecs Signed-off-by: Carlos Song <carlos.song@nxp.com> Signed-off-by: Haibo Chen <haibo.chen@nxp.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Link: https://lore.kernel.org/r/20241125142108.1613016-1-carlos.song@nxp.com Signed-off-by: Andi Shyti <andi.shyti@kernel.org> Signed-off-by: Jared Kangas <jkangas@redhat.com>
1 parent 7cfaff1 commit 7638826

File tree

1 file changed

+38
-1
lines changed

1 file changed

+38
-1
lines changed

drivers/i2c/busses/i2c-imx.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1768,7 +1768,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
17681768
goto rpm_disable;
17691769

17701770
/* Request IRQ */
1771-
ret = request_irq(irq, i2c_imx_isr, IRQF_SHARED, pdev->name, i2c_imx);
1771+
ret = request_irq(irq, i2c_imx_isr, IRQF_SHARED | IRQF_NO_SUSPEND,
1772+
pdev->name, i2c_imx);
17721773
if (ret) {
17731774
dev_err(&pdev->dev, "can't claim irq %d\n", irq);
17741775
goto rpm_disable;
@@ -1886,7 +1887,43 @@ static int i2c_imx_runtime_resume(struct device *dev)
18861887
return ret;
18871888
}
18881889

1890+
static int i2c_imx_suspend(struct device *dev)
1891+
{
1892+
/*
1893+
* Some I2C devices may need the I2C controller to remain active
1894+
* during resume_noirq() or suspend_noirq(). If the controller is
1895+
* autosuspended, there is no way to wake it up once runtime PM is
1896+
* disabled (in suspend_late()).
1897+
*
1898+
* During system resume, the I2C controller will be available only
1899+
* after runtime PM is re-enabled (in resume_early()). However, this
1900+
* may be too late for some devices.
1901+
*
1902+
* Wake up the controller in the suspend() callback while runtime PM
1903+
* is still enabled. The I2C controller will remain available until
1904+
* the suspend_noirq() callback (pm_runtime_force_suspend()) is
1905+
* called. During resume, the I2C controller can be restored by the
1906+
* resume_noirq() callback (pm_runtime_force_resume()).
1907+
*
1908+
* Finally, the resume() callback re-enables autosuspend, ensuring
1909+
* the I2C controller remains available until the system enters
1910+
* suspend_noirq() and from resume_noirq().
1911+
*/
1912+
return pm_runtime_resume_and_get(dev);
1913+
}
1914+
1915+
static int i2c_imx_resume(struct device *dev)
1916+
{
1917+
pm_runtime_mark_last_busy(dev);
1918+
pm_runtime_put_autosuspend(dev);
1919+
1920+
return 0;
1921+
}
1922+
18891923
static const struct dev_pm_ops i2c_imx_pm_ops = {
1924+
NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
1925+
pm_runtime_force_resume)
1926+
SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume)
18901927
RUNTIME_PM_OPS(i2c_imx_runtime_suspend, i2c_imx_runtime_resume, NULL)
18911928
};
18921929

0 commit comments

Comments
 (0)