linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 01/01] gpio: support pca9574 and pca9575
       [not found] <2011041802>
@ 2011-04-18 14:12 ` Haojian Zhuang
  2011-05-26 20:00   ` Grant Likely
  0 siblings, 1 reply; 2+ messages in thread
From: Haojian Zhuang @ 2011-04-18 14:12 UTC (permalink / raw)
  To: haojian.zhuang, linux-kernel, linux; +Cc: Haojian Zhuang, Grant Likely

PCA957x is i2c gpio expander, and similar to PCA953x. Although register
configurations are different between PCA957x and PCA953x. They can share
a lot of components, such as IRQ handling, GPIO IN/OUT. So updating PCA953x
driver to support PCA957x chips.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
 drivers/gpio/pca953x.c |  249 +++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 191 insertions(+), 58 deletions(-)

diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index b473429..0de208f 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -24,33 +24,46 @@
 #include <linux/of_gpio.h>
 #endif
 
-#define PCA953X_INPUT          0
-#define PCA953X_OUTPUT         1
-#define PCA953X_INVERT         2
-#define PCA953X_DIRECTION      3
-
-#define PCA953X_GPIOS	       0x00FF
-#define PCA953X_INT	       0x0100
+#define PCA953X_INPUT		0
+#define PCA953X_OUTPUT		1
+#define PCA953X_INVERT		2
+#define PCA953X_DIRECTION	3
+
+#define PCA957X_IN		0
+#define PCA957X_INVRT		1
+#define PCA957X_BKEN		2
+#define PCA957X_PUPD		3
+#define PCA957X_CFG		4
+#define PCA957X_OUT		5
+#define PCA957X_MSK		6
+#define PCA957X_INTS		7
+
+#define PCA_GPIO_MASK		0x00FF
+#define PCA_INT			0x0100
+#define PCA953X_TYPE		0x1000
+#define PCA957X_TYPE		0x2000
 
 static const struct i2c_device_id pca953x_id[] = {
-	{ "pca9534", 8  | PCA953X_INT, },
-	{ "pca9535", 16 | PCA953X_INT, },
-	{ "pca9536", 4, },
-	{ "pca9537", 4  | PCA953X_INT, },
-	{ "pca9538", 8  | PCA953X_INT, },
-	{ "pca9539", 16 | PCA953X_INT, },
-	{ "pca9554", 8  | PCA953X_INT, },
-	{ "pca9555", 16 | PCA953X_INT, },
-	{ "pca9556", 8, },
-	{ "pca9557", 8, },
-
-	{ "max7310", 8, },
-	{ "max7312", 16 | PCA953X_INT, },
-	{ "max7313", 16 | PCA953X_INT, },
-	{ "max7315", 8  | PCA953X_INT, },
-	{ "pca6107", 8  | PCA953X_INT, },
-	{ "tca6408", 8  | PCA953X_INT, },
-	{ "tca6416", 16 | PCA953X_INT, },
+	{ "pca9534", 8  | PCA953X_TYPE | PCA_INT, },
+	{ "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
+	{ "pca9536", 4  | PCA953X_TYPE, },
+	{ "pca9537", 4  | PCA953X_TYPE | PCA_INT, },
+	{ "pca9538", 8  | PCA953X_TYPE | PCA_INT, },
+	{ "pca9539", 16 | PCA953X_TYPE | PCA_INT, },
+	{ "pca9554", 8  | PCA953X_TYPE | PCA_INT, },
+	{ "pca9555", 16 | PCA953X_TYPE | PCA_INT, },
+	{ "pca9556", 8  | PCA953X_TYPE, },
+	{ "pca9557", 8  | PCA953X_TYPE, },
+	{ "pca9574", 8  | PCA957X_TYPE | PCA_INT, },
+	{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
+
+	{ "max7310", 8  | PCA953X_TYPE, },
+	{ "max7312", 16 | PCA953X_TYPE | PCA_INT, },
+	{ "max7313", 16 | PCA953X_TYPE | PCA_INT, },
+	{ "max7315", 8  | PCA953X_TYPE | PCA_INT, },
+	{ "pca6107", 8  | PCA953X_TYPE | PCA_INT, },
+	{ "tca6408", 8  | PCA953X_TYPE | PCA_INT, },
+	{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
 	/* NYET:  { "tca6424", 24, }, */
 	{ }
 };
@@ -75,16 +88,32 @@ struct pca953x_chip {
 	struct pca953x_platform_data *dyn_pdata;
 	struct gpio_chip gpio_chip;
 	const char *const *names;
+	int	chip_type;
 };
 
 static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
 {
-	int ret;
+	int ret = 0;
 
 	if (chip->gpio_chip.ngpio <= 8)
 		ret = i2c_smbus_write_byte_data(chip->client, reg, val);
-	else
-		ret = i2c_smbus_write_word_data(chip->client, reg << 1, val);
+	else {
+		switch (chip->chip_type) {
+		case PCA953X_TYPE:
+			ret = i2c_smbus_write_word_data(chip->client,
+							reg << 1, val);
+			break;
+		case PCA957X_TYPE:
+			ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
+							val & 0xff);
+			if (ret < 0)
+				break;
+			ret = i2c_smbus_write_byte_data(chip->client,
+							(reg << 1) + 1,
+							(val & 0xff00) >> 8);
+			break;
+		}
+	}
 
 	if (ret < 0) {
 		dev_err(&chip->client->dev, "failed writing register\n");
@@ -116,13 +145,22 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 {
 	struct pca953x_chip *chip;
 	uint16_t reg_val;
-	int ret;
+	int ret, offset = 0;
 
 	chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
 	mutex_lock(&chip->i2c_lock);
 	reg_val = chip->reg_direction | (1u << off);
-	ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
+
+	switch (chip->chip_type) {
+	case PCA953X_TYPE:
+		offset = PCA953X_DIRECTION;
+		break;
+	case PCA957X_TYPE:
+		offset = PCA957X_CFG;
+		break;
+	}
+	ret = pca953x_write_reg(chip, offset, reg_val);
 	if (ret)
 		goto exit;
 
@@ -138,7 +176,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 {
 	struct pca953x_chip *chip;
 	uint16_t reg_val;
-	int ret;
+	int ret, offset = 0;
 
 	chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
@@ -149,7 +187,15 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 	else
 		reg_val = chip->reg_output & ~(1u << off);
 
-	ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
+	switch (chip->chip_type) {
+	case PCA953X_TYPE:
+		offset = PCA953X_OUTPUT;
+		break;
+	case PCA957X_TYPE:
+		offset = PCA957X_OUT;
+		break;
+	}
+	ret = pca953x_write_reg(chip, offset, reg_val);
 	if (ret)
 		goto exit;
 
@@ -157,7 +203,15 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 
 	/* then direction */
 	reg_val = chip->reg_direction & ~(1u << off);
-	ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
+	switch (chip->chip_type) {
+	case PCA953X_TYPE:
+		offset = PCA953X_DIRECTION;
+		break;
+	case PCA957X_TYPE:
+		offset = PCA957X_CFG;
+		break;
+	}
+	ret = pca953x_write_reg(chip, offset, reg_val);
 	if (ret)
 		goto exit;
 
@@ -172,12 +226,20 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 {
 	struct pca953x_chip *chip;
 	uint16_t reg_val;
-	int ret;
+	int ret, offset = 0;
 
 	chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
 	mutex_lock(&chip->i2c_lock);
-	ret = pca953x_read_reg(chip, PCA953X_INPUT, &reg_val);
+	switch (chip->chip_type) {
+	case PCA953X_TYPE:
+		offset = PCA953X_INPUT;
+		break;
+	case PCA957X_TYPE:
+		offset = PCA957X_IN;
+		break;
+	}
+	ret = pca953x_read_reg(chip, offset, &reg_val);
 	mutex_unlock(&chip->i2c_lock);
 	if (ret < 0) {
 		/* NOTE:  diagnostic already emitted; that's all we should
@@ -194,7 +256,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 {
 	struct pca953x_chip *chip;
 	uint16_t reg_val;
-	int ret;
+	int ret, offset = 0;
 
 	chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
@@ -204,7 +266,15 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 	else
 		reg_val = chip->reg_output & ~(1u << off);
 
-	ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
+	switch (chip->chip_type) {
+	case PCA953X_TYPE:
+		offset = PCA953X_OUTPUT;
+		break;
+	case PCA957X_TYPE:
+		offset = PCA957X_OUT;
+		break;
+	}
+	ret = pca953x_write_reg(chip, offset, reg_val);
 	if (ret)
 		goto exit;
 
@@ -322,9 +392,17 @@ static uint16_t pca953x_irq_pending(struct pca953x_chip *chip)
 	uint16_t old_stat;
 	uint16_t pending;
 	uint16_t trigger;
-	int ret;
-
-	ret = pca953x_read_reg(chip, PCA953X_INPUT, &cur_stat);
+	int ret, offset = 0;
+
+	switch (chip->chip_type) {
+	case PCA953X_TYPE:
+		offset = PCA953X_INPUT;
+		break;
+	case PCA957X_TYPE:
+		offset = PCA957X_IN;
+		break;
+	}
+	ret = pca953x_read_reg(chip, offset, &cur_stat);
 	if (ret)
 		return 0;
 
@@ -372,14 +450,21 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 {
 	struct i2c_client *client = chip->client;
 	struct pca953x_platform_data *pdata = client->dev.platform_data;
-	int ret;
+	int ret, offset = 0;
 
 	if (pdata->irq_base != -1
-			&& (id->driver_data & PCA953X_INT)) {
+			&& (id->driver_data & PCA_INT)) {
 		int lvl;
 
-		ret = pca953x_read_reg(chip, PCA953X_INPUT,
-				       &chip->irq_stat);
+		switch (chip->chip_type) {
+		case PCA953X_TYPE:
+			offset = PCA953X_INPUT;
+			break;
+		case PCA957X_TYPE:
+			offset = PCA957X_IN;
+			break;
+		}
+		ret = pca953x_read_reg(chip, offset, &chip->irq_stat);
 		if (ret)
 			goto out_failed;
 
@@ -439,7 +524,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 	struct i2c_client *client = chip->client;
 	struct pca953x_platform_data *pdata = client->dev.platform_data;
 
-	if (pdata->irq_base != -1 && (id->driver_data & PCA953X_INT))
+	if (pdata->irq_base != -1 && (id->driver_data & PCA_INT))
 		dev_warn(&client->dev, "interrupt support not compiled in\n");
 
 	return 0;
@@ -498,12 +583,65 @@ pca953x_get_alt_pdata(struct i2c_client *client)
 }
 #endif
 
+static int __devinit device_pca953x_init(struct pca953x_chip *chip, int invert)
+{
+	int ret;
+
+	ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
+	if (ret)
+		goto out;
+
+	ret = pca953x_read_reg(chip, PCA953X_DIRECTION,
+			       &chip->reg_direction);
+	if (ret)
+		goto out;
+
+	/* set platform specific polarity inversion */
+	ret = pca953x_write_reg(chip, PCA953X_INVERT, invert);
+	if (ret)
+		goto out;
+	return 0;
+out:
+	return ret;
+}
+
+static int __devinit device_pca957x_init(struct pca953x_chip *chip, int invert)
+{
+	int ret;
+	uint16_t val = 0;
+
+	/* Let every port in proper state, that could save power */
+	pca953x_write_reg(chip, PCA957X_PUPD, 0x0);
+	pca953x_write_reg(chip, PCA957X_CFG, 0xffff);
+	pca953x_write_reg(chip, PCA957X_OUT, 0x0);
+
+	ret = pca953x_read_reg(chip, PCA957X_IN, &val);
+	if (ret)
+		goto out;
+	ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output);
+	if (ret)
+		goto out;
+	ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction);
+	if (ret)
+		goto out;
+
+	/* set platform specific polarity inversion */
+	pca953x_write_reg(chip, PCA957X_INVRT, invert);
+
+	/* To enable register 6, 7 to controll pull up and pull down */
+	pca953x_write_reg(chip, PCA957X_BKEN, 0x202);
+
+	return 0;
+out:
+	return ret;
+}
+
 static int __devinit pca953x_probe(struct i2c_client *client,
 				   const struct i2c_device_id *id)
 {
 	struct pca953x_platform_data *pdata;
 	struct pca953x_chip *chip;
-	int ret;
+	int ret = 0;
 
 	chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
 	if (chip == NULL)
@@ -530,25 +668,20 @@ static int __devinit pca953x_probe(struct i2c_client *client,
 	chip->gpio_start = pdata->gpio_base;
 
 	chip->names = pdata->names;
+	chip->chip_type = id->driver_data & (PCA953X_TYPE | PCA957X_TYPE);
 
 	mutex_init(&chip->i2c_lock);
 
 	/* initialize cached registers from their original values.
 	 * we can't share this chip with another i2c master.
 	 */
-	pca953x_setup_gpio(chip, id->driver_data & PCA953X_GPIOS);
+	pca953x_setup_gpio(chip, id->driver_data & PCA_GPIO_MASK);
 
-	ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
-	if (ret)
-		goto out_failed;
-
-	ret = pca953x_read_reg(chip, PCA953X_DIRECTION, &chip->reg_direction);
-	if (ret)
-		goto out_failed;
-
-	/* set platform specific polarity inversion */
-	ret = pca953x_write_reg(chip, PCA953X_INVERT, pdata->invert);
-	if (ret)
+	if (chip->chip_type == PCA953X_TYPE)
+		device_pca953x_init(chip, pdata->invert);
+	else if (chip->chip_type == PCA957X_TYPE)
+		device_pca957x_init(chip, pdata->invert);
+	else
 		goto out_failed;
 
 	ret = pca953x_irq_setup(chip, id);
-- 
1.5.6.5


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH 01/01] gpio: support pca9574 and pca9575
  2011-04-18 14:12 ` [PATCH 01/01] gpio: support pca9574 and pca9575 Haojian Zhuang
@ 2011-05-26 20:00   ` Grant Likely
  0 siblings, 0 replies; 2+ messages in thread
From: Grant Likely @ 2011-05-26 20:00 UTC (permalink / raw)
  To: Haojian Zhuang; +Cc: haojian.zhuang, linux-kernel, linux

On Mon, Apr 18, 2011 at 10:12:46PM +0800, Haojian Zhuang wrote:
> PCA957x is i2c gpio expander, and similar to PCA953x. Although register
> configurations are different between PCA957x and PCA953x. They can share
> a lot of components, such as IRQ handling, GPIO IN/OUT. So updating PCA953x
> driver to support PCA957x chips.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>

Applied, thanks.

g.

> ---
>  drivers/gpio/pca953x.c |  249 +++++++++++++++++++++++++++++++++++++-----------
>  1 files changed, 191 insertions(+), 58 deletions(-)
> 
> diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
> index b473429..0de208f 100644
> --- a/drivers/gpio/pca953x.c
> +++ b/drivers/gpio/pca953x.c
> @@ -24,33 +24,46 @@
>  #include <linux/of_gpio.h>
>  #endif
>  
> -#define PCA953X_INPUT          0
> -#define PCA953X_OUTPUT         1
> -#define PCA953X_INVERT         2
> -#define PCA953X_DIRECTION      3
> -
> -#define PCA953X_GPIOS	       0x00FF
> -#define PCA953X_INT	       0x0100
> +#define PCA953X_INPUT		0
> +#define PCA953X_OUTPUT		1
> +#define PCA953X_INVERT		2
> +#define PCA953X_DIRECTION	3
> +
> +#define PCA957X_IN		0
> +#define PCA957X_INVRT		1
> +#define PCA957X_BKEN		2
> +#define PCA957X_PUPD		3
> +#define PCA957X_CFG		4
> +#define PCA957X_OUT		5
> +#define PCA957X_MSK		6
> +#define PCA957X_INTS		7
> +
> +#define PCA_GPIO_MASK		0x00FF
> +#define PCA_INT			0x0100
> +#define PCA953X_TYPE		0x1000
> +#define PCA957X_TYPE		0x2000
>  
>  static const struct i2c_device_id pca953x_id[] = {
> -	{ "pca9534", 8  | PCA953X_INT, },
> -	{ "pca9535", 16 | PCA953X_INT, },
> -	{ "pca9536", 4, },
> -	{ "pca9537", 4  | PCA953X_INT, },
> -	{ "pca9538", 8  | PCA953X_INT, },
> -	{ "pca9539", 16 | PCA953X_INT, },
> -	{ "pca9554", 8  | PCA953X_INT, },
> -	{ "pca9555", 16 | PCA953X_INT, },
> -	{ "pca9556", 8, },
> -	{ "pca9557", 8, },
> -
> -	{ "max7310", 8, },
> -	{ "max7312", 16 | PCA953X_INT, },
> -	{ "max7313", 16 | PCA953X_INT, },
> -	{ "max7315", 8  | PCA953X_INT, },
> -	{ "pca6107", 8  | PCA953X_INT, },
> -	{ "tca6408", 8  | PCA953X_INT, },
> -	{ "tca6416", 16 | PCA953X_INT, },
> +	{ "pca9534", 8  | PCA953X_TYPE | PCA_INT, },
> +	{ "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
> +	{ "pca9536", 4  | PCA953X_TYPE, },
> +	{ "pca9537", 4  | PCA953X_TYPE | PCA_INT, },
> +	{ "pca9538", 8  | PCA953X_TYPE | PCA_INT, },
> +	{ "pca9539", 16 | PCA953X_TYPE | PCA_INT, },
> +	{ "pca9554", 8  | PCA953X_TYPE | PCA_INT, },
> +	{ "pca9555", 16 | PCA953X_TYPE | PCA_INT, },
> +	{ "pca9556", 8  | PCA953X_TYPE, },
> +	{ "pca9557", 8  | PCA953X_TYPE, },
> +	{ "pca9574", 8  | PCA957X_TYPE | PCA_INT, },
> +	{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
> +
> +	{ "max7310", 8  | PCA953X_TYPE, },
> +	{ "max7312", 16 | PCA953X_TYPE | PCA_INT, },
> +	{ "max7313", 16 | PCA953X_TYPE | PCA_INT, },
> +	{ "max7315", 8  | PCA953X_TYPE | PCA_INT, },
> +	{ "pca6107", 8  | PCA953X_TYPE | PCA_INT, },
> +	{ "tca6408", 8  | PCA953X_TYPE | PCA_INT, },
> +	{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
>  	/* NYET:  { "tca6424", 24, }, */
>  	{ }
>  };
> @@ -75,16 +88,32 @@ struct pca953x_chip {
>  	struct pca953x_platform_data *dyn_pdata;
>  	struct gpio_chip gpio_chip;
>  	const char *const *names;
> +	int	chip_type;
>  };
>  
>  static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
>  {
> -	int ret;
> +	int ret = 0;
>  
>  	if (chip->gpio_chip.ngpio <= 8)
>  		ret = i2c_smbus_write_byte_data(chip->client, reg, val);
> -	else
> -		ret = i2c_smbus_write_word_data(chip->client, reg << 1, val);
> +	else {
> +		switch (chip->chip_type) {
> +		case PCA953X_TYPE:
> +			ret = i2c_smbus_write_word_data(chip->client,
> +							reg << 1, val);
> +			break;
> +		case PCA957X_TYPE:
> +			ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
> +							val & 0xff);
> +			if (ret < 0)
> +				break;
> +			ret = i2c_smbus_write_byte_data(chip->client,
> +							(reg << 1) + 1,
> +							(val & 0xff00) >> 8);
> +			break;
> +		}
> +	}
>  
>  	if (ret < 0) {
>  		dev_err(&chip->client->dev, "failed writing register\n");
> @@ -116,13 +145,22 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
>  {
>  	struct pca953x_chip *chip;
>  	uint16_t reg_val;
> -	int ret;
> +	int ret, offset = 0;
>  
>  	chip = container_of(gc, struct pca953x_chip, gpio_chip);
>  
>  	mutex_lock(&chip->i2c_lock);
>  	reg_val = chip->reg_direction | (1u << off);
> -	ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
> +
> +	switch (chip->chip_type) {
> +	case PCA953X_TYPE:
> +		offset = PCA953X_DIRECTION;
> +		break;
> +	case PCA957X_TYPE:
> +		offset = PCA957X_CFG;
> +		break;
> +	}
> +	ret = pca953x_write_reg(chip, offset, reg_val);
>  	if (ret)
>  		goto exit;
>  
> @@ -138,7 +176,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
>  {
>  	struct pca953x_chip *chip;
>  	uint16_t reg_val;
> -	int ret;
> +	int ret, offset = 0;
>  
>  	chip = container_of(gc, struct pca953x_chip, gpio_chip);
>  
> @@ -149,7 +187,15 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
>  	else
>  		reg_val = chip->reg_output & ~(1u << off);
>  
> -	ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
> +	switch (chip->chip_type) {
> +	case PCA953X_TYPE:
> +		offset = PCA953X_OUTPUT;
> +		break;
> +	case PCA957X_TYPE:
> +		offset = PCA957X_OUT;
> +		break;
> +	}
> +	ret = pca953x_write_reg(chip, offset, reg_val);
>  	if (ret)
>  		goto exit;
>  
> @@ -157,7 +203,15 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
>  
>  	/* then direction */
>  	reg_val = chip->reg_direction & ~(1u << off);
> -	ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
> +	switch (chip->chip_type) {
> +	case PCA953X_TYPE:
> +		offset = PCA953X_DIRECTION;
> +		break;
> +	case PCA957X_TYPE:
> +		offset = PCA957X_CFG;
> +		break;
> +	}
> +	ret = pca953x_write_reg(chip, offset, reg_val);
>  	if (ret)
>  		goto exit;
>  
> @@ -172,12 +226,20 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
>  {
>  	struct pca953x_chip *chip;
>  	uint16_t reg_val;
> -	int ret;
> +	int ret, offset = 0;
>  
>  	chip = container_of(gc, struct pca953x_chip, gpio_chip);
>  
>  	mutex_lock(&chip->i2c_lock);
> -	ret = pca953x_read_reg(chip, PCA953X_INPUT, &reg_val);
> +	switch (chip->chip_type) {
> +	case PCA953X_TYPE:
> +		offset = PCA953X_INPUT;
> +		break;
> +	case PCA957X_TYPE:
> +		offset = PCA957X_IN;
> +		break;
> +	}
> +	ret = pca953x_read_reg(chip, offset, &reg_val);
>  	mutex_unlock(&chip->i2c_lock);
>  	if (ret < 0) {
>  		/* NOTE:  diagnostic already emitted; that's all we should
> @@ -194,7 +256,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
>  {
>  	struct pca953x_chip *chip;
>  	uint16_t reg_val;
> -	int ret;
> +	int ret, offset = 0;
>  
>  	chip = container_of(gc, struct pca953x_chip, gpio_chip);
>  
> @@ -204,7 +266,15 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
>  	else
>  		reg_val = chip->reg_output & ~(1u << off);
>  
> -	ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
> +	switch (chip->chip_type) {
> +	case PCA953X_TYPE:
> +		offset = PCA953X_OUTPUT;
> +		break;
> +	case PCA957X_TYPE:
> +		offset = PCA957X_OUT;
> +		break;
> +	}
> +	ret = pca953x_write_reg(chip, offset, reg_val);
>  	if (ret)
>  		goto exit;
>  
> @@ -322,9 +392,17 @@ static uint16_t pca953x_irq_pending(struct pca953x_chip *chip)
>  	uint16_t old_stat;
>  	uint16_t pending;
>  	uint16_t trigger;
> -	int ret;
> -
> -	ret = pca953x_read_reg(chip, PCA953X_INPUT, &cur_stat);
> +	int ret, offset = 0;
> +
> +	switch (chip->chip_type) {
> +	case PCA953X_TYPE:
> +		offset = PCA953X_INPUT;
> +		break;
> +	case PCA957X_TYPE:
> +		offset = PCA957X_IN;
> +		break;
> +	}
> +	ret = pca953x_read_reg(chip, offset, &cur_stat);
>  	if (ret)
>  		return 0;
>  
> @@ -372,14 +450,21 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
>  {
>  	struct i2c_client *client = chip->client;
>  	struct pca953x_platform_data *pdata = client->dev.platform_data;
> -	int ret;
> +	int ret, offset = 0;
>  
>  	if (pdata->irq_base != -1
> -			&& (id->driver_data & PCA953X_INT)) {
> +			&& (id->driver_data & PCA_INT)) {
>  		int lvl;
>  
> -		ret = pca953x_read_reg(chip, PCA953X_INPUT,
> -				       &chip->irq_stat);
> +		switch (chip->chip_type) {
> +		case PCA953X_TYPE:
> +			offset = PCA953X_INPUT;
> +			break;
> +		case PCA957X_TYPE:
> +			offset = PCA957X_IN;
> +			break;
> +		}
> +		ret = pca953x_read_reg(chip, offset, &chip->irq_stat);
>  		if (ret)
>  			goto out_failed;
>  
> @@ -439,7 +524,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
>  	struct i2c_client *client = chip->client;
>  	struct pca953x_platform_data *pdata = client->dev.platform_data;
>  
> -	if (pdata->irq_base != -1 && (id->driver_data & PCA953X_INT))
> +	if (pdata->irq_base != -1 && (id->driver_data & PCA_INT))
>  		dev_warn(&client->dev, "interrupt support not compiled in\n");
>  
>  	return 0;
> @@ -498,12 +583,65 @@ pca953x_get_alt_pdata(struct i2c_client *client)
>  }
>  #endif
>  
> +static int __devinit device_pca953x_init(struct pca953x_chip *chip, int invert)
> +{
> +	int ret;
> +
> +	ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
> +	if (ret)
> +		goto out;
> +
> +	ret = pca953x_read_reg(chip, PCA953X_DIRECTION,
> +			       &chip->reg_direction);
> +	if (ret)
> +		goto out;
> +
> +	/* set platform specific polarity inversion */
> +	ret = pca953x_write_reg(chip, PCA953X_INVERT, invert);
> +	if (ret)
> +		goto out;
> +	return 0;
> +out:
> +	return ret;
> +}
> +
> +static int __devinit device_pca957x_init(struct pca953x_chip *chip, int invert)
> +{
> +	int ret;
> +	uint16_t val = 0;
> +
> +	/* Let every port in proper state, that could save power */
> +	pca953x_write_reg(chip, PCA957X_PUPD, 0x0);
> +	pca953x_write_reg(chip, PCA957X_CFG, 0xffff);
> +	pca953x_write_reg(chip, PCA957X_OUT, 0x0);
> +
> +	ret = pca953x_read_reg(chip, PCA957X_IN, &val);
> +	if (ret)
> +		goto out;
> +	ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output);
> +	if (ret)
> +		goto out;
> +	ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction);
> +	if (ret)
> +		goto out;
> +
> +	/* set platform specific polarity inversion */
> +	pca953x_write_reg(chip, PCA957X_INVRT, invert);
> +
> +	/* To enable register 6, 7 to controll pull up and pull down */
> +	pca953x_write_reg(chip, PCA957X_BKEN, 0x202);
> +
> +	return 0;
> +out:
> +	return ret;
> +}
> +
>  static int __devinit pca953x_probe(struct i2c_client *client,
>  				   const struct i2c_device_id *id)
>  {
>  	struct pca953x_platform_data *pdata;
>  	struct pca953x_chip *chip;
> -	int ret;
> +	int ret = 0;
>  
>  	chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
>  	if (chip == NULL)
> @@ -530,25 +668,20 @@ static int __devinit pca953x_probe(struct i2c_client *client,
>  	chip->gpio_start = pdata->gpio_base;
>  
>  	chip->names = pdata->names;
> +	chip->chip_type = id->driver_data & (PCA953X_TYPE | PCA957X_TYPE);
>  
>  	mutex_init(&chip->i2c_lock);
>  
>  	/* initialize cached registers from their original values.
>  	 * we can't share this chip with another i2c master.
>  	 */
> -	pca953x_setup_gpio(chip, id->driver_data & PCA953X_GPIOS);
> +	pca953x_setup_gpio(chip, id->driver_data & PCA_GPIO_MASK);
>  
> -	ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
> -	if (ret)
> -		goto out_failed;
> -
> -	ret = pca953x_read_reg(chip, PCA953X_DIRECTION, &chip->reg_direction);
> -	if (ret)
> -		goto out_failed;
> -
> -	/* set platform specific polarity inversion */
> -	ret = pca953x_write_reg(chip, PCA953X_INVERT, pdata->invert);
> -	if (ret)
> +	if (chip->chip_type == PCA953X_TYPE)
> +		device_pca953x_init(chip, pdata->invert);
> +	else if (chip->chip_type == PCA957X_TYPE)
> +		device_pca957x_init(chip, pdata->invert);
> +	else
>  		goto out_failed;
>  
>  	ret = pca953x_irq_setup(chip, id);
> -- 
> 1.5.6.5
> 

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2011-05-26 20:00 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <2011041802>
2011-04-18 14:12 ` [PATCH 01/01] gpio: support pca9574 and pca9575 Haojian Zhuang
2011-05-26 20:00   ` Grant Likely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).