diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-08-14 09:13:48 +0100 |
---|---|---|
committer | Jonas ABERG <jonas.aberg@stericsson.com> | 2011-10-20 14:22:20 +0200 |
commit | ed0d0fe71f91eb63ede64a4ecaa316410d0d338c (patch) | |
tree | 55da647c58aa5a44c662913220b667e28ed08c74 /drivers/amba | |
parent | 1577f9902fcffb7dac61d03e82b8e6c6cd0269e5 (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.c | 57 |
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); |