in pinctrl-starfive.c [472:625]
static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np,
struct pinctrl_map **maps,
unsigned int *num_maps)
{
struct starfive_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
struct device *dev = sfp->gc.parent;
struct device_node *child;
struct pinctrl_map *map;
const char **pgnames;
const char *grpname;
u32 *pinmux;
int ngroups;
int *pins;
int nmaps;
int ret;
nmaps = 0;
ngroups = 0;
for_each_child_of_node(np, child) {
int npinmux = of_property_count_u32_elems(child, "pinmux");
int npins = of_property_count_u32_elems(child, "pins");
if (npinmux > 0 && npins > 0) {
dev_err(dev, "invalid pinctrl group %pOFn.%pOFn: both pinmux and pins set\n",
np, child);
of_node_put(child);
return -EINVAL;
}
if (npinmux == 0 && npins == 0) {
dev_err(dev, "invalid pinctrl group %pOFn.%pOFn: neither pinmux nor pins set\n",
np, child);
of_node_put(child);
return -EINVAL;
}
if (npinmux > 0)
nmaps += 2;
else
nmaps += 1;
ngroups += 1;
}
pgnames = devm_kcalloc(dev, ngroups, sizeof(*pgnames), GFP_KERNEL);
if (!pgnames)
return -ENOMEM;
map = kcalloc(nmaps, sizeof(*map), GFP_KERNEL);
if (!map)
return -ENOMEM;
nmaps = 0;
ngroups = 0;
for_each_child_of_node(np, child) {
int npins;
int i;
grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", np, child);
if (!grpname) {
ret = -ENOMEM;
goto put_child;
}
pgnames[ngroups++] = grpname;
if ((npins = of_property_count_u32_elems(child, "pinmux")) > 0) {
pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL);
if (!pins) {
ret = -ENOMEM;
goto put_child;
}
pinmux = devm_kcalloc(dev, npins, sizeof(*pinmux), GFP_KERNEL);
if (!pinmux) {
ret = -ENOMEM;
goto put_child;
}
ret = of_property_read_u32_array(child, "pinmux", pinmux, npins);
if (ret)
goto put_child;
for (i = 0; i < npins; i++) {
unsigned int gpio = starfive_pinmux_to_gpio(pinmux[i]);
pins[i] = starfive_gpio_to_pin(sfp, gpio);
}
map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP;
map[nmaps].data.mux.function = np->name;
map[nmaps].data.mux.group = grpname;
nmaps += 1;
} else if ((npins = of_property_count_u32_elems(child, "pins")) > 0) {
pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL);
if (!pins) {
ret = -ENOMEM;
goto put_child;
}
pinmux = NULL;
for (i = 0; i < npins; i++) {
u32 v;
ret = of_property_read_u32_index(child, "pins", i, &v);
if (ret)
goto put_child;
pins[i] = v;
}
} else {
ret = -EINVAL;
goto put_child;
}
ret = pinctrl_generic_add_group(pctldev, grpname, pins, npins, pinmux);
if (ret < 0) {
dev_err(dev, "error adding group %s: %d\n", grpname, ret);
goto put_child;
}
ret = pinconf_generic_parse_dt_config(child, pctldev,
&map[nmaps].data.configs.configs,
&map[nmaps].data.configs.num_configs);
if (ret) {
dev_err(dev, "error parsing pin config of group %s: %d\n",
grpname, ret);
goto put_child;
}
/* don't create a map if there are no pinconf settings */
if (map[nmaps].data.configs.num_configs == 0)
continue;
map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
map[nmaps].data.configs.group_or_pin = grpname;
nmaps += 1;
}
ret = pinmux_generic_add_function(pctldev, np->name, pgnames, ngroups, NULL);
if (ret < 0) {
dev_err(dev, "error adding function %s: %d\n", np->name, ret);
goto free_map;
}
*maps = map;
*num_maps = nmaps;
return 0;
put_child:
of_node_put(child);
free_map:
pinctrl_utils_free_map(pctldev, map, nmaps);
return ret;
}