summaryrefslogtreecommitdiff
path: root/drivers/amba
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2011-08-14 09:13:48 +0100
committerJonas ABERG <jonas.aberg@stericsson.com>2011-10-20 14:22:20 +0200
commited0d0fe71f91eb63ede64a4ecaa316410d0d338c (patch)
tree55da647c58aa5a44c662913220b667e28ed08c74 /drivers/amba
parent1577f9902fcffb7dac61d03e82b8e6c6cd0269e5 (diff)
PM: add runtime PM support to core Primecell driver
Add runtime PM support to the core Primecell driver, following the PCI model of how this is done. Rather than having every driver fiddle about with enabling runtime PM, that's dealt with in the core and instead, drivers just do a put() in their probe and a balancing get() in their remove function to activate runtime PM for the device. As we're dealing with enabling runtime PM in the core, fix up spi-pl022 as it must not enable and disable runtime PM itself anymore. Tested-by: Linus Walleij <linus.walleij@linaro.org> Acked-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Change-Id: Ia53383b68fdc189823f79445ddea0fceae127238 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/34445 Reviewed-by: Ulf HANSSON <ulf.hansson@stericsson.com> Tested-by: Ulf HANSSON <ulf.hansson@stericsson.com> Reviewed-by: Christopher BLAIR <chris.blair@stericsson.com>
Diffstat (limited to 'drivers/amba')
-rw-r--r--drivers/amba/bus.c57
1 files changed, 54 insertions, 3 deletions
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 6e4b1553afe..be75731f316 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -365,13 +365,47 @@ 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
static const struct dev_pm_ops amba_pm = {
USE_AMBA_PM_SLEEP_OPS
SET_RUNTIME_PM_OPS(
- pm_generic_runtime_suspend,
- pm_generic_runtime_resume,
+ amba_pm_runtime_suspend,
+ amba_pm_runtime_resume,
pm_generic_runtime_idle
)
};
@@ -481,10 +515,18 @@ static int amba_probe(struct device *dev)
if (ret)
break;
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
ret = pcdrv->probe(pcdev, id);
if (ret == 0)
break;
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
+
amba_put_disable_pclk(pcdev);
amba_put_disable_vcore(pcdev);
} while (0);
@@ -496,7 +538,16 @@ static int amba_remove(struct device *dev)
{
struct amba_device *pcdev = to_amba_device(dev);
struct amba_driver *drv = to_amba_driver(dev->driver);
- int ret = drv->remove(pcdev);
+ int ret;
+
+ pm_runtime_get_sync(dev);
+ ret = drv->remove(pcdev);
+ pm_runtime_put_noidle(dev);
+
+ /* Undo the runtime PM settings in amba_probe() */
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
amba_put_disable_pclk(pcdev);
amba_put_disable_vcore(pcdev);