]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
pinctrl: pinconf-generic: Handle string values for generic properties
authorAntonio Borneo <antonio.borneo@foss.st.com>
Thu, 23 Oct 2025 13:26:50 +0000 (15:26 +0200)
committerLinus Walleij <linus.walleij@linaro.org>
Tue, 28 Oct 2025 09:43:01 +0000 (10:43 +0100)
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>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/pinctrl/pinconf-generic.c
include/linux/pinctrl/pinconf-generic.h

index e3d10bbcdaebc45e6f06b5aced12d828cfe1e069..72906d71ae1a2ebba0e6d6da6fdfc505370d2673 100644 (file)
@@ -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) {
index d9245ecec71dc6f580ad4768695349f74c92d209..f82add5d3302debfa174953d553a1b690acf5fd3 100644 (file)
@@ -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,