This can be useful for debugging to exercise pinctrl for nodes that have no driver yet. Example:
setenv adc-joystick.of.pinctrl_state=default Signed-off-by: Ahmad Fatoum <[email protected]> --- drivers/base/driver.c | 4 ++ drivers/pinctrl/Kconfig | 4 ++ drivers/pinctrl/pinctrl.c | 92 +++++++++++++++++++++++++++++++++++++++ include/param.h | 2 + include/pinctrl.h | 10 +++++ lib/parameter.c | 6 ++- 6 files changed, 116 insertions(+), 2 deletions(-) diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 61118385f1df..33d9e2bcde5a 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -268,6 +268,8 @@ int register_device(struct device *new_device) bobject_init(&new_device->bobject); + of_pinctrl_register_consumer(new_device, new_device->device_node); + if (new_device->bus) { if (!new_device->parent) new_device->parent = &new_device->bus->dev; @@ -298,6 +300,8 @@ int unregister_device(struct device *old_dev) bobject_del(&old_dev->bobject); + of_pinctrl_unregister_consumer(old_dev); + if (old_dev->driver) device_remove(old_dev); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 72ca79aa9880..1d237db106ba 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -10,6 +10,10 @@ config PINCTRL from the devicetree. Legacy drivers here may not need this core support but instead provide their own SoC specific APIs +config PINCTRL_STATE_PARAM + bool "pinctrl state control via device parameters" + depends on PARAMETER && PINCTRL + # The following drivers are needed even without PINCTRL because # the either have a legacy iomux interface or also register a gpio # chip. diff --git a/drivers/pinctrl/pinctrl.c b/drivers/pinctrl/pinctrl.c index 106a4423184c..2f85a0f08f08 100644 --- a/drivers/pinctrl/pinctrl.c +++ b/drivers/pinctrl/pinctrl.c @@ -7,6 +7,7 @@ #include <common.h> #include <malloc.h> #include <pinctrl.h> +#include <linux/overflow.h> #include <errno.h> #include <of.h> @@ -14,10 +15,20 @@ struct pinctrl { struct device_node consumer_np; }; +static LIST_HEAD(pinctrl_consumer_list); + struct pinctrl_state { struct property prop; }; +struct pinctrl_consumer_info { + struct device *dev; + struct device_node *np; + int state; + struct list_head list; + const char *states[]; +}; + LIST_HEAD(pinctrl_list); static struct pinctrl_device *pin_to_pinctrl(unsigned int pin) @@ -104,6 +115,33 @@ of_property_pinctrl_get_state(struct property *prop) return container_of(prop, struct pinctrl_state, prop); } +static void pinctrl_update_state_param(struct pinctrl *pinctrl, + struct pinctrl_state *state) +{ + struct device_node *np = &pinctrl->consumer_np; + struct property *prop = &state->prop; + struct pinctrl_consumer_info *info; + u16 idx; + int ret; + + if (!IS_ENABLED(CONFIG_PINCTRL_STATE_PARAM)) + return; + + if (!strstarts(prop->name, "pinctrl-")) + return; + + ret = kstrtou16(&prop->name[sizeof("pinctrl-") - 1], 10, &idx); + if (ret) + return; + + list_for_each_entry(info, &pinctrl_consumer_list, list) { + if (info->np != np) + continue; + + info->state = idx; + } +} + struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *pinctrl, const char *name) { @@ -173,6 +211,8 @@ int pinctrl_select_state(struct pinctrl *pinctrl, struct pinctrl_state *state) if (ret < 0) goto err; } + + pinctrl_update_state_param(pinctrl, state); err: return ret; } @@ -238,3 +278,55 @@ void pinctrl_unregister(struct pinctrl_device *pdev) { list_del(&pdev->list); } + + +#ifdef CONFIG_PINCTRL_STATE_PARAM +static int pinctrl_state_param_set(struct param_d *p, void *priv) +{ + struct pinctrl_consumer_info *info = priv; + + return of_pinctrl_select_state(info->np, info->states[info->state]); +} + +void of_pinctrl_register_consumer(struct device *dev, + struct device_node *np) +{ + struct pinctrl_consumer_info *info; + int ret, nstates; + + nstates = of_property_count_strings(np, "pinctrl-names"); + if (nstates <= 0) + return; + + info = malloc(struct_size(info, states, nstates)); + if (!info) + return; + + info->dev = dev; + info->np = np; + info->state = PARAM_ENUM_UNKNOWN; + + ret = of_property_read_string_array(np, "pinctrl-names", info->states, nstates); + if (ret < 0) + return; + + list_add(&info->list, &pinctrl_consumer_list); + + dev_add_param_enum(dev, "pinctrl_state", + pinctrl_state_param_set, NULL, + &info->state, info->states, nstates, info); +} + +void of_pinctrl_unregister_consumer(struct device *dev) +{ + struct pinctrl_consumer_info *info; + + list_for_each_entry(info, &pinctrl_consumer_list, list) { + if (info->dev != dev) + continue; + + list_del(&info->list); + return; + } +} +#endif diff --git a/include/param.h b/include/param.h index 59aa8a3a385f..1713a18c378e 100644 --- a/include/param.h +++ b/include/param.h @@ -42,6 +42,8 @@ struct param_d { enum param_type type; }; +#define PARAM_ENUM_UNKNOWN (-1000000) + enum param_tristate { PARAM_TRISTATE_UNKNOWN, PARAM_TRISTATE_TRUE, PARAM_TRISTATE_FALSE }; #ifdef CONFIG_PARAMETER diff --git a/include/pinctrl.h b/include/pinctrl.h index 4ba7b489345b..5c031fb4008b 100644 --- a/include/pinctrl.h +++ b/include/pinctrl.h @@ -25,4 +25,14 @@ struct pinctrl_device { int pinctrl_register(struct pinctrl_device *pdev); void pinctrl_unregister(struct pinctrl_device *pdev); +#ifdef CONFIG_PINCTRL_STATE_PARAM +void of_pinctrl_register_consumer(struct device *dev, struct device_node *np); +void of_pinctrl_unregister_consumer(struct device *dev); +#else +static inline void of_pinctrl_register_consumer(struct device *dev, struct device_node *np) +{ +} +static inline void of_pinctrl_unregister_consumer(struct device *dev) {} +#endif + #endif /* PINCTRL_H */ diff --git a/lib/parameter.c b/lib/parameter.c index f36d77d119fa..b9a449c32657 100644 --- a/lib/parameter.c +++ b/lib/parameter.c @@ -612,7 +612,9 @@ static const char *param_enum_get(struct bobject *bobj, struct param_d *p) free(p->value); - if (*pe->value >= pe->num_names) + if (*pe->value == PARAM_ENUM_UNKNOWN) + p->value = strdup("unknown"); + else if (*pe->value >= pe->num_names) p->value = basprintf("invalid:%d", *pe->value); else p->value = strdup(pe->names[*pe->value]); @@ -625,7 +627,7 @@ static void param_enum_info(struct param_d *p) struct param_enum *pe = to_param_enum(p); int i; - if (pe->num_names <= 1) + if (pe->num_names <= 1 && *pe->value != PARAM_ENUM_UNKNOWN) return; printf(" (values: "); -- 2.47.3
