static int pcs_parse_one_pinctrl_entry()

in pinctrl-single.c [996:1108]


static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
						struct device_node *np,
						struct pinctrl_map **map,
						unsigned *num_maps,
						const char **pgnames)
{
	const char *name = "pinctrl-single,pins";
	struct pcs_func_vals *vals;
	int rows, *pins, found = 0, res = -ENOMEM, i, fsel, gsel;
	struct pcs_function *function = NULL;

	rows = pinctrl_count_index_with_args(np, name);
	if (rows <= 0) {
		dev_err(pcs->dev, "Invalid number of rows: %d\n", rows);
		return -EINVAL;
	}

	vals = devm_kcalloc(pcs->dev, rows, sizeof(*vals), GFP_KERNEL);
	if (!vals)
		return -ENOMEM;

	pins = devm_kcalloc(pcs->dev, rows, sizeof(*pins), GFP_KERNEL);
	if (!pins)
		goto free_vals;

	for (i = 0; i < rows; i++) {
		struct of_phandle_args pinctrl_spec;
		unsigned int offset;
		int pin;

		res = pinctrl_parse_index_with_args(np, name, i, &pinctrl_spec);
		if (res)
			return res;

		if (pinctrl_spec.args_count < 2 || pinctrl_spec.args_count > 3) {
			dev_err(pcs->dev, "invalid args_count for spec: %i\n",
				pinctrl_spec.args_count);
			break;
		}

		offset = pinctrl_spec.args[0];
		vals[found].reg = pcs->base + offset;

		switch (pinctrl_spec.args_count) {
		case 2:
			vals[found].val = pinctrl_spec.args[1];
			break;
		case 3:
			vals[found].val = (pinctrl_spec.args[1] | pinctrl_spec.args[2]);
			break;
		}

		dev_dbg(pcs->dev, "%pOFn index: 0x%x value: 0x%x\n",
			pinctrl_spec.np, offset, vals[found].val);

		pin = pcs_get_pin_by_offset(pcs, offset);
		if (pin < 0) {
			dev_err(pcs->dev,
				"could not add functions for %pOFn %ux\n",
				np, offset);
			break;
		}
		pins[found++] = pin;
	}

	pgnames[0] = np->name;
	mutex_lock(&pcs->mutex);
	fsel = pcs_add_function(pcs, &function, np->name, vals, found,
				pgnames, 1);
	if (fsel < 0) {
		res = fsel;
		goto free_pins;
	}

	gsel = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs);
	if (gsel < 0) {
		res = gsel;
		goto free_function;
	}

	(*map)->type = PIN_MAP_TYPE_MUX_GROUP;
	(*map)->data.mux.group = np->name;
	(*map)->data.mux.function = np->name;

	if (PCS_HAS_PINCONF && function) {
		res = pcs_parse_pinconf(pcs, np, function, map);
		if (res == 0)
			*num_maps = 2;
		else if (res == -ENOTSUPP)
			*num_maps = 1;
		else
			goto free_pingroups;
	} else {
		*num_maps = 1;
	}
	mutex_unlock(&pcs->mutex);

	return 0;

free_pingroups:
	pinctrl_generic_remove_group(pcs->pctl, gsel);
	*num_maps = 1;
free_function:
	pinmux_generic_remove_function(pcs->pctl, fsel);
free_pins:
	mutex_unlock(&pcs->mutex);
	devm_kfree(pcs->dev, pins);

free_vals:
	devm_kfree(pcs->dev, vals);

	return res;
}