linux/drivers/pinctrl/pinconf-generic.c
<<
>>
Prefs
   1/*
   2 * Core driver for the generic pin config portions of the pin control subsystem
   3 *
   4 * Copyright (C) 2011 ST-Ericsson SA
   5 * Written on behalf of Linaro for ST-Ericsson
   6 *
   7 * Author: Linus Walleij <linus.walleij@linaro.org>
   8 *
   9 * License terms: GNU General Public License (GPL) version 2
  10 */
  11
  12#define pr_fmt(fmt) "generic pinconfig core: " fmt
  13
  14#include <linux/kernel.h>
  15#include <linux/module.h>
  16#include <linux/init.h>
  17#include <linux/device.h>
  18#include <linux/slab.h>
  19#include <linux/debugfs.h>
  20#include <linux/seq_file.h>
  21#include <linux/pinctrl/pinctrl.h>
  22#include <linux/pinctrl/pinconf.h>
  23#include <linux/pinctrl/pinconf-generic.h>
  24#include <linux/of.h>
  25#include "core.h"
  26#include "pinconf.h"
  27#include "pinctrl-utils.h"
  28
  29#ifdef CONFIG_DEBUG_FS
  30
  31struct pin_config_item {
  32        const enum pin_config_param param;
  33        const char * const display;
  34        const char * const format;
  35};
  36
  37#define PCONFDUMP(a, b, c) { .param = a, .display = b, .format = c }
  38
  39static struct pin_config_item conf_items[] = {
  40        PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL),
  41        PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL),
  42        PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL),
  43        PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL),
  44        PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL),
  45        PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT,
  46                                "input bias pull to pin specific state", NULL),
  47        PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL),
  48        PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL),
  49        PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL),
  50        PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA"),
  51        PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL),
  52        PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL),
  53        PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec"),
  54        PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"),
  55        PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL),
  56        PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode"),
  57        PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level"),
  58};
  59
  60void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
  61                              struct seq_file *s, unsigned pin)
  62{
  63        const struct pinconf_ops *ops = pctldev->desc->confops;
  64        int i;
  65
  66        if (!ops->is_generic)
  67                return;
  68
  69        for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
  70                unsigned long config;
  71                int ret;
  72
  73                /* We want to check out this parameter */
  74                config = pinconf_to_config_packed(conf_items[i].param, 0);
  75                ret = pin_config_get_for_pin(pctldev, pin, &config);
  76                /* These are legal errors */
  77                if (ret == -EINVAL || ret == -ENOTSUPP)
  78                        continue;
  79                if (ret) {
  80                        seq_printf(s, "ERROR READING CONFIG SETTING %d ", i);
  81                        continue;
  82                }
  83                /* Space between multiple configs */
  84                seq_puts(s, " ");
  85                seq_puts(s, conf_items[i].display);
  86                /* Print unit if available */
  87                if (conf_items[i].format &&
  88                    pinconf_to_config_argument(config) != 0)
  89                        seq_printf(s, " (%u %s)",
  90                                   pinconf_to_config_argument(config),
  91                                   conf_items[i].format);
  92        }
  93}
  94
  95void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
  96                              struct seq_file *s, const char *gname)
  97{
  98        const struct pinconf_ops *ops = pctldev->desc->confops;
  99        int i;
 100
 101        if (!ops->is_generic)
 102                return;
 103
 104        for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
 105                unsigned long config;
 106                int ret;
 107
 108                /* We want to check out this parameter */
 109                config = pinconf_to_config_packed(conf_items[i].param, 0);
 110                ret = pin_config_group_get(dev_name(pctldev->dev), gname,
 111                                           &config);
 112                /* These are legal errors */
 113                if (ret == -EINVAL || ret == -ENOTSUPP)
 114                        continue;
 115                if (ret) {
 116                        seq_printf(s, "ERROR READING CONFIG SETTING %d ", i);
 117                        continue;
 118                }
 119                /* Space between multiple configs */
 120                seq_puts(s, " ");
 121                seq_puts(s, conf_items[i].display);
 122                /* Print unit if available */
 123                if (conf_items[i].format && config != 0)
 124                        seq_printf(s, " (%u %s)",
 125                                   pinconf_to_config_argument(config),
 126                                   conf_items[i].format);
 127        }
 128}
 129
 130void 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}
 142EXPORT_SYMBOL_GPL(pinconf_generic_dump_config);
 143#endif
 144
 145#ifdef CONFIG_OF
 146struct pinconf_generic_dt_params {
 147        const char * const property;
 148        enum pin_config_param param;
 149        u32 default_value;
 150};
 151
 152static struct pinconf_generic_dt_params dt_params[] = {
 153        { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
 154        { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
 155        { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
 156        { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
 157        { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
 158        { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
 159        { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
 160        { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
 161        { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
 162        { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
 163        { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
 164        { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
 165        { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
 166        { "low-power-enable", PIN_CONFIG_LOW_POWER_MODE, 1 },
 167        { "low-power-disable", PIN_CONFIG_LOW_POWER_MODE, 0 },
 168        { "output-low", PIN_CONFIG_OUTPUT, 0, },
 169        { "output-high", PIN_CONFIG_OUTPUT, 1, },
 170};
 171
 172/**
 173 * pinconf_generic_parse_dt_config()
 174 * parse the config properties into generic pinconfig values.
 175 * @np: node containing the pinconfig properties
 176 * @configs: array with nconfigs entries containing the generic pinconf values
 177 * @nconfigs: umber of configurations
 178 */
 179int pinconf_generic_parse_dt_config(struct device_node *np,
 180                                    unsigned long **configs,
 181                                    unsigned int *nconfigs)
 182{
 183        unsigned long *cfg;
 184        unsigned int ncfg = 0;
 185        int ret;
 186        int i;
 187        u32 val;
 188
 189        if (!np)
 190                return -EINVAL;
 191
 192        /* allocate a temporary array big enough to hold one of each option */
 193        cfg = kzalloc(sizeof(*cfg) * ARRAY_SIZE(dt_params), GFP_KERNEL);
 194        if (!cfg)
 195                return -ENOMEM;
 196
 197        for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
 198                struct pinconf_generic_dt_params *par = &dt_params[i];
 199                ret = of_property_read_u32(np, par->property, &val);
 200
 201                /* property not found */
 202                if (ret == -EINVAL)
 203                        continue;
 204
 205                /* use default value, when no value is specified */
 206                if (ret)
 207                        val = par->default_value;
 208
 209                pr_debug("found %s with value %u\n", par->property, val);
 210                cfg[ncfg] = pinconf_to_config_packed(par->param, val);
 211                ncfg++;
 212        }
 213
 214        ret = 0;
 215
 216        /* no configs found at all */
 217        if (ncfg == 0) {
 218                *configs = NULL;
 219                *nconfigs = 0;
 220                goto out;
 221        }
 222
 223        /*
 224         * Now limit the number of configs to the real number of
 225         * found properties.
 226         */
 227        *configs = kzalloc(ncfg * sizeof(unsigned long), GFP_KERNEL);
 228        if (!*configs) {
 229                ret = -ENOMEM;
 230                goto out;
 231        }
 232
 233        memcpy(*configs, cfg, ncfg * sizeof(unsigned long));
 234        *nconfigs = ncfg;
 235
 236out:
 237        kfree(cfg);
 238        return ret;
 239}
 240
 241int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
 242                struct device_node *np, struct pinctrl_map **map,
 243                unsigned *reserved_maps, unsigned *num_maps,
 244                enum pinctrl_map_type type)
 245{
 246        int ret;
 247        const char *function;
 248        struct device *dev = pctldev->dev;
 249        unsigned long *configs = NULL;
 250        unsigned num_configs = 0;
 251        unsigned reserve;
 252        struct property *prop;
 253        const char *group;
 254
 255        ret = of_property_read_string(np, "function", &function);
 256        if (ret < 0) {
 257                /* EINVAL=missing, which is fine since it's optional */
 258                if (ret != -EINVAL)
 259                        dev_err(dev, "could not parse property function\n");
 260                function = NULL;
 261        }
 262
 263        ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
 264        if (ret < 0) {
 265                dev_err(dev, "could not parse node property\n");
 266                return ret;
 267        }
 268
 269        reserve = 0;
 270        if (function != NULL)
 271                reserve++;
 272        if (num_configs)
 273                reserve++;
 274        ret = of_property_count_strings(np, "pins");
 275        if (ret < 0) {
 276                dev_err(dev, "could not parse property pins\n");
 277                goto exit;
 278        }
 279        reserve *= ret;
 280
 281        ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps,
 282                        num_maps, reserve);
 283        if (ret < 0)
 284                goto exit;
 285
 286        of_property_for_each_string(np, "pins", prop, group) {
 287                if (function) {
 288                        ret = pinctrl_utils_add_map_mux(pctldev, map,
 289                                        reserved_maps, num_maps, group,
 290                                        function);
 291                        if (ret < 0)
 292                                goto exit;
 293                }
 294
 295                if (num_configs) {
 296                        ret = pinctrl_utils_add_map_configs(pctldev, map,
 297                                        reserved_maps, num_maps, group, configs,
 298                                        num_configs, type);
 299                        if (ret < 0)
 300                                goto exit;
 301                }
 302        }
 303        ret = 0;
 304
 305exit:
 306        kfree(configs);
 307        return ret;
 308}
 309EXPORT_SYMBOL_GPL(pinconf_generic_dt_subnode_to_map);
 310
 311int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
 312                struct device_node *np_config, struct pinctrl_map **map,
 313                unsigned *num_maps, enum pinctrl_map_type type)
 314{
 315        unsigned reserved_maps;
 316        struct device_node *np;
 317        int ret;
 318
 319        reserved_maps = 0;
 320        *map = NULL;
 321        *num_maps = 0;
 322
 323        for_each_child_of_node(np_config, np) {
 324                ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map,
 325                                        &reserved_maps, num_maps, type);
 326                if (ret < 0) {
 327                        pinctrl_utils_dt_free_map(pctldev, *map, *num_maps);
 328                        return ret;
 329                }
 330        }
 331        return 0;
 332}
 333EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map);
 334
 335#endif
 336
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.