uboot/drivers/pinctrl/pinctrl-generic.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015  Masahiro Yamada <yamada.masahiro@socionext.com>
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 */
   6
   7#include <common.h>
   8#include <linux/compat.h>
   9#include <dm/device.h>
  10#include <dm/pinctrl.h>
  11
  12DECLARE_GLOBAL_DATA_PTR;
  13
  14/**
  15 * pinctrl_pin_name_to_selector() - return the pin selector for a pin
  16 *
  17 * @dev: pin controller device
  18 * @pin: the pin name to look up
  19 * @return: pin selector, or negative error code on failure
  20 */
  21static int pinctrl_pin_name_to_selector(struct udevice *dev, const char *pin)
  22{
  23        const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
  24        unsigned npins, selector;
  25
  26        if (!ops->get_pins_count || !ops->get_pin_name) {
  27                dev_dbg(dev, "get_pins_count or get_pin_name missing\n");
  28                return -ENOSYS;
  29        }
  30
  31        npins = ops->get_pins_count(dev);
  32
  33        /* See if this pctldev has this pin */
  34        for (selector = 0; selector < npins; selector++) {
  35                const char *pname = ops->get_pin_name(dev, selector);
  36
  37                if (!strcmp(pin, pname))
  38                        return selector;
  39        }
  40
  41        return -ENOSYS;
  42}
  43
  44/**
  45 * pinctrl_group_name_to_selector() - return the group selector for a group
  46 *
  47 * @dev: pin controller device
  48 * @group: the pin group name to look up
  49 * @return: pin group selector, or negative error code on failure
  50 */
  51static int pinctrl_group_name_to_selector(struct udevice *dev,
  52                                          const char *group)
  53{
  54        const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
  55        unsigned ngroups, selector;
  56
  57        if (!ops->get_groups_count || !ops->get_group_name) {
  58                dev_dbg(dev, "get_groups_count or get_group_name missing\n");
  59                return -ENOSYS;
  60        }
  61
  62        ngroups = ops->get_groups_count(dev);
  63
  64        /* See if this pctldev has this group */
  65        for (selector = 0; selector < ngroups; selector++) {
  66                const char *gname = ops->get_group_name(dev, selector);
  67
  68                if (!strcmp(group, gname))
  69                        return selector;
  70        }
  71
  72        return -ENOSYS;
  73}
  74
  75#if CONFIG_IS_ENABLED(PINMUX)
  76/**
  77 * pinmux_func_name_to_selector() - return the function selector for a function
  78 *
  79 * @dev: pin controller device
  80 * @function: the function name to look up
  81 * @return: function selector, or negative error code on failure
  82 */
  83static int pinmux_func_name_to_selector(struct udevice *dev,
  84                                        const char *function)
  85{
  86        const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
  87        unsigned nfuncs, selector = 0;
  88
  89        if (!ops->get_functions_count || !ops->get_function_name) {
  90                dev_dbg(dev,
  91                        "get_functions_count or get_function_name missing\n");
  92                return -ENOSYS;
  93        }
  94
  95        nfuncs = ops->get_functions_count(dev);
  96
  97        /* See if this pctldev has this function */
  98        for (selector = 0; selector < nfuncs; selector++) {
  99                const char *fname = ops->get_function_name(dev, selector);
 100
 101                if (!strcmp(function, fname))
 102                        return selector;
 103        }
 104
 105        return -ENOSYS;
 106}
 107
 108/**
 109 * pinmux_enable_setting() - enable pin-mux setting for a certain pin/group
 110 *
 111 * @dev: pin controller device
 112 * @is_group: target of operation (true: pin group, false: pin)
 113 * @selector: pin selector or group selector, depending on @is_group
 114 * @func_selector: function selector
 115 * @return: 0 on success, or negative error code on failure
 116 */
 117static int pinmux_enable_setting(struct udevice *dev, bool is_group,
 118                                 unsigned selector, unsigned func_selector)
 119{
 120        const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
 121
 122        if (is_group) {
 123                if (!ops->pinmux_group_set) {
 124                        dev_dbg(dev, "pinmux_group_set op missing\n");
 125                        return -ENOSYS;
 126                }
 127
 128                return ops->pinmux_group_set(dev, selector, func_selector);
 129        } else {
 130                if (!ops->pinmux_set) {
 131                        dev_dbg(dev, "pinmux_set op missing\n");
 132                        return -ENOSYS;
 133                }
 134                return ops->pinmux_set(dev, selector, func_selector);
 135        }
 136}
 137#else
 138static int pinmux_func_name_to_selector(struct udevice *dev,
 139                                        const char *function)
 140{
 141        return 0;
 142}
 143
 144static int pinmux_enable_setting(struct udevice *dev, bool is_group,
 145                                 unsigned selector, unsigned func_selector)
 146{
 147        return 0;
 148}
 149#endif
 150
 151#if CONFIG_IS_ENABLED(PINCONF)
 152/**
 153 * pinconf_prop_name_to_param() - return parameter ID for a property name
 154 *
 155 * @dev: pin controller device
 156 * @property: property name in DTS, such as "bias-pull-up", "slew-rate", etc.
 157 * @default_value: return default value in case no value is specified in DTS
 158 * @return: return pamater ID, or negative error code on failure
 159 */
 160static int pinconf_prop_name_to_param(struct udevice *dev,
 161                                      const char *property, u32 *default_value)
 162{
 163        const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
 164        const struct pinconf_param *p, *end;
 165
 166        if (!ops->pinconf_num_params || !ops->pinconf_params) {
 167                dev_dbg(dev, "pinconf_num_params or pinconf_params missing\n");
 168                return -ENOSYS;
 169        }
 170
 171        p = ops->pinconf_params;
 172        end = p + ops->pinconf_num_params;
 173
 174        /* See if this pctldev supports this parameter */
 175        for (; p < end; p++) {
 176                if (!strcmp(property, p->property)) {
 177                        *default_value = p->default_value;
 178                        return p->param;
 179                }
 180        }
 181
 182        return -ENOSYS;
 183}
 184
 185/**
 186 * pinconf_enable_setting() - apply pin configuration for a certain pin/group
 187 *
 188 * @dev: pin controller device
 189 * @is_group: target of operation (true: pin group, false: pin)
 190 * @selector: pin selector or group selector, depending on @is_group
 191 * @param: configuration paramter
 192 * @argument: argument taken by some configuration parameters
 193 * @return: 0 on success, or negative error code on failure
 194 */
 195static int pinconf_enable_setting(struct udevice *dev, bool is_group,
 196                                  unsigned selector, unsigned param,
 197                                  u32 argument)
 198{
 199        const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
 200
 201        if (is_group) {
 202                if (!ops->pinconf_group_set) {
 203                        dev_dbg(dev, "pinconf_group_set op missing\n");
 204                        return -ENOSYS;
 205                }
 206
 207                return ops->pinconf_group_set(dev, selector, param,
 208                                              argument);
 209        } else {
 210                if (!ops->pinconf_set) {
 211                        dev_dbg(dev, "pinconf_set op missing\n");
 212                        return -ENOSYS;
 213                }
 214                return ops->pinconf_set(dev, selector, param, argument);
 215        }
 216}
 217#else
 218static int pinconf_prop_name_to_param(struct udevice *dev,
 219                                      const char *property, u32 *default_value)
 220{
 221        return -ENOSYS;
 222}
 223
 224static int pinconf_enable_setting(struct udevice *dev, bool is_group,
 225                                  unsigned selector, unsigned param,
 226                                  u32 argument)
 227{
 228        return 0;
 229}
 230#endif
 231
 232/**
 233 * pinctrl_generic_set_state_one() - set state for a certain pin/group
 234 * Apply all pin multiplexing and pin configurations specified by @config
 235 * for a given pin or pin group.
 236 *
 237 * @dev: pin controller device
 238 * @config: pseudo device pointing to config node
 239 * @is_group: target of operation (true: pin group, false: pin)
 240 * @selector: pin selector or group selector, depending on @is_group
 241 * @return: 0 on success, or negative error code on failure
 242 */
 243static int pinctrl_generic_set_state_one(struct udevice *dev,
 244                                         struct udevice *config,
 245                                         bool is_group, unsigned selector)
 246{
 247        const void *fdt = gd->fdt_blob;
 248        int node_offset = dev_of_offset(config);
 249        const char *propname;
 250        const void *value;
 251        int prop_offset, len, func_selector, param, ret;
 252        u32 arg, default_val;
 253
 254        for (prop_offset = fdt_first_property_offset(fdt, node_offset);
 255             prop_offset > 0;
 256             prop_offset = fdt_next_property_offset(fdt, prop_offset)) {
 257                value = fdt_getprop_by_offset(fdt, prop_offset,
 258                                              &propname, &len);
 259                if (!value)
 260                        return -EINVAL;
 261
 262                if (!strcmp(propname, "function")) {
 263                        func_selector = pinmux_func_name_to_selector(dev,
 264                                                                     value);
 265                        if (func_selector < 0)
 266                                return func_selector;
 267                        ret = pinmux_enable_setting(dev, is_group,
 268                                                    selector,
 269                                                    func_selector);
 270                } else {
 271                        param = pinconf_prop_name_to_param(dev, propname,
 272                                                           &default_val);
 273                        if (param < 0)
 274                                continue; /* just skip unknown properties */
 275
 276                        if (len >= sizeof(fdt32_t))
 277                                arg = fdt32_to_cpu(*(fdt32_t *)value);
 278                        else
 279                                arg = default_val;
 280
 281                        ret = pinconf_enable_setting(dev, is_group,
 282                                                     selector, param, arg);
 283                }
 284
 285                if (ret)
 286                        return ret;
 287        }
 288
 289        return 0;
 290}
 291
 292/**
 293 * pinctrl_generic_set_state_subnode() - apply all settings in config node
 294 *
 295 * @dev: pin controller device
 296 * @config: pseudo device pointing to config node
 297 * @return: 0 on success, or negative error code on failure
 298 */
 299static int pinctrl_generic_set_state_subnode(struct udevice *dev,
 300                                             struct udevice *config)
 301{
 302        const void *fdt = gd->fdt_blob;
 303        int node = dev_of_offset(config);
 304        const char *subnode_target_type = "pins";
 305        bool is_group = false;
 306        const char *name;
 307        int strings_count, selector, i, ret;
 308
 309        strings_count = fdt_stringlist_count(fdt, node, subnode_target_type);
 310        if (strings_count < 0) {
 311                subnode_target_type = "groups";
 312                is_group = true;
 313                strings_count = fdt_stringlist_count(fdt, node,
 314                                                     subnode_target_type);
 315                if (strings_count < 0) {
 316                        /* skip this node; may contain config child nodes */
 317                        return 0;
 318                }
 319        }
 320
 321        for (i = 0; i < strings_count; i++) {
 322                name = fdt_stringlist_get(fdt, node, subnode_target_type, i,
 323                                          NULL);
 324                if (!name)
 325                        return -EINVAL;
 326
 327                if (is_group)
 328                        selector = pinctrl_group_name_to_selector(dev, name);
 329                else
 330                        selector = pinctrl_pin_name_to_selector(dev, name);
 331                if (selector < 0)
 332                        return selector;
 333
 334                ret = pinctrl_generic_set_state_one(dev, config,
 335                                                    is_group, selector);
 336                if (ret)
 337                        return ret;
 338        }
 339
 340        return 0;
 341}
 342
 343int pinctrl_generic_set_state(struct udevice *dev, struct udevice *config)
 344{
 345        struct udevice *child;
 346        int ret;
 347
 348        ret = pinctrl_generic_set_state_subnode(dev, config);
 349        if (ret)
 350                return ret;
 351
 352        for (device_find_first_child(config, &child);
 353             child;
 354             device_find_next_child(&child)) {
 355                ret = pinctrl_generic_set_state_subnode(dev, child);
 356                if (ret)
 357                        return ret;
 358        }
 359
 360        return 0;
 361}
 362