pinconf-generic.c (12763B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Core driver for the generic pin config portions of the pin control subsystem 4 * 5 * Copyright (C) 2011 ST-Ericsson SA 6 * Written on behalf of Linaro for ST-Ericsson 7 * 8 * Author: Linus Walleij <linus.walleij@linaro.org> 9 */ 10 11#define pr_fmt(fmt) "generic pinconfig core: " fmt 12 13#include <linux/kernel.h> 14#include <linux/module.h> 15#include <linux/init.h> 16#include <linux/device.h> 17#include <linux/slab.h> 18#include <linux/debugfs.h> 19#include <linux/seq_file.h> 20#include <linux/pinctrl/pinctrl.h> 21#include <linux/pinctrl/pinconf.h> 22#include <linux/pinctrl/pinconf-generic.h> 23#include <linux/of.h> 24#include "core.h" 25#include "pinconf.h" 26#include "pinctrl-utils.h" 27 28#ifdef CONFIG_DEBUG_FS 29static const struct pin_config_item conf_items[] = { 30 PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL, false), 31 PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false), 32 PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false), 33 PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", "ohms", true), 34 PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 35 "input bias pull to pin specific state", "ohms", true), 36 PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", "ohms", true), 37 PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL, false), 38 PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL, false), 39 PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL, false), 40 PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA", true), 41 PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH_UA, "output drive strength", "uA", true), 42 PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec", true), 43 PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL, false), 44 PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL, false), 45 PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL, false), 46 PCONFDUMP(PIN_CONFIG_MODE_LOW_POWER, "pin low power", "mode", true), 47 PCONFDUMP(PIN_CONFIG_OUTPUT_ENABLE, "output enabled", NULL, false), 48 PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level", true), 49 PCONFDUMP(PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS, "output impedance", "ohms", true), 50 PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector", true), 51 PCONFDUMP(PIN_CONFIG_SLEEP_HARDWARE_STATE, "sleep hardware state", NULL, false), 52 PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL, true), 53 PCONFDUMP(PIN_CONFIG_SKEW_DELAY, "skew delay", NULL, true), 54}; 55 56static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev, 57 struct seq_file *s, const char *gname, 58 unsigned pin, 59 const struct pin_config_item *items, 60 int nitems, int *print_sep) 61{ 62 int i; 63 64 for (i = 0; i < nitems; i++) { 65 unsigned long config; 66 int ret; 67 68 /* We want to check out this parameter */ 69 config = pinconf_to_config_packed(items[i].param, 0); 70 if (gname) 71 ret = pin_config_group_get(dev_name(pctldev->dev), 72 gname, &config); 73 else 74 ret = pin_config_get_for_pin(pctldev, pin, &config); 75 /* These are legal errors */ 76 if (ret == -EINVAL || ret == -ENOTSUPP) 77 continue; 78 if (ret) { 79 seq_printf(s, "ERROR READING CONFIG SETTING %d ", i); 80 continue; 81 } 82 /* comma between multiple configs */ 83 if (*print_sep) 84 seq_puts(s, ", "); 85 *print_sep = 1; 86 seq_puts(s, items[i].display); 87 /* Print unit if available */ 88 if (items[i].has_arg) { 89 seq_printf(s, " (%u", 90 pinconf_to_config_argument(config)); 91 if (items[i].format) 92 seq_printf(s, " %s)", items[i].format); 93 else 94 seq_puts(s, ")"); 95 } 96 } 97} 98 99/** 100 * pinconf_generic_dump_pins - Print information about pin or group of pins 101 * @pctldev: Pincontrol device 102 * @s: File to print to 103 * @gname: Group name specifying pins 104 * @pin: Pin number specyfying pin 105 * 106 * Print the pinconf configuration for the requested pin(s) to @s. Pins can be 107 * specified either by pin using @pin or by group using @gname. Only one needs 108 * to be specified the other can be NULL/0. 109 */ 110void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, struct seq_file *s, 111 const char *gname, unsigned pin) 112{ 113 const struct pinconf_ops *ops = pctldev->desc->confops; 114 int print_sep = 0; 115 116 if (!ops->is_generic) 117 return; 118 119 /* generic parameters */ 120 pinconf_generic_dump_one(pctldev, s, gname, pin, conf_items, 121 ARRAY_SIZE(conf_items), &print_sep); 122 /* driver-specific parameters */ 123 if (pctldev->desc->num_custom_params && 124 pctldev->desc->custom_conf_items) 125 pinconf_generic_dump_one(pctldev, s, gname, pin, 126 pctldev->desc->custom_conf_items, 127 pctldev->desc->num_custom_params, 128 &print_sep); 129} 130 131void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, 132 struct seq_file *s, unsigned long config) 133{ 134 int i; 135 136 for (i = 0; i < ARRAY_SIZE(conf_items); i++) { 137 if (pinconf_to_config_param(config) != conf_items[i].param) 138 continue; 139 seq_printf(s, "%s: 0x%x", conf_items[i].display, 140 pinconf_to_config_argument(config)); 141 } 142 143 if (!pctldev->desc->num_custom_params || 144 !pctldev->desc->custom_conf_items) 145 return; 146 147 for (i = 0; i < pctldev->desc->num_custom_params; i++) { 148 if (pinconf_to_config_param(config) != 149 pctldev->desc->custom_conf_items[i].param) 150 continue; 151 seq_printf(s, "%s: 0x%x", 152 pctldev->desc->custom_conf_items[i].display, 153 pinconf_to_config_argument(config)); 154 } 155} 156EXPORT_SYMBOL_GPL(pinconf_generic_dump_config); 157#endif 158 159#ifdef CONFIG_OF 160static const struct pinconf_generic_params dt_params[] = { 161 { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 }, 162 { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, 163 { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 }, 164 { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, 165 { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 }, 166 { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, 167 { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, 168 { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 }, 169 { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 }, 170 { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, 171 { "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 }, 172 { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, 173 { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, 174 { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, 175 { "input-schmitt", PIN_CONFIG_INPUT_SCHMITT, 0 }, 176 { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, 177 { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, 178 { "low-power-disable", PIN_CONFIG_MODE_LOW_POWER, 0 }, 179 { "low-power-enable", PIN_CONFIG_MODE_LOW_POWER, 1 }, 180 { "output-disable", PIN_CONFIG_OUTPUT_ENABLE, 0 }, 181 { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 }, 182 { "output-high", PIN_CONFIG_OUTPUT, 1, }, 183 { "output-impedance-ohms", PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS, 0 }, 184 { "output-low", PIN_CONFIG_OUTPUT, 0, }, 185 { "power-source", PIN_CONFIG_POWER_SOURCE, 0 }, 186 { "sleep-hardware-state", PIN_CONFIG_SLEEP_HARDWARE_STATE, 0 }, 187 { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 }, 188 { "skew-delay", PIN_CONFIG_SKEW_DELAY, 0 }, 189}; 190 191/** 192 * parse_dt_cfg() - Parse DT pinconf parameters 193 * @np: DT node 194 * @params: Array of describing generic parameters 195 * @count: Number of entries in @params 196 * @cfg: Array of parsed config options 197 * @ncfg: Number of entries in @cfg 198 * 199 * Parse the config options described in @params from @np and puts the result 200 * in @cfg. @cfg does not need to be empty, entries are added beginning at 201 * @ncfg. @ncfg is updated to reflect the number of entries after parsing. @cfg 202 * needs to have enough memory allocated to hold all possible entries. 203 */ 204static void parse_dt_cfg(struct device_node *np, 205 const struct pinconf_generic_params *params, 206 unsigned int count, unsigned long *cfg, 207 unsigned int *ncfg) 208{ 209 int i; 210 211 for (i = 0; i < count; i++) { 212 u32 val; 213 int ret; 214 const struct pinconf_generic_params *par = ¶ms[i]; 215 216 ret = of_property_read_u32(np, par->property, &val); 217 218 /* property not found */ 219 if (ret == -EINVAL) 220 continue; 221 222 /* use default value, when no value is specified */ 223 if (ret) 224 val = par->default_value; 225 226 pr_debug("found %s with value %u\n", par->property, val); 227 cfg[*ncfg] = pinconf_to_config_packed(par->param, val); 228 (*ncfg)++; 229 } 230} 231 232/** 233 * pinconf_generic_parse_dt_config() 234 * parse the config properties into generic pinconfig values. 235 * @np: node containing the pinconfig properties 236 * @pctldev: pincontrol device 237 * @configs: array with nconfigs entries containing the generic pinconf values 238 * must be freed when no longer necessary. 239 * @nconfigs: number of configurations 240 */ 241int pinconf_generic_parse_dt_config(struct device_node *np, 242 struct pinctrl_dev *pctldev, 243 unsigned long **configs, 244 unsigned int *nconfigs) 245{ 246 unsigned long *cfg; 247 unsigned int max_cfg, ncfg = 0; 248 int ret; 249 250 if (!np) 251 return -EINVAL; 252 253 /* allocate a temporary array big enough to hold one of each option */ 254 max_cfg = ARRAY_SIZE(dt_params); 255 if (pctldev) 256 max_cfg += pctldev->desc->num_custom_params; 257 cfg = kcalloc(max_cfg, sizeof(*cfg), GFP_KERNEL); 258 if (!cfg) 259 return -ENOMEM; 260 261 parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg); 262 if (pctldev && pctldev->desc->num_custom_params && 263 pctldev->desc->custom_params) 264 parse_dt_cfg(np, pctldev->desc->custom_params, 265 pctldev->desc->num_custom_params, cfg, &ncfg); 266 267 ret = 0; 268 269 /* no configs found at all */ 270 if (ncfg == 0) { 271 *configs = NULL; 272 *nconfigs = 0; 273 goto out; 274 } 275 276 /* 277 * Now limit the number of configs to the real number of 278 * found properties. 279 */ 280 *configs = kmemdup(cfg, ncfg * sizeof(unsigned long), GFP_KERNEL); 281 if (!*configs) { 282 ret = -ENOMEM; 283 goto out; 284 } 285 286 *nconfigs = ncfg; 287 288out: 289 kfree(cfg); 290 return ret; 291} 292EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_config); 293 294int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, 295 struct device_node *np, struct pinctrl_map **map, 296 unsigned *reserved_maps, unsigned *num_maps, 297 enum pinctrl_map_type type) 298{ 299 int ret; 300 const char *function; 301 struct device *dev = pctldev->dev; 302 unsigned long *configs = NULL; 303 unsigned num_configs = 0; 304 unsigned reserve, strings_count; 305 struct property *prop; 306 const char *group; 307 const char *subnode_target_type = "pins"; 308 309 ret = of_property_count_strings(np, "pins"); 310 if (ret < 0) { 311 ret = of_property_count_strings(np, "groups"); 312 if (ret < 0) 313 /* skip this node; may contain config child nodes */ 314 return 0; 315 if (type == PIN_MAP_TYPE_INVALID) 316 type = PIN_MAP_TYPE_CONFIGS_GROUP; 317 subnode_target_type = "groups"; 318 } else { 319 if (type == PIN_MAP_TYPE_INVALID) 320 type = PIN_MAP_TYPE_CONFIGS_PIN; 321 } 322 strings_count = ret; 323 324 ret = of_property_read_string(np, "function", &function); 325 if (ret < 0) { 326 /* EINVAL=missing, which is fine since it's optional */ 327 if (ret != -EINVAL) 328 dev_err(dev, "%pOF: could not parse property function\n", 329 np); 330 function = NULL; 331 } 332 333 ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, 334 &num_configs); 335 if (ret < 0) { 336 dev_err(dev, "%pOF: could not parse node property\n", np); 337 return ret; 338 } 339 340 reserve = 0; 341 if (function != NULL) 342 reserve++; 343 if (num_configs) 344 reserve++; 345 346 reserve *= strings_count; 347 348 ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, 349 num_maps, reserve); 350 if (ret < 0) 351 goto exit; 352 353 of_property_for_each_string(np, subnode_target_type, prop, group) { 354 if (function) { 355 ret = pinctrl_utils_add_map_mux(pctldev, map, 356 reserved_maps, num_maps, group, 357 function); 358 if (ret < 0) 359 goto exit; 360 } 361 362 if (num_configs) { 363 ret = pinctrl_utils_add_map_configs(pctldev, map, 364 reserved_maps, num_maps, group, configs, 365 num_configs, type); 366 if (ret < 0) 367 goto exit; 368 } 369 } 370 ret = 0; 371 372exit: 373 kfree(configs); 374 return ret; 375} 376EXPORT_SYMBOL_GPL(pinconf_generic_dt_subnode_to_map); 377 378int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, 379 struct device_node *np_config, struct pinctrl_map **map, 380 unsigned *num_maps, enum pinctrl_map_type type) 381{ 382 unsigned reserved_maps; 383 struct device_node *np; 384 int ret; 385 386 reserved_maps = 0; 387 *map = NULL; 388 *num_maps = 0; 389 390 ret = pinconf_generic_dt_subnode_to_map(pctldev, np_config, map, 391 &reserved_maps, num_maps, type); 392 if (ret < 0) 393 goto exit; 394 395 for_each_available_child_of_node(np_config, np) { 396 ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map, 397 &reserved_maps, num_maps, type); 398 if (ret < 0) 399 goto exit; 400 } 401 return 0; 402 403exit: 404 pinctrl_utils_free_map(pctldev, *map, *num_maps); 405 return ret; 406} 407EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map); 408 409void pinconf_generic_dt_free_map(struct pinctrl_dev *pctldev, 410 struct pinctrl_map *map, 411 unsigned num_maps) 412{ 413 pinctrl_utils_free_map(pctldev, map, num_maps); 414} 415EXPORT_SYMBOL_GPL(pinconf_generic_dt_free_map); 416 417#endif