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