Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Core driver for the generic pin config portions of the pin control subsystem
0004  *
0005  * Copyright (C) 2011 ST-Ericsson SA
0006  * Written on behalf of Linaro for ST-Ericsson
0007  *
0008  * Author: Linus Walleij <linus.walleij@linaro.org>
0009  */
0010 
0011 #define pr_fmt(fmt) "generic pinconfig core: " fmt
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/init.h>
0016 #include <linux/device.h>
0017 #include <linux/slab.h>
0018 #include <linux/debugfs.h>
0019 #include <linux/seq_file.h>
0020 #include <linux/pinctrl/pinctrl.h>
0021 #include <linux/pinctrl/pinconf.h>
0022 #include <linux/pinctrl/pinconf-generic.h>
0023 #include <linux/of.h>
0024 #include "core.h"
0025 #include "pinconf.h"
0026 #include "pinctrl-utils.h"
0027 
0028 #ifdef CONFIG_DEBUG_FS
0029 static const struct pin_config_item conf_items[] = {
0030     PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL, false),
0031     PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false),
0032     PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false),
0033     PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", "ohms", true),
0034     PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT,
0035                 "input bias pull to pin specific state", "ohms", true),
0036     PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", "ohms", true),
0037     PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL, false),
0038     PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL, false),
0039     PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL, false),
0040     PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA", true),
0041     PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH_UA, "output drive strength", "uA", true),
0042     PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec", true),
0043     PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL, false),
0044     PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL, false),
0045     PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL, false),
0046     PCONFDUMP(PIN_CONFIG_MODE_LOW_POWER, "pin low power", "mode", true),
0047     PCONFDUMP(PIN_CONFIG_OUTPUT_ENABLE, "output enabled", NULL, false),
0048     PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level", true),
0049     PCONFDUMP(PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS, "output impedance", "ohms", true),
0050     PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector", true),
0051     PCONFDUMP(PIN_CONFIG_SLEEP_HARDWARE_STATE, "sleep hardware state", NULL, false),
0052     PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL, true),
0053     PCONFDUMP(PIN_CONFIG_SKEW_DELAY, "skew delay", NULL, true),
0054 };
0055 
0056 static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
0057                      struct seq_file *s, const char *gname,
0058                      unsigned pin,
0059                      const struct pin_config_item *items,
0060                      int nitems, int *print_sep)
0061 {
0062     int i;
0063 
0064     for (i = 0; i < nitems; i++) {
0065         unsigned long config;
0066         int ret;
0067 
0068         /* We want to check out this parameter */
0069         config = pinconf_to_config_packed(items[i].param, 0);
0070         if (gname)
0071             ret = pin_config_group_get(dev_name(pctldev->dev),
0072                            gname, &config);
0073         else
0074             ret = pin_config_get_for_pin(pctldev, pin, &config);
0075         /* These are legal errors */
0076         if (ret == -EINVAL || ret == -ENOTSUPP)
0077             continue;
0078         if (ret) {
0079             seq_printf(s, "ERROR READING CONFIG SETTING %d ", i);
0080             continue;
0081         }
0082         /* comma between multiple configs */
0083         if (*print_sep)
0084             seq_puts(s, ", ");
0085         *print_sep = 1;
0086         seq_puts(s, items[i].display);
0087         /* Print unit if available */
0088         if (items[i].has_arg) {
0089             seq_printf(s, " (%u",
0090                    pinconf_to_config_argument(config));
0091             if (items[i].format)
0092                 seq_printf(s, " %s)", items[i].format);
0093             else
0094                 seq_puts(s, ")");
0095         }
0096     }
0097 }
0098 
0099 /**
0100  * pinconf_generic_dump_pins - Print information about pin or group of pins
0101  * @pctldev:    Pincontrol device
0102  * @s:      File to print to
0103  * @gname:  Group name specifying pins
0104  * @pin:    Pin number specyfying pin
0105  *
0106  * Print the pinconf configuration for the requested pin(s) to @s. Pins can be
0107  * specified either by pin using @pin or by group using @gname. Only one needs
0108  * to be specified the other can be NULL/0.
0109  */
0110 void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, struct seq_file *s,
0111                    const char *gname, unsigned pin)
0112 {
0113     const struct pinconf_ops *ops = pctldev->desc->confops;
0114     int print_sep = 0;
0115 
0116     if (!ops->is_generic)
0117         return;
0118 
0119     /* generic parameters */
0120     pinconf_generic_dump_one(pctldev, s, gname, pin, conf_items,
0121                  ARRAY_SIZE(conf_items), &print_sep);
0122     /* driver-specific parameters */
0123     if (pctldev->desc->num_custom_params &&
0124         pctldev->desc->custom_conf_items)
0125         pinconf_generic_dump_one(pctldev, s, gname, pin,
0126                      pctldev->desc->custom_conf_items,
0127                      pctldev->desc->num_custom_params,
0128                      &print_sep);
0129 }
0130 
0131 void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
0132                  struct seq_file *s, unsigned long config)
0133 {
0134     int i;
0135 
0136     for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
0137         if (pinconf_to_config_param(config) != conf_items[i].param)
0138             continue;
0139         seq_printf(s, "%s: 0x%x", conf_items[i].display,
0140                pinconf_to_config_argument(config));
0141     }
0142 
0143     if (!pctldev->desc->num_custom_params ||
0144         !pctldev->desc->custom_conf_items)
0145         return;
0146 
0147     for (i = 0; i < pctldev->desc->num_custom_params; i++) {
0148         if (pinconf_to_config_param(config) !=
0149             pctldev->desc->custom_conf_items[i].param)
0150             continue;
0151         seq_printf(s, "%s: 0x%x",
0152                 pctldev->desc->custom_conf_items[i].display,
0153                 pinconf_to_config_argument(config));
0154     }
0155 }
0156 EXPORT_SYMBOL_GPL(pinconf_generic_dump_config);
0157 #endif
0158 
0159 #ifdef CONFIG_OF
0160 static const struct pinconf_generic_params dt_params[] = {
0161     { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
0162     { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
0163     { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
0164     { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
0165     { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
0166     { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
0167     { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
0168     { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
0169     { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
0170     { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
0171     { "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 },
0172     { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
0173     { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
0174     { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
0175     { "input-schmitt", PIN_CONFIG_INPUT_SCHMITT, 0 },
0176     { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
0177     { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
0178     { "low-power-disable", PIN_CONFIG_MODE_LOW_POWER, 0 },
0179     { "low-power-enable", PIN_CONFIG_MODE_LOW_POWER, 1 },
0180     { "output-disable", PIN_CONFIG_OUTPUT_ENABLE, 0 },
0181     { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 },
0182     { "output-high", PIN_CONFIG_OUTPUT, 1, },
0183     { "output-impedance-ohms", PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS, 0 },
0184     { "output-low", PIN_CONFIG_OUTPUT, 0, },
0185     { "power-source", PIN_CONFIG_POWER_SOURCE, 0 },
0186     { "sleep-hardware-state", PIN_CONFIG_SLEEP_HARDWARE_STATE, 0 },
0187     { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 },
0188     { "skew-delay", PIN_CONFIG_SKEW_DELAY, 0 },
0189 };
0190 
0191 /**
0192  * parse_dt_cfg() - Parse DT pinconf parameters
0193  * @np: DT node
0194  * @params: Array of describing generic parameters
0195  * @count:  Number of entries in @params
0196  * @cfg:    Array of parsed config options
0197  * @ncfg:   Number of entries in @cfg
0198  *
0199  * Parse the config options described in @params from @np and puts the result
0200  * in @cfg. @cfg does not need to be empty, entries are added beginning at
0201  * @ncfg. @ncfg is updated to reflect the number of entries after parsing. @cfg
0202  * needs to have enough memory allocated to hold all possible entries.
0203  */
0204 static void parse_dt_cfg(struct device_node *np,
0205              const struct pinconf_generic_params *params,
0206              unsigned int count, unsigned long *cfg,
0207              unsigned int *ncfg)
0208 {
0209     int i;
0210 
0211     for (i = 0; i < count; i++) {
0212         u32 val;
0213         int ret;
0214         const struct pinconf_generic_params *par = &params[i];
0215 
0216         ret = of_property_read_u32(np, par->property, &val);
0217 
0218         /* property not found */
0219         if (ret == -EINVAL)
0220             continue;
0221 
0222         /* use default value, when no value is specified */
0223         if (ret)
0224             val = par->default_value;
0225 
0226         pr_debug("found %s with value %u\n", par->property, val);
0227         cfg[*ncfg] = pinconf_to_config_packed(par->param, val);
0228         (*ncfg)++;
0229     }
0230 }
0231 
0232 /**
0233  * pinconf_generic_parse_dt_config()
0234  * parse the config properties into generic pinconfig values.
0235  * @np: node containing the pinconfig properties
0236  * @pctldev: pincontrol device
0237  * @configs: array with nconfigs entries containing the generic pinconf values
0238  *           must be freed when no longer necessary.
0239  * @nconfigs: number of configurations
0240  */
0241 int pinconf_generic_parse_dt_config(struct device_node *np,
0242                     struct pinctrl_dev *pctldev,
0243                     unsigned long **configs,
0244                     unsigned int *nconfigs)
0245 {
0246     unsigned long *cfg;
0247     unsigned int max_cfg, ncfg = 0;
0248     int ret;
0249 
0250     if (!np)
0251         return -EINVAL;
0252 
0253     /* allocate a temporary array big enough to hold one of each option */
0254     max_cfg = ARRAY_SIZE(dt_params);
0255     if (pctldev)
0256         max_cfg += pctldev->desc->num_custom_params;
0257     cfg = kcalloc(max_cfg, sizeof(*cfg), GFP_KERNEL);
0258     if (!cfg)
0259         return -ENOMEM;
0260 
0261     parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg);
0262     if (pctldev && pctldev->desc->num_custom_params &&
0263         pctldev->desc->custom_params)
0264         parse_dt_cfg(np, pctldev->desc->custom_params,
0265                  pctldev->desc->num_custom_params, cfg, &ncfg);
0266 
0267     ret = 0;
0268 
0269     /* no configs found at all */
0270     if (ncfg == 0) {
0271         *configs = NULL;
0272         *nconfigs = 0;
0273         goto out;
0274     }
0275 
0276     /*
0277      * Now limit the number of configs to the real number of
0278      * found properties.
0279      */
0280     *configs = kmemdup(cfg, ncfg * sizeof(unsigned long), GFP_KERNEL);
0281     if (!*configs) {
0282         ret = -ENOMEM;
0283         goto out;
0284     }
0285 
0286     *nconfigs = ncfg;
0287 
0288 out:
0289     kfree(cfg);
0290     return ret;
0291 }
0292 EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_config);
0293 
0294 int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
0295         struct device_node *np, struct pinctrl_map **map,
0296         unsigned *reserved_maps, unsigned *num_maps,
0297         enum pinctrl_map_type type)
0298 {
0299     int ret;
0300     const char *function;
0301     struct device *dev = pctldev->dev;
0302     unsigned long *configs = NULL;
0303     unsigned num_configs = 0;
0304     unsigned reserve, strings_count;
0305     struct property *prop;
0306     const char *group;
0307     const char *subnode_target_type = "pins";
0308 
0309     ret = of_property_count_strings(np, "pins");
0310     if (ret < 0) {
0311         ret = of_property_count_strings(np, "groups");
0312         if (ret < 0)
0313             /* skip this node; may contain config child nodes */
0314             return 0;
0315         if (type == PIN_MAP_TYPE_INVALID)
0316             type = PIN_MAP_TYPE_CONFIGS_GROUP;
0317         subnode_target_type = "groups";
0318     } else {
0319         if (type == PIN_MAP_TYPE_INVALID)
0320             type = PIN_MAP_TYPE_CONFIGS_PIN;
0321     }
0322     strings_count = ret;
0323 
0324     ret = of_property_read_string(np, "function", &function);
0325     if (ret < 0) {
0326         /* EINVAL=missing, which is fine since it's optional */
0327         if (ret != -EINVAL)
0328             dev_err(dev, "%pOF: could not parse property function\n",
0329                 np);
0330         function = NULL;
0331     }
0332 
0333     ret = pinconf_generic_parse_dt_config(np, pctldev, &configs,
0334                           &num_configs);
0335     if (ret < 0) {
0336         dev_err(dev, "%pOF: could not parse node property\n", np);
0337         return ret;
0338     }
0339 
0340     reserve = 0;
0341     if (function != NULL)
0342         reserve++;
0343     if (num_configs)
0344         reserve++;
0345 
0346     reserve *= strings_count;
0347 
0348     ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps,
0349             num_maps, reserve);
0350     if (ret < 0)
0351         goto exit;
0352 
0353     of_property_for_each_string(np, subnode_target_type, prop, group) {
0354         if (function) {
0355             ret = pinctrl_utils_add_map_mux(pctldev, map,
0356                     reserved_maps, num_maps, group,
0357                     function);
0358             if (ret < 0)
0359                 goto exit;
0360         }
0361 
0362         if (num_configs) {
0363             ret = pinctrl_utils_add_map_configs(pctldev, map,
0364                     reserved_maps, num_maps, group, configs,
0365                     num_configs, type);
0366             if (ret < 0)
0367                 goto exit;
0368         }
0369     }
0370     ret = 0;
0371 
0372 exit:
0373     kfree(configs);
0374     return ret;
0375 }
0376 EXPORT_SYMBOL_GPL(pinconf_generic_dt_subnode_to_map);
0377 
0378 int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
0379         struct device_node *np_config, struct pinctrl_map **map,
0380         unsigned *num_maps, enum pinctrl_map_type type)
0381 {
0382     unsigned reserved_maps;
0383     struct device_node *np;
0384     int ret;
0385 
0386     reserved_maps = 0;
0387     *map = NULL;
0388     *num_maps = 0;
0389 
0390     ret = pinconf_generic_dt_subnode_to_map(pctldev, np_config, map,
0391                         &reserved_maps, num_maps, type);
0392     if (ret < 0)
0393         goto exit;
0394 
0395     for_each_available_child_of_node(np_config, np) {
0396         ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map,
0397                     &reserved_maps, num_maps, type);
0398         if (ret < 0)
0399             goto exit;
0400     }
0401     return 0;
0402 
0403 exit:
0404     pinctrl_utils_free_map(pctldev, *map, *num_maps);
0405     return ret;
0406 }
0407 EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map);
0408 
0409 void pinconf_generic_dt_free_map(struct pinctrl_dev *pctldev,
0410                  struct pinctrl_map *map,
0411                  unsigned num_maps)
0412 {
0413     pinctrl_utils_free_map(pctldev, map, num_maps);
0414 }
0415 EXPORT_SYMBOL_GPL(pinconf_generic_dt_free_map);
0416 
0417 #endif