summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@stericsson.com>2011-10-27 13:56:21 +0200
committerLinus WALLEIJ <linus.walleij@stericsson.com>2011-10-27 16:35:53 +0200
commitf3e44d9f258f8d298cb177ea2ace0bf3ed002a74 (patch)
tree4d80143d1ae967bc6a9a7bad3c735533dd397118
parentdbcf2d4cfd7b08f1c051f3bf220c291f21022349 (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.c108
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