uboot/drivers/gpio/pca953x.c
<<
>>
Prefs
   1/*
   2 * Copyright 2008 Extreme Engineering Solutions, Inc.
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0
   5 */
   6
   7/*
   8 * Driver for NXP's 4, 8 and 16 bit I2C gpio expanders (eg pca9537, pca9557,
   9 * pca9539, etc)
  10 */
  11
  12#include <common.h>
  13#include <i2c.h>
  14#include <pca953x.h>
  15
  16/* Default to an address that hopefully won't corrupt other i2c devices */
  17#ifndef CONFIG_SYS_I2C_PCA953X_ADDR
  18#define CONFIG_SYS_I2C_PCA953X_ADDR     (~0)
  19#endif
  20
  21enum {
  22        PCA953X_CMD_INFO,
  23        PCA953X_CMD_DEVICE,
  24        PCA953X_CMD_OUTPUT,
  25        PCA953X_CMD_INPUT,
  26        PCA953X_CMD_INVERT,
  27};
  28
  29#ifdef CONFIG_SYS_I2C_PCA953X_WIDTH
  30struct pca953x_chip_ngpio {
  31        uint8_t chip;
  32        uint8_t ngpio;
  33};
  34
  35static struct pca953x_chip_ngpio pca953x_chip_ngpios[] =
  36    CONFIG_SYS_I2C_PCA953X_WIDTH;
  37
  38/*
  39 * Determine the number of GPIO pins supported. If we don't know we assume
  40 * 8 pins.
  41 */
  42static int pca953x_ngpio(uint8_t chip)
  43{
  44        int i;
  45
  46        for (i = 0; i < ARRAY_SIZE(pca953x_chip_ngpios); i++)
  47                if (pca953x_chip_ngpios[i].chip == chip)
  48                        return pca953x_chip_ngpios[i].ngpio;
  49
  50        return 8;
  51}
  52#else
  53static int pca953x_ngpio(uint8_t chip)
  54{
  55        return 8;
  56}
  57#endif
  58
  59/*
  60 * Modify masked bits in register
  61 */
  62static int pca953x_reg_write(uint8_t chip, uint addr, uint mask, uint data)
  63{
  64        uint8_t valb;
  65        uint16_t valw;
  66
  67        if (pca953x_ngpio(chip) <= 8) {
  68                if (i2c_read(chip, addr, 1, &valb, 1))
  69                        return -1;
  70
  71                valb &= ~mask;
  72                valb |= data;
  73
  74                return i2c_write(chip, addr, 1, &valb, 1);
  75        } else {
  76                if (i2c_read(chip, addr << 1, 1, (u8*)&valw, 2))
  77                        return -1;
  78
  79                valw = le16_to_cpu(valw);
  80                valw &= ~mask;
  81                valw |= data;
  82                valw = cpu_to_le16(valw);
  83
  84                return i2c_write(chip, addr << 1, 1, (u8*)&valw, 2);
  85        }
  86}
  87
  88static int pca953x_reg_read(uint8_t chip, uint addr, uint *data)
  89{
  90        uint8_t valb;
  91        uint16_t valw;
  92
  93        if (pca953x_ngpio(chip) <= 8) {
  94                if (i2c_read(chip, addr, 1, &valb, 1))
  95                        return -1;
  96                *data = (int)valb;
  97        } else {
  98                if (i2c_read(chip, addr << 1, 1, (u8*)&valw, 2))
  99                        return -1;
 100                *data = (uint)le16_to_cpu(valw);
 101        }
 102        return 0;
 103}
 104
 105/*
 106 * Set output value of IO pins in 'mask' to corresponding value in 'data'
 107 * 0 = low, 1 = high
 108 */
 109int pca953x_set_val(uint8_t chip, uint mask, uint data)
 110{
 111        return pca953x_reg_write(chip, PCA953X_OUT, mask, data);
 112}
 113
 114/*
 115 * Set read polarity of IO pins in 'mask' to corresponding value in 'data'
 116 * 0 = read pin value, 1 = read inverted pin value
 117 */
 118int pca953x_set_pol(uint8_t chip, uint mask, uint data)
 119{
 120        return pca953x_reg_write(chip, PCA953X_POL, mask, data);
 121}
 122
 123/*
 124 * Set direction of IO pins in 'mask' to corresponding value in 'data'
 125 * 0 = output, 1 = input
 126 */
 127int pca953x_set_dir(uint8_t chip, uint mask, uint data)
 128{
 129        return pca953x_reg_write(chip, PCA953X_CONF, mask, data);
 130}
 131
 132/*
 133 * Read current logic level of all IO pins
 134 */
 135int pca953x_get_val(uint8_t chip)
 136{
 137        uint val;
 138
 139        if (pca953x_reg_read(chip, PCA953X_IN, &val) < 0)
 140                return -1;
 141
 142        return (int)val;
 143}
 144
 145#ifdef CONFIG_CMD_PCA953X
 146#ifdef CONFIG_CMD_PCA953X_INFO
 147/*
 148 * Display pca953x information
 149 */
 150static int pca953x_info(uint8_t chip)
 151{
 152        int i;
 153        uint data;
 154        int nr_gpio = pca953x_ngpio(chip);
 155        int msb = nr_gpio - 1;
 156
 157        printf("pca953x@ 0x%x (%d pins):\n\n", chip, nr_gpio);
 158        printf("gpio pins: ");
 159        for (i = msb; i >= 0; i--)
 160                printf("%x", i);
 161        printf("\n");
 162        for (i = 11 + nr_gpio; i > 0; i--)
 163                printf("-");
 164        printf("\n");
 165
 166        if (pca953x_reg_read(chip, PCA953X_CONF, &data) < 0)
 167                return -1;
 168        printf("conf:      ");
 169        for (i = msb; i >= 0; i--)
 170                printf("%c", data & (1 << i) ? 'i' : 'o');
 171        printf("\n");
 172
 173        if (pca953x_reg_read(chip, PCA953X_POL, &data) < 0)
 174                return -1;
 175        printf("invert:    ");
 176        for (i = msb; i >= 0; i--)
 177                printf("%c", data & (1 << i) ? '1' : '0');
 178        printf("\n");
 179
 180        if (pca953x_reg_read(chip, PCA953X_IN, &data) < 0)
 181                return -1;
 182        printf("input:     ");
 183        for (i = msb; i >= 0; i--)
 184                printf("%c", data & (1 << i) ? '1' : '0');
 185        printf("\n");
 186
 187        if (pca953x_reg_read(chip, PCA953X_OUT, &data) < 0)
 188                return -1;
 189        printf("output:    ");
 190        for (i = msb; i >= 0; i--)
 191                printf("%c", data & (1 << i) ? '1' : '0');
 192        printf("\n");
 193
 194        return 0;
 195}
 196#endif /* CONFIG_CMD_PCA953X_INFO */
 197
 198cmd_tbl_t cmd_pca953x[] = {
 199        U_BOOT_CMD_MKENT(device, 3, 0, (void *)PCA953X_CMD_DEVICE, "", ""),
 200        U_BOOT_CMD_MKENT(output, 4, 0, (void *)PCA953X_CMD_OUTPUT, "", ""),
 201        U_BOOT_CMD_MKENT(input, 3, 0, (void *)PCA953X_CMD_INPUT, "", ""),
 202        U_BOOT_CMD_MKENT(invert, 4, 0, (void *)PCA953X_CMD_INVERT, "", ""),
 203#ifdef CONFIG_CMD_PCA953X_INFO
 204        U_BOOT_CMD_MKENT(info, 2, 0, (void *)PCA953X_CMD_INFO, "", ""),
 205#endif
 206};
 207
 208int do_pca953x(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 209{
 210        static uint8_t chip = CONFIG_SYS_I2C_PCA953X_ADDR;
 211        int ret = CMD_RET_USAGE, val;
 212        ulong ul_arg2 = 0;
 213        ulong ul_arg3 = 0;
 214        cmd_tbl_t *c;
 215
 216        c = find_cmd_tbl(argv[1], cmd_pca953x, ARRAY_SIZE(cmd_pca953x));
 217
 218        /* All commands but "device" require 'maxargs' arguments */
 219        if (!c || !((argc == (c->maxargs)) ||
 220                (((long)c->cmd == PCA953X_CMD_DEVICE) &&
 221                 (argc == (c->maxargs - 1))))) {
 222                return CMD_RET_USAGE;
 223        }
 224
 225        /* arg2 used as chip number or pin number */
 226        if (argc > 2)
 227                ul_arg2 = simple_strtoul(argv[2], NULL, 16);
 228
 229        /* arg3 used as pin or invert value */
 230        if (argc > 3)
 231                ul_arg3 = simple_strtoul(argv[3], NULL, 16) & 0x1;
 232
 233        switch ((long)c->cmd) {
 234#ifdef CONFIG_CMD_PCA953X_INFO
 235        case PCA953X_CMD_INFO:
 236                ret = pca953x_info(chip);
 237                if (ret)
 238                        ret = CMD_RET_FAILURE;
 239                break;
 240#endif
 241
 242        case PCA953X_CMD_DEVICE:
 243                if (argc == 3)
 244                        chip = (uint8_t)ul_arg2;
 245                printf("Current device address: 0x%x\n", chip);
 246                ret = CMD_RET_SUCCESS;
 247                break;
 248
 249        case PCA953X_CMD_INPUT:
 250                ret = pca953x_set_dir(chip, (1 << ul_arg2),
 251                                PCA953X_DIR_IN << ul_arg2);
 252                val = (pca953x_get_val(chip) & (1 << ul_arg2)) != 0;
 253
 254                if (ret)
 255                        ret = CMD_RET_FAILURE;
 256                else
 257                        printf("chip 0x%02x, pin 0x%lx = %d\n", chip, ul_arg2,
 258                                                                        val);
 259                break;
 260
 261        case PCA953X_CMD_OUTPUT:
 262                ret = pca953x_set_dir(chip, (1 << ul_arg2),
 263                                (PCA953X_DIR_OUT << ul_arg2));
 264                if (!ret)
 265                        ret = pca953x_set_val(chip, (1 << ul_arg2),
 266                                                (ul_arg3 << ul_arg2));
 267                if (ret)
 268                        ret = CMD_RET_FAILURE;
 269                break;
 270
 271        case PCA953X_CMD_INVERT:
 272                ret = pca953x_set_pol(chip, (1 << ul_arg2),
 273                                        (ul_arg3 << ul_arg2));
 274                if (ret)
 275                        ret = CMD_RET_FAILURE;
 276                break;
 277        }
 278
 279        if (ret == CMD_RET_FAILURE)
 280                eprintf("Error talking to chip at 0x%x\n", chip);
 281
 282        return ret;
 283}
 284
 285U_BOOT_CMD(
 286        pca953x,        5,      1,      do_pca953x,
 287        "pca953x gpio access",
 288        "device [dev]\n"
 289        "       - show or set current device address\n"
 290#ifdef CONFIG_CMD_PCA953X_INFO
 291        "pca953x info\n"
 292        "       - display info for current chip\n"
 293#endif
 294        "pca953x output pin 0|1\n"
 295        "       - set pin as output and drive low or high\n"
 296        "pca953x invert pin 0|1\n"
 297        "       - disable/enable polarity inversion for reads\n"
 298        "pca953x input pin\n"
 299        "       - set pin as input and read value"
 300);
 301
 302#endif /* CONFIG_CMD_PCA953X */
 303