uboot/drivers/pinctrl/meson/pinctrl-meson.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com>
   4 */
   5
   6#include <common.h>
   7#include <dm.h>
   8#include <log.h>
   9#include <malloc.h>
  10#include <dm/device-internal.h>
  11#include <dm/device_compat.h>
  12#include <dm/lists.h>
  13#include <dm/pinctrl.h>
  14#include <fdt_support.h>
  15#include <linux/bitops.h>
  16#include <linux/err.h>
  17#include <linux/io.h>
  18#include <linux/libfdt.h>
  19#include <linux/sizes.h>
  20#include <asm/gpio.h>
  21
  22#include "pinctrl-meson.h"
  23
  24DECLARE_GLOBAL_DATA_PTR;
  25
  26static const char *meson_pinctrl_dummy_name = "_dummy";
  27
  28static char pin_name[PINNAME_SIZE];
  29
  30int meson_pinctrl_get_groups_count(struct udevice *dev)
  31{
  32        struct meson_pinctrl *priv = dev_get_priv(dev);
  33
  34        return priv->data->num_groups;
  35}
  36
  37const char *meson_pinctrl_get_group_name(struct udevice *dev,
  38                                         unsigned int selector)
  39{
  40        struct meson_pinctrl *priv = dev_get_priv(dev);
  41
  42        if (!priv->data->groups[selector].name)
  43                return meson_pinctrl_dummy_name;
  44
  45        return priv->data->groups[selector].name;
  46}
  47
  48int meson_pinctrl_get_pins_count(struct udevice *dev)
  49{
  50        struct meson_pinctrl *priv = dev_get_priv(dev);
  51
  52        return priv->data->num_pins;
  53}
  54
  55const char *meson_pinctrl_get_pin_name(struct udevice *dev,
  56                                       unsigned int selector)
  57{
  58        struct meson_pinctrl *priv = dev_get_priv(dev);
  59
  60        if (selector > priv->data->num_pins ||
  61            selector > priv->data->funcs[0].num_groups)
  62                snprintf(pin_name, PINNAME_SIZE, "Error");
  63        else
  64                snprintf(pin_name, PINNAME_SIZE, "%s",
  65                         priv->data->funcs[0].groups[selector]);
  66
  67        return pin_name;
  68}
  69
  70int meson_pinmux_get_functions_count(struct udevice *dev)
  71{
  72        struct meson_pinctrl *priv = dev_get_priv(dev);
  73
  74        return priv->data->num_funcs;
  75}
  76
  77const char *meson_pinmux_get_function_name(struct udevice *dev,
  78                                           unsigned int selector)
  79{
  80        struct meson_pinctrl *priv = dev_get_priv(dev);
  81
  82        return priv->data->funcs[selector].name;
  83}
  84
  85static int meson_gpio_calc_reg_and_bit(struct udevice *dev, unsigned int offset,
  86                                       enum meson_reg_type reg_type,
  87                                       unsigned int *reg, unsigned int *bit)
  88{
  89        struct meson_pinctrl *priv = dev_get_priv(dev);
  90        struct meson_bank *bank = NULL;
  91        struct meson_reg_desc *desc;
  92        unsigned int pin;
  93        int i;
  94
  95        pin = priv->data->pin_base + offset;
  96
  97        for (i = 0; i < priv->data->num_banks; i++) {
  98                if (pin >= priv->data->banks[i].first &&
  99                    pin <= priv->data->banks[i].last) {
 100                        bank = &priv->data->banks[i];
 101                        break;
 102                }
 103        }
 104
 105        if (!bank)
 106                return -EINVAL;
 107
 108        desc = &bank->regs[reg_type];
 109        *reg = desc->reg * 4;
 110        *bit = desc->bit + pin - bank->first;
 111
 112        return 0;
 113}
 114
 115int meson_gpio_get(struct udevice *dev, unsigned int offset)
 116{
 117        struct meson_pinctrl *priv = dev_get_priv(dev->parent);
 118        unsigned int reg, bit;
 119        int ret;
 120
 121        ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_IN, &reg,
 122                                          &bit);
 123        if (ret)
 124                return ret;
 125
 126        return !!(readl(priv->reg_gpio + reg) & BIT(bit));
 127}
 128
 129int meson_gpio_set(struct udevice *dev, unsigned int offset, int value)
 130{
 131        struct meson_pinctrl *priv = dev_get_priv(dev->parent);
 132        unsigned int reg, bit;
 133        int ret;
 134
 135        ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_OUT, &reg,
 136                                          &bit);
 137        if (ret)
 138                return ret;
 139
 140        clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0);
 141
 142        return 0;
 143}
 144
 145int meson_gpio_get_direction(struct udevice *dev, unsigned int offset)
 146{
 147        struct meson_pinctrl *priv = dev_get_priv(dev->parent);
 148        unsigned int reg, bit, val;
 149        int ret;
 150
 151        ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, &reg,
 152                                          &bit);
 153        if (ret)
 154                return ret;
 155
 156        val = readl(priv->reg_gpio + reg);
 157
 158        return (val & BIT(bit)) ? GPIOF_INPUT : GPIOF_OUTPUT;
 159}
 160
 161int meson_gpio_direction_input(struct udevice *dev, unsigned int offset)
 162{
 163        struct meson_pinctrl *priv = dev_get_priv(dev->parent);
 164        unsigned int reg, bit;
 165        int ret;
 166
 167        ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, &reg,
 168                                          &bit);
 169        if (ret)
 170                return ret;
 171
 172        setbits_le32(priv->reg_gpio + reg, BIT(bit));
 173
 174        return 0;
 175}
 176
 177int meson_gpio_direction_output(struct udevice *dev,
 178                                unsigned int offset, int value)
 179{
 180        struct meson_pinctrl *priv = dev_get_priv(dev->parent);
 181        unsigned int reg, bit;
 182        int ret;
 183
 184        ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, &reg,
 185                                          &bit);
 186        if (ret)
 187                return ret;
 188
 189        clrbits_le32(priv->reg_gpio + reg, BIT(bit));
 190
 191        ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_OUT, &reg,
 192                                          &bit);
 193        if (ret)
 194                return ret;
 195
 196        clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0);
 197
 198        return 0;
 199}
 200
 201static int meson_pinconf_bias_set(struct udevice *dev, unsigned int pin,
 202                                  unsigned int param)
 203{
 204        struct meson_pinctrl *priv = dev_get_priv(dev);
 205        unsigned int offset = pin - priv->data->pin_base;
 206        unsigned int reg, bit;
 207        int ret;
 208
 209        ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_PULLEN, &reg, &bit);
 210        if (ret)
 211                return ret;
 212
 213        if (param == PIN_CONFIG_BIAS_DISABLE) {
 214                clrsetbits_le32(priv->reg_pullen + reg, BIT(bit), 0);
 215                return 0;
 216        }
 217
 218        /* othewise, enable the bias and select level */
 219        clrsetbits_le32(priv->reg_pullen + reg, BIT(bit), BIT(bit));
 220        ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_PULL, &reg, &bit);
 221        if (ret)
 222                return ret;
 223
 224        clrsetbits_le32(priv->reg_pull + reg, BIT(bit),
 225                        (param == PIN_CONFIG_BIAS_PULL_UP ? BIT(bit) : 0));
 226
 227        return 0;
 228}
 229
 230static int meson_pinconf_drive_strength_set(struct udevice *dev,
 231                                            unsigned int pin,
 232                                            unsigned int drive_strength_ua)
 233{
 234        struct meson_pinctrl *priv = dev_get_priv(dev);
 235        unsigned int offset = pin - priv->data->pin_base;
 236        unsigned int reg, bit;
 237        unsigned int ds_val;
 238        int ret;
 239
 240        if (!priv->reg_ds) {
 241                dev_err(dev, "drive-strength-microamp not supported\n");
 242                return -ENOTSUPP;
 243        }
 244
 245        ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DS, &reg, &bit);
 246        if (ret)
 247                return ret;
 248
 249        bit = bit << 1;
 250
 251        if (drive_strength_ua <= 500) {
 252                ds_val = MESON_PINCONF_DRV_500UA;
 253        } else if (drive_strength_ua <= 2500) {
 254                ds_val = MESON_PINCONF_DRV_2500UA;
 255        } else if (drive_strength_ua <= 3000) {
 256                ds_val = MESON_PINCONF_DRV_3000UA;
 257        } else if (drive_strength_ua <= 4000) {
 258                ds_val = MESON_PINCONF_DRV_4000UA;
 259        } else {
 260                dev_warn(dev,
 261                         "pin %u: invalid drive-strength-microamp : %d , default to 4mA\n",
 262                         pin, drive_strength_ua);
 263                ds_val = MESON_PINCONF_DRV_4000UA;
 264        }
 265
 266        clrsetbits_le32(priv->reg_ds + reg, 0x3 << bit, ds_val << bit);
 267
 268        return 0;
 269}
 270
 271int meson_pinconf_set(struct udevice *dev, unsigned int pin,
 272                      unsigned int param, unsigned int arg)
 273{
 274        int ret;
 275
 276        switch (param) {
 277        case PIN_CONFIG_BIAS_DISABLE:
 278        case PIN_CONFIG_BIAS_PULL_UP:
 279        case PIN_CONFIG_BIAS_PULL_DOWN:
 280                ret = meson_pinconf_bias_set(dev, pin, param);
 281                break;
 282        case PIN_CONFIG_DRIVE_STRENGTH_UA:
 283                ret = meson_pinconf_drive_strength_set(dev, pin, arg);
 284                break;
 285        default:
 286                dev_err(dev, "unsupported configuration parameter %u\n", param);
 287                return -EINVAL;
 288        }
 289
 290        return ret;
 291}
 292
 293int meson_pinconf_group_set(struct udevice *dev,
 294                            unsigned int group_selector,
 295                            unsigned int param, unsigned int arg)
 296{
 297        struct meson_pinctrl *priv = dev_get_priv(dev);
 298        struct meson_pmx_group *grp = &priv->data->groups[group_selector];
 299        int i, ret;
 300
 301        for (i = 0; i < grp->num_pins; i++) {
 302                ret = meson_pinconf_set(dev, grp->pins[i], param, arg);
 303                if (ret)
 304                        return ret;
 305        }
 306
 307        return 0;
 308}
 309
 310int meson_gpio_probe(struct udevice *dev)
 311{
 312        struct meson_pinctrl *priv = dev_get_priv(dev->parent);
 313        struct gpio_dev_priv *uc_priv;
 314
 315        uc_priv = dev_get_uclass_priv(dev);
 316        uc_priv->bank_name = priv->data->name;
 317        uc_priv->gpio_count = priv->data->num_pins;
 318
 319        return 0;
 320}
 321
 322static fdt_addr_t parse_address(int offset, const char *name, int na, int ns)
 323{
 324        int index, len = 0;
 325        const fdt32_t *reg;
 326
 327        index = fdt_stringlist_search(gd->fdt_blob, offset, "reg-names", name);
 328        if (index < 0)
 329                return FDT_ADDR_T_NONE;
 330
 331        reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
 332        if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns))))
 333                return FDT_ADDR_T_NONE;
 334
 335        reg += index * (na + ns);
 336
 337        return fdt_translate_address((void *)gd->fdt_blob, offset, reg);
 338}
 339
 340int meson_pinctrl_probe(struct udevice *dev)
 341{
 342        struct meson_pinctrl *priv = dev_get_priv(dev);
 343        struct uclass_driver *drv;
 344        struct udevice *gpio_dev;
 345        fdt_addr_t addr;
 346        int node, gpio = -1, len;
 347        int na, ns;
 348        char *name;
 349
 350        na = fdt_address_cells(gd->fdt_blob, dev_of_offset(dev->parent));
 351        if (na < 1) {
 352                debug("bad #address-cells\n");
 353                return -EINVAL;
 354        }
 355
 356        ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent));
 357        if (ns < 1) {
 358                debug("bad #size-cells\n");
 359                return -EINVAL;
 360        }
 361
 362        fdt_for_each_subnode(node, gd->fdt_blob, dev_of_offset(dev)) {
 363                if (fdt_getprop(gd->fdt_blob, node, "gpio-controller", &len)) {
 364                        gpio = node;
 365                        break;
 366                }
 367        }
 368
 369        if (!gpio) {
 370                debug("gpio node not found\n");
 371                return -EINVAL;
 372        }
 373
 374        addr = parse_address(gpio, "mux", na, ns);
 375        if (addr == FDT_ADDR_T_NONE) {
 376                debug("mux address not found\n");
 377                return -EINVAL;
 378        }
 379        priv->reg_mux = (void __iomem *)addr;
 380
 381        addr = parse_address(gpio, "gpio", na, ns);
 382        if (addr == FDT_ADDR_T_NONE) {
 383                debug("gpio address not found\n");
 384                return -EINVAL;
 385        }
 386        priv->reg_gpio = (void __iomem *)addr;
 387
 388        addr = parse_address(gpio, "pull", na, ns);
 389        /* Use gpio region if pull one is not present */
 390        if (addr == FDT_ADDR_T_NONE)
 391                priv->reg_pull = priv->reg_gpio;
 392        else
 393                priv->reg_pull = (void __iomem *)addr;
 394
 395        addr = parse_address(gpio, "pull-enable", na, ns);
 396        /* Use pull region if pull-enable one is not present */
 397        if (addr == FDT_ADDR_T_NONE)
 398                priv->reg_pullen = priv->reg_pull;
 399        else
 400                priv->reg_pullen = (void __iomem *)addr;
 401
 402        addr = parse_address(gpio, "ds", na, ns);
 403        /* Drive strength region is optional */
 404        if (addr == FDT_ADDR_T_NONE)
 405                priv->reg_ds = NULL;
 406        else
 407                priv->reg_ds = (void __iomem *)addr;
 408
 409        priv->data = (struct meson_pinctrl_data *)dev_get_driver_data(dev);
 410
 411        /* Lookup GPIO driver */
 412        drv = lists_uclass_lookup(UCLASS_GPIO);
 413        if (!drv) {
 414                puts("Cannot find GPIO driver\n");
 415                return -ENOENT;
 416        }
 417
 418        name = calloc(1, 32);
 419        sprintf(name, "meson-gpio");
 420
 421        /* Create child device UCLASS_GPIO and bind it */
 422        device_bind(dev, priv->data->gpio_driver, name, NULL, gpio, &gpio_dev);
 423        dev_set_of_offset(gpio_dev, gpio);
 424
 425        return 0;
 426}
 427