1
0
mirror of https://github.com/torvalds/linux.git synced 2025-04-12 06:49:52 +00:00

i2c: imx-lpi2c: make controller available until the system enters suspend_noirq() and from resume_noirq().

This is a general i2c controller feature. Some I2C devices may need the
I2C controller to remain active during resume_noirq() or suspend_noirq().
If the controller is autosuspended, there is no way to wake it up once
runtime PM disabled (in suspend_late()). During system resume, the I2C
controller will be available only after runtime PM is re-enabled
(in resume_early()). However, this may be too late for some devices.

Wake up the controller in the suspend() callback while runtime PM is
still enabled. The I2C controller will remain available until the
suspend_noirq() callback (pm_runtime_force_suspend()) is called. During
resume, the I2C controller can be restored by the resume_noirq() callback
(pm_runtime_force_resume()). Finally, the resume() callback re-enables
autosuspend. As a result, the I2C controller can remain available until
the system enters suspend_noirq() and from resume_noirq().

Signed-off-by: Carlos Song <carlos.song@nxp.com>
Link: https://lore.kernel.org/r/20241227084736.1323943-1-carlos.song@nxp.com
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
This commit is contained in:
Carlos Song 2024-12-27 16:47:36 +08:00 committed by Andi Shyti
parent 8abbc711da
commit 4262df2a69

@ -1318,7 +1318,7 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
if (ret)
lpi2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ;
ret = devm_request_irq(&pdev->dev, irq, lpi2c_imx_isr, 0,
ret = devm_request_irq(&pdev->dev, irq, lpi2c_imx_isr, IRQF_NO_SUSPEND,
pdev->name, lpi2c_imx);
if (ret)
return dev_err_probe(&pdev->dev, ret, "can't claim irq %d\n", irq);
@ -1447,9 +1447,43 @@ static int __maybe_unused lpi2c_resume_noirq(struct device *dev)
return 0;
}
static int lpi2c_suspend(struct device *dev)
{
/*
* Some I2C devices may need the I2C controller to remain active
* during resume_noirq() or suspend_noirq(). If the controller is
* autosuspended, there is no way to wake it up once runtime PM is
* disabled (in suspend_late()).
*
* During system resume, the I2C controller will be available only
* after runtime PM is re-enabled (in resume_early()). However, this
* may be too late for some devices.
*
* Wake up the controller in the suspend() callback while runtime PM
* is still enabled. The I2C controller will remain available until
* the suspend_noirq() callback (pm_runtime_force_suspend()) is
* called. During resume, the I2C controller can be restored by the
* resume_noirq() callback (pm_runtime_force_resume()).
*
* Finally, the resume() callback re-enables autosuspend, ensuring
* the I2C controller remains available until the system enters
* suspend_noirq() and from resume_noirq().
*/
return pm_runtime_resume_and_get(dev);
}
static int lpi2c_resume(struct device *dev)
{
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
}
static const struct dev_pm_ops lpi2c_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(lpi2c_suspend_noirq,
lpi2c_resume_noirq)
SYSTEM_SLEEP_PM_OPS(lpi2c_suspend, lpi2c_resume)
SET_RUNTIME_PM_OPS(lpi2c_runtime_suspend,
lpi2c_runtime_resume, NULL)
};