From patchwork Tue Dec 7 22:00:48 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Packham X-Patchwork-Id: 74604 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id CB1FAB70B8 for ; Wed, 8 Dec 2010 09:00:59 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 2208528154; Tue, 7 Dec 2010 23:00:58 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id jFDEnYLxyo1J; Tue, 7 Dec 2010 23:00:57 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 9378128127; Tue, 7 Dec 2010 23:00:55 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 2B8F728127 for ; Tue, 7 Dec 2010 23:00:53 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 2e-96EymD2QC for ; Tue, 7 Dec 2010 23:00:51 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-qw0-f44.google.com (mail-qw0-f44.google.com [209.85.216.44]) by theia.denx.de (Postfix) with ESMTP id 0EE3D28126 for ; Tue, 7 Dec 2010 23:00:49 +0100 (CET) Received: by qwg5 with SMTP id 5so410369qwg.3 for ; Tue, 07 Dec 2010 14:00:48 -0800 (PST) MIME-Version: 1.0 Received: by 10.229.189.72 with SMTP id dd8mr6155769qcb.123.1291759248314; Tue, 07 Dec 2010 14:00:48 -0800 (PST) Received: by 10.229.80.135 with HTTP; Tue, 7 Dec 2010 14:00:48 -0800 (PST) Date: Wed, 8 Dec 2010 11:00:48 +1300 Message-ID: From: Chris Packham To: u-boot@lists.denx.de Cc: Peter Tyser Subject: [U-Boot] [PATCHv2] pca953x: support 16-pin devices X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de This adds support for for the PCA9535/PCA9539 family of gpio devices which have 16 output pins. To let the driver know which devices are 16-pin it is necessary to define CONFIG_SYS_I2C_PCA953X_WIDTH in your board config file. This is used to create an array of {chip, ngpio} tuples that are used to determine the width of a particular chip. For backwards compatibility it is assumed that any chip not defined in CONFIG_SYS_I2C_PCA953X_WIDTH has 8 pins. --- As suggested by Peter I've implemented the 16-pin support in the existing pca953x driver. So this is pretty much a re-write of the v1 patch. Is the commit message sufficient to document CONFIG_SYS_I2C_PCA953X_WIDTH or is there something under doc/ that I should be adding to. drivers/gpio/pca953x.c | 107 ++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 85 insertions(+), 22 deletions(-) diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 6e82bd6..491b79e 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -17,8 +17,8 @@ */ /* - * 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) */ #include @@ -38,22 +38,78 @@ enum { PCA953X_CMD_INVERT, }; +#ifdef CONFIG_SYS_I2C_PCA953X_WIDTH +struct chip_ngpio { + uint8_t chip; + uint8_t ngpio; +}; + +static struct chip_ngpio chip_ngpios[] = CONFIG_SYS_I2C_PCA953X_WIDTH; +#define NUM_CHIP_GPIOS (sizeof(chip_ngpios) / sizeof(struct chip_ngpio)) + +/* + * Determine the number of GPIO pins supported. If we don't know we assume + * 8 pins. + */ +static int ngpio(uint8_t chip) +{ + int i; + + for (i = 0; i < NUM_CHIP_GPIOS; i++) { + if (chip_ngpios[i].chip == chip) + return chip_ngpios[i].ngpio; + } + return 8; +} +#else +#define ngpio(chip) 8 +#endif + /* * Modify masked bits in register */ static int pca953x_reg_write(uint8_t chip, uint addr, uint mask, uint data) { - uint8_t val; + uint8_t valb; + uint16_t valw; - if (i2c_read(chip, addr, 1, &val, 1)) - return -1; + if (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; + + valw &= ~mask; + valw |= data; + + return i2c_write(chip, addr << 1, 1, (u8*)&valw, 2); + } +} - val &= ~mask; - val |= data; +static int pca953x_reg_read(uint8_t chip, uint addr, uint *data) +{ + uint8_t valb; + uint16_t valw; - return i2c_write(chip, addr, 1, &val, 1); + if (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 = (int) valw; + } + return 0; } + /* * Set output value of IO pins in 'mask' to corresponding value in 'data' * 0 = low, 1 = high @@ -86,9 +142,9 @@ int pca953x_set_dir(uint8_t chip, uint mask, uint data) */ int pca953x_get_val(uint8_t chip) { - uint8_t val; + uint val; - if (i2c_read(chip, 0, 1, &val, 1)) + if (pca953x_reg_read(chip, PCA953X_IN, &val) < 0) return -1; return (int)val; @@ -102,37 +158,44 @@ int pca953x_get_val(uint8_t chip) static int pca953x_info(uint8_t chip) { int i; - uint8_t data; + uint data; + int nr_gpio = ngpio(chip); + int msb = nr_gpio - 1; - printf("pca953x@ 0x%x:\n\n", chip); - printf("gpio pins: 76543210\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"); + if (nr_gpio > 8) + printf("--------"); printf("-------------------\n"); - if (i2c_read(chip, PCA953X_CONF, 1, &data, 1)) + if (pca953x_reg_read(chip, PCA953X_CONF, &data) < 0) return -1; printf("conf: "); - for (i = 7; i >= 0; i--) + for (i = msb; i >= 0; i--) printf("%c", data & (1 << i) ? 'i' : 'o'); printf("\n"); - if (i2c_read(chip, PCA953X_POL, 1, &data, 1)) + if (pca953x_reg_read(chip, PCA953X_POL, &data) < 0) return -1; printf("invert: "); - for (i = 7; i >= 0; i--) + for (i = msb; i >= 0; i--) printf("%c", data & (1 << i) ? '1' : '0'); printf("\n"); - if (i2c_read(chip, PCA953X_IN, 1, &data, 1)) + if (pca953x_reg_read(chip, PCA953X_IN, &data) < 0) return -1; printf("input: "); - for (i = 7; i >= 0; i--) + for (i = msb; i >= 0; i--) printf("%c", data & (1 << i) ? '1' : '0'); printf("\n"); - if (i2c_read(chip, PCA953X_OUT, 1, &data, 1)) + if (pca953x_reg_read(chip, PCA953X_OUT, &data) < 0) return -1; printf("output: "); - for (i = 7; i >= 0; i--) + for (i = msb; i >= 0; i--) printf("%c", data & (1 << i) ? '1' : '0'); printf("\n");