Skip to content

Commit 33e4c63

Browse files
Ulf Hanssongregkh
authored andcommitted
i2c: designware: Fix system suspend
commit a23318feeff662c8d25d21623daebdd2e55ec221 upstream. The commit 8503ff1 ("i2c: designware: Avoid unnecessary resuming during system suspend"), may suggest to the PM core to try out the so called direct_complete path for system sleep. In this path, the PM core treats a runtime suspended device as it's already in a proper low power state for system sleep, which makes it skip calling the system sleep callbacks for the device, except for the ->prepare() and the ->complete() callbacks. However, the PM core may unset the direct_complete flag for a parent device, in case its child device are being system suspended before. In this scenario, the PM core invokes the system sleep callbacks, no matter if the device is runtime suspended or not. Particularly in cases of an existing i2c slave device, the above path is triggered, which breaks the assumption that the i2c device is always runtime resumed whenever the dw_i2c_plat_suspend() is being called. More precisely, dw_i2c_plat_suspend() calls clk_core_disable() and clk_core_unprepare(), for an already disabled/unprepared clock, leading to a splat in the log about clocks calls being wrongly balanced and breaking system sleep. To still allow the direct_complete path in cases when it's possible, but also to keep the fix simple, let's runtime resume the i2c device in the ->suspend() callback, before continuing to put the device into low power state. Note, in cases when the i2c device is attached to the ACPI PM domain, this problem doesn't occur, because ACPI's ->suspend() callback, assigned to acpi_subsys_suspend(), already calls pm_runtime_resume() for the device. It should also be noted that this change does not fix commit 8503ff1 ("i2c: designware: Avoid unnecessary resuming during system suspend"). Because for the non-ACPI case, the system sleep support was already broken prior that point. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: John Stultz <john.stultz@linaro.org> Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 10814c1 commit 33e4c63

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

drivers/i2c/busses/i2c-designware-platdrv.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ static void dw_i2c_plat_complete(struct device *dev)
294294
#endif
295295

296296
#ifdef CONFIG_PM
297-
static int dw_i2c_plat_suspend(struct device *dev)
297+
static int dw_i2c_plat_runtime_suspend(struct device *dev)
298298
{
299299
struct platform_device *pdev = to_platform_device(dev);
300300
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
@@ -318,11 +318,21 @@ static int dw_i2c_plat_resume(struct device *dev)
318318
return 0;
319319
}
320320

321+
#ifdef CONFIG_PM_SLEEP
322+
static int dw_i2c_plat_suspend(struct device *dev)
323+
{
324+
pm_runtime_resume(dev);
325+
return dw_i2c_plat_runtime_suspend(dev);
326+
}
327+
#endif
328+
321329
static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
322330
.prepare = dw_i2c_plat_prepare,
323331
.complete = dw_i2c_plat_complete,
324332
SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
325-
SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL)
333+
SET_RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend,
334+
dw_i2c_plat_resume,
335+
NULL)
326336
};
327337

328338
#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)

0 commit comments

Comments
 (0)