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