improved support for runtime muxing for pinctrl
Subsystems (3)
v2 cover improved support for runtime muxing for pinctrl
Hi all,
Here's this series again with hopefully all the comments addressed.
As discussed earlier, the pinctrl support for changing some of the consumer device pins during runtime needs some improvment.
Regards,
Tony
---
Tony Lindgren (4):
pinctrl: Remove duplicate code in pinctrl_pm_select_state functions
pinctrl: Allow pinctrl to have multiple active states
pinctrl: Add support for additional dynamic states
drivers: Add pinctrl handling for dynamic pin states
Documentation/pinctrl.txt | 77 ++++++++- drivers/base/pinctrl.c | 39 ++++ drivers/pinctrl/core.c | 291 +++++++++++++++++++++++++++------ drivers/pinctrl/core.h | 10 + include/linux/pinctrl/consumer.h | 46 +++++ include/linux/pinctrl/devinfo.h | 4 include/linux/pinctrl/pinctrl-state.h | 15 +- 7 files changed, 420 insertions(+), 62 deletions(-)
Signature · 1 line
Signature
PATCH v2 1/4 pinctrl: Remove duplicate code in pinctrl_pm_select_state functions
There's no need to duplicate essentially the same functions. Let's introduce static int pinctrl_pm_select_state() and make the other related functions call that.
This allows us to add support later on for multiple active states, and more optimized dynamic remuxing.
Note that we still need to export the various pinctrl_pm_select functions as we want to keep struct pinctrl_state private to the pinctrl code, and cannot replace those with inline functions.
--- drivers/pinctrl/core.c | 55 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 28 deletions(-)
drivers/pinctrl/core.c +27 -28
@@ -1227,23 +1227,36 @@ EXPORT_SYMBOL_GPL(pinctrl_force_default);#ifdef CONFIG_PM /** -* pinctrl_pm_select_default_state() - select default pinctrl state for PM +* pinctrl_pm_select_state() - select pinctrl state for PM * @dev: device to select default state for +* @state: state to set */ -int pinctrl_pm_select_default_state (struct device *dev) +static int pinctrl_pm_select_state (struct device *dev, +struct pinctrl_state *state) {struct dev_pin_info *pins = dev->pins;int ret; -if (!pins) -return 0 ; -if (IS_ERR (pins->default_state)) -return 0 ;/* No default state */ - ret =pinctrl_select_state (pins->p, pins->default_state); +if (IS_ERR (state)) +return 0 ;/* No such state */ + ret =pinctrl_select_state (pins->p, state);if (ret) -dev_err (dev,"failed to activate default pinctrl state\n" ); +dev_err (dev,"failed to activate pinctrl state %s\n" , + state->name);return ret; } + +/** +* pinctrl_pm_select_default_state() - select default pinctrl state for PM +* @dev: device to select default state for +*/ +int pinctrl_pm_select_default_state (struct device *dev) +{ +if (!dev->pins) +return 0 ; + +return pinctrl_pm_select_state (dev, dev->pins->default_state); +}EXPORT_SYMBOL_GPL (pinctrl_pm_select_default_state);/**
@@ -1252,17 +1265,10 @@ EXPORT_SYMBOL_GPL(pinctrl_pm_select_default_state);*/ int pinctrl_pm_select_sleep_state (struct device *dev) { -struct dev_pin_info *pins = dev->pins; -int ret; - -if (!pins) +if (!dev->pins)return 0 ; -if (IS_ERR (pins->sleep_state)) -return 0 ;/* No sleep state */ - ret =pinctrl_select_state (pins->p, pins->sleep_state); -if (ret) -dev_err (dev,"failed to activate pinctrl sleep state\n" ); -return ret; + +return pinctrl_pm_select_state (dev, dev->pins->sleep_state); }EXPORT_SYMBOL_GPL (pinctrl_pm_select_sleep_state);
@@ -1272,17 +1278,10 @@ EXPORT_SYMBOL_GPL(pinctrl_pm_select_sleep_state);*/ int pinctrl_pm_select_idle_state (struct device *dev) { -struct dev_pin_info *pins = dev->pins; -int ret; - -if (!pins) +if (!dev->pins)return 0 ; -if (IS_ERR (pins->idle_state)) -return 0 ;/* No idle state */ - ret =pinctrl_select_state (pins->p, pins->idle_state); -if (ret) -dev_err (dev,"failed to activate pinctrl idle state\n" ); -return ret; + +return pinctrl_pm_select_state (dev, dev->pins->idle_state); }EXPORT_SYMBOL_GPL (pinctrl_pm_select_idle_state);#endif
Re: [PATCH 1/4] pinctrl: Remove duplicate code in pinctrl_pm_select_state functions
Quoted 7 lines · Tony Lindgren
There's no need to duplicate essentially the same functions. Let's introduce static int
pinctrl_pm_select_state()and make the other related functions call that.This allows us to add support later on for multiple active states, and more optimized dynamic remuxing.
Quoted 8 lines
Note that we still need to export the various
pinctrl_pm_selectfunctions as we want to keep structpinctrl_stateprivate to the pinctrl code, and cannot replace those with inline functions.Cc Felipe Balbi <[email protected]>Cc Stephen Warren <[email protected]>Signed-off-by Grygorii Strashko <[email protected]>Signed-off-by Tony Lindgren <[email protected]>
Aha that is how to do it. Stephen complained about it earlier but I couldn't come up with a good enough refactoring.
Patch applied.
Yours,
Linus Walleij
PATCH v2 2/4 pinctrl: Allow pinctrl to have multiple active states
In reply to Tony LindgrenIt's quite common that we need to dynamically change some pins for a device for runtime PM, or toggle a pin between rx and tx. Changing all the pins for a device is not efficient way of doing it.
So let's allow setting up multiple active states for pinctrl. Currently we only need PINCTRL_STATIC and PINCTRL_DYNAMIC, where PINCTRL_STATIC covers the current default pins, and PINCTRL_DYNAMIC holds the dynamic pins that need to be toggled.
--- drivers/pinctrl/core.c | 18 ++++++++++-------- drivers/pinctrl/core.h | 10 ++++++++-- 2 files changed, 18 insertions(+), 10 deletions(-)
drivers/pinctrl/core.c +10 -8
@@ -885,7 +885,8 @@ static void pinctrl_free(struct pinctrl *p, bool inlist)mutex_lock (&pinctrl_list_mutex);list_for_each_entry_safe (state, n1, &p->states, node) {list_for_each_entry_safe (setting, n2, &state->settings, node) { -pinctrl_free_setting (state == p->state, setting); +pinctrl_free_setting (state == p->state[PINCTRL_STATIC ], + setting);list_del (&setting->node);kfree (setting); }
@@ -955,13 +956,13 @@ EXPORT_SYMBOL_GPL(pinctrl_lookup_state);int pinctrl_select_state (struct pinctrl *p,struct pinctrl_state *state) {struct pinctrl_setting *setting, *setting2; -struct pinctrl_state *old_state = p->state; +struct pinctrl_state *old_state = p->state[PINCTRL_STATIC ];int ret; -if (p->state == state) +if (old_state == state)return 0 ; -if (p->state) { +if (old_state) {/* * The set of groups with a mux configuration in the old state * may not be identical to the set of groups with a mux setting
@@ -971,7 +972,7 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)* but not in the new state, this code puts that group into a * safe/disabled state. */ -list_for_each_entry (setting, &p->state->settings, node) { +list_for_each_entry (setting, &old_state->settings, node) {bool found = false;if (setting->type !=PIN_MAP_TYPE_MUX_GROUP )continue ;
@@ -989,7 +990,7 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) } } - p->state =NULL ; + p->state[PINCTRL_STATIC ] =NULL ;/* Apply all the settings for the new state */ list_for_each_entry (setting, &state->settings, node) {
@@ -1011,7 +1012,7 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) } } - p->state = state; + p->state[PINCTRL_STATIC ] = state;return 0 ;
@@ -1492,7 +1493,8 @@ static int pinctrl_show(struct seq_file *s, void *what)list_for_each_entry (p, &pinctrl_list, node) {seq_printf (s,"device: %s current state: %s\n" ,dev_name (p->dev), - p->state ? p->state->name :"none" ); + p->state[PINCTRL_STATIC ] ? + p->state[PINCTRL_STATIC ]->name :"none" );list_for_each_entry (state, &p->states, node) {seq_printf (s," state: %s\n" , state->name);
drivers/pinctrl/core.h +8 -2
@@ -53,12 +53,18 @@ struct pinctrl_dev {#endif }; +enum pinctrl_states { +PINCTRL_STATIC , +PINCTRL_DYNAMIC , +PINCTRL_NR_STATES , +}; +/** * struct pinctrl - per-device pin control state holder * @node: global list node * @dev: the device using this pin control handle * @states: a list of states for this device -* @state: the current state +* @state: the current state(s) * @dt_maps: the mapping table chunks dynamically parsed from device tree for * this device, if any * @users: reference count
@@ -67,7 +73,7 @@ struct pinctrl {struct list_head node;struct device *dev;struct list_head states; -struct pinctrl_state *state; +struct pinctrl_state *state[PINCTRL_NR_STATES ];struct list_head dt_maps;struct kref users; };
Re: [PATCH 2/4] pinctrl: Allow pinctrl to have multiple active states
Quoted 2 lines · Tony Lindgren
It's quite common that we need to dynamically change some pins for a device for runtime PM, or toggle a pin between rx and tx. Changing all
What does "change" mean above?
Please reword to "remux" if that is what is meant.
Quoted 3 lines
the pins for a device is not efficient way of doing it.
So let's allow setting up multiple active states for pinctrl.
Do you mean multiple default states?
I have a hard time understanding so please help me out :-/
Quoted 4 lines
Currently
we only needPINCTRL_STATICandPINCTRL_DYNAMIC, wherePINCTRL_STATICcovers the current default pins, andPINCTRL_DYNAMICholds the dynamic pins that need to be toggled.
Toggled when?
When changing state to another one? Any other state? Or back to this state? Sorry not following ... this needs to be more verbose.
Quoted 83 lines
Cc Felipe Balbi <[email protected]>Cc Grygorii Strashko <[email protected]>Cc Stephen Warren <[email protected]>Signed-off-by Tony Lindgren <[email protected]>--- drivers/pinctrl/core.c | 18 ++++++++++-------- drivers/pinctrl/core.h | 10 ++++++++-- 2 files changed, 18 insertions(+), 10 deletions(-)drivers/pinctrl/core.c +10
-8@@ -885,7 +885,8 @@ static void pinctrl_free(struct pinctrl *p, bool inlist)mutex_lock (&pinctrl_list_mutex);list_for_each_entry_safe (state, n1, &p->states, node) {list_for_each_entry_safe (setting, n2, &state->settings, node) { -pinctrl_free_setting (state == p->state, setting); +pinctrl_free_setting (state == p->state[PINCTRL_STATIC ], + setting);list_del (&setting->node);kfree (setting); }@@ -955,13 +956,13 @@ EXPORT_SYMBOL_GPL(pinctrl_lookup_state);int pinctrl_select_state (struct pinctrl *p,struct pinctrl_state *state) {struct pinctrl_setting *setting, *setting2; -struct pinctrl_state *old_state = p->state; +struct pinctrl_state *old_state = p->state[PINCTRL_STATIC ];int ret; -if (p->state == state) +if (old_state == state)return 0 ; -if (p->state) { +if (old_state) {/* * The set of groups with a mux configuration in the old state * may not be identical to the set of groups with a mux setting @@ -971,7 +972,7 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)* but not in the new state, this code puts that group into a * safe/disabled state. */ -list_for_each_entry (setting, &p->state->settings, node) { +list_for_each_entry (setting, &old_state->settings, node) {bool found = false;if (setting->type !=PIN_MAP_TYPE_MUX_GROUP )continue ;@@ -989,7 +990,7 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) } } - p->state =NULL ; + p->state[PINCTRL_STATIC ] =NULL ;/* Apply all the settings for the new state */ list_for_each_entry (setting, &state->settings, node) {@@ -1011,7 +1012,7 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) } } - p->state = state; + p->state[PINCTRL_STATIC ] = state;return 0 ;@@ -1492,7 +1493,8 @@ static int pinctrl_show(struct seq_file *s, void *what)list_for_each_entry (p, &pinctrl_list, node) {seq_printf (s,"device: %s current state: %s\n" ,dev_name (p->dev), - p->state ? p->state->name :"none" ); + p->state[PINCTRL_STATIC ] ? + p->state[PINCTRL_STATIC ]->name :"none" );list_for_each_entry (state, &p->states, node) {seq_printf (s," state: %s\n" , state->name);drivers/pinctrl/core.h +0
-0
drivers/pinctrl/core.h struct pinctrl_dev { · line 60
Quoted 8 lines
drivers/pinctrl/core.h +5
-0@@ -53,12 +53,18 @@ struct pinctrl_dev {#endif }; +enum pinctrl_states { +PINCTRL_STATIC , +PINCTRL_DYNAMIC , +PINCTRL_NR_STATES , +};
This needs some very precise kerneldoc so it is chrystal clear what these states are all about. "pinctrl_states" is not a good name for this enum, please find some more precise name, because we have functions with names like pinctrl_select_state() which is not related to this.
Is this substates or?
drivers/pinctrl/core.h struct pinctrl_dev { · line 67
Quoted 8 lines
drivers/pinctrl/core.h +2
-1+/** * struct pinctrl - per-device pin control state holder * @node: global list node * @dev: the device using this pin control handle * @states: a list of states for this device -* @state: the current state +* @state: the current state(s)
How can more than one state be the current state? Sorry I don't get this. This needs to be more precise I think.
drivers/pinctrl/core.h struct pinctrl { · line 79
Quoted 12 lines
drivers/pinctrl/core.h +1
-1* @dt_maps: the mapping table chunks dynamically parsed from device tree for * this device, if any * @users: reference count @@ -67,7 +73,7 @@ struct pinctrl {struct list_head node;struct device *dev;struct list_head states; -struct pinctrl_state *state; +struct pinctrl_state *state[PINCTRL_NR_STATES ];struct list_head dt_maps;struct kref users; };
Yours,
Linus Walleij
Re: [PATCH 2/4] pinctrl: Allow pinctrl to have multiple active states
Quoted 8 lines · Linus Walleij
Quoted 2 lines · Tony Lindgren
It's quite common that we need to dynamically change some pins for a device for runtime PM, or toggle a pin between rx and tx. Changing all
What does "change" mean above?
Please reword to "remux" if that is what is meant.
Yes remux or reconfigure the pinconf depending on the hardware. And possibly based on the board specific configuration if both options are available.
Quoted 7 lines
Quoted 3 lines
the pins for a device is not efficient way of doing it.
So let's allow setting up multiple active states for pinctrl.
Do you mean multiple default states?
I have a hard time understanding so please help me out :-/
One default state, which should only contain the static pins that don't need to be remuxed or reconfigured during runtime PM.
It should probably say "support for multiple currently activated states", does that make it clearer?
Quoted 6 lines
Quoted 4 lines
Currently
we only needPINCTRL_STATICandPINCTRL_DYNAMIC, wherePINCTRL_STATICcovers the current default pins, andPINCTRL_DYNAMICholds the dynamic pins that need to be toggled.Toggled when?
Remuxed or reconfigured constantly for runtime PM.
Quoted 2 lines
When changing state to another one? Any other state? Or back to this state? Sorry not following ... this needs to be more verbose.
How about "toggle dynamic pins between active and idle state for runtime PM"?
Quoted 17 lines
drivers/pinctrl/core.h struct pinctrl_dev { · line 60
Quoted 11 lines
drivers/pinctrl/core.h +5
-0@@ -53,12 +53,18 @@ struct pinctrl_dev {#endif }; +enum pinctrl_states { +PINCTRL_STATIC , +PINCTRL_DYNAMIC , +PINCTRL_NR_STATES , +};This needs some very precise kerneldoc so it is chrystal clear what these states are all about. "
pinctrl_states" is not a good name for this enum, please find some more precise name, because we have functions with names likepinctrl_select_state()which is not related to this.
Quoted 1 line
Is this substates or?
This lists the sets of pins that can be activated the same time. So after this, we support two sets of pins that a pinctrl consumer driver can have activated the same time:
static pins and dynamic pins. There can be any number of named modes for dynamic pins, but typically only active and idle.
Then if for some reason we need more than two sets activated the same time, we can expand the array as needed. So that's mostly to try to keep things future proof and not limit things to two sets as noted by Stephen earlier.
Quoted 11 lines
drivers/pinctrl/core.h struct pinctrl_dev { · line 67
Quoted 8 lines
drivers/pinctrl/core.h +2
-1+/** * struct pinctrl - per-device pin control state holder * @node: global list node * @dev: the device using this pin control handle * @states: a list of states for this device -* @state: the current state +* @state: the current state(s) How can more than one state be the current state? Sorry I don't get this. This needs to be more precise I think.
Hopefully the explanation above helps with that, if not, let me know.
Regards,
Tony
PATCH v2 3/4 pinctrl: Add support for additional dynamic states
In reply to Tony LindgrenTo toggle dynamic states, let's add the optional active state in addition to the static default state. Then if the optional active state is defined, we can require that idle and sleep states cover the same pingroups as the active state.
Then let's add pinctrl_check_dynamic() and pinctrl_select_dynamic() to use instead of pinctrl_select() to avoid breaking existing users.
With pinctrl_check_dynamic() we can check that idle and sleep states match the active state for pingroups during init, and don't need to do it during runtime.
Then with the states pre-validated, pinctrl_select_dynamic() can just toggle between the dynamic states without extra checks.
Note that pinctr_select_state() still has valid use cases, such as changing states when the pins can be shared between two drivers and don't necessarily cover the same pingroups. For dynamic runtime toggling of pin states, we should eventually always use just pinctrl_select_dynamic().
--- Documentation/pinctrl.txt | 77 ++++++++++- drivers/pinctrl/core.c | 226 ++++++++++++++++++++++++++++++--- include/linux/pinctrl/consumer.h | 46 +++++++ include/linux/pinctrl/devinfo.h | 4 + include/linux/pinctrl/pinctrl-state.h | 15 ++ 5 files changed, 342 insertions(+), 26 deletions(-)
Documentation/pinctrl.txt +71 -6
@@ -1283,12 +1283,77 @@ This gives the exact same result as the above construction. Runtime pinmuxing ================= -It is possible to mux a certain function in and out at runtime, say to move -an SPI port from one set of pins to another set of pins. Say for example for -spi0 in the example above, we expose two different groups of pins for the same -function, but with different named in the mapping as described under -"Advanced mapping" above. So that for an SPI device, we have two states named -"pos-A" and "pos-B". +Typically runtime pinmuxing is done for runtime PM to mux a device RX pin +to GPIO for wake-up events. And In some cases a shared RX/TX pin may need to +be toggled. Sometimes pins can be also shared between two device drivers. + +In most cases runtime pinmuxing only is needed for some pins on a device, and +most pins can be static. To avoid continuously having to check for all the +pins of a device, pinctrl framework supports grouping device pin states to +static and dynamic states. + +Most devices only need to use the static default state. If a devices has a +need for runtime pinmuxing, the device must define the static default state, +and then the optional dynamic states using the following rules: + +1. The default dynamic states are in addition to the static default state. + +2. The default dynamic states are active, sleep and idle, or active and idle. + +3. At least active and idle, or active and sleep states must be defined. + +4. Out of the dynamic pin states, only one of the active, sleep or idle states + can be active at a time. + +5. The dynamic pin states must all toggle the same pins to avoid unnecessary + checks during runtime. + +6. The pinctrl consumer driver must use pinctrl_select_dynamic() instead of + pinctrl_select_state() to toggle between the dynamic states. + +For example, to mux a serial driver RX pin to GPIO for runtime PM wake-up +events, something like the following can be done. Most of the work is done +by the pinctrl framework as long as the default, active and idle states are +properly defined. + +#include <linux/pinctrl/consumer.h> + +serial_foo_probe() +{ + ... + if (!pinctrl_pm_is_idle_state_error()) + /* Set driver specific flags for runtime PM */ + ... +} + +static int serial_foo_runtime_suspend(struct device *dev) +{ + ... + res = pinctrl_pm_select_idle_state(dev); + if (ret < 0) + return ret; + ... +} + +static int serial_foo_runtime_resume(struct device *dev) +{ + ... + res = pinctrl_pm_select_active_state(dev); + if (ret < 0) + return ret; + ... +} + +Currently only runtime muxing for runtime PM has been optimized as that can +happen@high rate every time when idling and unidling devices. For less +latency critical runtime remuxing it is possible to use pinctrl_select_state() +as described below. + +For example, it is possible to move an SPI port from one set of pins to another +set of pins. Say for example for spi0 in the example above, we expose two +different groups of pins for the same function, but with different named in +the mapping as described under "Advanced mapping" above. So that for an SPI +device, we have two states named "pos-A" and "pos-B". This snippet first muxes the function in the pins defined by group A, enables it, disables and releases it, and muxes it in on the pins defined by group B:
drivers/pinctrl/core.c +208 -18
276 lines not on this page · raw message
include/linux/pinctrl/consumer.h +46 -0
89 lines not on this page · raw message
include/linux/pinctrl/devinfo.h +4 -0
@@ -24,10 +24,14 @@* struct dev_pin_info - pin state container for devices * @p: pinctrl handle for the containing device * @default_state: the default state for the handle, if found +* @active_state: the default state for the handle, if found +* @sleep_state: the default state for the handle, if found +* @idle_state: the default state for the handle, if found */ struct dev_pin_info {struct pinctrl *p;struct pinctrl_state *default_state; +struct pinctrl_state *active_state;#ifdef CONFIG_PM struct pinctrl_state *sleep_state;struct pinctrl_state *idle_state;
include/linux/pinctrl/pinctrl-state.h +13 -2
@@ -9,16 +9,27 @@* hogs to configure muxing and pins at boot, and also as a state * to go into when returning from sleep and idle in * .pm_runtime_resume() or ordinary .resume() for example. +* @PINCTRL_STATE_ACTIVE: optional state of dynamic pins in addition to +* PINCTRL_STATE_DEFAULT that are needed during runtime. * @PINCTRL_STATE_IDLE: the state the pinctrl handle shall be put into * when the pins are idle. This is a state where the system is relaxed * but not fully sleeping - some power may be on but clocks gated for * example. Could typically be set from a pm_runtime_suspend() or -* pm_runtime_idle() operation. +* pm_runtime_idle() operation. If PINCTRL_STATE_ACTIVE pins are +* defined, PINCTRL_STATE_IDLE pin groups must cover the same pin +* groups as PINCTRL_STATE_ACTIVE and selecting PINCTRL_STATE_IDLE +* must be done using pinctrl_select_state_dynamic() instead of +* pinctrl_select_state(). * @PINCTRL_STATE_SLEEP: the state the pinctrl handle shall be put into * when the pins are sleeping. This is a state where the system is in * its lowest sleep state. Could typically be set from an -* ordinary .suspend() function. +* ordinary .suspend() function. If PINCTRL_STATE_ACTIVE pins are +* defined, PINCTRL_STATE_SLEEP pin groups must cover the same pin +* groups as PINCTRL_STATE_ACTIVE and selecting PINCTRL_STATE_SLEEP +* must be done using pinctrl_select_state_dynamic() instead of +* pinctrl_select_state(). */ #define PINCTRL_STATE_DEFAULT "default" +#define PINCTRL_STATE_ACTIVE "active"#define PINCTRL_STATE_IDLE "idle"#define PINCTRL_STATE_SLEEP "sleep"
PATCH v2 4/4 drivers: Add pinctrl handling for dynamic pin states
In reply to Tony LindgrenWe want to have static pin states handled separately from dynamic pin states, so let's add optional state_active.
Then if state_active is defined, let's check and make sure state_idle and state_sleep match state_active for the pin groups to avoid checking them during runtime as the active and idle pins may need to be toggled for many devices every time we enter and exit idle.
See also Documentation/pinctrl.txt regarding runtime muxing of pins.
--- drivers/base/pinctrl.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-)
drivers/base/pinctrl.c +37 -2
@@ -34,6 +34,7 @@ int pinctrl_bind_pins(struct device *dev) goto cleanup_alloc; } +/* Default static pins that don't need to change */ dev->pins->default_state =pinctrl_lookup_state (dev->pins->p,PINCTRL_STATE_DEFAULT );if (IS_ERR (dev->pins->default_state)) {
@@ -48,23 +49,57 @@ int pinctrl_bind_pins(struct device *dev) goto cleanup_get; } +/* Optional runtime dynamic pins in addition to the static pins */ + dev->pins->active_state =pinctrl_lookup_state (dev->pins->p, +PINCTRL_STATE_ACTIVE ); +if (IS_ERR (dev->pins->active_state)) { +/* Not supplying this state is perfectly legal */ +dev_dbg (dev,"no active pinctrl state\n" ); + }else { + ret =pinctrl_select_dynamic (dev->pins->p, + dev->pins->active_state); +if (ret) { +dev_dbg (dev,"failed to select active pinctrl state\n" ); + goto cleanup_get; + } + } +#ifdef CONFIG_PM /* * If power management is enabled, we also look for the optional * sleep and idle pin states, with semantics as defined in * <linux/pinctrl/pinctrl-state.h> +* +* Note that if active state is defined, sleep and idle states must +* cover the same pin groups as active state. */ dev->pins->sleep_state =pinctrl_lookup_state (dev->pins->p,PINCTRL_STATE_SLEEP ); -if (IS_ERR (dev->pins->sleep_state)) +if (IS_ERR (dev->pins->sleep_state)) {/* Not supplying this state is perfectly legal */ dev_dbg (dev,"no sleep pinctrl state\n" ); + }else if (!IS_ERR (dev->pins->active_state)) { + ret =pinctrl_check_dynamic (dev, dev->pins->active_state, + dev->pins->sleep_state); +if (ret) { +dev_err (dev,"sleep state groups do not match active state\n" ); + dev->pins->sleep_state =ERR_PTR (-EINVAL ); + } + } dev->pins->idle_state =pinctrl_lookup_state (dev->pins->p,PINCTRL_STATE_IDLE ); -if (IS_ERR (dev->pins->idle_state)) +if (IS_ERR (dev->pins->idle_state)) {/* Not supplying this state is perfectly legal */ dev_dbg (dev,"no idle pinctrl state\n" ); + }else if (!IS_ERR (dev->pins->active_state)) { + ret =pinctrl_check_dynamic (dev, dev->pins->active_state, + dev->pins->idle_state); +if (ret) { +dev_err (dev,"idle state groups do not match active state\n" ); + dev->pins->idle_state =ERR_PTR (-EINVAL ); + } + }#endif return 0 ;