// SPDX-License-Identifier: GPL-2.0-only /* * Device tree integration for the pin control subsystem * * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
*/
/** * struct pinctrl_dt_map - mapping table chunk parsed from device tree * @node: list node for struct pinctrl's @dt_maps field * @pctldev: the pin controller that allocated this struct, and will free it * @map: the mapping table entries * @num_maps: number of mapping table entries
*/ struct pinctrl_dt_map { struct list_head node; struct pinctrl_dev *pctldev; struct pinctrl_map *map; unsignedint num_maps;
};
for (i = 0; i < num_maps; ++i) {
kfree_const(map[i].dev_name);
map[i].dev_name = NULL;
}
if (pctldev) { conststruct pinctrl_ops *ops = pctldev->desc->pctlops; if (ops->dt_free_map)
ops->dt_free_map(pctldev, map, num_maps);
} else { /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
kfree(map);
}
}
/* Find the pin controller containing np_config */
np_pctldev = of_node_get(np_config); for (;;) { if (!allow_default)
allow_default = of_property_read_bool(np_pctldev, "pinctrl-use-default");
np_pctldev = of_get_next_parent(np_pctldev); if (!np_pctldev || of_node_is_root(np_pctldev)) {
of_node_put(np_pctldev);
ret = -ENODEV; /* keep deferring if modules are enabled */ if (IS_ENABLED(CONFIG_MODULES) && !allow_default && ret < 0)
ret = -EPROBE_DEFER; return ret;
} /* If we're creating a hog we can use the passed pctldev */ if (hog_pctldev && (np_pctldev == p->dev->of_node)) {
pctldev = hog_pctldev; break;
}
pctldev = get_pinctrl_dev_from_of_node(np_pctldev); if (pctldev) break; /* * Do not defer probing of hogs (circular loop) * * Return 1 to let the caller catch the case.
*/ if (np_pctldev == p->dev->of_node) {
of_node_put(np_pctldev); return 1;
}
}
of_node_put(np_pctldev);
/* * Call pinctrl driver to parse device tree node, and * generate mapping table entries
*/
ops = pctldev->desc->pctlops; if (!ops->dt_node_to_map) {
dev_err(p->dev, "pctldev %s doesn't support DT\n",
dev_name(pctldev->dev)); return -ENODEV;
}
ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps); if (ret < 0) return ret; elseif (num_maps == 0) { /* * If we have no valid maps (maybe caused by empty pinctrl node * or typing error) ther is no need remember this, so just * return.
*/
dev_info(p->dev, "there is not valid maps for state %s\n", statename); return 0;
}
/* Stash the mapping table chunk away for later use */ return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
}
/* CONFIG_OF enabled, p->dev not instantiated from DT */ if (!np) { if (of_have_populated_dt())
dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n"); return 0;
}
/* We may store pointers to property names within the node */
of_node_get(np);
/* For each defined state ID */ for (state = 0; ; state++) { /* Retrieve the pinctrl-* property */
propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state); if (!propname) {
ret = -ENOMEM; goto err;
}
prop = of_find_property(np, propname, &size);
kfree(propname); if (!prop) { if (state == 0) {
ret = -ENODEV; goto err;
} break;
}
list = prop->value;
size /= sizeof(*list);
/* Determine whether pinctrl-names property names the state */
ret = of_property_read_string_index(np, "pinctrl-names",
state, &statename); /* * If not, statename is just the integer state ID. But rather * than dynamically allocate it and have to free it later, * just point part way into the property name for the string.
*/ if (ret < 0)
statename = prop->name + strlen("pinctrl-");
/* For every referenced pin configuration node in it */ for (config = 0; config < size; config++) {
phandle = be32_to_cpup(list++);
/* Look up the pin configuration node */
np_config = of_find_node_by_phandle(phandle); if (!np_config) {
dev_err(p->dev, "prop %s index %i invalid phandle\n",
prop->name, config);
ret = -EINVAL; goto err;
}
/* Parse the node */
ret = dt_to_map_one_config(p, pctldev, statename,
np_config);
of_node_put(np_config); if (ret == 1) continue; if (ret < 0) goto err;
}
/* No entries in DT? Generate a dummy state table entry */ if (!size) {
ret = dt_remember_dummy_state(p, statename); if (ret < 0) goto err;
}
}
return 0;
err:
pinctrl_dt_free_maps(p); return ret;
}
/* * For pinctrl binding, typically #pinctrl-cells is for the pin controller * device, so either parent or grandparent. See pinctrl-bindings.txt.
*/ staticint pinctrl_find_cells_size(conststruct device_node *np)
{ constchar *cells_name = "#pinctrl-cells"; int cells_size, error;
error = of_property_read_u32(np->parent, cells_name, &cells_size); if (error) {
error = of_property_read_u32(np->parent->parent,
cells_name, &cells_size); if (error) return -ENOENT;
}
return cells_size;
}
/** * pinctrl_get_list_and_count - Gets the list and it's cell size and number * @np: pointer to device node with the property * @list_name: property that contains the list * @list: pointer for the list found * @cells_size: pointer for the cell size found * @nr_elements: pointer for the number of elements found * * Typically np is a single pinctrl entry containing the list.
*/ staticint pinctrl_get_list_and_count(conststruct device_node *np, constchar *list_name, const __be32 **list, int *cells_size, int *nr_elements)
{ int size;
*cells_size = 0;
*nr_elements = 0;
*list = of_get_property(np, list_name, &size); if (!*list) return -ENOENT;
*cells_size = pinctrl_find_cells_size(np); if (*cells_size < 0) return -ENOENT;
/* First element is always the index within the pinctrl device */
*nr_elements = (size / sizeof(**list)) / (*cells_size + 1);
return 0;
}
/** * pinctrl_count_index_with_args - Count number of elements in a pinctrl entry * @np: pointer to device node with the property * @list_name: property that contains the list * * Counts the number of elements in a pinctrl array consisting of an index * within the controller and a number of u32 entries specified for each * entry. Note that device_node is always for the parent pin controller device.
*/ int pinctrl_count_index_with_args(conststruct device_node *np, constchar *list_name)
{ const __be32 *list; int size, nr_cells, error;
/** * pinctrl_copy_args - Populates of_phandle_args based on index * @np: pointer to device node with the property * @list: pointer to a list with the elements * @index: entry within the list of elements * @nr_cells: number of cells in the list * @nr_elem: number of elements for each entry in the list * @out_args: returned values * * Populates the of_phandle_args based on the index in the list.
*/ staticint pinctrl_copy_args(conststruct device_node *np, const __be32 *list, int index, int nr_cells, int nr_elem, struct of_phandle_args *out_args)
{ int i;
for (i = 0; i < nr_cells + 1; i++)
out_args->args[i] = be32_to_cpup(list++);
return 0;
}
/** * pinctrl_parse_index_with_args - Find a node pointed by index in a list * @np: pointer to device node with the property * @list_name: property that contains the list * @index: index within the list * @out_args: entries in the list pointed by index * * Finds the selected element in a pinctrl array consisting of an index * within the controller and a number of u32 entries specified for each * entry. Note that device_node is always for the parent pin controller device.
*/ int pinctrl_parse_index_with_args(conststruct device_node *np, constchar *list_name, int index, struct of_phandle_args *out_args)
{ const __be32 *list; int nr_elem, nr_cells, error;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.