root/drivers/pinctrl/pinconf-generic.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pinconf_generic_dump_one
  2. pinconf_generic_dump_pins
  3. pinconf_generic_dump_config
  4. parse_dt_cfg
  5. pinconf_generic_parse_dt_config
  6. pinconf_generic_dt_subnode_to_map
  7. pinconf_generic_dt_node_to_map
  8. pinconf_generic_dt_free_map

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

/* [<][>][^][v][top][bottom][index][help] */