[PATCH] drivers: pinctrl: add active state to core

Linus Walleij linus.walleij at linaro.org
Tue Jun 11 15:53:17 EDT 2013


On Tue, Jun 11, 2013 at 6:33 PM, Stephen Warren <swarren at wwwdotorg.org> wrote:
> On 06/11/2013 02:16 AM, Linus Walleij wrote:
>> From: Linus Walleij <linus.walleij at linaro.org>
>>
>> In addition to the recently introduced pinctrl core
>> control, the PM runtime pin control for the OMAP platforms
>> require a fourth state in addtition to the default, idle and
>> sleep states already handled by the core: an explicit "active"
>> state. Let's introduce this to the core in addition to the
>> other states already defined.
>
> Surely "default" /is/ "active"? That's what it's meant so far.

I thought so too, until Tony informed us that in the OMAP world
this state is not always the active one.

But I don't know the exact reasons for.

I guess that some "default" states on the OMAP may mean these
are configured as decoupled, inactive, until explicitly activated
or something like that.

> Since the pinctrl states are represented in DT, the DT bindings of all
> devices potentially get affected by changes like this. They'd need to be
> documented in a DT binding document, and the exact semantics of the
> different states clearly explained.

Incidentally pinctrl-bindings.txt refers to the states
"active" and "idle" in the examples, but not "default".
(git blame tells me you wrote this ;-)

We should probably patch that document a bit to reflect
the semantics we agree upon here.

> It may be better for struct device, struct platform_driver, or similar,
> to contain a list of the states that are required by the driver or its
> binding. That way, the list of states (or states beyond the basic
> default) is driver-/DT-binding- specific, and custom stuff like this for
> OMAP wouldn't require explicit code in drivers/base/pinctrl.c, but
> rather simply iterating over a custom list.

Hm, I was more out to nail down some common semantics
here, especially with these helper functions:

extern int pinctrl_pm_select_default_state(struct device *dev);
extern int pinctrl_pm_select_active_state(struct device *dev);
extern int pinctrl_pm_select_sleep_state(struct device *dev);
extern int pinctrl_pm_select_idle_state(struct device *dev);

I am intending this to be *all* for the PM consensual states.
Any other states will be up to the special cases and drivers to
handle still, I have no intention of retrieveing and caching all
possible states in the core.

> Related to that, I'm not sure we should be deriving what we put into DT
> based on the runtime PM requirements of drivers; DT is supposed to be
> driven by HW definitions, although I suppose you could argue that the
> drivers implement what they do because they're implementing the HW
> requirements.

Yes that's a circular proof that we do it this way becuse this is the
way we have to do it :-)

But there is some truth to that.

The idea with these PM states is to correspond to such states
often found in electronic specifications, i.e. derived from a larger
set of hardware, not from runtime PM or Linux.

I conjured the following doc patch as a starter:

diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
index f6e664b..a34ea92 100644
--- a/Documentation/pinctrl.txt
+++ b/Documentation/pinctrl.txt
@@ -1196,6 +1196,124 @@ registered. Thus make sure that the error path
in your driver gracefully
 cleans up and is ready to retry the probing later in the startup process.


+Default and power management related states
+===========================================
+
+As mentioned earlier the device core will automatically try to obtain a
+pinctrl handle and activate the "default" state on all drivers.
+
+However, for power management and power saving, it is sometimes necessary
+to switch pin states at runtime. Electrically speaking this involves
+for example reconfigure some pins to be grounded or pulled-down when the
+system as a whole goes to sleep, or a pull-up could be turned off when pins
+are idle, reducing leak current.
+
+To help out with this, if CONFIG_PM is selected in the Kconfig, three
+additional states will also be obtained by the driver core and cached
+there:
+
+"active"   this is indended as an explicit active state, if the "default"
+           state is not synonymous with the active one.
+
+"idle"     this is a state that is relaxing the pins when the system as a
+           whole is up and running, but these particular pins are unused.
+
+"sleep"    this is a state that is used when the whole system goes to
+           suspend, becomes uninteractive, unresponsive to anything but
+           specific wake-up events.
+
+These correspond to the definitions found in <linux/pinctrl/pinctrl-state.h>
+where the same strings are encoded.
+
+When CONFIG_PM is set, the following functions will simultaneously be made
+available to switch between these power-related states:
+
+#include <linux/pinctrl/consumer.h>
+
+int pinctrl_pm_select_default_state(struct device *dev);
+int pinctrl_pm_select_active_state(struct device *dev);
+int pinctrl_pm_select_sleep_state(struct device *dev);
+int pinctrl_pm_select_idle_state(struct device *dev);
+
+As the corresponding pinctrl handle and states are cached in the driver
+core, nothing apart from these calls is needed to move the pins between
+these states.
+
+For a typical runtime PM enabled (see Documentation/power/runtime_pm.txt)
+driver the following outline could be followed:
+
+probe():
+    pinctrl_pm_select_default_state()
+
+runtime_suspend():
+    pinctrl_pm_select_idle_state()
+
+runtime_resume():
+    pinctrl_pm_select_default_state()
+
+suspend:
+    pinctrl_pm_select_sleep_state()
+
+resume:
+    pinctrl_pm_select_idle_state()
+
+Some of the state selectors could be skipped if the driver is for a
+certain system where e.g. the "active" state is not defined, instead
+relying on the "default" state to make the pins active at all times.
+For a driver only supporting suspend and resume, the "idle" state also
+loose its meaning.
+
+A state-chart diagram would look like this:
+
+                +---------+                          +----------+
+    probe() ->  | default |  -> runtime_suspend() -> | idle     |
+                |         |  <- runtime_resume()  <- |          |
+                +---------+                          +----------+
+                                                        |     ^
+                                                        |     |
+                                                  suspend()  resume()
+                                                        |     |
+                                                        V     |
+                                                      +---------+
+                                                      |  sleep  |
+                                                      +---------+
+
+This reflects the runtime PM concept that we are always runtime
+suspended when we go to suspend.
+
+A more complex example is a driver written for many different
+hardware configurations, some which have only the default state,
+some which have the default state and the sleep state, some that
+have no idle state but indeed a default state and so on. Since
+all states are basically optional (the core will not complain if
+they are not found) we can write our state transitions like
+this:
+
+probe():
+    pinctrl_pm_select_default_state()
+
+runtime_suspend():
+    pinctrl_pm_select_idle_state()
+
+runtime_resume():
+    pinctrl_pm_select_default_state()
+    pinctrl_pm_select_active_state()
+
+suspend:
+    pinctrl_pm_select_sleep_state()
+
+resume:
+    pinctrl_pm_select_default_state()
+    pinctrl_pm_select_idle_state()
+
+Here runtime_resume() and resume() passes through the "default"
+state to the "active" and "idle" states respectively since everything
+but "default" is optional. For example it is OK to only supply the
+"default" and "sleep" state pair with this code, and it will
+transition the pins from "default" to "sleep" and leaving the rest
+as no-ops.
+
+
 Drivers needing both pin control and GPIOs
 ==========================================


Yours,
Linus Walleij



More information about the linux-arm-kernel mailing list