pinctrl: pinconf-generic: Handle string values for generic properties

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>
This commit is contained in:
Antonio Borneo 2025-10-23 15:26:50 +02:00 committed by Linus Walleij
parent 4a6cc9655f
commit 90a18c5128
2 changed files with 50 additions and 18 deletions

View File

@ -65,11 +65,12 @@ static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
int i; int i;
for (i = 0; i < nitems; i++) { for (i = 0; i < nitems; i++) {
const struct pin_config_item *item = &items[i];
unsigned long config; unsigned long config;
int ret; int ret;
/* We want to check out this parameter */ /* 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) if (gname)
ret = pin_config_group_get(dev_name(pctldev->dev), ret = pin_config_group_get(dev_name(pctldev->dev),
gname, &config); gname, &config);
@ -86,15 +87,22 @@ static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
if (*print_sep) if (*print_sep)
seq_puts(s, ", "); seq_puts(s, ", ");
*print_sep = 1; *print_sep = 1;
seq_puts(s, items[i].display); seq_puts(s, item->display);
/* Print unit if available */ /* Print unit if available */
if (items[i].has_arg) { if (item->has_arg) {
u32 val = pinconf_to_config_argument(config); u32 val = pinconf_to_config_argument(config);
if (items[i].format) if (item->format)
seq_printf(s, " (%u %s)", val, items[i].format); seq_printf(s, " (%u %s)", val, item->format);
else else
seq_printf(s, " (0x%x)", val); 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 * @ncfg. @ncfg is updated to reflect the number of entries after parsing. @cfg
* needs to have enough memory allocated to hold all possible entries. * needs to have enough memory allocated to hold all possible entries.
*/ */
static void parse_dt_cfg(struct device_node *np, static int parse_dt_cfg(struct device_node *np,
const struct pinconf_generic_params *params, const struct pinconf_generic_params *params,
unsigned int count, unsigned long *cfg, unsigned int count, unsigned long *cfg,
unsigned int *ncfg) unsigned int *ncfg)
{ {
int i; int i;
@ -217,7 +225,19 @@ static void parse_dt_cfg(struct device_node *np,
int ret; int ret;
const struct pinconf_generic_params *par = &params[i]; 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 */ /* property not found */
if (ret == -EINVAL) 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); cfg[*ncfg] = pinconf_to_config_packed(par->param, val);
(*ncfg)++; (*ncfg)++;
} }
return 0;
} }
/** /**
@ -323,13 +345,16 @@ int pinconf_generic_parse_dt_config(struct device_node *np,
if (!cfg) if (!cfg)
return -ENOMEM; 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 && if (pctldev && pctldev->desc->num_custom_params &&
pctldev->desc->custom_params) pctldev->desc->custom_params) {
parse_dt_cfg(np, pctldev->desc->custom_params, ret = parse_dt_cfg(np, pctldev->desc->custom_params,
pctldev->desc->num_custom_params, cfg, &ncfg); pctldev->desc->num_custom_params, cfg, &ncfg);
if (ret)
ret = 0; return ret;
}
/* no configs found at all */ /* no configs found at all */
if (ncfg == 0) { if (ncfg == 0) {

View File

@ -181,21 +181,28 @@ static inline unsigned long pinconf_to_config_packed(enum pin_config_param param
return PIN_CONF_PACKED(param, argument); return PIN_CONF_PACKED(param, argument);
} }
#define PCONFDUMP(a, b, c, d) { \ #define PCONFDUMP_WITH_VALUES(a, b, c, d, e, f) { \
.param = a, .display = b, .format = c, .has_arg = d \ .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 { struct pin_config_item {
const enum pin_config_param param; const enum pin_config_param param;
const char * const display; const char * const display;
const char * const format; const char * const format;
bool has_arg; bool has_arg;
const char * const *values;
size_t num_values;
}; };
struct pinconf_generic_params { struct pinconf_generic_params {
const char * const property; const char * const property;
enum pin_config_param param; enum pin_config_param param;
u32 default_value; u32 default_value;
const char * const *values;
size_t num_values;
}; };
int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,