in renesas/pinctrl-rzg2l.c [236:372]
static int rzg2l_dt_subnode_to_map(struct pinctrl_dev *pctldev,
struct device_node *np,
struct pinctrl_map **map,
unsigned int *num_maps,
unsigned int *index)
{
struct rzg2l_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
struct pinctrl_map *maps = *map;
unsigned int nmaps = *num_maps;
unsigned long *configs = NULL;
unsigned int *pins, *psel_val;
unsigned int num_pinmux = 0;
unsigned int idx = *index;
unsigned int num_pins, i;
unsigned int num_configs;
struct property *pinmux;
struct property *prop;
int ret, gsel, fsel;
const char **pin_fn;
const char *pin;
pinmux = of_find_property(np, "pinmux", NULL);
if (pinmux)
num_pinmux = pinmux->length / sizeof(u32);
ret = of_property_count_strings(np, "pins");
if (ret == -EINVAL) {
num_pins = 0;
} else if (ret < 0) {
dev_err(pctrl->dev, "Invalid pins list in DT\n");
return ret;
} else {
num_pins = ret;
}
if (!num_pinmux && !num_pins)
return 0;
if (num_pinmux && num_pins) {
dev_err(pctrl->dev,
"DT node must contain either a pinmux or pins and not both\n");
return -EINVAL;
}
ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &num_configs);
if (ret < 0)
return ret;
if (num_pins && !num_configs) {
dev_err(pctrl->dev, "DT node must contain a config\n");
ret = -ENODEV;
goto done;
}
if (num_pinmux)
nmaps += 1;
if (num_pins)
nmaps += num_pins;
maps = krealloc_array(maps, nmaps, sizeof(*maps), GFP_KERNEL);
if (!maps) {
ret = -ENOMEM;
goto done;
}
*map = maps;
*num_maps = nmaps;
if (num_pins) {
of_property_for_each_string(np, "pins", prop, pin) {
ret = rzg2l_map_add_config(&maps[idx], pin,
PIN_MAP_TYPE_CONFIGS_PIN,
configs, num_configs);
if (ret < 0)
goto done;
idx++;
}
ret = 0;
goto done;
}
pins = devm_kcalloc(pctrl->dev, num_pinmux, sizeof(*pins), GFP_KERNEL);
psel_val = devm_kcalloc(pctrl->dev, num_pinmux, sizeof(*psel_val),
GFP_KERNEL);
pin_fn = devm_kzalloc(pctrl->dev, sizeof(*pin_fn), GFP_KERNEL);
if (!pins || !psel_val || !pin_fn) {
ret = -ENOMEM;
goto done;
}
/* Collect pin locations and mux settings from DT properties */
for (i = 0; i < num_pinmux; ++i) {
u32 value;
ret = of_property_read_u32_index(np, "pinmux", i, &value);
if (ret)
goto done;
pins[i] = value & MUX_PIN_ID_MASK;
psel_val[i] = MUX_FUNC(value);
}
/* Register a single pin group listing all the pins we read from DT */
gsel = pinctrl_generic_add_group(pctldev, np->name, pins, num_pinmux, NULL);
if (gsel < 0) {
ret = gsel;
goto done;
}
/*
* Register a single group function where the 'data' is an array PSEL
* register values read from DT.
*/
pin_fn[0] = np->name;
fsel = pinmux_generic_add_function(pctldev, np->name, pin_fn, 1,
psel_val);
if (fsel < 0) {
ret = fsel;
goto remove_group;
}
maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
maps[idx].data.mux.group = np->name;
maps[idx].data.mux.function = np->name;
idx++;
dev_dbg(pctrl->dev, "Parsed %pOF with %d pins\n", np, num_pinmux);
ret = 0;
goto done;
remove_group:
pinctrl_generic_remove_group(pctldev, gsel);
done:
*index = idx;
kfree(configs);
return ret;
}