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