1e92739d3SPeter Tyser /* 2e92739d3SPeter Tyser * Copyright 2008 Extreme Engineering Solutions, Inc. 3e92739d3SPeter Tyser * 4e92739d3SPeter Tyser * This program is free software; you can redistribute it and/or 5e92739d3SPeter Tyser * modify it under the terms of the GNU General Public License 6e92739d3SPeter Tyser * Version 2 as published by the Free Software Foundation. 7e92739d3SPeter Tyser * 8e92739d3SPeter Tyser * This program is distributed in the hope that it will be useful, 9e92739d3SPeter Tyser * but WITHOUT ANY WARRANTY; without even the implied warranty of 10e92739d3SPeter Tyser * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11e92739d3SPeter Tyser * GNU General Public License for more details. 12e92739d3SPeter Tyser * 13e92739d3SPeter Tyser * You should have received a copy of the GNU General Public License 14e92739d3SPeter Tyser * along with this program; if not, write to the Free Software 15e92739d3SPeter Tyser * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 16e92739d3SPeter Tyser * MA 02111-1307 USA 17e92739d3SPeter Tyser */ 18e92739d3SPeter Tyser 19e92739d3SPeter Tyser /* 20e92739d3SPeter Tyser * Driver for NXP's 4 and 8 bit I2C gpio expanders (eg pca9537, pca9557, etc) 21e92739d3SPeter Tyser * TODO: support additional devices with more than 8-bits GPIO 22e92739d3SPeter Tyser */ 23e92739d3SPeter Tyser 24e92739d3SPeter Tyser #include <common.h> 25e92739d3SPeter Tyser #include <i2c.h> 26e92739d3SPeter Tyser #include <pca953x.h> 27e92739d3SPeter Tyser 28e92739d3SPeter Tyser /* Default to an address that hopefully won't corrupt other i2c devices */ 29e92739d3SPeter Tyser #ifndef CONFIG_SYS_I2C_PCA953X_ADDR 30e92739d3SPeter Tyser #define CONFIG_SYS_I2C_PCA953X_ADDR (~0) 31e92739d3SPeter Tyser #endif 32e92739d3SPeter Tyser 33e92739d3SPeter Tyser enum { 34e92739d3SPeter Tyser PCA953X_CMD_INFO, 35e92739d3SPeter Tyser PCA953X_CMD_DEVICE, 36e92739d3SPeter Tyser PCA953X_CMD_OUTPUT, 37e92739d3SPeter Tyser PCA953X_CMD_INPUT, 38e92739d3SPeter Tyser PCA953X_CMD_INVERT, 39e92739d3SPeter Tyser }; 40e92739d3SPeter Tyser 41e92739d3SPeter Tyser /* 42e92739d3SPeter Tyser * Modify masked bits in register 43e92739d3SPeter Tyser */ 44e92739d3SPeter Tyser static int pca953x_reg_write(uint8_t chip, uint addr, uint mask, uint data) 45e92739d3SPeter Tyser { 46e92739d3SPeter Tyser uint8_t val; 47e92739d3SPeter Tyser 48e92739d3SPeter Tyser if (i2c_read(chip, addr, 1, &val, 1)) 49e92739d3SPeter Tyser return -1; 50e92739d3SPeter Tyser 51e92739d3SPeter Tyser val &= ~mask; 52e92739d3SPeter Tyser val |= data; 53e92739d3SPeter Tyser 54e92739d3SPeter Tyser return i2c_write(chip, addr, 1, &val, 1); 55e92739d3SPeter Tyser } 56e92739d3SPeter Tyser 57e92739d3SPeter Tyser /* 58e92739d3SPeter Tyser * Set output value of IO pins in 'mask' to corresponding value in 'data' 59e92739d3SPeter Tyser * 0 = low, 1 = high 60e92739d3SPeter Tyser */ 61e92739d3SPeter Tyser int pca953x_set_val(uint8_t chip, uint mask, uint data) 62e92739d3SPeter Tyser { 63e92739d3SPeter Tyser return pca953x_reg_write(chip, PCA953X_OUT, mask, data); 64e92739d3SPeter Tyser } 65e92739d3SPeter Tyser 66e92739d3SPeter Tyser /* 67e92739d3SPeter Tyser * Set read polarity of IO pins in 'mask' to corresponding value in 'data' 68e92739d3SPeter Tyser * 0 = read pin value, 1 = read inverted pin value 69e92739d3SPeter Tyser */ 70e92739d3SPeter Tyser int pca953x_set_pol(uint8_t chip, uint mask, uint data) 71e92739d3SPeter Tyser { 72e92739d3SPeter Tyser return pca953x_reg_write(chip, PCA953X_POL, mask, data); 73e92739d3SPeter Tyser } 74e92739d3SPeter Tyser 75e92739d3SPeter Tyser /* 76e92739d3SPeter Tyser * Set direction of IO pins in 'mask' to corresponding value in 'data' 77e92739d3SPeter Tyser * 0 = output, 1 = input 78e92739d3SPeter Tyser */ 79e92739d3SPeter Tyser int pca953x_set_dir(uint8_t chip, uint mask, uint data) 80e92739d3SPeter Tyser { 81e92739d3SPeter Tyser return pca953x_reg_write(chip, PCA953X_CONF, mask, data); 82e92739d3SPeter Tyser } 83e92739d3SPeter Tyser 84e92739d3SPeter Tyser /* 85e92739d3SPeter Tyser * Read current logic level of all IO pins 86e92739d3SPeter Tyser */ 87e92739d3SPeter Tyser int pca953x_get_val(uint8_t chip) 88e92739d3SPeter Tyser { 89e92739d3SPeter Tyser uint8_t val; 90e92739d3SPeter Tyser 91e92739d3SPeter Tyser if (i2c_read(chip, 0, 1, &val, 1)) 92e92739d3SPeter Tyser return -1; 93e92739d3SPeter Tyser 94e92739d3SPeter Tyser return (int)val; 95e92739d3SPeter Tyser } 96e92739d3SPeter Tyser 97e92739d3SPeter Tyser #ifdef CONFIG_CMD_PCA953X 98e92739d3SPeter Tyser #ifdef CONFIG_CMD_PCA953X_INFO 99e92739d3SPeter Tyser /* 100e92739d3SPeter Tyser * Display pca953x information 101e92739d3SPeter Tyser */ 102e92739d3SPeter Tyser static int pca953x_info(uint8_t chip) 103e92739d3SPeter Tyser { 104e92739d3SPeter Tyser int i; 105e92739d3SPeter Tyser uint8_t data; 106e92739d3SPeter Tyser 107e92739d3SPeter Tyser printf("pca953x@ 0x%x:\n\n", chip); 108e92739d3SPeter Tyser printf("gpio pins: 76543210\n"); 109e92739d3SPeter Tyser printf("-------------------\n"); 110e92739d3SPeter Tyser 111e92739d3SPeter Tyser if (i2c_read(chip, PCA953X_CONF, 1, &data, 1)) 112e92739d3SPeter Tyser return -1; 113e92739d3SPeter Tyser printf("conf: "); 114e92739d3SPeter Tyser for (i = 7; i >= 0; i--) 115e92739d3SPeter Tyser printf("%c", data & (1 << i) ? 'i' : 'o'); 116e92739d3SPeter Tyser printf("\n"); 117e92739d3SPeter Tyser 118e92739d3SPeter Tyser if (i2c_read(chip, PCA953X_POL, 1, &data, 1)) 119e92739d3SPeter Tyser return -1; 120e92739d3SPeter Tyser printf("invert: "); 121e92739d3SPeter Tyser for (i = 7; i >= 0; i--) 122e92739d3SPeter Tyser printf("%c", data & (1 << i) ? '1' : '0'); 123e92739d3SPeter Tyser printf("\n"); 124e92739d3SPeter Tyser 125e92739d3SPeter Tyser if (i2c_read(chip, PCA953X_IN, 1, &data, 1)) 126e92739d3SPeter Tyser return -1; 127e92739d3SPeter Tyser printf("input: "); 128e92739d3SPeter Tyser for (i = 7; i >= 0; i--) 129e92739d3SPeter Tyser printf("%c", data & (1 << i) ? '1' : '0'); 130e92739d3SPeter Tyser printf("\n"); 131e92739d3SPeter Tyser 132e92739d3SPeter Tyser if (i2c_read(chip, PCA953X_OUT, 1, &data, 1)) 133e92739d3SPeter Tyser return -1; 134e92739d3SPeter Tyser printf("output: "); 135e92739d3SPeter Tyser for (i = 7; i >= 0; i--) 136e92739d3SPeter Tyser printf("%c", data & (1 << i) ? '1' : '0'); 137e92739d3SPeter Tyser printf("\n"); 138e92739d3SPeter Tyser 139e92739d3SPeter Tyser return 0; 140e92739d3SPeter Tyser } 141e92739d3SPeter Tyser #endif /* CONFIG_CMD_PCA953X_INFO */ 142e92739d3SPeter Tyser 143e92739d3SPeter Tyser cmd_tbl_t cmd_pca953x[] = { 144e92739d3SPeter Tyser U_BOOT_CMD_MKENT(device, 3, 0, (void *)PCA953X_CMD_DEVICE, "", ""), 145e92739d3SPeter Tyser U_BOOT_CMD_MKENT(output, 4, 0, (void *)PCA953X_CMD_OUTPUT, "", ""), 146e92739d3SPeter Tyser U_BOOT_CMD_MKENT(input, 3, 0, (void *)PCA953X_CMD_INPUT, "", ""), 147e92739d3SPeter Tyser U_BOOT_CMD_MKENT(invert, 4, 0, (void *)PCA953X_CMD_INVERT, "", ""), 148e92739d3SPeter Tyser #ifdef CONFIG_CMD_PCA953X_INFO 149e92739d3SPeter Tyser U_BOOT_CMD_MKENT(info, 2, 0, (void *)PCA953X_CMD_INFO, "", ""), 150e92739d3SPeter Tyser #endif 151e92739d3SPeter Tyser }; 152e92739d3SPeter Tyser 153e92739d3SPeter Tyser int do_pca953x(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 154e92739d3SPeter Tyser { 155e92739d3SPeter Tyser static uint8_t chip = CONFIG_SYS_I2C_PCA953X_ADDR; 156e92739d3SPeter Tyser int val; 157e92739d3SPeter Tyser ulong ul_arg2 = 0; 158e92739d3SPeter Tyser ulong ul_arg3 = 0; 159e92739d3SPeter Tyser cmd_tbl_t *c; 160e92739d3SPeter Tyser 161e92739d3SPeter Tyser c = find_cmd_tbl(argv[1], cmd_pca953x, ARRAY_SIZE(cmd_pca953x)); 162e92739d3SPeter Tyser 163e92739d3SPeter Tyser /* All commands but "device" require 'maxargs' arguments */ 164e92739d3SPeter Tyser if (!c || !((argc == (c->maxargs)) || 165e92739d3SPeter Tyser (((int)c->cmd == PCA953X_CMD_DEVICE) && 166e92739d3SPeter Tyser (argc == (c->maxargs - 1))))) { 16762c3ae7cSPeter Tyser cmd_usage(cmdtp); 168e92739d3SPeter Tyser return 1; 169e92739d3SPeter Tyser } 170e92739d3SPeter Tyser 171e92739d3SPeter Tyser /* arg2 used as chip number or pin number */ 172e92739d3SPeter Tyser if (argc > 2) 173e92739d3SPeter Tyser ul_arg2 = simple_strtoul(argv[2], NULL, 16); 174e92739d3SPeter Tyser 175e92739d3SPeter Tyser /* arg3 used as pin or invert value */ 176e92739d3SPeter Tyser if (argc > 3) 177e92739d3SPeter Tyser ul_arg3 = simple_strtoul(argv[3], NULL, 16) & 0x1; 178e92739d3SPeter Tyser 179e92739d3SPeter Tyser switch ((int)c->cmd) { 180e92739d3SPeter Tyser #ifdef CONFIG_CMD_PCA953X_INFO 181e92739d3SPeter Tyser case PCA953X_CMD_INFO: 182e92739d3SPeter Tyser return pca953x_info(chip); 183e92739d3SPeter Tyser #endif 184e92739d3SPeter Tyser case PCA953X_CMD_DEVICE: 185e92739d3SPeter Tyser if (argc == 3) 186e92739d3SPeter Tyser chip = (uint8_t)ul_arg2; 187e92739d3SPeter Tyser printf("Current device address: 0x%x\n", chip); 188e92739d3SPeter Tyser return 0; 189e92739d3SPeter Tyser case PCA953X_CMD_INPUT: 190e92739d3SPeter Tyser pca953x_set_dir(chip, (1 << ul_arg2), 191e92739d3SPeter Tyser PCA953X_DIR_IN << ul_arg2); 192e92739d3SPeter Tyser val = (pca953x_get_val(chip) & (1 << ul_arg2)) != 0; 193e92739d3SPeter Tyser 194e92739d3SPeter Tyser printf("chip 0x%02x, pin 0x%lx = %d\n", chip, ul_arg2, val); 195e92739d3SPeter Tyser return val; 196e92739d3SPeter Tyser case PCA953X_CMD_OUTPUT: 197e92739d3SPeter Tyser pca953x_set_dir(chip, (1 << ul_arg2), 198e92739d3SPeter Tyser (PCA953X_DIR_OUT << ul_arg2)); 199e92739d3SPeter Tyser return pca953x_set_val(chip, (1 << ul_arg2), 200e92739d3SPeter Tyser (ul_arg3 << ul_arg2)); 201e92739d3SPeter Tyser case PCA953X_CMD_INVERT: 202e92739d3SPeter Tyser return pca953x_set_pol(chip, (1 << ul_arg2), 203e92739d3SPeter Tyser (ul_arg3 << ul_arg2)); 204e92739d3SPeter Tyser default: 205e92739d3SPeter Tyser /* We should never get here */ 206e92739d3SPeter Tyser return 1; 207e92739d3SPeter Tyser } 208e92739d3SPeter Tyser } 209e92739d3SPeter Tyser 210e92739d3SPeter Tyser U_BOOT_CMD( 211e92739d3SPeter Tyser pca953x, 5, 1, do_pca953x, 2122fb2604dSPeter Tyser "pca953x gpio access", 213e92739d3SPeter Tyser "device [dev]\n" 214e92739d3SPeter Tyser " - show or set current device address\n" 215e92739d3SPeter Tyser #ifdef CONFIG_CMD_PCA953X_INFO 216e92739d3SPeter Tyser "pca953x info\n" 217e92739d3SPeter Tyser " - display info for current chip\n" 218e92739d3SPeter Tyser #endif 219e92739d3SPeter Tyser "pca953x output pin 0|1\n" 220e92739d3SPeter Tyser " - set pin as output and drive low or high\n" 221e92739d3SPeter Tyser "pca953x invert pin 0|1\n" 222e92739d3SPeter Tyser " - disable/enable polarity inversion for reads\n" 223e92739d3SPeter Tyser "pca953x intput pin\n" 224*a89c33dbSWolfgang Denk " - set pin as input and read value" 225e92739d3SPeter Tyser ); 226e92739d3SPeter Tyser 227e92739d3SPeter Tyser #endif /* CONFIG_CMD_PCA953X */ 228