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