Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

pinctrl: add generic functions + pins mapper

Add a generic function to allow creation of groups and functions at
runtime based on devicetree content, before setting up mux mappings.
It works similarly to pinconf_generic_dt_node_to_map(), and
therefore parses pinconf properties and maps those too, allowing it
to be used as the dt_node_to_map member of the pinctrl_ops struct.

Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>

authored by

Conor Dooley and committed by
Linus Walleij
43722575 95c1762a

+212
+6
drivers/pinctrl/Kconfig
··· 25 25 bool 26 26 select PINCONF 27 27 28 + config GENERIC_PINCTRL 29 + bool 30 + depends on GENERIC_PINCONF 31 + depends on GENERIC_PINCTRL_GROUPS 32 + depends on GENERIC_PINMUX_FUNCTIONS 33 + 28 34 config DEBUG_PINCTRL 29 35 bool "Debug PINCTRL calls" 30 36 depends on DEBUG_KERNEL
+1
drivers/pinctrl/Makefile
··· 7 7 obj-$(CONFIG_PINMUX) += pinmux.o 8 8 obj-$(CONFIG_PINCONF) += pinconf.o 9 9 obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o 10 + obj-$(CONFIG_GENERIC_PINCTRL) += pinctrl-generic.o 10 11 obj-$(CONFIG_OF) += devicetree.o 11 12 12 13 obj-$(CONFIG_PINCTRL_AMD) += pinctrl-amd.o
+16
drivers/pinctrl/pinconf.h
··· 160 160 return -ENOTSUPP; 161 161 } 162 162 #endif 163 + 164 + #if defined(CONFIG_GENERIC_PINCTRL) && defined (CONFIG_OF) 165 + int pinctrl_generic_pins_function_dt_node_to_map(struct pinctrl_dev *pctldev, 166 + struct device_node *np, 167 + struct pinctrl_map **maps, 168 + unsigned int *num_maps); 169 + #else 170 + static inline int 171 + pinctrl_generic_pins_function_dt_node_to_map(struct pinctrl_dev *pctldev, 172 + struct device_node *np, 173 + struct pinctrl_map **maps, 174 + unsigned int *num_maps) 175 + { 176 + return -ENOTSUPP; 177 + } 178 + #endif
+189
drivers/pinctrl/pinctrl-generic.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #define pr_fmt(fmt) "generic pinconfig core: " fmt 4 + 5 + #include <linux/array_size.h> 6 + #include <linux/device.h> 7 + #include <linux/module.h> 8 + #include <linux/of.h> 9 + #include <linux/slab.h> 10 + 11 + #include <linux/pinctrl/pinconf-generic.h> 12 + #include <linux/pinctrl/pinconf.h> 13 + #include <linux/pinctrl/pinctrl.h> 14 + 15 + #include "core.h" 16 + #include "pinconf.h" 17 + #include "pinctrl-utils.h" 18 + #include "pinmux.h" 19 + 20 + static int pinctrl_generic_pins_function_dt_subnode_to_map(struct pinctrl_dev *pctldev, 21 + struct device_node *parent, 22 + struct device_node *np, 23 + struct pinctrl_map **maps, 24 + unsigned int *num_maps, 25 + unsigned int *num_reserved_maps, 26 + const char **group_names, 27 + unsigned int ngroups) 28 + { 29 + struct device *dev = pctldev->dev; 30 + const char **functions; 31 + const char *group_name; 32 + unsigned long *configs; 33 + unsigned int num_configs, pin, *pins; 34 + int npins, ret, reserve = 1; 35 + 36 + npins = of_property_count_u32_elems(np, "pins"); 37 + 38 + if (npins < 1) { 39 + dev_err(dev, "invalid pinctrl group %pOFn.%pOFn %d\n", 40 + parent, np, npins); 41 + return npins; 42 + } 43 + 44 + group_name = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", parent, np); 45 + if (!group_name) 46 + return -ENOMEM; 47 + 48 + group_names[ngroups] = group_name; 49 + 50 + pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); 51 + if (!pins) 52 + return -ENOMEM; 53 + 54 + functions = devm_kcalloc(dev, npins, sizeof(*functions), GFP_KERNEL); 55 + if (!functions) 56 + return -ENOMEM; 57 + 58 + for (int i = 0; i < npins; i++) { 59 + ret = of_property_read_u32_index(np, "pins", i, &pin); 60 + if (ret) 61 + return ret; 62 + 63 + pins[i] = pin; 64 + 65 + ret = of_property_read_string(np, "function", &functions[i]); 66 + if (ret) 67 + return ret; 68 + } 69 + 70 + ret = pinctrl_utils_reserve_map(pctldev, maps, num_reserved_maps, num_maps, reserve); 71 + if (ret) 72 + return ret; 73 + 74 + ret = pinctrl_utils_add_map_mux(pctldev, maps, num_reserved_maps, num_maps, group_name, 75 + parent->name); 76 + if (ret < 0) 77 + return ret; 78 + 79 + ret = pinctrl_generic_add_group(pctldev, group_name, pins, npins, functions); 80 + if (ret < 0) 81 + return dev_err_probe(dev, ret, "failed to add group %s: %d\n", 82 + group_name, ret); 83 + 84 + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, &num_configs); 85 + if (ret) 86 + return dev_err_probe(dev, ret, "failed to parse pin config of group %s\n", 87 + group_name); 88 + 89 + if (num_configs == 0) 90 + return 0; 91 + 92 + ret = pinctrl_utils_reserve_map(pctldev, maps, num_reserved_maps, num_maps, reserve); 93 + if (ret) 94 + return ret; 95 + 96 + ret = pinctrl_utils_add_map_configs(pctldev, maps, num_reserved_maps, num_maps, group_name, 97 + configs, 98 + num_configs, PIN_MAP_TYPE_CONFIGS_GROUP); 99 + kfree(configs); 100 + if (ret) 101 + return ret; 102 + 103 + return 0; 104 + }; 105 + 106 + /* 107 + * For platforms that do not define groups or functions in the driver, but 108 + * instead use the devicetree to describe them. This function will, unlike 109 + * pinconf_generic_dt_node_to_map() etc which rely on driver defined groups 110 + * and functions, create them in addition to parsing pinconf properties and 111 + * adding mappings. 112 + */ 113 + int pinctrl_generic_pins_function_dt_node_to_map(struct pinctrl_dev *pctldev, 114 + struct device_node *np, 115 + struct pinctrl_map **maps, 116 + unsigned int *num_maps) 117 + { 118 + struct device *dev = pctldev->dev; 119 + struct device_node *child_np; 120 + const char **group_names; 121 + unsigned int num_reserved_maps = 0; 122 + int ngroups = 0; 123 + int ret; 124 + 125 + *maps = NULL; 126 + *num_maps = 0; 127 + 128 + /* 129 + * Check if this is actually the pins node, or a parent containing 130 + * multiple pins nodes. 131 + */ 132 + if (!of_property_present(np, "pins")) 133 + goto parent; 134 + 135 + group_names = devm_kcalloc(dev, 1, sizeof(*group_names), GFP_KERNEL); 136 + if (!group_names) 137 + return -ENOMEM; 138 + 139 + ret = pinctrl_generic_pins_function_dt_subnode_to_map(pctldev, np, np, 140 + maps, num_maps, 141 + &num_reserved_maps, 142 + group_names, 143 + ngroups); 144 + if (ret) { 145 + pinctrl_utils_free_map(pctldev, *maps, *num_maps); 146 + return dev_err_probe(dev, ret, "error figuring out mappings for %s\n", np->name); 147 + } 148 + 149 + ret = pinmux_generic_add_function(pctldev, np->name, group_names, 1, NULL); 150 + if (ret < 0) { 151 + pinctrl_utils_free_map(pctldev, *maps, *num_maps); 152 + return dev_err_probe(dev, ret, "error adding function %s\n", np->name); 153 + } 154 + 155 + return 0; 156 + 157 + parent: 158 + for_each_available_child_of_node(np, child_np) 159 + ngroups += 1; 160 + 161 + group_names = devm_kcalloc(dev, ngroups, sizeof(*group_names), GFP_KERNEL); 162 + if (!group_names) 163 + return -ENOMEM; 164 + 165 + ngroups = 0; 166 + for_each_available_child_of_node_scoped(np, child_np) { 167 + ret = pinctrl_generic_pins_function_dt_subnode_to_map(pctldev, np, child_np, 168 + maps, num_maps, 169 + &num_reserved_maps, 170 + group_names, 171 + ngroups); 172 + if (ret) { 173 + pinctrl_utils_free_map(pctldev, *maps, *num_maps); 174 + return dev_err_probe(dev, ret, "error figuring out mappings for %s\n", 175 + np->name); 176 + } 177 + 178 + ngroups++; 179 + } 180 + 181 + ret = pinmux_generic_add_function(pctldev, np->name, group_names, ngroups, NULL); 182 + if (ret < 0) { 183 + pinctrl_utils_free_map(pctldev, *maps, *num_maps); 184 + return dev_err_probe(dev, ret, "error adding function %s\n", np->name); 185 + } 186 + 187 + return 0; 188 + } 189 + EXPORT_SYMBOL_GPL(pinctrl_generic_pins_function_dt_node_to_map);