[PATCH v4 02/12] pinctrl: pinconf-generic: Handle string values for generic properties

Antonio Borneo posted 12 patches 1 month, 3 weeks ago
[PATCH v4 02/12] pinctrl: pinconf-generic: Handle string values for generic properties
Posted by Antonio Borneo 1 month, 3 weeks ago
Allow a generic pinconf property to specify its argument as one of
the strings in a match list.
Convert the matching string to an integer value using the index in
the list, then keep using this value in the generic pinconf code.

Signed-off-by: Antonio Borneo <antonio.borneo@foss.st.com>
---
 drivers/pinctrl/pinconf-generic.c       | 57 ++++++++++++++++++-------
 include/linux/pinctrl/pinconf-generic.h | 11 ++++-
 2 files changed, 50 insertions(+), 18 deletions(-)

diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index e3d10bbcdaebc..72906d71ae1a2 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -65,11 +65,12 @@ static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
 	int i;
 
 	for (i = 0; i < nitems; i++) {
+		const struct pin_config_item *item = &items[i];
 		unsigned long config;
 		int ret;
 
 		/* We want to check out this parameter */
-		config = pinconf_to_config_packed(items[i].param, 0);
+		config = pinconf_to_config_packed(item->param, 0);
 		if (gname)
 			ret = pin_config_group_get(dev_name(pctldev->dev),
 						   gname, &config);
@@ -86,15 +87,22 @@ static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
 		if (*print_sep)
 			seq_puts(s, ", ");
 		*print_sep = 1;
-		seq_puts(s, items[i].display);
+		seq_puts(s, item->display);
 		/* Print unit if available */
-		if (items[i].has_arg) {
+		if (item->has_arg) {
 			u32 val = pinconf_to_config_argument(config);
 
-			if (items[i].format)
-				seq_printf(s, " (%u %s)", val, items[i].format);
+			if (item->format)
+				seq_printf(s, " (%u %s)", val, item->format);
 			else
 				seq_printf(s, " (0x%x)", val);
+
+			if (item->values && item->num_values) {
+				if (val < item->num_values)
+					seq_printf(s, " \"%s\"", item->values[val]);
+				else
+					seq_puts(s, " \"(unknown)\"");
+			}
 		}
 	}
 }
@@ -205,10 +213,10 @@ static const struct pinconf_generic_params dt_params[] = {
  * @ncfg. @ncfg is updated to reflect the number of entries after parsing. @cfg
  * needs to have enough memory allocated to hold all possible entries.
  */
-static void parse_dt_cfg(struct device_node *np,
-			 const struct pinconf_generic_params *params,
-			 unsigned int count, unsigned long *cfg,
-			 unsigned int *ncfg)
+static int parse_dt_cfg(struct device_node *np,
+			const struct pinconf_generic_params *params,
+			unsigned int count, unsigned long *cfg,
+			unsigned int *ncfg)
 {
 	int i;
 
@@ -217,7 +225,19 @@ static void parse_dt_cfg(struct device_node *np,
 		int ret;
 		const struct pinconf_generic_params *par = &params[i];
 
-		ret = of_property_read_u32(np, par->property, &val);
+		if (par->values && par->num_values) {
+			ret = fwnode_property_match_property_string(of_fwnode_handle(np),
+								    par->property,
+								    par->values, par->num_values);
+			if (ret == -ENOENT)
+				return ret;
+			if (ret >= 0) {
+				val = ret;
+				ret = 0;
+			}
+		} else {
+			ret = of_property_read_u32(np, par->property, &val);
+		}
 
 		/* property not found */
 		if (ret == -EINVAL)
@@ -231,6 +251,8 @@ static void parse_dt_cfg(struct device_node *np,
 		cfg[*ncfg] = pinconf_to_config_packed(par->param, val);
 		(*ncfg)++;
 	}
+
+	return 0;
 }
 
 /**
@@ -323,13 +345,16 @@ int pinconf_generic_parse_dt_config(struct device_node *np,
 	if (!cfg)
 		return -ENOMEM;
 
-	parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg);
+	ret = parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg);
+	if (ret)
+		return ret;
 	if (pctldev && pctldev->desc->num_custom_params &&
-		pctldev->desc->custom_params)
-		parse_dt_cfg(np, pctldev->desc->custom_params,
-			     pctldev->desc->num_custom_params, cfg, &ncfg);
-
-	ret = 0;
+		pctldev->desc->custom_params) {
+		ret = parse_dt_cfg(np, pctldev->desc->custom_params,
+				   pctldev->desc->num_custom_params, cfg, &ncfg);
+		if (ret)
+			return ret;
+	}
 
 	/* no configs found at all */
 	if (ncfg == 0) {
diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h
index d9245ecec71dc..f82add5d3302d 100644
--- a/include/linux/pinctrl/pinconf-generic.h
+++ b/include/linux/pinctrl/pinconf-generic.h
@@ -181,21 +181,28 @@ static inline unsigned long pinconf_to_config_packed(enum pin_config_param param
 	return PIN_CONF_PACKED(param, argument);
 }
 
-#define PCONFDUMP(a, b, c, d) {					\
-	.param = a, .display = b, .format = c, .has_arg = d	\
+#define PCONFDUMP_WITH_VALUES(a, b, c, d, e, f) {		\
+	.param = a, .display = b, .format = c, .has_arg = d,	\
+	.values = e, .num_values = f				\
 	}
 
+#define PCONFDUMP(a, b, c, d)	PCONFDUMP_WITH_VALUES(a, b, c, d, NULL, 0)
+
 struct pin_config_item {
 	const enum pin_config_param param;
 	const char * const display;
 	const char * const format;
 	bool has_arg;
+	const char * const *values;
+	size_t num_values;
 };
 
 struct pinconf_generic_params {
 	const char * const property;
 	enum pin_config_param param;
 	u32 default_value;
+	const char * const *values;
+	size_t num_values;
 };
 
 int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
-- 
2.34.1
Re: [PATCH v4 02/12] pinctrl: pinconf-generic: Handle string values for generic properties
Posted by Linus Walleij 1 month, 2 weeks ago
On Thu, Oct 23, 2025 at 3:27 PM Antonio Borneo
<antonio.borneo@foss.st.com> wrote:

> Allow a generic pinconf property to specify its argument as one of
> the strings in a match list.
> Convert the matching string to an integer value using the index in
> the list, then keep using this value in the generic pinconf code.
>
> Signed-off-by: Antonio Borneo <antonio.borneo@foss.st.com>

Patch applied, I had a hard time to follow the patch fully and unsure
if we should add some docs as well? But let's toss it in there and see
if it works.

Yours,
Linus Walleij