uboot/drivers/pinctrl/pinctrl-stmfx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
   4 *
   5 * Driver for STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander
   6 * based on Linux driver : pinctrl/pinctrl-stmfx.c
   7 */
   8#include <common.h>
   9#include <dm.h>
  10#include <i2c.h>
  11#include <asm/gpio.h>
  12#include <dm/device.h>
  13#include <dm/device-internal.h>
  14#include <dm/device_compat.h>
  15#include <dm/lists.h>
  16#include <dm/pinctrl.h>
  17#include <linux/bitfield.h>
  18#include <linux/bitops.h>
  19#include <linux/delay.h>
  20#include <power/regulator.h>
  21
  22/* STMFX pins = GPIO[15:0] + aGPIO[7:0] */
  23#define STMFX_MAX_GPIO                  16
  24#define STMFX_MAX_AGPIO                 8
  25
  26/* General */
  27#define STMFX_REG_CHIP_ID               0x00 /* R */
  28#define STMFX_REG_FW_VERSION_MSB        0x01 /* R */
  29#define STMFX_REG_FW_VERSION_LSB        0x02 /* R */
  30#define STMFX_REG_SYS_CTRL              0x40 /* RW */
  31
  32/* MFX boot time is around 10ms, so after reset, we have to wait this delay */
  33#define STMFX_BOOT_TIME_MS 10
  34
  35/* GPIOs expander */
  36/* GPIO_STATE1 0x10, GPIO_STATE2 0x11, GPIO_STATE3 0x12 */
  37#define STMFX_REG_GPIO_STATE            0x10 /* R */
  38/* GPIO_DIR1 0x60, GPIO_DIR2 0x61, GPIO_DIR3 0x63 */
  39#define STMFX_REG_GPIO_DIR              0x60 /* RW */
  40/* GPIO_TYPE1 0x64, GPIO_TYPE2 0x65, GPIO_TYPE3 0x66 */
  41#define STMFX_REG_GPIO_TYPE             0x64 /* RW */
  42/* GPIO_PUPD1 0x68, GPIO_PUPD2 0x69, GPIO_PUPD3 0x6A */
  43#define STMFX_REG_GPIO_PUPD             0x68 /* RW */
  44/* GPO_SET1 0x6C, GPO_SET2 0x6D, GPO_SET3 0x6E */
  45#define STMFX_REG_GPO_SET               0x6C /* RW */
  46/* GPO_CLR1 0x70, GPO_CLR2 0x71, GPO_CLR3 0x72 */
  47#define STMFX_REG_GPO_CLR               0x70 /* RW */
  48
  49/* STMFX_REG_CHIP_ID bitfields */
  50#define STMFX_REG_CHIP_ID_MASK          GENMASK(7, 0)
  51
  52/* STMFX_REG_SYS_CTRL bitfields */
  53#define STMFX_REG_SYS_CTRL_GPIO_EN      BIT(0)
  54#define STMFX_REG_SYS_CTRL_ALTGPIO_EN   BIT(3)
  55#define STMFX_REG_SYS_CTRL_SWRST        BIT(7)
  56
  57#define NR_GPIO_REGS                    3
  58#define NR_GPIOS_PER_REG                8
  59#define get_reg(offset)                 ((offset) / NR_GPIOS_PER_REG)
  60#define get_shift(offset)               ((offset) % NR_GPIOS_PER_REG)
  61#define get_mask(offset)                (BIT(get_shift(offset)))
  62
  63struct stmfx_pinctrl {
  64        struct udevice *gpio;
  65};
  66
  67static int stmfx_read(struct udevice *dev, uint offset)
  68{
  69        return  dm_i2c_reg_read(dev_get_parent(dev), offset);
  70}
  71
  72static int stmfx_write(struct udevice *dev, uint offset, unsigned int val)
  73{
  74        return dm_i2c_reg_write(dev_get_parent(dev), offset, val);
  75}
  76
  77static int stmfx_read_reg(struct udevice *dev, u8 reg_base, uint offset)
  78{
  79        u8 reg = reg_base + get_reg(offset);
  80        u32 mask = get_mask(offset);
  81        int ret;
  82
  83        ret = stmfx_read(dev, reg);
  84        if (ret < 0)
  85                return ret;
  86
  87        return ret < 0 ? ret : !!(ret & mask);
  88}
  89
  90static int stmfx_write_reg(struct udevice *dev, u8 reg_base, uint offset,
  91                           uint val)
  92{
  93        u8 reg = reg_base + get_reg(offset);
  94        u32 mask = get_mask(offset);
  95        int ret;
  96
  97        ret = stmfx_read(dev, reg);
  98        if (ret < 0)
  99                return ret;
 100        ret = (ret & ~mask) | (val ? mask : 0);
 101
 102        return stmfx_write(dev, reg, ret);
 103}
 104
 105static int stmfx_conf_set_pupd(struct udevice *dev, unsigned int offset,
 106                               uint pupd)
 107{
 108        return stmfx_write_reg(dev, STMFX_REG_GPIO_PUPD, offset, pupd);
 109}
 110
 111static int stmfx_conf_get_pupd(struct udevice *dev, unsigned int offset)
 112{
 113        return stmfx_read_reg(dev, STMFX_REG_GPIO_PUPD, offset);
 114}
 115
 116static int stmfx_conf_set_type(struct udevice *dev, unsigned int offset,
 117                               uint type)
 118{
 119        return stmfx_write_reg(dev, STMFX_REG_GPIO_TYPE, offset, type);
 120}
 121
 122static int stmfx_conf_get_type(struct udevice *dev, unsigned int offset)
 123{
 124        return stmfx_read_reg(dev, STMFX_REG_GPIO_TYPE, offset);
 125}
 126
 127static int stmfx_gpio_get(struct udevice *dev, unsigned int offset)
 128{
 129        return stmfx_read_reg(dev, STMFX_REG_GPIO_STATE, offset);
 130}
 131
 132static int stmfx_gpio_set(struct udevice *dev, unsigned int offset, int value)
 133{
 134        u32 reg = value ? STMFX_REG_GPO_SET : STMFX_REG_GPO_CLR;
 135        u32 mask = get_mask(offset);
 136
 137        return stmfx_write(dev, reg + get_reg(offset), mask);
 138}
 139
 140static int stmfx_gpio_get_function(struct udevice *dev, unsigned int offset)
 141{
 142        int ret = stmfx_read_reg(dev, STMFX_REG_GPIO_DIR, offset);
 143
 144        if (ret < 0)
 145                return ret;
 146        /* On stmfx, gpio pins direction is (0)input, (1)output. */
 147
 148        return ret ? GPIOF_OUTPUT : GPIOF_INPUT;
 149}
 150
 151static int stmfx_gpio_direction_input(struct udevice *dev, unsigned int offset)
 152{
 153        return stmfx_write_reg(dev, STMFX_REG_GPIO_DIR, offset, 0);
 154}
 155
 156static int stmfx_gpio_direction_output(struct udevice *dev,
 157                                       unsigned int offset, int value)
 158{
 159        int ret = stmfx_gpio_set(dev, offset, value);
 160        if (ret < 0)
 161                return ret;
 162
 163        return stmfx_write_reg(dev, STMFX_REG_GPIO_DIR, offset, 1);
 164}
 165
 166static int stmfx_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
 167                                    ulong flags)
 168{
 169        int ret = -ENOTSUPP;
 170
 171        if (flags & GPIOD_IS_OUT) {
 172                if (flags & GPIOD_OPEN_SOURCE)
 173                        return -ENOTSUPP;
 174                if (flags & GPIOD_OPEN_DRAIN)
 175                        ret = stmfx_conf_set_type(dev, offset, 0);
 176                else /* PUSH-PULL */
 177                        ret = stmfx_conf_set_type(dev, offset, 1);
 178                if (ret)
 179                        return ret;
 180                ret = stmfx_gpio_direction_output(dev, offset,
 181                                                  GPIOD_FLAGS_OUTPUT(flags));
 182        } else if (flags & GPIOD_IS_IN) {
 183                ret = stmfx_gpio_direction_input(dev, offset);
 184                if (ret)
 185                        return ret;
 186                if (flags & GPIOD_PULL_UP) {
 187                        ret = stmfx_conf_set_type(dev, offset, 1);
 188                        if (ret)
 189                                return ret;
 190                        ret = stmfx_conf_set_pupd(dev, offset, 1);
 191                } else if (flags & GPIOD_PULL_DOWN) {
 192                        ret = stmfx_conf_set_type(dev, offset, 1);
 193                        if (ret)
 194                                return ret;
 195                        ret = stmfx_conf_set_pupd(dev, offset, 0);
 196                }
 197        }
 198
 199        return ret;
 200}
 201
 202static int stmfx_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
 203                                    ulong *flags)
 204{
 205        ulong dir_flags = 0;
 206        int ret;
 207
 208        if (stmfx_gpio_get_function(dev, offset) == GPIOF_OUTPUT) {
 209                dir_flags |= GPIOD_IS_OUT;
 210                ret = stmfx_conf_get_type(dev, offset);
 211                if (ret < 0)
 212                        return ret;
 213                if (ret == 0)
 214                        dir_flags |= GPIOD_OPEN_DRAIN;
 215                        /* 1 = push-pull (default), open source not supported */
 216                ret = stmfx_gpio_get(dev, offset);
 217                if (ret < 0)
 218                        return ret;
 219                if (ret)
 220                        dir_flags |= GPIOD_IS_OUT_ACTIVE;
 221        } else {
 222                dir_flags |= GPIOD_IS_IN;
 223                ret = stmfx_conf_get_type(dev, offset);
 224                if (ret < 0)
 225                        return ret;
 226                if (ret == 1) {
 227                        ret = stmfx_conf_get_pupd(dev, offset);
 228                        if (ret < 0)
 229                                return ret;
 230                        if (ret == 1)
 231                                dir_flags |= GPIOD_PULL_UP;
 232                        else
 233                                dir_flags |= GPIOD_PULL_DOWN;
 234                }
 235        }
 236        *flags = dir_flags;
 237
 238        return 0;
 239}
 240
 241static int stmfx_gpio_probe(struct udevice *dev)
 242{
 243        struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 244        struct ofnode_phandle_args args;
 245        u8 sys_ctrl;
 246
 247        uc_priv->bank_name = "stmfx";
 248        uc_priv->gpio_count = STMFX_MAX_GPIO + STMFX_MAX_AGPIO;
 249        if (!dev_read_phandle_with_args(dev, "gpio-ranges",
 250                                        NULL, 3, 0, &args)) {
 251                uc_priv->gpio_count = args.args[2];
 252        }
 253
 254        /* enable GPIO function */
 255        sys_ctrl = STMFX_REG_SYS_CTRL_GPIO_EN;
 256        if (uc_priv->gpio_count > STMFX_MAX_GPIO)
 257                sys_ctrl |= STMFX_REG_SYS_CTRL_ALTGPIO_EN;
 258        stmfx_write(dev, STMFX_REG_SYS_CTRL, sys_ctrl);
 259
 260        return 0;
 261}
 262
 263static const struct dm_gpio_ops stmfx_gpio_ops = {
 264        .set_value = stmfx_gpio_set,
 265        .get_value = stmfx_gpio_get,
 266        .get_function = stmfx_gpio_get_function,
 267        .direction_input = stmfx_gpio_direction_input,
 268        .direction_output = stmfx_gpio_direction_output,
 269        .set_dir_flags = stmfx_gpio_set_dir_flags,
 270        .get_dir_flags = stmfx_gpio_get_dir_flags,
 271};
 272
 273U_BOOT_DRIVER(stmfx_gpio) = {
 274        .name   = "stmfx-gpio",
 275        .id     = UCLASS_GPIO,
 276        .probe  = stmfx_gpio_probe,
 277        .ops    = &stmfx_gpio_ops,
 278};
 279
 280#if CONFIG_IS_ENABLED(PINCONF)
 281static const struct pinconf_param stmfx_pinctrl_conf_params[] = {
 282        { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
 283        { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 0 },
 284        { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 0 },
 285        { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 0 },
 286        { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
 287        { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
 288        { "output-high", PIN_CONFIG_OUTPUT, 1 },
 289        { "output-low", PIN_CONFIG_OUTPUT, 0 },
 290};
 291
 292static int stmfx_pinctrl_conf_set(struct udevice *dev, unsigned int pin,
 293                                  unsigned int param, unsigned int arg)
 294{
 295        int ret, dir;
 296        struct stmfx_pinctrl *plat = dev_get_platdata(dev);
 297
 298        dir = stmfx_gpio_get_function(plat->gpio, pin);
 299
 300        if (dir < 0)
 301                return dir;
 302
 303        switch (param) {
 304        case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
 305        case PIN_CONFIG_BIAS_DISABLE:
 306        case PIN_CONFIG_DRIVE_PUSH_PULL:
 307                ret = stmfx_conf_set_type(dev, pin, 0);
 308                break;
 309        case PIN_CONFIG_BIAS_PULL_DOWN:
 310                ret = stmfx_conf_set_type(dev, pin, 1);
 311                if (ret)
 312                        return ret;
 313                ret = stmfx_conf_set_pupd(dev, pin, 0);
 314                break;
 315        case PIN_CONFIG_BIAS_PULL_UP:
 316                ret = stmfx_conf_set_type(dev, pin, 1);
 317                if (ret)
 318                        return ret;
 319                ret = stmfx_conf_set_pupd(dev, pin, 1);
 320                break;
 321        case PIN_CONFIG_DRIVE_OPEN_DRAIN:
 322                ret = stmfx_conf_set_type(dev, pin, 1);
 323                break;
 324        case PIN_CONFIG_OUTPUT:
 325                ret = stmfx_gpio_direction_output(plat->gpio, pin, arg);
 326                break;
 327        default:
 328                return -ENOTSUPP;
 329        }
 330
 331        return ret;
 332}
 333#endif
 334
 335static int stmfx_pinctrl_get_pins_count(struct udevice *dev)
 336{
 337        struct stmfx_pinctrl *plat = dev_get_platdata(dev);
 338        struct gpio_dev_priv *uc_priv;
 339
 340        uc_priv = dev_get_uclass_priv(plat->gpio);
 341
 342        return uc_priv->gpio_count;
 343}
 344
 345/*
 346 * STMFX pins[15:0] are called "stmfx_gpio[15:0]"
 347 * and STMFX pins[23:16] are called "stmfx_agpio[7:0]"
 348 */
 349#define MAX_PIN_NAME_LEN 7
 350static char pin_name[MAX_PIN_NAME_LEN];
 351static const char *stmfx_pinctrl_get_pin_name(struct udevice *dev,
 352                                              unsigned int selector)
 353{
 354        if (selector < STMFX_MAX_GPIO)
 355                snprintf(pin_name, MAX_PIN_NAME_LEN, "stmfx_gpio%u", selector);
 356        else
 357                snprintf(pin_name, MAX_PIN_NAME_LEN, "stmfx_agpio%u", selector - 16);
 358        return pin_name;
 359}
 360
 361static const char *stmfx_pinctrl_get_pin_conf(struct udevice *dev,
 362                                              unsigned int pin, int func)
 363{
 364        int pupd, type;
 365
 366        type = stmfx_conf_get_type(dev, pin);
 367        if (type < 0)
 368                return "";
 369
 370        if (func == GPIOF_OUTPUT) {
 371                if (type)
 372                        return "drive-open-drain";
 373                else
 374                        return ""; /* default: push-pull*/
 375        }
 376        if (!type)
 377                return ""; /* default: bias-disable*/
 378
 379        pupd = stmfx_conf_get_pupd(dev, pin);
 380        if (pupd < 0)
 381                return "";
 382
 383        if (pupd)
 384                return "bias-pull-up";
 385        else
 386                return "bias-pull-down";
 387}
 388
 389static int stmfx_pinctrl_get_pin_muxing(struct udevice *dev,
 390                                        unsigned int selector,
 391                                        char *buf, int size)
 392{
 393        struct stmfx_pinctrl *plat = dev_get_platdata(dev);
 394        int func;
 395
 396        func = stmfx_gpio_get_function(plat->gpio, selector);
 397        if (func < 0)
 398                return func;
 399
 400        snprintf(buf, size, "%s ", func == GPIOF_INPUT ? "input" : "output");
 401
 402        strncat(buf, stmfx_pinctrl_get_pin_conf(dev, selector, func), size);
 403
 404        return 0;
 405}
 406
 407static int stmfx_pinctrl_bind(struct udevice *dev)
 408{
 409        struct stmfx_pinctrl *plat = dev_get_platdata(dev);
 410
 411        /* subnode name is not explicit: use father name */
 412        device_set_name(dev, dev->parent->name);
 413
 414        return device_bind_driver_to_node(dev->parent,
 415                                          "stmfx-gpio", dev->parent->name,
 416                                          dev_ofnode(dev), &plat->gpio);
 417};
 418
 419static int stmfx_pinctrl_probe(struct udevice *dev)
 420{
 421        struct stmfx_pinctrl *plat = dev_get_platdata(dev);
 422
 423        return device_probe(plat->gpio);
 424};
 425
 426const struct pinctrl_ops stmfx_pinctrl_ops = {
 427        .get_pins_count = stmfx_pinctrl_get_pins_count,
 428        .get_pin_name = stmfx_pinctrl_get_pin_name,
 429        .set_state = pinctrl_generic_set_state,
 430        .get_pin_muxing = stmfx_pinctrl_get_pin_muxing,
 431#if CONFIG_IS_ENABLED(PINCONF)
 432        .pinconf_set = stmfx_pinctrl_conf_set,
 433        .pinconf_num_params = ARRAY_SIZE(stmfx_pinctrl_conf_params),
 434        .pinconf_params = stmfx_pinctrl_conf_params,
 435#endif
 436};
 437
 438static const struct udevice_id stmfx_pinctrl_match[] = {
 439        { .compatible = "st,stmfx-0300-pinctrl", },
 440};
 441
 442U_BOOT_DRIVER(stmfx_pinctrl) = {
 443        .name = "stmfx-pinctrl",
 444        .id = UCLASS_PINCTRL,
 445        .of_match = of_match_ptr(stmfx_pinctrl_match),
 446        .bind = stmfx_pinctrl_bind,
 447        .probe = stmfx_pinctrl_probe,
 448        .ops = &stmfx_pinctrl_ops,
 449        .platdata_auto_alloc_size = sizeof(struct stmfx_pinctrl),
 450};
 451
 452static int stmfx_chip_init(struct udevice *dev)
 453{
 454        u8 id;
 455        u8 version[2];
 456        int ret;
 457        struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
 458
 459        ret = dm_i2c_reg_read(dev, STMFX_REG_CHIP_ID);
 460        if (ret < 0) {
 461                dev_err(dev, "error reading chip id: %d\n", ret);
 462                return ret;
 463        }
 464        id = (u8)ret;
 465        /*
 466         * Check that ID is the complement of the I2C address:
 467         * STMFX I2C address follows the 7-bit format (MSB), that's why
 468         * client->addr is shifted.
 469         *
 470         * STMFX_I2C_ADDR|       STMFX         |        Linux
 471         *   input pin   | I2C device address  | I2C device address
 472         *---------------------------------------------------------
 473         *       0       | b: 1000 010x h:0x84 |       0x42
 474         *       1       | b: 1000 011x h:0x86 |       0x43
 475         */
 476        if (FIELD_GET(STMFX_REG_CHIP_ID_MASK, ~id) != (chip->chip_addr << 1)) {
 477                dev_err(dev, "unknown chip id: %#x\n", id);
 478                return -EINVAL;
 479        }
 480
 481        ret = dm_i2c_read(dev, STMFX_REG_FW_VERSION_MSB,
 482                          version, sizeof(version));
 483        if (ret) {
 484                dev_err(dev, "error reading fw version: %d\n", ret);
 485                return ret;
 486        }
 487
 488        dev_info(dev, "STMFX id: %#x, fw version: %x.%02x\n",
 489                 id, version[0], version[1]);
 490
 491        ret = dm_i2c_reg_read(dev, STMFX_REG_SYS_CTRL);
 492
 493        if (ret < 0)
 494                return ret;
 495
 496        ret = dm_i2c_reg_write(dev, STMFX_REG_SYS_CTRL,
 497                               ret | STMFX_REG_SYS_CTRL_SWRST);
 498        if (ret)
 499                return ret;
 500
 501        mdelay(STMFX_BOOT_TIME_MS);
 502
 503        return ret;
 504}
 505
 506static int stmfx_probe(struct udevice *dev)
 507{
 508        struct udevice *vdd;
 509        int ret;
 510
 511        ret = device_get_supply_regulator(dev, "vdd-supply", &vdd);
 512        if (ret && ret != -ENOENT) {
 513                dev_err(dev, "vdd regulator error:%d\n", ret);
 514                return ret;
 515        }
 516        if (!ret) {
 517                ret = regulator_set_enable(vdd, true);
 518                if (ret) {
 519                        dev_err(dev, "vdd enable failed: %d\n", ret);
 520                        return ret;
 521                }
 522        }
 523
 524        return stmfx_chip_init(dev);
 525}
 526
 527static const struct udevice_id stmfx_match[] = {
 528        { .compatible = "st,stmfx-0300", },
 529};
 530
 531U_BOOT_DRIVER(stmfx) = {
 532        .name = "stmfx",
 533        .id = UCLASS_I2C_GENERIC,
 534        .of_match = of_match_ptr(stmfx_match),
 535        .probe = stmfx_probe,
 536        .bind = dm_scan_fdt_dev,
 537};
 538