Home | History | Annotate | Download | only in gpio
      1 /*
      2  * Copyright 2013 Texas Instruments, Inc.
      3  * Author: Dan Murphy <dmurphy (at) 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 #if defined(CONFIG_CMD_TCA642X) && !defined(CONFIG_SPL_BUILD)
    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 static 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 static 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 */
    334