diff options
author | Ulf Hansson <ulf.hansson@stericsson.com> | 2011-10-27 13:56:21 +0200 |
---|---|---|
committer | Linus WALLEIJ <linus.walleij@stericsson.com> | 2011-10-27 16:35:53 +0200 |
commit | f3e44d9f258f8d298cb177ea2ace0bf3ed002a74 (patch) | |
tree | 4d80143d1ae967bc6a9a7bad3c735533dd397118 | |
parent | dbcf2d4cfd7b08f1c051f3bf220c291f21022349 (diff) |
AMBA: Use suspend_noriq to force devices into runtime suspend
To be able to make sure devices are put into runtime suspend
after a suspend sequence, the suspend_noirq callback is used.
Previously it was was possible for drivers doing pm_runtime_suspend
and pm_runtime_put_sync directly from it's suspend callbacks.
This is now not possible due to the following commit, which solve a
race issue:
PM: Limit race conditions between runtime PM and system sleep (v2)
Change-Id: I48b988e9f7e411a0a122a58c0967fbee61256f89
Signed-off-by: Ulf Hansson <ulf.hansson@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/35505
Reviewed-by: Linus WALLEIJ <linus.walleij@stericsson.com>
-rw-r--r-- | drivers/amba/bus.c | 108 |
1 files changed, 74 insertions, 34 deletions
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index be75731f316..3ea72cbf522 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -135,6 +135,73 @@ void amba_pm_complete(struct device *dev) #endif /* !CONFIG_PM_SLEEP */ +#ifdef CONFIG_PM_RUNTIME +/* + * Hooks to provide runtime PM of the pclk (bus clock). It is safe to + * enable/disable the bus clock at runtime PM suspend/resume as this + * does not result in loss of context. However, disabling vcore power + * would do, so we leave that to the driver. + */ +static int amba_pm_runtime_suspend(struct device *dev) +{ + struct amba_device *pcdev = to_amba_device(dev); + int ret = pm_generic_runtime_suspend(dev); + + if (ret == 0 && dev->driver) + clk_disable(pcdev->pclk); + + return ret; +} + +static int amba_pm_runtime_suspend_noirq(struct device *dev) +{ + int ret = 0; + + /* + * If the amba device is not already runtime suspended + * force it into this state to save power. + */ + if (!pm_runtime_status_suspended(dev)) + ret = amba_pm_runtime_suspend(dev); + + return ret; +} + +static int amba_pm_runtime_resume(struct device *dev) +{ + struct amba_device *pcdev = to_amba_device(dev); + int ret; + + if (dev->driver) { + ret = clk_enable(pcdev->pclk); + /* Failure is probably fatal to the system, but... */ + if (ret) + return ret; + } + + return pm_generic_runtime_resume(dev); +} + +static int amba_pm_runtime_resume_noirq(struct device *dev) +{ + int ret = 0; + + /* + * If the amba device has been forced into runtime suspend state, + * we must make sure to restore it back into runtime resumed state. + */ + if (!pm_runtime_status_suspended(dev)) + ret = amba_pm_runtime_resume(dev); + + return ret; +} +#else /* !CONFIG_PM_RUNTIME */ + +#define amba_pm_runtime_suspend_noirq NULL +#define amba_pm_runtime_resume_noirq NULL + +#endif /* !CONFIG_PM_RUNTIME */ + #ifdef CONFIG_SUSPEND int amba_pm_suspend(struct device *dev) @@ -163,7 +230,10 @@ int amba_pm_suspend_noirq(struct device *dev) if (!drv) return 0; - if (drv->pm) { + if (amba_pm_runtime_suspend_noirq) + ret = amba_pm_runtime_suspend_noirq(dev); + + if (!ret && drv->pm) { if (drv->pm->suspend_noirq) ret = drv->pm->suspend_noirq(dev); } @@ -202,6 +272,9 @@ int amba_pm_resume_noirq(struct device *dev) ret = drv->pm->resume_noirq(dev); } + if (!ret && amba_pm_runtime_resume_noirq) + ret = amba_pm_runtime_resume_noirq(dev); + return ret; } @@ -365,39 +438,6 @@ int amba_pm_restore_noirq(struct device *dev) #endif /* !CONFIG_HIBERNATE_CALLBACKS */ -#ifdef CONFIG_PM_RUNTIME -/* - * Hooks to provide runtime PM of the pclk (bus clock). It is safe to - * enable/disable the bus clock at runtime PM suspend/resume as this - * does not result in loss of context. However, disabling vcore power - * would do, so we leave that to the driver. - */ -static int amba_pm_runtime_suspend(struct device *dev) -{ - struct amba_device *pcdev = to_amba_device(dev); - int ret = pm_generic_runtime_suspend(dev); - - if (ret == 0 && dev->driver) - clk_disable(pcdev->pclk); - - return ret; -} - -static int amba_pm_runtime_resume(struct device *dev) -{ - struct amba_device *pcdev = to_amba_device(dev); - int ret; - - if (dev->driver) { - ret = clk_enable(pcdev->pclk); - /* Failure is probably fatal to the system, but... */ - if (ret) - return ret; - } - - return pm_generic_runtime_resume(dev); -} -#endif #ifdef CONFIG_PM |