Skip to content

Commit

Permalink
i2c: designware: Avoid unnecessary resuming during system suspend
Browse files Browse the repository at this point in the history
Commit 1fc2fe2 ("i2c: designware: Add runtime PM hooks") adds
runtime pm support using the same ops for system pm and runtime pm.
When suspend to ram, the i2c host may have been runtime suspended, thus
i2c_dw_disable() hangs.

Previously, I fixed this issue by separating ops for system pm and
runtime pm, then in the system suspend/resume path, runtime pm apis are
used to ensure the device is at correct state.

But as Mika Westerberg pointed out: it sounds a bit silly to resume the
device just because you want to call i2c_dw_disable() for it before
suspending again. He then suggested an elegant solution which keeps the
device runtime suspended during system suspend with the help of
'dev->power.direct_complete'. This patch adopted this solution, and in
fact Mika provided the main code.

Signed-off-by: Jisheng Zhang <jszhang@marvell.com>
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
  • Loading branch information
Jisheng Zhang authored and Wolfram Sang committed Jun 2, 2015
1 parent 7e2dc81 commit 8503ff1
Showing 1 changed file with 28 additions and 4 deletions.
32 changes: 28 additions & 4 deletions drivers/i2c/busses/i2c-designware-platdrv.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,22 @@ static const struct of_device_id dw_i2c_of_match[] = {
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
#endif

#ifdef CONFIG_PM_SLEEP
static int dw_i2c_prepare(struct device *dev)
{
return pm_runtime_suspended(dev);
}

static void dw_i2c_complete(struct device *dev)
{
if (dev->power.direct_complete)
pm_request_resume(dev);
}
#else
#define dw_i2c_prepare NULL
#define dw_i2c_complete NULL
#endif

#ifdef CONFIG_PM
static int dw_i2c_suspend(struct device *dev)
{
Expand All @@ -322,10 +338,18 @@ static int dw_i2c_resume(struct device *dev)

return 0;
}
#endif

static UNIVERSAL_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend,
dw_i2c_resume, NULL);
static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
.prepare = dw_i2c_prepare,
.complete = dw_i2c_complete,
SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_suspend, dw_i2c_resume)
SET_RUNTIME_PM_OPS(dw_i2c_suspend, dw_i2c_resume, NULL)
};

#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
#else
#define DW_I2C_DEV_PMOPS NULL
#endif

/* work with hotplug and coldplug */
MODULE_ALIAS("platform:i2c_designware");
Expand All @@ -337,7 +361,7 @@ static struct platform_driver dw_i2c_driver = {
.name = "i2c_designware",
.of_match_table = of_match_ptr(dw_i2c_of_match),
.acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
.pm = &dw_i2c_dev_pm_ops,
.pm = DW_I2C_DEV_PMOPS,
},
};

Expand Down

0 comments on commit 8503ff1

Please sign in to comment.