[07/17] spi: pl022: Don't ignore power domain and amba bus at system suspend

Message ID 1391529538-21685-8-git-send-email-ulf.hansson@linaro.org
State New
Headers show

Commit Message

Ulf Hansson Feb. 4, 2014, 3:58 p.m.
Due to the available runtime PM callbacks for CONFIG_PM, we are now
able to put the device into complete low power state at system suspend.

Previously only the resources controlled by the driver were put into
low power state at system suspend. Both the amba bus and a potential
power domain were ignored, which now isn't the case any more.

Moreover, putting the device into low power state couldn't be done
without first bringing it back to full power. This constraint don't
exists any more.

Cc: Mark Brown <broonie@kernel.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/spi/spi-pl022.c |   74 +++++++++++++++++++++++------------------------
 1 file changed, 37 insertions(+), 37 deletions(-)

Comments

Ulf Hansson Feb. 10, 2014, 12:33 p.m. | #1
On 4 February 2014 20:16, Mark Brown <broonie@kernel.org> wrote:
> On Tue, Feb 04, 2014 at 04:58:48PM +0100, Ulf Hansson wrote:
>
>> @@ -2328,8 +2300,23 @@ static int pl022_suspend(struct device *dev)
>>               return ret;
>>       }
>>
>> -     pm_runtime_get_sync(dev);
>> -     pl022_suspend_resources(pl022, false);
>> +     pm_runtime_disable(dev);
>> +
>> +     if (!pm_runtime_status_suspended(dev)) {
>> +             if (dev->pm_domain && dev->pm_domain->ops.runtime_suspend)
>> +                     ret = dev->pm_domain->ops.runtime_suspend(dev);
>> +             else
>> +                     ret = dev->bus->pm->runtime_suspend(dev);
>> +
>> +             if (ret) {
>> +                     pm_runtime_enable(dev);
>> +                     return ret;
>> +             }
>> +
>> +             pm_runtime_set_suspended(dev);
>> +     }
>
> This seems like a fairly hideous thing to be having to open code in an
> individual driver, it all looks generic and like something that most if
> not all devices ought to be doing and it looks very vulnerable to being
> broken by changes in the core.  At the very least I would expect this to
> be done in a helper function, though it would be even nicer if the
> driver core were figuring this stuff out for us based on the device
> level callback so that drivers didn't need to worry about being in power
> domains or manually calling bus level callbacks.
>
> Putting it in a helper would at least mean that it's easier for the
> mechanics to be transferred to the core proper later on.

I agree, a helper function would be nice. I have earlier sent a patch
to the PM core, that is similar to the code above, though it was
rejected in it's current form. Let me follow up on this again.

At this point, would a way forward be to still go ahead with this
patch and then convert to, when/if, the helper function from the PM
core becomes available?

Kind regards
Ulf Hansson
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson Feb. 19, 2014, 2:15 p.m. | #2
On 10 February 2014 13:51, Mark Brown <broonie@kernel.org> wrote:
> On Mon, Feb 10, 2014 at 01:33:50PM +0100, Ulf Hansson wrote:
>> On 4 February 2014 20:16, Mark Brown <broonie@kernel.org> wrote:
>
>> > This seems like a fairly hideous thing to be having to open code in an
>> > individual driver, it all looks generic and like something that most if
>
> ...
>
>> > Putting it in a helper would at least mean that it's easier for the
>> > mechanics to be transferred to the core proper later on.
>
>> I agree, a helper function would be nice. I have earlier sent a patch
>> to the PM core, that is similar to the code above, though it was
>> rejected in it's current form. Let me follow up on this again.
>
>> At this point, would a way forward be to still go ahead with this
>> patch and then convert to, when/if, the helper function from the PM
>> core becomes available?
>
> It's definitely *a* way forward, but I'm not convinced it's a good way
> forward.  Since it's something that I'd expect us to be doing in all
> drivers we'd want to replicate it all over the place which is obviously
> not good, or conversely if there are issues that prevented the code
> being added to the PM core then presumably we're just adding problematic
> code to the driver (you've not mentioned what the problems were with
> doing this in the PM core).

I have posted a patch which adds a runtime PM helper function to the
PM core, I am hoping to get some comments soon.
http://marc.info/?l=linux-pm&m=139228211505423&w=2

So I agree, let's put this patch on hold until we sorted out how to
proceed. Though I will rebase and send a v2 of it, just to keep it as
a reference for later use.

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Patch

diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 70fa907..db829a1 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -2288,35 +2288,7 @@  pl022_remove(struct amba_device *adev)
 	return 0;
 }
 
-#ifdef CONFIG_PM
-/*
- * These two functions are used from both suspend/resume and
- * the runtime counterparts to handle external resources like
- * clocks, pins and regulators when going to sleep.
- */
-static void pl022_suspend_resources(struct pl022 *pl022, bool runtime)
-{
-	clk_disable(pl022->clk);
-
-	if (runtime)
-		pinctrl_pm_select_idle_state(&pl022->adev->dev);
-	else
-		pinctrl_pm_select_sleep_state(&pl022->adev->dev);
-}
-
-static void pl022_resume_resources(struct pl022 *pl022, bool runtime)
-{
-	/* First go to the default state */
-	pinctrl_pm_select_default_state(&pl022->adev->dev);
-	if (!runtime)
-		/* Then let's idle the pins until the next transfer happens */
-		pinctrl_pm_select_idle_state(&pl022->adev->dev);
-
-	clk_enable(pl022->clk);
-}
-#endif
-
-#ifdef CONFIG_SUSPEND
+#ifdef CONFIG_PM_SLEEP
 static int pl022_suspend(struct device *dev)
 {
 	struct pl022 *pl022 = dev_get_drvdata(dev);
@@ -2328,8 +2300,23 @@  static int pl022_suspend(struct device *dev)
 		return ret;
 	}
 
-	pm_runtime_get_sync(dev);
-	pl022_suspend_resources(pl022, false);
+	pm_runtime_disable(dev);
+
+	if (!pm_runtime_status_suspended(dev)) {
+		if (dev->pm_domain && dev->pm_domain->ops.runtime_suspend)
+			ret = dev->pm_domain->ops.runtime_suspend(dev);
+		else
+			ret = dev->bus->pm->runtime_suspend(dev);
+
+		if (ret) {
+			pm_runtime_enable(dev);
+			return ret;
+		}
+
+		pm_runtime_set_suspended(dev);
+	}
+
+	pinctrl_pm_select_sleep_state(dev);
 
 	dev_dbg(dev, "suspended\n");
 	return 0;
@@ -2338,10 +2325,19 @@  static int pl022_suspend(struct device *dev)
 static int pl022_resume(struct device *dev)
 {
 	struct pl022 *pl022 = dev_get_drvdata(dev);
-	int ret;
+	int ret = 0;
 
-	pl022_resume_resources(pl022, false);
-	pm_runtime_put(dev);
+	if (dev->pm_domain && dev->pm_domain->ops.runtime_resume)
+		ret = dev->pm_domain->ops.runtime_resume(dev);
+	else
+		ret = dev->bus->pm->runtime_resume(dev);
+
+	if (ret)
+		dev_err(dev, "problem resuming\n");
+	else
+		pm_runtime_set_active(dev);
+
+	pm_runtime_enable(dev);
 
 	/* Start the queue running */
 	ret = spi_master_resume(pl022->master);
@@ -2352,14 +2348,16 @@  static int pl022_resume(struct device *dev)
 
 	return ret;
 }
-#endif	/* CONFIG_PM */
+#endif
 
 #ifdef CONFIG_PM
 static int pl022_runtime_suspend(struct device *dev)
 {
 	struct pl022 *pl022 = dev_get_drvdata(dev);
 
-	pl022_suspend_resources(pl022, true);
+	clk_disable(pl022->clk);
+	pinctrl_pm_select_idle_state(dev);
+
 	return 0;
 }
 
@@ -2367,7 +2365,9 @@  static int pl022_runtime_resume(struct device *dev)
 {
 	struct pl022 *pl022 = dev_get_drvdata(dev);
 
-	pl022_resume_resources(pl022, true);
+	pinctrl_pm_select_default_state(dev);
+	clk_enable(pl022->clk);
+
 	return 0;
 }
 #endif