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 <config.h> 24#include <command.h> 25#include <i2c.h> 26#include <tca642x.h> 27 28/* tca642x register address definitions */ 29struct tca642x_bank_info tca642x_regs[] = { 30 { .input_reg = 0x00, 31 .output_reg = 0x04, 32 .polarity_reg = 0x08, 33 .configuration_reg = 0x0c }, 34 { .input_reg = 0x01, 35 .output_reg = 0x05, 36 .polarity_reg = 0x09, 37 .configuration_reg = 0x0d }, 38 { .input_reg = 0x02, 39 .output_reg = 0x06, 40 .polarity_reg = 0x0a, 41 .configuration_reg = 0x0e }, 42}; 43 44/* 45 * Modify masked bits in register 46 */ 47static int tca642x_reg_write(uchar chip, uint8_t addr, 48 uint8_t reg_bit, uint8_t data) 49{ 50 uint8_t valw; 51 int org_bus_num; 52 int ret; 53 54 org_bus_num = i2c_get_bus_num(); 55 i2c_set_bus_num(CFG_SYS_I2C_TCA642X_BUS_NUM); 56 57 if (i2c_read(chip, addr, 1, (uint8_t *)&valw, 1)) { 58 printf("Could not read before writing\n"); 59 ret = -1; 60 goto error; 61 } 62 valw &= ~reg_bit; 63 valw |= data; 64 65 ret = i2c_write(chip, addr, 1, (u8 *)&valw, 1); 66 67error: 68 i2c_set_bus_num(org_bus_num); 69 return ret; 70} 71 72static int tca642x_reg_read(uchar chip, uint8_t addr, uint8_t *data) 73{ 74 uint8_t valw; 75 int org_bus_num; 76 int ret = 0; 77 78 org_bus_num = i2c_get_bus_num(); 79 i2c_set_bus_num(CFG_SYS_I2C_TCA642X_BUS_NUM); 80 if (i2c_read(chip, addr, 1, (u8 *)&valw, 1)) { 81 ret = -1; 82 goto error; 83 } 84 85 *data = valw; 86 87error: 88 i2c_set_bus_num(org_bus_num); 89 return ret; 90} 91 92/* 93 * Set output value of IO pins in 'reg_bit' to corresponding value in 'data' 94 * 0 = low, 1 = high 95 */ 96int tca642x_set_val(uchar chip, uint8_t gpio_bank, 97 uint8_t reg_bit, uint8_t data) 98{ 99 uint8_t out_reg = tca642x_regs[gpio_bank].output_reg; 100 101 return tca642x_reg_write(chip, out_reg, reg_bit, data); 102} 103 104/* 105 * Set read polarity of IO pins in 'reg_bit' to corresponding value in 'data' 106 * 0 = read pin value, 1 = read inverted pin value 107 */ 108int tca642x_set_pol(uchar chip, uint8_t gpio_bank, 109 uint8_t reg_bit, uint8_t data) 110{ 111 uint8_t pol_reg = tca642x_regs[gpio_bank].polarity_reg; 112 113 return tca642x_reg_write(chip, pol_reg, reg_bit, data); 114} 115 116/* 117 * Set direction of IO pins in 'reg_bit' to corresponding value in 'data' 118 * 0 = output, 1 = input 119 */ 120int tca642x_set_dir(uchar chip, uint8_t gpio_bank, 121 uint8_t reg_bit, uint8_t data) 122{ 123 uint8_t config_reg = tca642x_regs[gpio_bank].configuration_reg; 124 125 return tca642x_reg_write(chip, config_reg, reg_bit, data); 126} 127 128/* 129 * Read current logic level of all IO pins 130 */ 131int tca642x_get_val(uchar chip, uint8_t gpio_bank) 132{ 133 uint8_t val; 134 uint8_t in_reg = tca642x_regs[gpio_bank].input_reg; 135 136 if (tca642x_reg_read(chip, in_reg, &val) < 0) 137 return -1; 138 139 return (int)val; 140} 141 142/* 143 * Set the inital register states for the tca642x gpio expander 144 */ 145int tca642x_set_inital_state(uchar chip, struct tca642x_bank_info init_data[]) 146{ 147 int i, ret; 148 uint8_t config_reg; 149 uint8_t polarity_reg; 150 uint8_t output_reg; 151 152 for (i = 0; i < 3; i++) { 153 config_reg = tca642x_regs[i].configuration_reg; 154 ret = tca642x_reg_write(chip, config_reg, 0xff, 155 init_data[i].configuration_reg); 156 polarity_reg = tca642x_regs[i].polarity_reg; 157 ret = tca642x_reg_write(chip, polarity_reg, 0xff, 158 init_data[i].polarity_reg); 159 output_reg = tca642x_regs[i].output_reg; 160 ret = tca642x_reg_write(chip, output_reg, 0xff, 161 init_data[i].output_reg); 162 } 163 164 return ret; 165} 166 167#if defined(CONFIG_CMD_TCA642X) && !defined(CONFIG_SPL_BUILD) 168/* 169 * Display tca642x information 170 */ 171static int tca642x_info(uchar chip) 172{ 173 int i, j; 174 uint8_t data; 175 176 printf("tca642x@ 0x%x (%d pins):\n", chip, 24); 177 for (i = 0; i < 3; i++) { 178 printf("Bank %i\n", i); 179 if (tca642x_reg_read(chip, 180 tca642x_regs[i].configuration_reg, 181 &data) < 0) 182 return -1; 183 printf("\tConfiguration: "); 184 for (j = 7; j >= 0; j--) 185 printf("%c", data & (1 << j) ? 'i' : 'o'); 186 printf("\n"); 187 188 if (tca642x_reg_read(chip, 189 tca642x_regs[i].polarity_reg, &data) < 0) 190 return -1; 191 printf("\tPolarity: "); 192 for (j = 7; j >= 0; j--) 193 printf("%c", data & (1 << j) ? '1' : '0'); 194 printf("\n"); 195 196 if (tca642x_reg_read(chip, 197 tca642x_regs[i].input_reg, &data) < 0) 198 return -1; 199 printf("\tInput value: "); 200 for (j = 7; j >= 0; j--) 201 printf("%c", data & (1 << j) ? '1' : '0'); 202 printf("\n"); 203 204 if (tca642x_reg_read(chip, 205 tca642x_regs[i].output_reg, &data) < 0) 206 return -1; 207 printf("\tOutput value: "); 208 for (j = 7; j >= 0; j--) 209 printf("%c", data & (1 << j) ? '1' : '0'); 210 printf("\n"); 211 } 212 213 return 0; 214} 215 216static int tca642x_get_bank(int pin) 217{ 218 int gpio_bank; 219 220 if (pin <= 7) { 221 gpio_bank = 0; 222 } else if ((pin >= 10) && (pin <= 17)) { 223 gpio_bank = 1; 224 } else if ((pin >= 20) && (pin <= 27)) { 225 gpio_bank = 2; 226 } else { 227 printf("Requested pin is not available\n"); 228 gpio_bank = -1; 229 } 230 231 return gpio_bank; 232} 233 234static struct cmd_tbl cmd_tca642x[] = { 235 U_BOOT_CMD_MKENT(device, 3, 0, (void *)TCA642X_CMD_DEVICE, "", ""), 236 U_BOOT_CMD_MKENT(output, 4, 0, (void *)TCA642X_CMD_OUTPUT, "", ""), 237 U_BOOT_CMD_MKENT(input, 3, 0, (void *)TCA642X_CMD_INPUT, "", ""), 238 U_BOOT_CMD_MKENT(invert, 4, 0, (void *)TCA642X_CMD_INVERT, "", ""), 239 U_BOOT_CMD_MKENT(info, 2, 0, (void *)TCA642X_CMD_INFO, "", ""), 240}; 241 242static int do_tca642x(struct cmd_tbl *cmdtp, int flag, int argc, 243 char *const argv[]) 244{ 245 static uchar chip = CFG_SYS_I2C_TCA642X_ADDR; 246 int ret = CMD_RET_USAGE, val; 247 int gpio_bank = 0; 248 uint8_t bank_shift; 249 ulong ul_arg2 = 0; 250 ulong ul_arg3 = 0; 251 struct cmd_tbl *c; 252 253 c = find_cmd_tbl(argv[1], cmd_tca642x, ARRAY_SIZE(cmd_tca642x)); 254 255 /* All commands but "device" require 'maxargs' arguments */ 256 if (!c || 257 !((argc == (c->maxargs)) || 258 (((int)c->cmd == TCA642X_CMD_DEVICE) && 259 (argc == (c->maxargs - 1))))) { 260 return CMD_RET_USAGE; 261 } 262 263 /* arg2 used as chip number or pin number */ 264 if (argc > 2) 265 ul_arg2 = dectoul(argv[2], NULL); 266 267 /* arg3 used as pin or invert value */ 268 if (argc > 3) 269 ul_arg3 = dectoul(argv[3], NULL) & 0x1; 270 271 switch ((int)c->cmd) { 272 case TCA642X_CMD_INFO: 273 ret = tca642x_info(chip); 274 if (ret) 275 ret = CMD_RET_FAILURE; 276 break; 277 278 case TCA642X_CMD_DEVICE: 279 if (argc == 3) 280 chip = (uint8_t)ul_arg2; 281 printf("Current device address: 0x%x\n", chip); 282 ret = CMD_RET_SUCCESS; 283 break; 284 285 case TCA642X_CMD_INPUT: 286 gpio_bank = tca642x_get_bank(ul_arg2); 287 if (gpio_bank < 0) { 288 ret = CMD_RET_FAILURE; 289 goto error; 290 } 291 bank_shift = ul_arg2 - (gpio_bank * 10); 292 ret = tca642x_set_dir(chip, gpio_bank, (1 << bank_shift), 293 TCA642X_DIR_IN << bank_shift); 294 val = (tca642x_get_val(chip, gpio_bank) & 295 (1 << bank_shift)) != 0; 296 297 if (ret) 298 ret = CMD_RET_FAILURE; 299 else 300 printf("chip 0x%02x, pin 0x%lx = %d\n", chip, 301 ul_arg2, val); 302 break; 303 304 case TCA642X_CMD_OUTPUT: 305 gpio_bank = tca642x_get_bank(ul_arg2); 306 if (gpio_bank < 0) { 307 ret = CMD_RET_FAILURE; 308 goto error; 309 } 310 bank_shift = ul_arg2 - (gpio_bank * 10); 311 ret = tca642x_set_dir(chip, gpio_bank, (1 << bank_shift), 312 (TCA642X_DIR_OUT << bank_shift)); 313 if (!ret) 314 ret = tca642x_set_val(chip, 315 gpio_bank, (1 << bank_shift), 316 (ul_arg3 << bank_shift)); 317 if (ret) 318 ret = CMD_RET_FAILURE; 319 break; 320 321 case TCA642X_CMD_INVERT: 322 gpio_bank = tca642x_get_bank(ul_arg2); 323 if (gpio_bank < 0) { 324 ret = CMD_RET_FAILURE; 325 goto error; 326 } 327 bank_shift = ul_arg2 - (gpio_bank * 10); 328 ret = tca642x_set_pol(chip, gpio_bank, (1 << bank_shift), 329 (ul_arg3 << bank_shift)); 330 if (ret) 331 ret = CMD_RET_FAILURE; 332 break; 333 } 334error: 335 if (ret == CMD_RET_FAILURE) 336 eprintf("Error talking to chip at 0x%x\n", chip); 337 338 return ret; 339} 340 341U_BOOT_CMD( 342 tca642x, 5, 1, do_tca642x, 343 "tca642x gpio access", 344 "device [dev]\n" 345 " - show or set current device address\n" 346 "tca642x info\n" 347 " - display info for current chip\n" 348 "tca642x output pin 0|1\n" 349 " - set pin as output and drive low or high\n" 350 "tca642x invert pin 0|1\n" 351 " - disable/enable polarity inversion for reads\n" 352 "tca642x input pin\n" 353 " - set pin as input and read value" 354); 355 356#endif /* CONFIG_CMD_TCA642X */ 357