* [PATCH] pinctrl: support selecting states from command line
@ 2025-10-27 6:39 Ahmad Fatoum
2025-10-28 7:46 ` Sascha Hauer
0 siblings, 1 reply; 2+ messages in thread
From: Ahmad Fatoum @ 2025-10-27 6:39 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
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 <a.fatoum@barebox.org>
---
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
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-10-28 7:46 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-27 6:39 [PATCH] pinctrl: support selecting states from command line Ahmad Fatoum
2025-10-28 7:46 ` Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox