uboot/drivers/gpio/pca953x_gpio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Take linux kernel driver drivers/gpio/gpio-pca953x.c for reference.
   4 *
   5 * Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
   6 *
   7 */
   8
   9/*
  10 * Note:
  11 * The driver's compatible table is borrowed from Linux Kernel,
  12 * but now max supported gpio pins is 24 and only PCA953X_TYPE
  13 * is supported. PCA957X_TYPE is not supported now.
  14 * Also the Polarity Inversion feature is not supported now.
  15 *
  16 * TODO:
  17 * 1. Support PCA957X_TYPE
  18 * 2. Support Polarity Inversion
  19 */
  20
  21#include <common.h>
  22#include <errno.h>
  23#include <dm.h>
  24#include <fdtdec.h>
  25#include <i2c.h>
  26#include <malloc.h>
  27#include <asm/gpio.h>
  28#include <asm/io.h>
  29#include <dm/device_compat.h>
  30#include <dt-bindings/gpio/gpio.h>
  31#include <linux/bitops.h>
  32
  33#define PCA953X_INPUT           0
  34#define PCA953X_OUTPUT          1
  35#define PCA953X_INVERT          2
  36#define PCA953X_DIRECTION       3
  37
  38#define PCA957X_INPUT           0
  39#define PCA957X_OUTPUT          5
  40#define PCA957X_INVERT          1
  41#define PCA957X_DIRECTION       4
  42
  43
  44#define PCA_GPIO_MASK           0x00FF
  45#define PCA_INT                 0x0100
  46#define PCA_PCAL                BIT(9)
  47#define PCA_LATCH_INT           (PCA_PCAL | PCA_INT)
  48#define PCA953X_TYPE            0x1000
  49#define PCA957X_TYPE            0x2000
  50#define PCA_TYPE_MASK           0xF000
  51#define PCA_CHIP_TYPE(x)        ((x) & PCA_TYPE_MASK)
  52
  53enum {
  54        PCA953X_DIRECTION_IN,
  55        PCA953X_DIRECTION_OUT,
  56};
  57
  58#define MAX_BANK 5
  59#define BANK_SZ 8
  60
  61struct pca95xx_reg {
  62        int input;
  63        int output;
  64        int invert;
  65        int direction;
  66};
  67
  68static const struct pca95xx_reg pca953x_regs = {
  69        .direction = PCA953X_DIRECTION,
  70        .output = PCA953X_OUTPUT,
  71        .input = PCA953X_INPUT,
  72        .invert = PCA953X_INVERT,
  73};
  74
  75static const struct pca95xx_reg pca957x_regs = {
  76        .direction = PCA957X_DIRECTION,
  77        .output = PCA957X_OUTPUT,
  78        .input = PCA957X_INPUT,
  79        .invert = PCA957X_INVERT,
  80};
  81
  82/*
  83 * struct pca953x_info - Data for pca953x/pca957x
  84 *
  85 * @dev: udevice structure for the device
  86 * @addr: i2c slave address
  87 * @invert: Polarity inversion or not
  88 * @gpio_count: the number of gpio pins that the device supports
  89 * @chip_type: indicate the chip type,PCA953X or PCA957X
  90 * @bank_count: the number of banks that the device supports
  91 * @reg_output: array to hold the value of output registers
  92 * @reg_direction: array to hold the value of direction registers
  93 * @regs: struct to hold the registers addresses
  94 */
  95struct pca953x_info {
  96        struct udevice *dev;
  97        int addr;
  98        int invert;
  99        int gpio_count;
 100        int chip_type;
 101        int bank_count;
 102        u8 reg_output[MAX_BANK];
 103        u8 reg_direction[MAX_BANK];
 104        const struct pca95xx_reg *regs;
 105};
 106
 107static int pca953x_write_single(struct udevice *dev, int reg, u8 val,
 108                                int offset)
 109{
 110        struct pca953x_info *info = dev_get_plat(dev);
 111        int bank_shift = fls((info->gpio_count - 1) / BANK_SZ);
 112        int off = offset / BANK_SZ;
 113        int ret = 0;
 114
 115        ret = dm_i2c_write(dev, (reg << bank_shift) + off, &val, 1);
 116        if (ret) {
 117                dev_err(dev, "%s error\n", __func__);
 118                return ret;
 119        }
 120
 121        return 0;
 122}
 123
 124static int pca953x_read_single(struct udevice *dev, int reg, u8 *val,
 125                               int offset)
 126{
 127        struct pca953x_info *info = dev_get_plat(dev);
 128        int bank_shift = fls((info->gpio_count - 1) / BANK_SZ);
 129        int off = offset / BANK_SZ;
 130        int ret;
 131        u8 byte;
 132
 133        ret = dm_i2c_read(dev, (reg << bank_shift) + off, &byte, 1);
 134        if (ret) {
 135                dev_err(dev, "%s error\n", __func__);
 136                return ret;
 137        }
 138
 139        *val = byte;
 140
 141        return 0;
 142}
 143
 144static int pca953x_read_regs(struct udevice *dev, int reg, u8 *val)
 145{
 146        struct pca953x_info *info = dev_get_plat(dev);
 147        int ret = 0;
 148
 149        if (info->gpio_count <= 8) {
 150                ret = dm_i2c_read(dev, reg, val, 1);
 151        } else if (info->gpio_count <= 16) {
 152                ret = dm_i2c_read(dev, reg << 1, val, info->bank_count);
 153        } else if (info->gpio_count <= 24) {
 154                /* Auto increment */
 155                ret = dm_i2c_read(dev, (reg << 2) | 0x80, val,
 156                                  info->bank_count);
 157        } else if (info->gpio_count == 40) {
 158                /* Auto increment */
 159                ret = dm_i2c_read(dev, (reg << 3) | 0x80, val,
 160                                  info->bank_count);
 161        } else {
 162                dev_err(dev, "Unsupported now\n");
 163                return -EINVAL;
 164        }
 165
 166        return ret;
 167}
 168
 169static int pca953x_write_regs(struct udevice *dev, int reg, u8 *val)
 170{
 171        struct pca953x_info *info = dev_get_plat(dev);
 172        int ret = 0;
 173
 174        if (info->gpio_count <= 8) {
 175                ret = dm_i2c_write(dev, reg, val, 1);
 176        } else if (info->gpio_count <= 16) {
 177                ret = dm_i2c_write(dev, reg << 1, val, info->bank_count);
 178        } else if (info->gpio_count <= 24) {
 179                /* Auto increment */
 180                ret = dm_i2c_write(dev, (reg << 2) | 0x80, val,
 181                                   info->bank_count);
 182        } else if (info->gpio_count == 40) {
 183                /* Auto increment */
 184                ret = dm_i2c_write(dev, (reg << 3) | 0x80, val, info->bank_count);
 185        } else {
 186                return -EINVAL;
 187        }
 188
 189        return ret;
 190}
 191
 192static int pca953x_is_output(struct udevice *dev, int offset)
 193{
 194        struct pca953x_info *info = dev_get_plat(dev);
 195
 196        int bank = offset / BANK_SZ;
 197        int off = offset % BANK_SZ;
 198
 199        /*0: output; 1: input */
 200        return !(info->reg_direction[bank] & (1 << off));
 201}
 202
 203static int pca953x_get_value(struct udevice *dev, uint offset)
 204{
 205        struct pca953x_info *info = dev_get_plat(dev);
 206        int ret;
 207        u8 val = 0;
 208
 209        int off = offset % BANK_SZ;
 210
 211        ret = pca953x_read_single(dev, info->regs->input, &val, offset);
 212        if (ret)
 213                return ret;
 214
 215        return (val >> off) & 0x1;
 216}
 217
 218static int pca953x_set_value(struct udevice *dev, uint offset, int value)
 219{
 220        struct pca953x_info *info = dev_get_plat(dev);
 221        int bank = offset / BANK_SZ;
 222        int off = offset % BANK_SZ;
 223        u8 val;
 224        int ret;
 225
 226        if (value)
 227                val = info->reg_output[bank] | (1 << off);
 228        else
 229                val = info->reg_output[bank] & ~(1 << off);
 230
 231        ret = pca953x_write_single(dev, info->regs->output, val, offset);
 232        if (ret)
 233                return ret;
 234
 235        info->reg_output[bank] = val;
 236
 237        return 0;
 238}
 239
 240static int pca953x_set_direction(struct udevice *dev, uint offset, int dir)
 241{
 242        struct pca953x_info *info = dev_get_plat(dev);
 243        int bank = offset / BANK_SZ;
 244        int off = offset % BANK_SZ;
 245        u8 val;
 246        int ret;
 247
 248        if (dir == PCA953X_DIRECTION_IN)
 249                val = info->reg_direction[bank] | (1 << off);
 250        else
 251                val = info->reg_direction[bank] & ~(1 << off);
 252
 253        ret = pca953x_write_single(dev, info->regs->direction, val, offset);
 254        if (ret)
 255                return ret;
 256
 257        info->reg_direction[bank] = val;
 258
 259        return 0;
 260}
 261
 262static int pca953x_direction_input(struct udevice *dev, uint offset)
 263{
 264        return pca953x_set_direction(dev, offset, PCA953X_DIRECTION_IN);
 265}
 266
 267static int pca953x_direction_output(struct udevice *dev, uint offset, int value)
 268{
 269        /* Configure output value. */
 270        pca953x_set_value(dev, offset, value);
 271
 272        /* Configure direction as output. */
 273        pca953x_set_direction(dev, offset, PCA953X_DIRECTION_OUT);
 274
 275        return 0;
 276}
 277
 278static int pca953x_get_function(struct udevice *dev, uint offset)
 279{
 280        if (pca953x_is_output(dev, offset))
 281                return GPIOF_OUTPUT;
 282        else
 283                return GPIOF_INPUT;
 284}
 285
 286static int pca953x_xlate(struct udevice *dev, struct gpio_desc *desc,
 287                         struct ofnode_phandle_args *args)
 288{
 289        desc->offset = args->args[0];
 290        desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
 291
 292        return 0;
 293}
 294
 295static const struct dm_gpio_ops pca953x_ops = {
 296        .direction_input        = pca953x_direction_input,
 297        .direction_output       = pca953x_direction_output,
 298        .get_value              = pca953x_get_value,
 299        .set_value              = pca953x_set_value,
 300        .get_function           = pca953x_get_function,
 301        .xlate                  = pca953x_xlate,
 302};
 303
 304static int pca953x_probe(struct udevice *dev)
 305{
 306        struct pca953x_info *info = dev_get_plat(dev);
 307        struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 308        char name[32], label[8], *str;
 309        int addr;
 310        ulong driver_data;
 311        int ret;
 312        int size;
 313        const u8 *tmp;
 314        u8 val[MAX_BANK];
 315
 316        addr = dev_read_addr(dev);
 317        if (addr == 0)
 318                return -ENODEV;
 319
 320        info->addr = addr;
 321
 322        driver_data = dev_get_driver_data(dev);
 323
 324        info->gpio_count = driver_data & PCA_GPIO_MASK;
 325        if (info->gpio_count > MAX_BANK * BANK_SZ) {
 326                dev_err(dev, "Max support %d pins now\n", MAX_BANK * BANK_SZ);
 327                return -EINVAL;
 328        }
 329
 330        info->chip_type = PCA_CHIP_TYPE(driver_data);
 331        if (info->chip_type == PCA953X_TYPE)
 332                info->regs = &pca953x_regs;
 333        else
 334                info->regs = &pca957x_regs;
 335
 336        info->bank_count = DIV_ROUND_UP(info->gpio_count, BANK_SZ);
 337
 338        ret = pca953x_read_regs(dev, info->regs->output, info->reg_output);
 339        if (ret) {
 340                dev_err(dev, "Error reading output register\n");
 341                return ret;
 342        }
 343
 344        ret = pca953x_read_regs(dev, PCA953X_DIRECTION, info->reg_direction);
 345        if (ret) {
 346                dev_err(dev, "Error reading direction register\n");
 347                return ret;
 348        }
 349
 350        tmp = dev_read_prop(dev, "label", &size);
 351
 352        if (tmp) {
 353                memcpy(label, tmp, sizeof(label) - 1);
 354                label[sizeof(label) - 1] = '\0';
 355                snprintf(name, sizeof(name), "%s@%x_", label, info->addr);
 356        } else {
 357                snprintf(name, sizeof(name), "gpio@%x_", info->addr);
 358        }
 359
 360        /* Clear the polarity registers to no invert */
 361        memset(val, 0, MAX_BANK);
 362        ret = pca953x_write_regs(dev, info->regs->invert, val);
 363        if (ret < 0) {
 364                dev_err(dev, "Error writing invert register\n");
 365                return ret;
 366        }
 367
 368        str = strdup(name);
 369        if (!str)
 370                return -ENOMEM;
 371        uc_priv->bank_name = str;
 372        uc_priv->gpio_count = info->gpio_count;
 373
 374        dev_dbg(dev, "%s is ready\n", str);
 375
 376        return 0;
 377}
 378
 379#define OF_953X(__nrgpio, __int) (ulong)(__nrgpio | PCA953X_TYPE | __int)
 380#define OF_957X(__nrgpio, __int) (ulong)(__nrgpio | PCA957X_TYPE | __int)
 381
 382static const struct udevice_id pca953x_ids[] = {
 383        { .compatible = "nxp,pca9505", .data = OF_953X(40, PCA_INT), },
 384        { .compatible = "nxp,pca9534", .data = OF_953X(8, PCA_INT), },
 385        { .compatible = "nxp,pca9535", .data = OF_953X(16, PCA_INT), },
 386        { .compatible = "nxp,pca9536", .data = OF_953X(4, 0), },
 387        { .compatible = "nxp,pca9537", .data = OF_953X(4, PCA_INT), },
 388        { .compatible = "nxp,pca9538", .data = OF_953X(8, PCA_INT), },
 389        { .compatible = "nxp,pca9539", .data = OF_953X(16, PCA_INT), },
 390        { .compatible = "nxp,pca9554", .data = OF_953X(8, PCA_INT), },
 391        { .compatible = "nxp,pca9555", .data = OF_953X(16, PCA_INT), },
 392        { .compatible = "nxp,pca9556", .data = OF_953X(8, 0), },
 393        { .compatible = "nxp,pca9557", .data = OF_953X(8, 0), },
 394        { .compatible = "nxp,pca9574", .data = OF_957X(8, PCA_INT), },
 395        { .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
 396        { .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
 397
 398        { .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), },
 399
 400        { .compatible = "maxim,max7310", .data = OF_953X(8, 0), },
 401        { .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
 402        { .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), },
 403        { .compatible = "maxim,max7315", .data = OF_953X(8, PCA_INT), },
 404
 405        { .compatible = "ti,pca6107", .data = OF_953X(8, PCA_INT), },
 406        { .compatible = "ti,tca6408", .data = OF_953X(8, PCA_INT), },
 407        { .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
 408        { .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
 409        { .compatible = "ti,tca9539", .data = OF_953X(16, PCA_INT), },
 410
 411        { .compatible = "onsemi,pca9654", .data = OF_953X(8, PCA_INT), },
 412
 413        { .compatible = "exar,xra1202", .data = OF_953X(8, 0), },
 414        { }
 415};
 416
 417U_BOOT_DRIVER(pca953x) = {
 418        .name           = "pca953x",
 419        .id             = UCLASS_GPIO,
 420        .ops            = &pca953x_ops,
 421        .probe          = pca953x_probe,
 422        .plat_auto      = sizeof(struct pca953x_info),
 423        .of_match       = pca953x_ids,
 424};
 425