Commit 61c1775f16ed122a07168545afbc1a04ece2bc22

Authored by Dan Murphy
Committed by Tom Rini
1 parent f881a4df4f

gpio: tca642x: Add the tca642x gpio expander driver

Add the tca642x gpio expander driver

Datasheet:
http://www.ti.com/product/tca6424a

Signed-off-by: Dan Murphy <dmurphy@ti.com>

Showing 3 changed files with 403 additions and 0 deletions Side-by-side Diff

drivers/gpio/Makefile
... ... @@ -33,6 +33,7 @@
33 33 COBJS-$(CONFIG_S3C2440_GPIO) += s3c2440_gpio.o
34 34 COBJS-$(CONFIG_XILINX_GPIO) += xilinx_gpio.o
35 35 COBJS-$(CONFIG_ADI_GPIO2) += adi_gpio2.o
  36 +COBJS-$(CONFIG_TCA642X) += tca642x.o
36 37  
37 38 COBJS := $(COBJS-y)
38 39 SRCS := $(COBJS:.o=.c)
drivers/gpio/tca642x.c
  1 +/*
  2 + * Copyright 2013 Texas Instruments, Inc.
  3 + * Author: Dan Murphy <dmurphy@ti.com>
  4 + *
  5 + * Derived work from the pca953x.c driver
  6 + *
  7 + * This program is free software; you can redistribute it and/or
  8 + * modify it under the terms of the GNU General Public License as
  9 + * published by the Free Software Foundation; either version 2 of
  10 + * the License, or (at your option) any later version.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 + * MA 02111-1307 USA
  21 + */
  22 +
  23 +#include <common.h>
  24 +#include <i2c.h>
  25 +#include <tca642x.h>
  26 +
  27 +/* tca642x register address definitions */
  28 +struct tca642x_bank_info tca642x_regs[] = {
  29 + { .input_reg = 0x00,
  30 + .output_reg = 0x04,
  31 + .polarity_reg = 0x08,
  32 + .configuration_reg = 0x0c },
  33 + { .input_reg = 0x01,
  34 + .output_reg = 0x05,
  35 + .polarity_reg = 0x09,
  36 + .configuration_reg = 0x0d },
  37 + { .input_reg = 0x02,
  38 + .output_reg = 0x06,
  39 + .polarity_reg = 0x0a,
  40 + .configuration_reg = 0x0e },
  41 +};
  42 +
  43 +/*
  44 + * Modify masked bits in register
  45 + */
  46 +static int tca642x_reg_write(uchar chip, uint8_t addr,
  47 + uint8_t reg_bit, uint8_t data)
  48 +{
  49 + uint8_t valw;
  50 + int org_bus_num;
  51 + int ret;
  52 +
  53 + org_bus_num = i2c_get_bus_num();
  54 + i2c_set_bus_num(CONFIG_SYS_I2C_TCA642X_BUS_NUM);
  55 +
  56 + if (i2c_read(chip, addr, 1, (uint8_t *)&valw, 1)) {
  57 + printf("Could not read before writing\n");
  58 + ret = -1;
  59 + goto error;
  60 + }
  61 + valw &= ~reg_bit;
  62 + valw |= data;
  63 +
  64 + ret = i2c_write(chip, addr, 1, (u8 *)&valw, 1);
  65 +
  66 +error:
  67 + i2c_set_bus_num(org_bus_num);
  68 + return ret;
  69 +}
  70 +
  71 +static int tca642x_reg_read(uchar chip, uint8_t addr, uint8_t *data)
  72 +{
  73 + uint8_t valw;
  74 + int org_bus_num;
  75 + int ret = 0;
  76 +
  77 + org_bus_num = i2c_get_bus_num();
  78 + i2c_set_bus_num(CONFIG_SYS_I2C_TCA642X_BUS_NUM);
  79 + if (i2c_read(chip, addr, 1, (u8 *)&valw, 1)) {
  80 + ret = -1;
  81 + goto error;
  82 + }
  83 +
  84 + *data = valw;
  85 +
  86 +error:
  87 + i2c_set_bus_num(org_bus_num);
  88 + return ret;
  89 +}
  90 +
  91 +/*
  92 + * Set output value of IO pins in 'reg_bit' to corresponding value in 'data'
  93 + * 0 = low, 1 = high
  94 + */
  95 +int tca642x_set_val(uchar chip, uint8_t gpio_bank,
  96 + uint8_t reg_bit, uint8_t data)
  97 +{
  98 + uint8_t out_reg = tca642x_regs[gpio_bank].output_reg;
  99 +
  100 + return tca642x_reg_write(chip, out_reg, reg_bit, data);
  101 +}
  102 +
  103 +/*
  104 + * Set read polarity of IO pins in 'reg_bit' to corresponding value in 'data'
  105 + * 0 = read pin value, 1 = read inverted pin value
  106 + */
  107 +int tca642x_set_pol(uchar chip, uint8_t gpio_bank,
  108 + uint8_t reg_bit, uint8_t data)
  109 +{
  110 + uint8_t pol_reg = tca642x_regs[gpio_bank].polarity_reg;
  111 +
  112 + return tca642x_reg_write(chip, pol_reg, reg_bit, data);
  113 +}
  114 +
  115 +/*
  116 + * Set direction of IO pins in 'reg_bit' to corresponding value in 'data'
  117 + * 0 = output, 1 = input
  118 + */
  119 +int tca642x_set_dir(uchar chip, uint8_t gpio_bank,
  120 + uint8_t reg_bit, uint8_t data)
  121 +{
  122 + uint8_t config_reg = tca642x_regs[gpio_bank].configuration_reg;
  123 +
  124 + return tca642x_reg_write(chip, config_reg, reg_bit, data);
  125 +}
  126 +
  127 +/*
  128 + * Read current logic level of all IO pins
  129 + */
  130 +int tca642x_get_val(uchar chip, uint8_t gpio_bank)
  131 +{
  132 + uint8_t val;
  133 + uint8_t in_reg = tca642x_regs[gpio_bank].input_reg;
  134 +
  135 + if (tca642x_reg_read(chip, in_reg, &val) < 0)
  136 + return -1;
  137 +
  138 + return (int)val;
  139 +}
  140 +
  141 +/*
  142 + * Set the inital register states for the tca642x gpio expander
  143 + */
  144 +int tca642x_set_inital_state(uchar chip, struct tca642x_bank_info init_data[])
  145 +{
  146 + int i, ret;
  147 + uint8_t config_reg;
  148 + uint8_t polarity_reg;
  149 + uint8_t output_reg;
  150 +
  151 + for (i = 0; i < 3; i++) {
  152 + config_reg = tca642x_regs[i].configuration_reg;
  153 + ret = tca642x_reg_write(chip, config_reg, 0xff,
  154 + init_data[i].configuration_reg);
  155 + polarity_reg = tca642x_regs[i].polarity_reg;
  156 + ret = tca642x_reg_write(chip, polarity_reg, 0xff,
  157 + init_data[i].polarity_reg);
  158 + output_reg = tca642x_regs[i].output_reg;
  159 + ret = tca642x_reg_write(chip, output_reg, 0xff,
  160 + init_data[i].output_reg);
  161 + }
  162 +
  163 + return ret;
  164 +}
  165 +
  166 +#ifdef CONFIG_CMD_TCA642X
  167 +/*
  168 + * Display tca642x information
  169 + */
  170 +static int tca642x_info(uchar chip)
  171 +{
  172 + int i, j;
  173 + uint8_t data;
  174 +
  175 + printf("tca642x@ 0x%x (%d pins):\n", chip, 24);
  176 + for (i = 0; i < 3; i++) {
  177 + printf("Bank %i\n", i);
  178 + if (tca642x_reg_read(chip,
  179 + tca642x_regs[i].configuration_reg,
  180 + &data) < 0)
  181 + return -1;
  182 + printf("\tConfiguration: ");
  183 + for (j = 7; j >= 0; j--)
  184 + printf("%c", data & (1 << j) ? 'i' : 'o');
  185 + printf("\n");
  186 +
  187 + if (tca642x_reg_read(chip,
  188 + tca642x_regs[i].polarity_reg, &data) < 0)
  189 + return -1;
  190 + printf("\tPolarity: ");
  191 + for (j = 7; j >= 0; j--)
  192 + printf("%c", data & (1 << j) ? '1' : '0');
  193 + printf("\n");
  194 +
  195 + if (tca642x_reg_read(chip,
  196 + tca642x_regs[i].input_reg, &data) < 0)
  197 + return -1;
  198 + printf("\tInput value: ");
  199 + for (j = 7; j >= 0; j--)
  200 + printf("%c", data & (1 << j) ? '1' : '0');
  201 + printf("\n");
  202 +
  203 + if (tca642x_reg_read(chip,
  204 + tca642x_regs[i].output_reg, &data) < 0)
  205 + return -1;
  206 + printf("\tOutput value: ");
  207 + for (j = 7; j >= 0; j--)
  208 + printf("%c", data & (1 << j) ? '1' : '0');
  209 + printf("\n");
  210 + }
  211 +
  212 + return 0;
  213 +}
  214 +
  215 +cmd_tbl_t cmd_tca642x[] = {
  216 + U_BOOT_CMD_MKENT(device, 3, 0, (void *)TCA642X_CMD_DEVICE, "", ""),
  217 + U_BOOT_CMD_MKENT(output, 4, 0, (void *)TCA642X_CMD_OUTPUT, "", ""),
  218 + U_BOOT_CMD_MKENT(input, 3, 0, (void *)TCA642X_CMD_INPUT, "", ""),
  219 + U_BOOT_CMD_MKENT(invert, 4, 0, (void *)TCA642X_CMD_INVERT, "", ""),
  220 + U_BOOT_CMD_MKENT(info, 2, 0, (void *)TCA642X_CMD_INFO, "", ""),
  221 +};
  222 +
  223 +int do_tca642x(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  224 +{
  225 + static uchar chip = CONFIG_SYS_I2C_TCA642X_ADDR;
  226 + int ret = CMD_RET_USAGE, val;
  227 + uint8_t gpio_bank = 0;
  228 + uint8_t bank_shift;
  229 + ulong ul_arg2 = 0;
  230 + ulong ul_arg3 = 0;
  231 + cmd_tbl_t *c;
  232 +
  233 + c = find_cmd_tbl(argv[1], cmd_tca642x, ARRAY_SIZE(cmd_tca642x));
  234 +
  235 + /* All commands but "device" require 'maxargs' arguments */
  236 + if (!c ||
  237 + !((argc == (c->maxargs)) ||
  238 + (((int)c->cmd == TCA642X_CMD_DEVICE) &&
  239 + (argc == (c->maxargs - 1))))) {
  240 + return CMD_RET_USAGE;
  241 + }
  242 +
  243 + /* arg2 used as chip number or pin number */
  244 + if (argc > 2)
  245 + ul_arg2 = simple_strtoul(argv[2], NULL, 10);
  246 +
  247 + /* arg3 used as pin or invert value */
  248 + if (argc > 3) {
  249 + ul_arg3 = simple_strtoul(argv[3], NULL, 10) & 0x1;
  250 + if (ul_arg2 <= 7) {
  251 + gpio_bank = 0;
  252 + } else if ((ul_arg2 >= 10) && (ul_arg2 <= 17)) {
  253 + gpio_bank = 1;
  254 + } else if ((ul_arg2 >= 20) && (ul_arg2 <= 27)) {
  255 + gpio_bank = 2;
  256 + } else {
  257 + printf("Requested pin is not available\n");
  258 + ret = CMD_RET_FAILURE;
  259 + goto error;
  260 + }
  261 + }
  262 +
  263 + switch ((int)c->cmd) {
  264 + case TCA642X_CMD_INFO:
  265 + ret = tca642x_info(chip);
  266 + if (ret)
  267 + ret = CMD_RET_FAILURE;
  268 + break;
  269 +
  270 + case TCA642X_CMD_DEVICE:
  271 + if (argc == 3)
  272 + chip = (uint8_t)ul_arg2;
  273 + printf("Current device address: 0x%x\n", chip);
  274 + ret = CMD_RET_SUCCESS;
  275 + break;
  276 +
  277 + case TCA642X_CMD_INPUT:
  278 + bank_shift = ul_arg2 - (gpio_bank * 10);
  279 + ret = tca642x_set_dir(chip, gpio_bank, (1 << bank_shift),
  280 + TCA642X_DIR_IN << bank_shift);
  281 + val = (tca642x_get_val(chip, gpio_bank) &
  282 + (1 << bank_shift)) != 0;
  283 +
  284 + if (ret)
  285 + ret = CMD_RET_FAILURE;
  286 + else
  287 + printf("chip 0x%02x, pin 0x%lx = %d\n", chip,
  288 + ul_arg2, val);
  289 + break;
  290 +
  291 + case TCA642X_CMD_OUTPUT:
  292 + bank_shift = ul_arg2 - (gpio_bank * 10);
  293 + ret = tca642x_set_dir(chip, gpio_bank, (1 << bank_shift),
  294 + (TCA642X_DIR_OUT << bank_shift));
  295 + if (!ret)
  296 + ret = tca642x_set_val(chip,
  297 + gpio_bank, (1 << bank_shift),
  298 + (ul_arg3 << bank_shift));
  299 + if (ret)
  300 + ret = CMD_RET_FAILURE;
  301 + break;
  302 +
  303 + case TCA642X_CMD_INVERT:
  304 + bank_shift = ul_arg2 - (gpio_bank * 10);
  305 + ret = tca642x_set_pol(chip, gpio_bank, (1 << bank_shift),
  306 + (ul_arg3 << bank_shift));
  307 + if (ret)
  308 + ret = CMD_RET_FAILURE;
  309 + break;
  310 + }
  311 +error:
  312 + if (ret == CMD_RET_FAILURE)
  313 + eprintf("Error talking to chip at 0x%x\n", chip);
  314 +
  315 + return ret;
  316 +}
  317 +
  318 +U_BOOT_CMD(
  319 + tca642x, 5, 1, do_tca642x,
  320 + "tca642x gpio access",
  321 + "device [dev]\n"
  322 + " - show or set current device address\n"
  323 + "tca642x info\n"
  324 + " - display info for current chip\n"
  325 + "tca642x output pin 0|1\n"
  326 + " - set pin as output and drive low or high\n"
  327 + "tca642x invert pin 0|1\n"
  328 + " - disable/enable polarity inversion for reads\n"
  329 + "tca642x input pin\n"
  330 + " - set pin as input and read value"
  331 +);
  332 +
  333 +#endif /* CONFIG_CMD_TCA642X */
  1 +/*
  2 + * Copyright 2013 Texas Instruments, Inc.
  3 + * Author: Dan Murphy <dmurphy@ti.com>
  4 + *
  5 + * Derived work from the pca953x.c driver
  6 + *
  7 + * This program is free software; you can redistribute it and/or
  8 + * modify it under the terms of the GNU General Public License as
  9 + * published by the Free Software Foundation; either version 2 of
  10 + * the License, or (at your option) any later version.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 + * MA 02111-1307 USA
  21 + */
  22 +
  23 +#ifndef __TCA642X_H_
  24 +#define __TCA642X_H_
  25 +
  26 +#ifdef CONFIG_CMD_TCA642X
  27 +enum {
  28 + TCA642X_CMD_INFO,
  29 + TCA642X_CMD_DEVICE,
  30 + TCA642X_CMD_OUTPUT,
  31 + TCA642X_CMD_INPUT,
  32 + TCA642X_CMD_INVERT,
  33 +};
  34 +#endif
  35 +
  36 +#define TCA642X_OUT_LOW 0
  37 +#define TCA642X_OUT_HIGH 1
  38 +#define TCA642X_POL_NORMAL 0
  39 +#define TCA642X_POL_INVERT 1
  40 +#define TCA642X_DIR_OUT 0
  41 +#define TCA642X_DIR_IN 1
  42 +
  43 +/* Default to an address that hopefully won't corrupt other i2c devices */
  44 +#ifndef CONFIG_SYS_I2C_TCA642X_ADDR
  45 +#define CONFIG_SYS_I2C_TCA642X_ADDR (~0)
  46 +#endif
  47 +
  48 +/* Default to an address that hopefully won't corrupt other i2c devices */
  49 +#ifndef CONFIG_SYS_I2C_TCA642X_BUS_NUM
  50 +#define CONFIG_SYS_I2C_TCA642X_BUS_NUM (0)
  51 +#endif
  52 +
  53 +struct tca642x_bank_info {
  54 + uint8_t input_reg;
  55 + uint8_t output_reg;
  56 + uint8_t polarity_reg;
  57 + uint8_t configuration_reg;
  58 +};
  59 +
  60 +int tca642x_set_val(uchar chip, uint8_t gpio_bank,
  61 + uint8_t reg_bit, uint8_t data);
  62 +int tca642x_set_pol(uchar chip, uint8_t gpio_bank,
  63 + uint8_t reg_bit, uint8_t data);
  64 +int tca642x_set_dir(uchar chip, uint8_t gpio_bank,
  65 + uint8_t reg_bit, uint8_t data);
  66 +int tca642x_get_val(uchar chip, uint8_t gpio_bank);
  67 +int tca642x_set_inital_state(uchar chip, struct tca642x_bank_info init_data[]);
  68 +
  69 +#endif /* __TCA642X_H_ */