From 0df349945752bf04cee52babf266bbf1f4812193 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 17 Oct 2012 14:27:08 +0200 Subject: [PATCH 1/3] spi/pl022: Minor simplification for runtime pm In probe pm_runtime_put_autosuspend has the same effect as doing pm_runtime_put. This due to upper layer in driver core is preventing the device from being runtime suspended by a pm_runtime_get*. Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/spi/spi-pl022.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 919464102d33..a9106c936edb 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2248,10 +2248,9 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) pm_runtime_set_autosuspend_delay(dev, platform_info->autosuspend_delay); pm_runtime_use_autosuspend(dev); - pm_runtime_put_autosuspend(dev); - } else { - pm_runtime_put(dev); } + pm_runtime_put(dev); + return 0; err_spi_register: From 4964a26df72c4a82e56c6b40818648d54bde93cc Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 17 Oct 2012 14:27:16 +0200 Subject: [PATCH 2/3] spi/pl022: Activate resourses before deactivate them in suspend To be able to deactivate resourses in suspend, the resourses must first be surely active. This is done with a pm_runtime_get_sync. Once the resourses are restored to active state again in resume, the runtime pm usage count can be decreased with a pm_runtime_put. Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/spi/spi-pl022.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index a9106c936edb..c220c2346276 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2349,6 +2349,8 @@ static int pl022_suspend(struct device *dev) dev_warn(dev, "cannot suspend master\n"); return ret; } + + pm_runtime_get_sync(dev); pl022_suspend_resources(pl022); dev_dbg(dev, "suspended\n"); @@ -2361,6 +2363,7 @@ static int pl022_resume(struct device *dev) int ret; pl022_resume_resources(pl022); + pm_runtime_put(dev); /* Start the queue running */ ret = spi_master_resume(pl022->master); From d8f18420c552de6d38e5464074133e0e9730abcd Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 17 Oct 2012 14:27:24 +0200 Subject: [PATCH 3/3] spi/pl022: add IDLE state pin management This commit allow to put pins in IDLE state in runtime_suspend and in SLEEP state in suspend, corresponding to defined semantics in . To do this, just add a boolean parameter runtime to pl022_resume_resources/pl022_suspend_resources which indicates if it's called from PM_RUNTIME callbacks or not. Signed-off-by: Patrice Chotard Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/spi/spi-pl022.c | 44 +++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index c220c2346276..7e3c4166e8f8 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -371,6 +371,7 @@ struct pl022 { /* Two optional pin states - default & sleep */ struct pinctrl *pinctrl; struct pinctrl_state *pins_default; + struct pinctrl_state *pins_idle; struct pinctrl_state *pins_sleep; struct spi_master *master; struct pl022_ssp_controller *master_info; @@ -2116,6 +2117,11 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) } else dev_err(dev, "could not get default pinstate\n"); + pl022->pins_idle = pinctrl_lookup_state(pl022->pinctrl, + PINCTRL_STATE_IDLE); + if (IS_ERR(pl022->pins_idle)) + dev_dbg(dev, "could not get idle pinstate\n"); + pl022->pins_sleep = pinctrl_lookup_state(pl022->pinctrl, PINCTRL_STATE_SLEEP); if (IS_ERR(pl022->pins_sleep)) @@ -2305,35 +2311,47 @@ pl022_remove(struct amba_device *adev) * the runtime counterparts to handle external resources like * clocks, pins and regulators when going to sleep. */ -static void pl022_suspend_resources(struct pl022 *pl022) +static void pl022_suspend_resources(struct pl022 *pl022, bool runtime) { int ret; + struct pinctrl_state *pins_state; clk_disable(pl022->clk); + pins_state = runtime ? pl022->pins_idle : pl022->pins_sleep; /* Optionally let pins go into sleep states */ - if (!IS_ERR(pl022->pins_sleep)) { - ret = pinctrl_select_state(pl022->pinctrl, - pl022->pins_sleep); + if (!IS_ERR(pins_state)) { + ret = pinctrl_select_state(pl022->pinctrl, pins_state); if (ret) - dev_err(&pl022->adev->dev, - "could not set pins to sleep state\n"); + dev_err(&pl022->adev->dev, "could not set %s pins\n", + runtime ? "idle" : "sleep"); } } -static void pl022_resume_resources(struct pl022 *pl022) +static void pl022_resume_resources(struct pl022 *pl022, bool runtime) { int ret; /* Optionaly enable pins to be muxed in and configured */ + /* First go to the default state */ if (!IS_ERR(pl022->pins_default)) { - ret = pinctrl_select_state(pl022->pinctrl, - pl022->pins_default); + ret = pinctrl_select_state(pl022->pinctrl, pl022->pins_default); if (ret) dev_err(&pl022->adev->dev, "could not set default pins\n"); } + if (!runtime) { + /* Then let's idle the pins until the next transfer happens */ + if (!IS_ERR(pl022->pins_idle)) { + ret = pinctrl_select_state(pl022->pinctrl, + pl022->pins_idle); + if (ret) + dev_err(&pl022->adev->dev, + "could not set idle pins\n"); + } + } + clk_enable(pl022->clk); } #endif @@ -2351,7 +2369,7 @@ static int pl022_suspend(struct device *dev) } pm_runtime_get_sync(dev); - pl022_suspend_resources(pl022); + pl022_suspend_resources(pl022, false); dev_dbg(dev, "suspended\n"); return 0; @@ -2362,7 +2380,7 @@ static int pl022_resume(struct device *dev) struct pl022 *pl022 = dev_get_drvdata(dev); int ret; - pl022_resume_resources(pl022); + pl022_resume_resources(pl022, false); pm_runtime_put(dev); /* Start the queue running */ @@ -2381,7 +2399,7 @@ static int pl022_runtime_suspend(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); - pl022_suspend_resources(pl022); + pl022_suspend_resources(pl022, true); return 0; } @@ -2389,7 +2407,7 @@ static int pl022_runtime_resume(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); - pl022_resume_resources(pl022); + pl022_resume_resources(pl022, true); return 0; } #endif