linux/drivers/pinctrl/pinconf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Core driver for the 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#define pr_fmt(fmt) "pinconfig core: " fmt
  11
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/init.h>
  15#include <linux/device.h>
  16#include <linux/slab.h>
  17#include <linux/debugfs.h>
  18#include <linux/seq_file.h>
  19#include <linux/pinctrl/machine.h>
  20#include <linux/pinctrl/pinctrl.h>
  21#include <linux/pinctrl/pinconf.h>
  22#include "core.h"
  23#include "pinconf.h"
  24
  25int pinconf_check_ops(struct pinctrl_dev *pctldev)
  26{
  27        const struct pinconf_ops *ops = pctldev->desc->confops;
  28
  29        /* We have to be able to config the pins in SOME way */
  30        if (!ops->pin_config_set && !ops->pin_config_group_set) {
  31                dev_err(pctldev->dev,
  32                        "pinconf has to be able to set a pins config\n");
  33                return -EINVAL;
  34        }
  35        return 0;
  36}
  37
  38int pinconf_validate_map(const struct pinctrl_map *map, int i)
  39{
  40        if (!map->data.configs.group_or_pin) {
  41                pr_err("failed to register map %s (%d): no group/pin given\n",
  42                       map->name, i);
  43                return -EINVAL;
  44        }
  45
  46        if (!map->data.configs.num_configs ||
  47                        !map->data.configs.configs) {
  48                pr_err("failed to register map %s (%d): no configs given\n",
  49                       map->name, i);
  50                return -EINVAL;
  51        }
  52
  53        return 0;
  54}
  55
  56int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
  57                           unsigned long *config)
  58{
  59        const struct pinconf_ops *ops = pctldev->desc->confops;
  60
  61        if (!ops || !ops->pin_config_get) {
  62                dev_dbg(pctldev->dev,
  63                        "cannot get pin configuration, .pin_config_get missing in driver\n");
  64                return -ENOTSUPP;
  65        }
  66
  67        return ops->pin_config_get(pctldev, pin, config);
  68}
  69
  70int pin_config_group_get(const char *dev_name, const char *pin_group,
  71                         unsigned long *config)
  72{
  73        struct pinctrl_dev *pctldev;
  74        const struct pinconf_ops *ops;
  75        int selector, ret;
  76
  77        pctldev = get_pinctrl_dev_from_devname(dev_name);
  78        if (!pctldev) {
  79                ret = -EINVAL;
  80                return ret;
  81        }
  82
  83        mutex_lock(&pctldev->mutex);
  84
  85        ops = pctldev->desc->confops;
  86
  87        if (!ops || !ops->pin_config_group_get) {
  88                dev_dbg(pctldev->dev,
  89                        "cannot get configuration for pin group, missing group config get function in driver\n");
  90                ret = -ENOTSUPP;
  91                goto unlock;
  92        }
  93
  94        selector = pinctrl_get_group_selector(pctldev, pin_group);
  95        if (selector < 0) {
  96                ret = selector;
  97                goto unlock;
  98        }
  99
 100        ret = ops->pin_config_group_get(pctldev, selector, config);
 101
 102unlock:
 103        mutex_unlock(&pctldev->mutex);
 104        return ret;
 105}
 106
 107int pinconf_map_to_setting(const struct pinctrl_map *map,
 108                          struct pinctrl_setting *setting)
 109{
 110        struct pinctrl_dev *pctldev = setting->pctldev;
 111        int pin;
 112
 113        switch (setting->type) {
 114        case PIN_MAP_TYPE_CONFIGS_PIN:
 115                pin = pin_get_from_name(pctldev,
 116                                        map->data.configs.group_or_pin);
 117                if (pin < 0) {
 118                        dev_err(pctldev->dev, "could not map pin config for \"%s\"",
 119                                map->data.configs.group_or_pin);
 120                        return pin;
 121                }
 122                setting->data.configs.group_or_pin = pin;
 123                break;
 124        case PIN_MAP_TYPE_CONFIGS_GROUP:
 125                pin = pinctrl_get_group_selector(pctldev,
 126                                         map->data.configs.group_or_pin);
 127                if (pin < 0) {
 128                        dev_err(pctldev->dev, "could not map group config for \"%s\"",
 129                                map->data.configs.group_or_pin);
 130                        return pin;
 131                }
 132                setting->data.configs.group_or_pin = pin;
 133                break;
 134        default:
 135                return -EINVAL;
 136        }
 137
 138        setting->data.configs.num_configs = map->data.configs.num_configs;
 139        setting->data.configs.configs = map->data.configs.configs;
 140
 141        return 0;
 142}
 143
 144void pinconf_free_setting(const struct pinctrl_setting *setting)
 145{
 146}
 147
 148int pinconf_apply_setting(const struct pinctrl_setting *setting)
 149{
 150        struct pinctrl_dev *pctldev = setting->pctldev;
 151        const struct pinconf_ops *ops = pctldev->desc->confops;
 152        int ret;
 153
 154        if (!ops) {
 155                dev_err(pctldev->dev, "missing confops\n");
 156                return -EINVAL;
 157        }
 158
 159        switch (setting->type) {
 160        case PIN_MAP_TYPE_CONFIGS_PIN:
 161                if (!ops->pin_config_set) {
 162                        dev_err(pctldev->dev, "missing pin_config_set op\n");
 163                        return -EINVAL;
 164                }
 165                ret = ops->pin_config_set(pctldev,
 166                                setting->data.configs.group_or_pin,
 167                                setting->data.configs.configs,
 168                                setting->data.configs.num_configs);
 169                if (ret < 0) {
 170                        dev_err(pctldev->dev,
 171                                "pin_config_set op failed for pin %d\n",
 172                                setting->data.configs.group_or_pin);
 173                        return ret;
 174                }
 175                break;
 176        case PIN_MAP_TYPE_CONFIGS_GROUP:
 177                if (!ops->pin_config_group_set) {
 178                        dev_err(pctldev->dev,
 179                                "missing pin_config_group_set op\n");
 180                        return -EINVAL;
 181                }
 182                ret = ops->pin_config_group_set(pctldev,
 183                                setting->data.configs.group_or_pin,
 184                                setting->data.configs.configs,
 185                                setting->data.configs.num_configs);
 186                if (ret < 0) {
 187                        dev_err(pctldev->dev,
 188                                "pin_config_group_set op failed for group %d\n",
 189                                setting->data.configs.group_or_pin);
 190                        return ret;
 191                }
 192                break;
 193        default:
 194                return -EINVAL;
 195        }
 196
 197        return 0;
 198}
 199
 200int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned pin,
 201                       unsigned long *configs, size_t nconfigs)
 202{
 203        const struct pinconf_ops *ops;
 204
 205        ops = pctldev->desc->confops;
 206        if (!ops || !ops->pin_config_set)
 207                return -ENOTSUPP;
 208
 209        return ops->pin_config_set(pctldev, pin, configs, nconfigs);
 210}
 211
 212#ifdef CONFIG_DEBUG_FS
 213
 214static void pinconf_show_config(struct seq_file *s, struct pinctrl_dev *pctldev,
 215                      unsigned long *configs, unsigned num_configs)
 216{
 217        const struct pinconf_ops *confops;
 218        int i;
 219
 220        if (pctldev)
 221                confops = pctldev->desc->confops;
 222        else
 223                confops = NULL;
 224
 225        for (i = 0; i < num_configs; i++) {
 226                seq_puts(s, "config ");
 227                if (confops && confops->pin_config_config_dbg_show)
 228                        confops->pin_config_config_dbg_show(pctldev, s,
 229                                                            configs[i]);
 230                else
 231                        seq_printf(s, "%08lx", configs[i]);
 232                seq_putc(s, '\n');
 233        }
 234}
 235
 236void pinconf_show_map(struct seq_file *s, const struct pinctrl_map *map)
 237{
 238        struct pinctrl_dev *pctldev;
 239
 240        pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
 241
 242        switch (map->type) {
 243        case PIN_MAP_TYPE_CONFIGS_PIN:
 244                seq_puts(s, "pin ");
 245                break;
 246        case PIN_MAP_TYPE_CONFIGS_GROUP:
 247                seq_puts(s, "group ");
 248                break;
 249        default:
 250                break;
 251        }
 252
 253        seq_printf(s, "%s\n", map->data.configs.group_or_pin);
 254
 255        pinconf_show_config(s, pctldev, map->data.configs.configs,
 256                            map->data.configs.num_configs);
 257}
 258
 259void pinconf_show_setting(struct seq_file *s,
 260                          const struct pinctrl_setting *setting)
 261{
 262        struct pinctrl_dev *pctldev = setting->pctldev;
 263        const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
 264        struct pin_desc *desc;
 265
 266        switch (setting->type) {
 267        case PIN_MAP_TYPE_CONFIGS_PIN:
 268                desc = pin_desc_get(setting->pctldev,
 269                                    setting->data.configs.group_or_pin);
 270                seq_printf(s, "pin %s (%d)", desc->name,
 271                           setting->data.configs.group_or_pin);
 272                break;
 273        case PIN_MAP_TYPE_CONFIGS_GROUP:
 274                seq_printf(s, "group %s (%d)",
 275                           pctlops->get_group_name(pctldev,
 276                                        setting->data.configs.group_or_pin),
 277                           setting->data.configs.group_or_pin);
 278                break;
 279        default:
 280                break;
 281        }
 282
 283        /*
 284         * FIXME: We should really get the pin controller to dump the config
 285         * values, so they can be decoded to something meaningful.
 286         */
 287        pinconf_show_config(s, pctldev, setting->data.configs.configs,
 288                            setting->data.configs.num_configs);
 289}
 290
 291static void pinconf_dump_pin(struct pinctrl_dev *pctldev,
 292                             struct seq_file *s, int pin)
 293{
 294        const struct pinconf_ops *ops = pctldev->desc->confops;
 295
 296        /* no-op when not using generic pin config */
 297        pinconf_generic_dump_pins(pctldev, s, NULL, pin);
 298        if (ops && ops->pin_config_dbg_show)
 299                ops->pin_config_dbg_show(pctldev, s, pin);
 300}
 301
 302static int pinconf_pins_show(struct seq_file *s, void *what)
 303{
 304        struct pinctrl_dev *pctldev = s->private;
 305        unsigned i, pin;
 306
 307        seq_puts(s, "Pin config settings per pin\n");
 308        seq_puts(s, "Format: pin (name): configs\n");
 309
 310        mutex_lock(&pctldev->mutex);
 311
 312        /* The pin number can be retrived from the pin controller descriptor */
 313        for (i = 0; i < pctldev->desc->npins; i++) {
 314                struct pin_desc *desc;
 315
 316                pin = pctldev->desc->pins[i].number;
 317                desc = pin_desc_get(pctldev, pin);
 318                /* Skip if we cannot search the pin */
 319                if (!desc)
 320                        continue;
 321
 322                seq_printf(s, "pin %d (%s): ", pin, desc->name);
 323
 324                pinconf_dump_pin(pctldev, s, pin);
 325                seq_putc(s, '\n');
 326        }
 327
 328        mutex_unlock(&pctldev->mutex);
 329
 330        return 0;
 331}
 332
 333static void pinconf_dump_group(struct pinctrl_dev *pctldev,
 334                               struct seq_file *s, unsigned selector,
 335                               const char *gname)
 336{
 337        const struct pinconf_ops *ops = pctldev->desc->confops;
 338
 339        /* no-op when not using generic pin config */
 340        pinconf_generic_dump_pins(pctldev, s, gname, 0);
 341        if (ops && ops->pin_config_group_dbg_show)
 342                ops->pin_config_group_dbg_show(pctldev, s, selector);
 343}
 344
 345static int pinconf_groups_show(struct seq_file *s, void *what)
 346{
 347        struct pinctrl_dev *pctldev = s->private;
 348        const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
 349        unsigned ngroups = pctlops->get_groups_count(pctldev);
 350        unsigned selector = 0;
 351
 352        seq_puts(s, "Pin config settings per pin group\n");
 353        seq_puts(s, "Format: group (name): configs\n");
 354
 355        while (selector < ngroups) {
 356                const char *gname = pctlops->get_group_name(pctldev, selector);
 357
 358                seq_printf(s, "%u (%s): ", selector, gname);
 359                pinconf_dump_group(pctldev, s, selector, gname);
 360                seq_putc(s, '\n');
 361                selector++;
 362        }
 363
 364        return 0;
 365}
 366
 367DEFINE_SHOW_ATTRIBUTE(pinconf_pins);
 368DEFINE_SHOW_ATTRIBUTE(pinconf_groups);
 369
 370void pinconf_init_device_debugfs(struct dentry *devroot,
 371                         struct pinctrl_dev *pctldev)
 372{
 373        debugfs_create_file("pinconf-pins", 0444,
 374                            devroot, pctldev, &pinconf_pins_fops);
 375        debugfs_create_file("pinconf-groups", 0444,
 376                            devroot, pctldev, &pinconf_groups_fops);
 377}
 378
 379#endif
 380