- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * Version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0
- * Driver for NXP's 4 and 8 bit I2C gpio expanders (eg pca9537, pca9557, etc)
- * TODO: support additional devices with more than 8-bits GPIO
+ * Driver for NXP's 4, 8 and 16 bit I2C gpio expanders (eg pca9537, pca9557,
+ * pca9539, etc)
+#ifdef CONFIG_SYS_I2C_PCA953X_WIDTH
+struct pca953x_chip_ngpio {
+ uint8_t chip;
+ uint8_t ngpio;
+};
+
+static struct pca953x_chip_ngpio pca953x_chip_ngpios[] =
+ CONFIG_SYS_I2C_PCA953X_WIDTH;
+
+/*
+ * Determine the number of GPIO pins supported. If we don't know we assume
+ * 8 pins.
+ */
+static int pca953x_ngpio(uint8_t chip)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pca953x_chip_ngpios); i++)
+ if (pca953x_chip_ngpios[i].chip == chip)
+ return pca953x_chip_ngpios[i].ngpio;
+
+ return 8;
+}
+#else
+static int pca953x_ngpio(uint8_t chip)
+{
+ return 8;
+}
+#endif
+
/*
* Modify masked bits in register
*/
static int pca953x_reg_write(uint8_t chip, uint addr, uint mask, uint data)
{
/*
* Modify masked bits in register
*/
static int pca953x_reg_write(uint8_t chip, uint addr, uint mask, uint data)
{
- if (i2c_read(chip, addr, 1, &val, 1))
- return -1;
+ if (pca953x_ngpio(chip) <= 8) {
+ if (i2c_read(chip, addr, 1, &valb, 1))
+ return -1;
+
+ valb &= ~mask;
+ valb |= data;
+
+ return i2c_write(chip, addr, 1, &valb, 1);
+ } else {
+ if (i2c_read(chip, addr << 1, 1, (u8*)&valw, 2))
+ return -1;
- return i2c_write(chip, addr, 1, &val, 1);
+ return i2c_write(chip, addr << 1, 1, (u8*)&valw, 2);
+ }
+}
+
+static int pca953x_reg_read(uint8_t chip, uint addr, uint *data)
+{
+ uint8_t valb;
+ uint16_t valw;
+
+ if (pca953x_ngpio(chip) <= 8) {
+ if (i2c_read(chip, addr, 1, &valb, 1))
+ return -1;
+ *data = (int)valb;
+ } else {
+ if (i2c_read(chip, addr << 1, 1, (u8*)&valw, 2))
+ return -1;
+ *data = (uint)le16_to_cpu(valw);
+ }
+ return 0;
- if (i2c_read(chip, 0, 1, &val, 1))
+ if (pca953x_reg_read(chip, PCA953X_IN, &val) < 0)
- printf("pca953x@ 0x%x:\n\n", chip);
- printf("gpio pins: 76543210\n");
- printf("-------------------\n");
+ printf("pca953x@ 0x%x (%d pins):\n\n", chip, nr_gpio);
+ printf("gpio pins: ");
+ for (i = msb; i >= 0; i--)
+ printf("%x", i);
+ printf("\n");
+ for (i = 11 + nr_gpio; i > 0; i--)
+ printf("-");
+ printf("\n");
- if (i2c_read(chip, PCA953X_CONF, 1, &data, 1))
+ if (pca953x_reg_read(chip, PCA953X_CONF, &data) < 0)
- if (i2c_read(chip, PCA953X_POL, 1, &data, 1))
+ if (pca953x_reg_read(chip, PCA953X_POL, &data) < 0)
- if (i2c_read(chip, PCA953X_IN, 1, &data, 1))
+ if (pca953x_reg_read(chip, PCA953X_IN, &data) < 0)
- if (i2c_read(chip, PCA953X_OUT, 1, &data, 1))
+ if (pca953x_reg_read(chip, PCA953X_OUT, &data) < 0)
cmd_tbl_t cmd_pca953x[] = {
U_BOOT_CMD_MKENT(device, 3, 0, (void *)PCA953X_CMD_DEVICE, "", ""),
U_BOOT_CMD_MKENT(output, 4, 0, (void *)PCA953X_CMD_OUTPUT, "", ""),
U_BOOT_CMD_MKENT(input, 3, 0, (void *)PCA953X_CMD_INPUT, "", ""),
U_BOOT_CMD_MKENT(invert, 4, 0, (void *)PCA953X_CMD_INVERT, "", ""),
cmd_tbl_t cmd_pca953x[] = {
U_BOOT_CMD_MKENT(device, 3, 0, (void *)PCA953X_CMD_DEVICE, "", ""),
U_BOOT_CMD_MKENT(output, 4, 0, (void *)PCA953X_CMD_OUTPUT, "", ""),
U_BOOT_CMD_MKENT(input, 3, 0, (void *)PCA953X_CMD_INPUT, "", ""),
U_BOOT_CMD_MKENT(invert, 4, 0, (void *)PCA953X_CMD_INVERT, "", ""),
U_BOOT_CMD_MKENT(info, 2, 0, (void *)PCA953X_CMD_INFO, "", ""),
U_BOOT_CMD_MKENT(info, 2, 0, (void *)PCA953X_CMD_INFO, "", ""),
-int do_pca953x(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+int do_pca953x(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
- printf("chip 0x%02x, pin 0x%lx = %d\n", chip, ul_arg2, val);
- return val;
+ if (ret)
+ ret = CMD_RET_FAILURE;
+ else
+ printf("chip 0x%02x, pin 0x%lx = %d\n", chip, ul_arg2,
+ val);
+ break;
+
"pca953x output pin 0|1\n"
" - set pin as output and drive low or high\n"
"pca953x invert pin 0|1\n"
" - disable/enable polarity inversion for reads\n"
"pca953x output pin 0|1\n"
" - set pin as output and drive low or high\n"
"pca953x invert pin 0|1\n"
" - disable/enable polarity inversion for reads\n"