static int starfive_dt_node_to_map()

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;
}