18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Device tree integration for the pin control subsystem 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/device.h> 98c2ecf20Sopenharmony_ci#include <linux/of.h> 108c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "core.h" 148c2ecf20Sopenharmony_ci#include "devicetree.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/** 178c2ecf20Sopenharmony_ci * struct pinctrl_dt_map - mapping table chunk parsed from device tree 188c2ecf20Sopenharmony_ci * @node: list node for struct pinctrl's @dt_maps field 198c2ecf20Sopenharmony_ci * @pctldev: the pin controller that allocated this struct, and will free it 208c2ecf20Sopenharmony_ci * @map: the mapping table entries 218c2ecf20Sopenharmony_ci * @num_maps: number of mapping table entries 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_cistruct pinctrl_dt_map { 248c2ecf20Sopenharmony_ci struct list_head node; 258c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev; 268c2ecf20Sopenharmony_ci struct pinctrl_map *map; 278c2ecf20Sopenharmony_ci unsigned num_maps; 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic void dt_free_map(struct pinctrl_dev *pctldev, 318c2ecf20Sopenharmony_ci struct pinctrl_map *map, unsigned num_maps) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci int i; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci for (i = 0; i < num_maps; ++i) { 368c2ecf20Sopenharmony_ci kfree_const(map[i].dev_name); 378c2ecf20Sopenharmony_ci map[i].dev_name = NULL; 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (pctldev) { 418c2ecf20Sopenharmony_ci const struct pinctrl_ops *ops = pctldev->desc->pctlops; 428c2ecf20Sopenharmony_ci if (ops->dt_free_map) 438c2ecf20Sopenharmony_ci ops->dt_free_map(pctldev, map, num_maps); 448c2ecf20Sopenharmony_ci } else { 458c2ecf20Sopenharmony_ci /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */ 468c2ecf20Sopenharmony_ci kfree(map); 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_civoid pinctrl_dt_free_maps(struct pinctrl *p) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct pinctrl_dt_map *dt_map, *n1; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci list_for_each_entry_safe(dt_map, n1, &p->dt_maps, node) { 558c2ecf20Sopenharmony_ci pinctrl_unregister_mappings(dt_map->map); 568c2ecf20Sopenharmony_ci list_del(&dt_map->node); 578c2ecf20Sopenharmony_ci dt_free_map(dt_map->pctldev, dt_map->map, 588c2ecf20Sopenharmony_ci dt_map->num_maps); 598c2ecf20Sopenharmony_ci kfree(dt_map); 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci of_node_put(p->dev->of_node); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int dt_remember_or_free_map(struct pinctrl *p, const char *statename, 668c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev, 678c2ecf20Sopenharmony_ci struct pinctrl_map *map, unsigned num_maps) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci int i; 708c2ecf20Sopenharmony_ci struct pinctrl_dt_map *dt_map; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* Initialize common mapping table entry fields */ 738c2ecf20Sopenharmony_ci for (i = 0; i < num_maps; i++) { 748c2ecf20Sopenharmony_ci const char *devname; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci devname = kstrdup_const(dev_name(p->dev), GFP_KERNEL); 778c2ecf20Sopenharmony_ci if (!devname) 788c2ecf20Sopenharmony_ci goto err_free_map; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci map[i].dev_name = devname; 818c2ecf20Sopenharmony_ci map[i].name = statename; 828c2ecf20Sopenharmony_ci if (pctldev) 838c2ecf20Sopenharmony_ci map[i].ctrl_dev_name = dev_name(pctldev->dev); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* Remember the converted mapping table entries */ 878c2ecf20Sopenharmony_ci dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL); 888c2ecf20Sopenharmony_ci if (!dt_map) 898c2ecf20Sopenharmony_ci goto err_free_map; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci dt_map->pctldev = pctldev; 928c2ecf20Sopenharmony_ci dt_map->map = map; 938c2ecf20Sopenharmony_ci dt_map->num_maps = num_maps; 948c2ecf20Sopenharmony_ci list_add_tail(&dt_map->node, &p->dt_maps); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return pinctrl_register_mappings(map, num_maps); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cierr_free_map: 998c2ecf20Sopenharmony_ci dt_free_map(pctldev, map, num_maps); 1008c2ecf20Sopenharmony_ci return -ENOMEM; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistruct pinctrl_dev *of_pinctrl_get(struct device_node *np) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci return get_pinctrl_dev_from_of_node(np); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_pinctrl_get); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int dt_to_map_one_config(struct pinctrl *p, 1108c2ecf20Sopenharmony_ci struct pinctrl_dev *hog_pctldev, 1118c2ecf20Sopenharmony_ci const char *statename, 1128c2ecf20Sopenharmony_ci struct device_node *np_config) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev = NULL; 1158c2ecf20Sopenharmony_ci struct device_node *np_pctldev; 1168c2ecf20Sopenharmony_ci const struct pinctrl_ops *ops; 1178c2ecf20Sopenharmony_ci int ret; 1188c2ecf20Sopenharmony_ci struct pinctrl_map *map; 1198c2ecf20Sopenharmony_ci unsigned num_maps; 1208c2ecf20Sopenharmony_ci bool allow_default = false; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* Find the pin controller containing np_config */ 1238c2ecf20Sopenharmony_ci np_pctldev = of_node_get(np_config); 1248c2ecf20Sopenharmony_ci for (;;) { 1258c2ecf20Sopenharmony_ci if (!allow_default) 1268c2ecf20Sopenharmony_ci allow_default = of_property_read_bool(np_pctldev, 1278c2ecf20Sopenharmony_ci "pinctrl-use-default"); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci np_pctldev = of_get_next_parent(np_pctldev); 1308c2ecf20Sopenharmony_ci if (!np_pctldev || of_node_is_root(np_pctldev)) { 1318c2ecf20Sopenharmony_ci of_node_put(np_pctldev); 1328c2ecf20Sopenharmony_ci ret = driver_deferred_probe_check_state(p->dev); 1338c2ecf20Sopenharmony_ci /* keep deferring if modules are enabled */ 1348c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_MODULES) && !allow_default && ret < 0) 1358c2ecf20Sopenharmony_ci ret = -EPROBE_DEFER; 1368c2ecf20Sopenharmony_ci return ret; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci /* If we're creating a hog we can use the passed pctldev */ 1398c2ecf20Sopenharmony_ci if (hog_pctldev && (np_pctldev == p->dev->of_node)) { 1408c2ecf20Sopenharmony_ci pctldev = hog_pctldev; 1418c2ecf20Sopenharmony_ci break; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci pctldev = get_pinctrl_dev_from_of_node(np_pctldev); 1448c2ecf20Sopenharmony_ci if (pctldev) 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci /* Do not defer probing of hogs (circular loop) */ 1478c2ecf20Sopenharmony_ci if (np_pctldev == p->dev->of_node) { 1488c2ecf20Sopenharmony_ci of_node_put(np_pctldev); 1498c2ecf20Sopenharmony_ci return -ENODEV; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci of_node_put(np_pctldev); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* 1558c2ecf20Sopenharmony_ci * Call pinctrl driver to parse device tree node, and 1568c2ecf20Sopenharmony_ci * generate mapping table entries 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_ci ops = pctldev->desc->pctlops; 1598c2ecf20Sopenharmony_ci if (!ops->dt_node_to_map) { 1608c2ecf20Sopenharmony_ci dev_err(p->dev, "pctldev %s doesn't support DT\n", 1618c2ecf20Sopenharmony_ci dev_name(pctldev->dev)); 1628c2ecf20Sopenharmony_ci return -ENODEV; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps); 1658c2ecf20Sopenharmony_ci if (ret < 0) 1668c2ecf20Sopenharmony_ci return ret; 1678c2ecf20Sopenharmony_ci else if (num_maps == 0) { 1688c2ecf20Sopenharmony_ci /* 1698c2ecf20Sopenharmony_ci * If we have no valid maps (maybe caused by empty pinctrl node 1708c2ecf20Sopenharmony_ci * or typing error) ther is no need remember this, so just 1718c2ecf20Sopenharmony_ci * return. 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ci dev_info(p->dev, 1748c2ecf20Sopenharmony_ci "there is not valid maps for state %s\n", statename); 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* Stash the mapping table chunk away for later use */ 1798c2ecf20Sopenharmony_ci return dt_remember_or_free_map(p, statename, pctldev, map, num_maps); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic int dt_remember_dummy_state(struct pinctrl *p, const char *statename) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct pinctrl_map *map; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci map = kzalloc(sizeof(*map), GFP_KERNEL); 1878c2ecf20Sopenharmony_ci if (!map) 1888c2ecf20Sopenharmony_ci return -ENOMEM; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */ 1918c2ecf20Sopenharmony_ci map->type = PIN_MAP_TYPE_DUMMY_STATE; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return dt_remember_or_free_map(p, statename, NULL, map, 1); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ciint pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct device_node *np = p->dev->of_node; 1998c2ecf20Sopenharmony_ci int state, ret; 2008c2ecf20Sopenharmony_ci char *propname; 2018c2ecf20Sopenharmony_ci struct property *prop; 2028c2ecf20Sopenharmony_ci const char *statename; 2038c2ecf20Sopenharmony_ci const __be32 *list; 2048c2ecf20Sopenharmony_ci int size, config; 2058c2ecf20Sopenharmony_ci phandle phandle; 2068c2ecf20Sopenharmony_ci struct device_node *np_config; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* CONFIG_OF enabled, p->dev not instantiated from DT */ 2098c2ecf20Sopenharmony_ci if (!np) { 2108c2ecf20Sopenharmony_ci if (of_have_populated_dt()) 2118c2ecf20Sopenharmony_ci dev_dbg(p->dev, 2128c2ecf20Sopenharmony_ci "no of_node; not parsing pinctrl DT\n"); 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* We may store pointers to property names within the node */ 2178c2ecf20Sopenharmony_ci of_node_get(np); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* For each defined state ID */ 2208c2ecf20Sopenharmony_ci for (state = 0; ; state++) { 2218c2ecf20Sopenharmony_ci /* Retrieve the pinctrl-* property */ 2228c2ecf20Sopenharmony_ci propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state); 2238c2ecf20Sopenharmony_ci if (!propname) { 2248c2ecf20Sopenharmony_ci ret = -ENOMEM; 2258c2ecf20Sopenharmony_ci goto err; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci prop = of_find_property(np, propname, &size); 2288c2ecf20Sopenharmony_ci kfree(propname); 2298c2ecf20Sopenharmony_ci if (!prop) { 2308c2ecf20Sopenharmony_ci if (state == 0) { 2318c2ecf20Sopenharmony_ci ret = -ENODEV; 2328c2ecf20Sopenharmony_ci goto err; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci list = prop->value; 2378c2ecf20Sopenharmony_ci size /= sizeof(*list); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* Determine whether pinctrl-names property names the state */ 2408c2ecf20Sopenharmony_ci ret = of_property_read_string_index(np, "pinctrl-names", 2418c2ecf20Sopenharmony_ci state, &statename); 2428c2ecf20Sopenharmony_ci /* 2438c2ecf20Sopenharmony_ci * If not, statename is just the integer state ID. But rather 2448c2ecf20Sopenharmony_ci * than dynamically allocate it and have to free it later, 2458c2ecf20Sopenharmony_ci * just point part way into the property name for the string. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci if (ret < 0) 2488c2ecf20Sopenharmony_ci statename = prop->name + strlen("pinctrl-"); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* For every referenced pin configuration node in it */ 2518c2ecf20Sopenharmony_ci for (config = 0; config < size; config++) { 2528c2ecf20Sopenharmony_ci phandle = be32_to_cpup(list++); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* Look up the pin configuration node */ 2558c2ecf20Sopenharmony_ci np_config = of_find_node_by_phandle(phandle); 2568c2ecf20Sopenharmony_ci if (!np_config) { 2578c2ecf20Sopenharmony_ci dev_err(p->dev, 2588c2ecf20Sopenharmony_ci "prop %s index %i invalid phandle\n", 2598c2ecf20Sopenharmony_ci prop->name, config); 2608c2ecf20Sopenharmony_ci ret = -EINVAL; 2618c2ecf20Sopenharmony_ci goto err; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* Parse the node */ 2658c2ecf20Sopenharmony_ci ret = dt_to_map_one_config(p, pctldev, statename, 2668c2ecf20Sopenharmony_ci np_config); 2678c2ecf20Sopenharmony_ci of_node_put(np_config); 2688c2ecf20Sopenharmony_ci if (ret < 0) 2698c2ecf20Sopenharmony_ci goto err; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* No entries in DT? Generate a dummy state table entry */ 2738c2ecf20Sopenharmony_ci if (!size) { 2748c2ecf20Sopenharmony_ci ret = dt_remember_dummy_state(p, statename); 2758c2ecf20Sopenharmony_ci if (ret < 0) 2768c2ecf20Sopenharmony_ci goto err; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return 0; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cierr: 2838c2ecf20Sopenharmony_ci pinctrl_dt_free_maps(p); 2848c2ecf20Sopenharmony_ci return ret; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/* 2888c2ecf20Sopenharmony_ci * For pinctrl binding, typically #pinctrl-cells is for the pin controller 2898c2ecf20Sopenharmony_ci * device, so either parent or grandparent. See pinctrl-bindings.txt. 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_cistatic int pinctrl_find_cells_size(const struct device_node *np) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci const char *cells_name = "#pinctrl-cells"; 2948c2ecf20Sopenharmony_ci int cells_size, error; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci error = of_property_read_u32(np->parent, cells_name, &cells_size); 2978c2ecf20Sopenharmony_ci if (error) { 2988c2ecf20Sopenharmony_ci error = of_property_read_u32(np->parent->parent, 2998c2ecf20Sopenharmony_ci cells_name, &cells_size); 3008c2ecf20Sopenharmony_ci if (error) 3018c2ecf20Sopenharmony_ci return -ENOENT; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return cells_size; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci/** 3088c2ecf20Sopenharmony_ci * pinctrl_get_list_and_count - Gets the list and it's cell size and number 3098c2ecf20Sopenharmony_ci * @np: pointer to device node with the property 3108c2ecf20Sopenharmony_ci * @list_name: property that contains the list 3118c2ecf20Sopenharmony_ci * @list: pointer for the list found 3128c2ecf20Sopenharmony_ci * @cells_size: pointer for the cell size found 3138c2ecf20Sopenharmony_ci * @nr_elements: pointer for the number of elements found 3148c2ecf20Sopenharmony_ci * 3158c2ecf20Sopenharmony_ci * Typically np is a single pinctrl entry containing the list. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_cistatic int pinctrl_get_list_and_count(const struct device_node *np, 3188c2ecf20Sopenharmony_ci const char *list_name, 3198c2ecf20Sopenharmony_ci const __be32 **list, 3208c2ecf20Sopenharmony_ci int *cells_size, 3218c2ecf20Sopenharmony_ci int *nr_elements) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci int size; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci *cells_size = 0; 3268c2ecf20Sopenharmony_ci *nr_elements = 0; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci *list = of_get_property(np, list_name, &size); 3298c2ecf20Sopenharmony_ci if (!*list) 3308c2ecf20Sopenharmony_ci return -ENOENT; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci *cells_size = pinctrl_find_cells_size(np); 3338c2ecf20Sopenharmony_ci if (*cells_size < 0) 3348c2ecf20Sopenharmony_ci return -ENOENT; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* First element is always the index within the pinctrl device */ 3378c2ecf20Sopenharmony_ci *nr_elements = (size / sizeof(**list)) / (*cells_size + 1); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return 0; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci/** 3438c2ecf20Sopenharmony_ci * pinctrl_count_index_with_args - Count number of elements in a pinctrl entry 3448c2ecf20Sopenharmony_ci * @np: pointer to device node with the property 3458c2ecf20Sopenharmony_ci * @list_name: property that contains the list 3468c2ecf20Sopenharmony_ci * 3478c2ecf20Sopenharmony_ci * Counts the number of elements in a pinctrl array consisting of an index 3488c2ecf20Sopenharmony_ci * within the controller and a number of u32 entries specified for each 3498c2ecf20Sopenharmony_ci * entry. Note that device_node is always for the parent pin controller device. 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_ciint pinctrl_count_index_with_args(const struct device_node *np, 3528c2ecf20Sopenharmony_ci const char *list_name) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci const __be32 *list; 3558c2ecf20Sopenharmony_ci int size, nr_cells, error; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci error = pinctrl_get_list_and_count(np, list_name, &list, 3588c2ecf20Sopenharmony_ci &nr_cells, &size); 3598c2ecf20Sopenharmony_ci if (error) 3608c2ecf20Sopenharmony_ci return error; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return size; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pinctrl_count_index_with_args); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/** 3678c2ecf20Sopenharmony_ci * pinctrl_copy_args - Populates of_phandle_args based on index 3688c2ecf20Sopenharmony_ci * @np: pointer to device node with the property 3698c2ecf20Sopenharmony_ci * @list: pointer to a list with the elements 3708c2ecf20Sopenharmony_ci * @index: entry within the list of elements 3718c2ecf20Sopenharmony_ci * @nr_cells: number of cells in the list 3728c2ecf20Sopenharmony_ci * @nr_elem: number of elements for each entry in the list 3738c2ecf20Sopenharmony_ci * @out_args: returned values 3748c2ecf20Sopenharmony_ci * 3758c2ecf20Sopenharmony_ci * Populates the of_phandle_args based on the index in the list. 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_cistatic int pinctrl_copy_args(const struct device_node *np, 3788c2ecf20Sopenharmony_ci const __be32 *list, 3798c2ecf20Sopenharmony_ci int index, int nr_cells, int nr_elem, 3808c2ecf20Sopenharmony_ci struct of_phandle_args *out_args) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci int i; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci memset(out_args, 0, sizeof(*out_args)); 3858c2ecf20Sopenharmony_ci out_args->np = (struct device_node *)np; 3868c2ecf20Sopenharmony_ci out_args->args_count = nr_cells + 1; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (index >= nr_elem) 3898c2ecf20Sopenharmony_ci return -EINVAL; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci list += index * (nr_cells + 1); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci for (i = 0; i < nr_cells + 1; i++) 3948c2ecf20Sopenharmony_ci out_args->args[i] = be32_to_cpup(list++); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci/** 4008c2ecf20Sopenharmony_ci * pinctrl_parse_index_with_args - Find a node pointed by index in a list 4018c2ecf20Sopenharmony_ci * @np: pointer to device node with the property 4028c2ecf20Sopenharmony_ci * @list_name: property that contains the list 4038c2ecf20Sopenharmony_ci * @index: index within the list 4048c2ecf20Sopenharmony_ci * @out_args: entries in the list pointed by index 4058c2ecf20Sopenharmony_ci * 4068c2ecf20Sopenharmony_ci * Finds the selected element in a pinctrl array consisting of an index 4078c2ecf20Sopenharmony_ci * within the controller and a number of u32 entries specified for each 4088c2ecf20Sopenharmony_ci * entry. Note that device_node is always for the parent pin controller device. 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_ciint pinctrl_parse_index_with_args(const struct device_node *np, 4118c2ecf20Sopenharmony_ci const char *list_name, int index, 4128c2ecf20Sopenharmony_ci struct of_phandle_args *out_args) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci const __be32 *list; 4158c2ecf20Sopenharmony_ci int nr_elem, nr_cells, error; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci error = pinctrl_get_list_and_count(np, list_name, &list, 4188c2ecf20Sopenharmony_ci &nr_cells, &nr_elem); 4198c2ecf20Sopenharmony_ci if (error || !nr_cells) 4208c2ecf20Sopenharmony_ci return error; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci error = pinctrl_copy_args(np, list, index, nr_cells, nr_elem, 4238c2ecf20Sopenharmony_ci out_args); 4248c2ecf20Sopenharmony_ci if (error) 4258c2ecf20Sopenharmony_ci return error; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pinctrl_parse_index_with_args); 430