All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V2 0/3] Add support for gpio expander pca9505 used on Mirabox
@ 2013-01-07 22:51 ` Gregory CLEMENT
  0 siblings, 0 replies; 16+ messages in thread
From: Gregory CLEMENT @ 2013-01-07 22:51 UTC (permalink / raw)
  To: Linus Walleij, Grant Likely
  Cc: Maxime Ripard, Andreas Schallenberg, Roland Stigge, Jason Cooper,
	Andrew Lunn, Thomas Petazzoni, Sebastian Hesselbarth,
	linux-arm-kernel, linux-kernel, Gregory CLEMENT

Hello,

This patch set adds the support for the i2c gpio expander pca9505 used
on the JTAG/GPIO box which can be connected to the Mirabox.

To be able to use the pca9505 I had to do several changes in the
driver. Indeed, until now the pca953x driver accessed all the bank of
a given register in a single command using only a 32 bits
variable. This expander comes with 40 GPIOs which no more fits in a 32
variable. This patch set makes the accesses to the registers more
generic by relying on an array of u8 variables. This fits exactly the
way the registers are represented in the hardware.

Once the per-bank representation was added, it was easier to introduce
helpers to access to a single register of a bank instead of reading or
writing all the banks for a given register. As the GPIO API allows
only the accesses to a single GPIO at a time there was no point to read
and write all the other banks. Hence it should help to decrease the
latency especially for the pca9505.

However as the block GPIO API from Roland Stigge is incoming I kept
the helpers used to access all the banks in the same time. I had to
make some modifications in the arguments that these functions
received, so it will have a conflict here. Currently my patch set is
based on v3.8-rc2, but I am willing to rebase onto gpio-for-next once
the GPIO block will be merged into it.

I also expected some tested-by as I was only able to test the pca9505
and I didn't test the IRQ part.

After the first feedback from Maxime Ripard I made some change in the
patch set. Now accessing GPIO should work at least on pca9555, and the
driver is compiling when IRQ is enable.

I have also updated the branch gpio-pca9505 available at:
https://github.com/MISL-EBU-System-SW/mainline-public.git

Changelog:
V1->V2:

- Fix the way to calculate the shift used to apply to register to
  access a given bank.
- Fix all the pending issue in the IRQ part which appeared once I have
  enable CONFIG_GPIO_PCA953X_IRQ!


Gregory CLEMENT (3):
  gpio: pca953x: make the register access by GPIO bank
  gpio: pca953x: add support for pca9505
  arm: mvebu: enable gpio expander over i2c on Mirabox platform

 arch/arm/boot/dts/armada-370-mirabox.dts |   10 ++
 drivers/gpio/gpio-pca953x.c              |  283 +++++++++++++++++++-----------
 2 files changed, 187 insertions(+), 106 deletions(-)

-- 
1.7.9.5


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

* [PATCH V2 0/3] Add support for gpio expander pca9505 used on Mirabox
@ 2013-01-07 22:51 ` Gregory CLEMENT
  0 siblings, 0 replies; 16+ messages in thread
From: Gregory CLEMENT @ 2013-01-07 22:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

This patch set adds the support for the i2c gpio expander pca9505 used
on the JTAG/GPIO box which can be connected to the Mirabox.

To be able to use the pca9505 I had to do several changes in the
driver. Indeed, until now the pca953x driver accessed all the bank of
a given register in a single command using only a 32 bits
variable. This expander comes with 40 GPIOs which no more fits in a 32
variable. This patch set makes the accesses to the registers more
generic by relying on an array of u8 variables. This fits exactly the
way the registers are represented in the hardware.

Once the per-bank representation was added, it was easier to introduce
helpers to access to a single register of a bank instead of reading or
writing all the banks for a given register. As the GPIO API allows
only the accesses to a single GPIO at a time there was no point to read
and write all the other banks. Hence it should help to decrease the
latency especially for the pca9505.

However as the block GPIO API from Roland Stigge is incoming I kept
the helpers used to access all the banks in the same time. I had to
make some modifications in the arguments that these functions
received, so it will have a conflict here. Currently my patch set is
based on v3.8-rc2, but I am willing to rebase onto gpio-for-next once
the GPIO block will be merged into it.

I also expected some tested-by as I was only able to test the pca9505
and I didn't test the IRQ part.

After the first feedback from Maxime Ripard I made some change in the
patch set. Now accessing GPIO should work at least on pca9555, and the
driver is compiling when IRQ is enable.

I have also updated the branch gpio-pca9505 available at:
https://github.com/MISL-EBU-System-SW/mainline-public.git

Changelog:
V1->V2:

- Fix the way to calculate the shift used to apply to register to
  access a given bank.
- Fix all the pending issue in the IRQ part which appeared once I have
  enable CONFIG_GPIO_PCA953X_IRQ!


Gregory CLEMENT (3):
  gpio: pca953x: make the register access by GPIO bank
  gpio: pca953x: add support for pca9505
  arm: mvebu: enable gpio expander over i2c on Mirabox platform

 arch/arm/boot/dts/armada-370-mirabox.dts |   10 ++
 drivers/gpio/gpio-pca953x.c              |  283 +++++++++++++++++++-----------
 2 files changed, 187 insertions(+), 106 deletions(-)

-- 
1.7.9.5

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

* [PATCH V2 1/3] gpio: pca953x: make the register access by GPIO bank
  2013-01-07 22:51 ` Gregory CLEMENT
@ 2013-01-07 22:51   ` Gregory CLEMENT
  -1 siblings, 0 replies; 16+ messages in thread
From: Gregory CLEMENT @ 2013-01-07 22:51 UTC (permalink / raw)
  To: Linus Walleij, Grant Likely
  Cc: Maxime Ripard, Andreas Schallenberg, Roland Stigge, Jason Cooper,
	Andrew Lunn, Thomas Petazzoni, Sebastian Hesselbarth,
	linux-arm-kernel, linux-kernel, Gregory CLEMENT

Until now the pca953x driver accessed all the bank of a given register
in a single command using only a 32 bits variable. New expanders from
the pca53x family come with 40 GPIOs which no more fit in a 32
variable. This patch make access to the registers more generic by
relying on an array of u8 variables. This fits exactly the way the
registers are represented in the hardware.

It also adds helpers to access to a single register of a bank instead
of reading or writing all the banks for a given register.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 drivers/gpio/gpio-pca953x.c |  281 +++++++++++++++++++++++++++----------------
 1 file changed, 175 insertions(+), 106 deletions(-)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index cc102d2..544a52f 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -71,18 +71,23 @@ static const struct i2c_device_id pca953x_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, pca953x_id);
 
+#define MAX_BANK 5
+#define BANK_SZ 8
+
+#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ)
+
 struct pca953x_chip {
 	unsigned gpio_start;
-	u32 reg_output;
-	u32 reg_direction;
+	u8 reg_output[MAX_BANK];
+	u8 reg_direction[MAX_BANK];
 	struct mutex i2c_lock;
 
 #ifdef CONFIG_GPIO_PCA953X_IRQ
 	struct mutex irq_lock;
-	u32 irq_mask;
-	u32 irq_stat;
-	u32 irq_trig_raise;
-	u32 irq_trig_fall;
+	u8 irq_mask[MAX_BANK];
+	u8 irq_stat[MAX_BANK];
+	u8 irq_trig_raise[MAX_BANK];
+	u8 irq_trig_fall[MAX_BANK];
 	int	 irq_base;
 	struct irq_domain *domain;
 #endif
@@ -93,33 +98,69 @@ struct pca953x_chip {
 	int	chip_type;
 };
 
-static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
+static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
+				int off)
+{
+	int ret;
+	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+	int offset = off / BANK_SZ;
+
+	ret = i2c_smbus_read_byte_data(chip->client,
+				(reg << bank_shift) + offset);
+	*val = ret;
+
+	if (ret < 0) {
+		dev_err(&chip->client->dev, "failed reading register\n", reg);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val,
+				int off)
+{
+	int ret = 0;
+	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+	int offset = off / BANK_SZ;
+
+	ret = i2c_smbus_write_byte_data(chip->client,
+					(reg << bank_shift) + offset, val);
+
+	if (ret < 0) {
+		dev_err(&chip->client->dev, "failed writing register\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
 {
 	int ret = 0;
 
 	if (chip->gpio_chip.ngpio <= 8)
-		ret = i2c_smbus_write_byte_data(chip->client, reg, val);
-	else if (chip->gpio_chip.ngpio == 24) {
-		cpu_to_le32s(&val);
+		ret = i2c_smbus_write_byte_data(chip->client, reg, *val);
+	else if (chip->gpio_chip.ngpio >= 24) {
+		int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
 		ret = i2c_smbus_write_i2c_block_data(chip->client,
-						(reg << 2) | REG_ADDR_AI,
-						3,
-						(u8 *) &val);
+					(reg << bank_shift) | REG_ADDR_AI,
+					NBANK(chip), val);
 	}
 	else {
 		switch (chip->chip_type) {
 		case PCA953X_TYPE:
 			ret = i2c_smbus_write_word_data(chip->client,
-							reg << 1, val);
+							reg << 1, (u16) *val);
 			break;
 		case PCA957X_TYPE:
 			ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
-							val & 0xff);
+							val[0]);
 			if (ret < 0)
 				break;
 			ret = i2c_smbus_write_byte_data(chip->client,
 							(reg << 1) + 1,
-							(val & 0xff00) >> 8);
+							val[1]);
 			break;
 		}
 	}
@@ -132,26 +173,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
 	return 0;
 }
 
-static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
+static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
 {
 	int ret;
 
 	if (chip->gpio_chip.ngpio <= 8) {
 		ret = i2c_smbus_read_byte_data(chip->client, reg);
 		*val = ret;
-	}
-	else if (chip->gpio_chip.ngpio == 24) {
-		*val = 0;
+	} else if (chip->gpio_chip.ngpio >= 24) {
+		int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+
 		ret = i2c_smbus_read_i2c_block_data(chip->client,
-						(reg << 2) | REG_ADDR_AI,
-						3,
-						(u8 *) val);
-		le32_to_cpus(val);
+					(reg << bank_shift) | REG_ADDR_AI,
+					NBANK(chip), val);
 	} else {
 		ret = i2c_smbus_read_word_data(chip->client, reg << 1);
-		*val = ret;
+		val[0] = (u16)ret & 0xFF;
+		val[1] = (u16)ret >> 8;
 	}
-
 	if (ret < 0) {
 		dev_err(&chip->client->dev, "failed reading register\n");
 		return ret;
@@ -163,13 +202,13 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
 static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 {
 	struct pca953x_chip *chip;
-	uint reg_val;
+	u8 reg_val;
 	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);
+	reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ));
 
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
@@ -179,11 +218,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 		offset = PCA957X_CFG;
 		break;
 	}
-	ret = pca953x_write_reg(chip, offset, reg_val);
+	ret = pca953x_write_single(chip, offset, reg_val, off);
 	if (ret)
 		goto exit;
 
-	chip->reg_direction = reg_val;
+	chip->reg_direction[off / BANK_SZ] = reg_val;
 	ret = 0;
 exit:
 	mutex_unlock(&chip->i2c_lock);
@@ -194,7 +233,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 		unsigned off, int val)
 {
 	struct pca953x_chip *chip;
-	uint reg_val;
+	u8 reg_val;
 	int ret, offset = 0;
 
 	chip = container_of(gc, struct pca953x_chip, gpio_chip);
@@ -202,9 +241,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 	mutex_lock(&chip->i2c_lock);
 	/* set output level */
 	if (val)
-		reg_val = chip->reg_output | (1u << off);
+		reg_val = chip->reg_output[off / BANK_SZ]
+			| (1u << (off % BANK_SZ));
 	else
-		reg_val = chip->reg_output & ~(1u << off);
+		reg_val = chip->reg_output[off / BANK_SZ]
+			& ~(1u << (off % BANK_SZ));
 
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
@@ -214,14 +255,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 		offset = PCA957X_OUT;
 		break;
 	}
-	ret = pca953x_write_reg(chip, offset, reg_val);
+	ret = pca953x_write_single(chip, offset, reg_val, off);
 	if (ret)
 		goto exit;
 
-	chip->reg_output = reg_val;
+	chip->reg_output[off / BANK_SZ] = reg_val;
 
 	/* then direction */
-	reg_val = chip->reg_direction & ~(1u << off);
+	reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ));
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
 		offset = PCA953X_DIRECTION;
@@ -230,11 +271,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 		offset = PCA957X_CFG;
 		break;
 	}
-	ret = pca953x_write_reg(chip, offset, reg_val);
+	ret = pca953x_write_single(chip, offset, reg_val, off);
 	if (ret)
 		goto exit;
 
-	chip->reg_direction = reg_val;
+	chip->reg_direction[off / BANK_SZ] = reg_val;
 	ret = 0;
 exit:
 	mutex_unlock(&chip->i2c_lock);
@@ -258,7 +299,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 		offset = PCA957X_IN;
 		break;
 	}
-	ret = pca953x_read_reg(chip, offset, &reg_val);
+	ret = pca953x_read_single(chip, offset, &reg_val, off);
 	mutex_unlock(&chip->i2c_lock);
 	if (ret < 0) {
 		/* NOTE:  diagnostic already emitted; that's all we should
@@ -274,16 +315,18 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 {
 	struct pca953x_chip *chip;
-	u32 reg_val;
+	u8 reg_val;
 	int ret, offset = 0;
 
 	chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
 	mutex_lock(&chip->i2c_lock);
 	if (val)
-		reg_val = chip->reg_output | (1u << off);
+		reg_val = chip->reg_output[off / BANK_SZ]
+			| (1u << (off % BANK_SZ));
 	else
-		reg_val = chip->reg_output & ~(1u << off);
+		reg_val = chip->reg_output[off / BANK_SZ]
+			& ~(1u << (off % BANK_SZ));
 
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
@@ -293,11 +336,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 		offset = PCA957X_OUT;
 		break;
 	}
-	ret = pca953x_write_reg(chip, offset, reg_val);
+	ret = pca953x_write_single(chip, offset, reg_val, off);
 	if (ret)
 		goto exit;
 
-	chip->reg_output = reg_val;
+	chip->reg_output[off / BANK_SZ] = reg_val;
 exit:
 	mutex_unlock(&chip->i2c_lock);
 }
@@ -335,14 +378,14 @@ static void pca953x_irq_mask(struct irq_data *d)
 {
 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
 
-	chip->irq_mask &= ~(1 << d->hwirq);
+	chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ));
 }
 
 static void pca953x_irq_unmask(struct irq_data *d)
 {
 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
 
-	chip->irq_mask |= 1 << d->hwirq;
+	chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ);
 }
 
 static void pca953x_irq_bus_lock(struct irq_data *d)
@@ -355,17 +398,20 @@ static void pca953x_irq_bus_lock(struct irq_data *d)
 static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 {
 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
-	u32 new_irqs;
-	u32 level;
+	u8 new_irqs;
+	int level, i;
 
 	/* Look for any newly setup interrupt */
-	new_irqs = chip->irq_trig_fall | chip->irq_trig_raise;
-	new_irqs &= ~chip->reg_direction;
-
-	while (new_irqs) {
-		level = __ffs(new_irqs);
-		pca953x_gpio_direction_input(&chip->gpio_chip, level);
-		new_irqs &= ~(1 << level);
+	for (i = 0; i < NBANK(chip); i++) {
+		new_irqs = chip->irq_trig_fall[i] | chip->irq_trig_raise[i];
+		new_irqs &= ~chip->reg_direction[i];
+
+		while (new_irqs) {
+			level = __ffs(new_irqs);
+			pca953x_gpio_direction_input(&chip->gpio_chip,
+							level + (BANK_SZ * i));
+			new_irqs &= ~(1 << level);
+		}
 	}
 
 	mutex_unlock(&chip->irq_lock);
@@ -374,7 +420,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
-	u32 mask = 1 << d->hwirq;
+	int bank_nb = d->hwirq / BANK_SZ;
+	u8 mask = 1 << (d->hwirq % BANK_SZ);
 
 	if (!(type & IRQ_TYPE_EDGE_BOTH)) {
 		dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
@@ -383,14 +430,14 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
 	}
 
 	if (type & IRQ_TYPE_EDGE_FALLING)
-		chip->irq_trig_fall |= mask;
+		chip->irq_trig_fall[bank_nb] |= mask;
 	else
-		chip->irq_trig_fall &= ~mask;
+		chip->irq_trig_fall[bank_nb] &= ~mask;
 
 	if (type & IRQ_TYPE_EDGE_RISING)
-		chip->irq_trig_raise |= mask;
+		chip->irq_trig_raise[bank_nb] |= mask;
 	else
-		chip->irq_trig_raise &= ~mask;
+		chip->irq_trig_raise[bank_nb] &= ~mask;
 
 	return 0;
 }
@@ -404,13 +451,13 @@ static struct irq_chip pca953x_irq_chip = {
 	.irq_set_type		= pca953x_irq_set_type,
 };
 
-static u32 pca953x_irq_pending(struct pca953x_chip *chip)
+static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
 {
-	u32 cur_stat;
-	u32 old_stat;
-	u32 pending;
-	u32 trigger;
-	int ret, offset = 0;
+	u8 cur_stat[MAX_BANK];
+	u8 old_stat[MAX_BANK];
+	u8 pendings = 0;
+	u8 trigger[MAX_BANK], triggers = 0;
+	int ret, i, offset = 0;
 
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
@@ -420,45 +467,54 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip)
 		offset = PCA957X_IN;
 		break;
 	}
-	ret = pca953x_read_reg(chip, offset, &cur_stat);
+	ret = pca953x_read_regs(chip, offset, cur_stat);
 	if (ret)
 		return 0;
 
 	/* Remove output pins from the equation */
-	cur_stat &= chip->reg_direction;
+	for (i = 0; i < NBANK(chip); i++)
+		cur_stat[i] &= chip->reg_direction[i];
 
-	old_stat = chip->irq_stat;
-	trigger = (cur_stat ^ old_stat) & chip->irq_mask;
+	memcpy(old_stat, chip->irq_stat, NBANK(chip));
 
-	if (!trigger)
+	for (i = 0; i < NBANK(chip); i++) {
+		trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
+		triggers += trigger[i];
+	}
+
+	if (!triggers)
 		return 0;
 
-	chip->irq_stat = cur_stat;
+	memcpy(chip->irq_stat, cur_stat, NBANK(chip));
 
-	pending = (old_stat & chip->irq_trig_fall) |
-		  (cur_stat & chip->irq_trig_raise);
-	pending &= trigger;
+	for (i = 0; i < NBANK(chip); i++) {
+		pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
+			(cur_stat[i] & chip->irq_trig_raise[i]);
+		pending[i] &= trigger[i];
+		pendings += pending[i];
+	}
 
-	return pending;
+	return pendings;
 }
 
 static irqreturn_t pca953x_irq_handler(int irq, void *devid)
 {
 	struct pca953x_chip *chip = devid;
-	u32 pending;
-	u32 level;
+	u8 pending[MAX_BANK];
+	u8 level;
+	int i;
 
-	pending = pca953x_irq_pending(chip);
-
-	if (!pending)
+	if (!pca953x_irq_pending(chip, pending))
 		return IRQ_HANDLED;
 
-	do {
-		level = __ffs(pending);
-		handle_nested_irq(irq_find_mapping(chip->domain, level));
-
-		pending &= ~(1 << level);
-	} while (pending);
+	for (i = 0; i < NBANK(chip); i++) {
+		do {
+			level = __ffs(pending[i]);
+			handle_nested_irq(irq_find_mapping(chip->domain,
+							level + (BANK_SZ * i)));
+			pending[i] &= ~(1 << level);
+		} while (pending[i]);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -468,8 +524,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 			     int irq_base)
 {
 	struct i2c_client *client = chip->client;
-	int ret, offset = 0;
-	u32 temporary;
+	int ret, i, offset = 0;
 
 	if (irq_base != -1
 			&& (id->driver_data & PCA_INT)) {
@@ -483,8 +538,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 			offset = PCA957X_IN;
 			break;
 		}
-		ret = pca953x_read_reg(chip, offset, &temporary);
-		chip->irq_stat = temporary;
+		ret = pca953x_read_regs(chip, offset, chip->irq_stat);
 		if (ret)
 			goto out_failed;
 
@@ -493,7 +547,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 		 * interrupt.  We have to rely on the previous read for
 		 * this purpose.
 		 */
-		chip->irq_stat &= chip->reg_direction;
+		for (i = 0; i < NBANK(chip); i++)
+			chip->irq_stat[i] &= chip->reg_direction[i];
 		mutex_init(&chip->irq_lock);
 
 		chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1);
@@ -619,18 +674,24 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
 static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
 {
 	int ret;
+	u8 val[MAX_BANK];
 
-	ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
+	ret = pca953x_read_regs(chip, PCA953X_OUTPUT, chip->reg_output);
 	if (ret)
 		goto out;
 
-	ret = pca953x_read_reg(chip, PCA953X_DIRECTION,
-			       &chip->reg_direction);
+	ret = pca953x_read_regs(chip, PCA953X_DIRECTION,
+			       chip->reg_direction);
 	if (ret)
 		goto out;
 
 	/* set platform specific polarity inversion */
-	ret = pca953x_write_reg(chip, PCA953X_INVERT, invert);
+	if (invert)
+		memset(val, 0xFF, NBANK(chip));
+	else
+		memset(val, 0, NBANK(chip));
+
+	ret = pca953x_write_regs(chip, PCA953X_INVERT, val);
 out:
 	return ret;
 }
@@ -638,28 +699,36 @@ out:
 static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
 {
 	int ret;
-	u32 val = 0;
+	u8 val[MAX_BANK];
 
 	/* 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);
+	memset(val, 0, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_PUPD, val);
+	memset(val, 0xFF, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_CFG, val);
+	memset(val, 0, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_OUT, val);
+
+	ret = pca953x_read_regs(chip, PCA957X_IN, val);
 	if (ret)
 		goto out;
-	ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output);
+	ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output);
 	if (ret)
 		goto out;
-	ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction);
+	ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction);
 	if (ret)
 		goto out;
 
 	/* set platform specific polarity inversion */
-	pca953x_write_reg(chip, PCA957X_INVRT, invert);
+	if (invert)
+		memset(val, 0xFF, NBANK(chip));
+	else
+		memset(val, 0, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_INVRT, val);
 
 	/* To enable register 6, 7 to controll pull up and pull down */
-	pca953x_write_reg(chip, PCA957X_BKEN, 0x202);
+	memset(val, 0x02, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_BKEN, val);
 
 	return 0;
 out:
-- 
1.7.9.5


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

* [PATCH V2 1/3] gpio: pca953x: make the register access by GPIO bank
@ 2013-01-07 22:51   ` Gregory CLEMENT
  0 siblings, 0 replies; 16+ messages in thread
From: Gregory CLEMENT @ 2013-01-07 22:51 UTC (permalink / raw)
  To: linux-arm-kernel

Until now the pca953x driver accessed all the bank of a given register
in a single command using only a 32 bits variable. New expanders from
the pca53x family come with 40 GPIOs which no more fit in a 32
variable. This patch make access to the registers more generic by
relying on an array of u8 variables. This fits exactly the way the
registers are represented in the hardware.

It also adds helpers to access to a single register of a bank instead
of reading or writing all the banks for a given register.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 drivers/gpio/gpio-pca953x.c |  281 +++++++++++++++++++++++++++----------------
 1 file changed, 175 insertions(+), 106 deletions(-)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index cc102d2..544a52f 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -71,18 +71,23 @@ static const struct i2c_device_id pca953x_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, pca953x_id);
 
+#define MAX_BANK 5
+#define BANK_SZ 8
+
+#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ)
+
 struct pca953x_chip {
 	unsigned gpio_start;
-	u32 reg_output;
-	u32 reg_direction;
+	u8 reg_output[MAX_BANK];
+	u8 reg_direction[MAX_BANK];
 	struct mutex i2c_lock;
 
 #ifdef CONFIG_GPIO_PCA953X_IRQ
 	struct mutex irq_lock;
-	u32 irq_mask;
-	u32 irq_stat;
-	u32 irq_trig_raise;
-	u32 irq_trig_fall;
+	u8 irq_mask[MAX_BANK];
+	u8 irq_stat[MAX_BANK];
+	u8 irq_trig_raise[MAX_BANK];
+	u8 irq_trig_fall[MAX_BANK];
 	int	 irq_base;
 	struct irq_domain *domain;
 #endif
@@ -93,33 +98,69 @@ struct pca953x_chip {
 	int	chip_type;
 };
 
-static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
+static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
+				int off)
+{
+	int ret;
+	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+	int offset = off / BANK_SZ;
+
+	ret = i2c_smbus_read_byte_data(chip->client,
+				(reg << bank_shift) + offset);
+	*val = ret;
+
+	if (ret < 0) {
+		dev_err(&chip->client->dev, "failed reading register\n", reg);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val,
+				int off)
+{
+	int ret = 0;
+	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+	int offset = off / BANK_SZ;
+
+	ret = i2c_smbus_write_byte_data(chip->client,
+					(reg << bank_shift) + offset, val);
+
+	if (ret < 0) {
+		dev_err(&chip->client->dev, "failed writing register\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
 {
 	int ret = 0;
 
 	if (chip->gpio_chip.ngpio <= 8)
-		ret = i2c_smbus_write_byte_data(chip->client, reg, val);
-	else if (chip->gpio_chip.ngpio == 24) {
-		cpu_to_le32s(&val);
+		ret = i2c_smbus_write_byte_data(chip->client, reg, *val);
+	else if (chip->gpio_chip.ngpio >= 24) {
+		int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
 		ret = i2c_smbus_write_i2c_block_data(chip->client,
-						(reg << 2) | REG_ADDR_AI,
-						3,
-						(u8 *) &val);
+					(reg << bank_shift) | REG_ADDR_AI,
+					NBANK(chip), val);
 	}
 	else {
 		switch (chip->chip_type) {
 		case PCA953X_TYPE:
 			ret = i2c_smbus_write_word_data(chip->client,
-							reg << 1, val);
+							reg << 1, (u16) *val);
 			break;
 		case PCA957X_TYPE:
 			ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
-							val & 0xff);
+							val[0]);
 			if (ret < 0)
 				break;
 			ret = i2c_smbus_write_byte_data(chip->client,
 							(reg << 1) + 1,
-							(val & 0xff00) >> 8);
+							val[1]);
 			break;
 		}
 	}
@@ -132,26 +173,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
 	return 0;
 }
 
-static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
+static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
 {
 	int ret;
 
 	if (chip->gpio_chip.ngpio <= 8) {
 		ret = i2c_smbus_read_byte_data(chip->client, reg);
 		*val = ret;
-	}
-	else if (chip->gpio_chip.ngpio == 24) {
-		*val = 0;
+	} else if (chip->gpio_chip.ngpio >= 24) {
+		int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+
 		ret = i2c_smbus_read_i2c_block_data(chip->client,
-						(reg << 2) | REG_ADDR_AI,
-						3,
-						(u8 *) val);
-		le32_to_cpus(val);
+					(reg << bank_shift) | REG_ADDR_AI,
+					NBANK(chip), val);
 	} else {
 		ret = i2c_smbus_read_word_data(chip->client, reg << 1);
-		*val = ret;
+		val[0] = (u16)ret & 0xFF;
+		val[1] = (u16)ret >> 8;
 	}
-
 	if (ret < 0) {
 		dev_err(&chip->client->dev, "failed reading register\n");
 		return ret;
@@ -163,13 +202,13 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
 static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 {
 	struct pca953x_chip *chip;
-	uint reg_val;
+	u8 reg_val;
 	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);
+	reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ));
 
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
@@ -179,11 +218,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 		offset = PCA957X_CFG;
 		break;
 	}
-	ret = pca953x_write_reg(chip, offset, reg_val);
+	ret = pca953x_write_single(chip, offset, reg_val, off);
 	if (ret)
 		goto exit;
 
-	chip->reg_direction = reg_val;
+	chip->reg_direction[off / BANK_SZ] = reg_val;
 	ret = 0;
 exit:
 	mutex_unlock(&chip->i2c_lock);
@@ -194,7 +233,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 		unsigned off, int val)
 {
 	struct pca953x_chip *chip;
-	uint reg_val;
+	u8 reg_val;
 	int ret, offset = 0;
 
 	chip = container_of(gc, struct pca953x_chip, gpio_chip);
@@ -202,9 +241,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 	mutex_lock(&chip->i2c_lock);
 	/* set output level */
 	if (val)
-		reg_val = chip->reg_output | (1u << off);
+		reg_val = chip->reg_output[off / BANK_SZ]
+			| (1u << (off % BANK_SZ));
 	else
-		reg_val = chip->reg_output & ~(1u << off);
+		reg_val = chip->reg_output[off / BANK_SZ]
+			& ~(1u << (off % BANK_SZ));
 
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
@@ -214,14 +255,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 		offset = PCA957X_OUT;
 		break;
 	}
-	ret = pca953x_write_reg(chip, offset, reg_val);
+	ret = pca953x_write_single(chip, offset, reg_val, off);
 	if (ret)
 		goto exit;
 
-	chip->reg_output = reg_val;
+	chip->reg_output[off / BANK_SZ] = reg_val;
 
 	/* then direction */
-	reg_val = chip->reg_direction & ~(1u << off);
+	reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ));
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
 		offset = PCA953X_DIRECTION;
@@ -230,11 +271,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 		offset = PCA957X_CFG;
 		break;
 	}
-	ret = pca953x_write_reg(chip, offset, reg_val);
+	ret = pca953x_write_single(chip, offset, reg_val, off);
 	if (ret)
 		goto exit;
 
-	chip->reg_direction = reg_val;
+	chip->reg_direction[off / BANK_SZ] = reg_val;
 	ret = 0;
 exit:
 	mutex_unlock(&chip->i2c_lock);
@@ -258,7 +299,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 		offset = PCA957X_IN;
 		break;
 	}
-	ret = pca953x_read_reg(chip, offset, &reg_val);
+	ret = pca953x_read_single(chip, offset, &reg_val, off);
 	mutex_unlock(&chip->i2c_lock);
 	if (ret < 0) {
 		/* NOTE:  diagnostic already emitted; that's all we should
@@ -274,16 +315,18 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 {
 	struct pca953x_chip *chip;
-	u32 reg_val;
+	u8 reg_val;
 	int ret, offset = 0;
 
 	chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
 	mutex_lock(&chip->i2c_lock);
 	if (val)
-		reg_val = chip->reg_output | (1u << off);
+		reg_val = chip->reg_output[off / BANK_SZ]
+			| (1u << (off % BANK_SZ));
 	else
-		reg_val = chip->reg_output & ~(1u << off);
+		reg_val = chip->reg_output[off / BANK_SZ]
+			& ~(1u << (off % BANK_SZ));
 
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
@@ -293,11 +336,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 		offset = PCA957X_OUT;
 		break;
 	}
-	ret = pca953x_write_reg(chip, offset, reg_val);
+	ret = pca953x_write_single(chip, offset, reg_val, off);
 	if (ret)
 		goto exit;
 
-	chip->reg_output = reg_val;
+	chip->reg_output[off / BANK_SZ] = reg_val;
 exit:
 	mutex_unlock(&chip->i2c_lock);
 }
@@ -335,14 +378,14 @@ static void pca953x_irq_mask(struct irq_data *d)
 {
 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
 
-	chip->irq_mask &= ~(1 << d->hwirq);
+	chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ));
 }
 
 static void pca953x_irq_unmask(struct irq_data *d)
 {
 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
 
-	chip->irq_mask |= 1 << d->hwirq;
+	chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ);
 }
 
 static void pca953x_irq_bus_lock(struct irq_data *d)
@@ -355,17 +398,20 @@ static void pca953x_irq_bus_lock(struct irq_data *d)
 static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 {
 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
-	u32 new_irqs;
-	u32 level;
+	u8 new_irqs;
+	int level, i;
 
 	/* Look for any newly setup interrupt */
-	new_irqs = chip->irq_trig_fall | chip->irq_trig_raise;
-	new_irqs &= ~chip->reg_direction;
-
-	while (new_irqs) {
-		level = __ffs(new_irqs);
-		pca953x_gpio_direction_input(&chip->gpio_chip, level);
-		new_irqs &= ~(1 << level);
+	for (i = 0; i < NBANK(chip); i++) {
+		new_irqs = chip->irq_trig_fall[i] | chip->irq_trig_raise[i];
+		new_irqs &= ~chip->reg_direction[i];
+
+		while (new_irqs) {
+			level = __ffs(new_irqs);
+			pca953x_gpio_direction_input(&chip->gpio_chip,
+							level + (BANK_SZ * i));
+			new_irqs &= ~(1 << level);
+		}
 	}
 
 	mutex_unlock(&chip->irq_lock);
@@ -374,7 +420,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
-	u32 mask = 1 << d->hwirq;
+	int bank_nb = d->hwirq / BANK_SZ;
+	u8 mask = 1 << (d->hwirq % BANK_SZ);
 
 	if (!(type & IRQ_TYPE_EDGE_BOTH)) {
 		dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
@@ -383,14 +430,14 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
 	}
 
 	if (type & IRQ_TYPE_EDGE_FALLING)
-		chip->irq_trig_fall |= mask;
+		chip->irq_trig_fall[bank_nb] |= mask;
 	else
-		chip->irq_trig_fall &= ~mask;
+		chip->irq_trig_fall[bank_nb] &= ~mask;
 
 	if (type & IRQ_TYPE_EDGE_RISING)
-		chip->irq_trig_raise |= mask;
+		chip->irq_trig_raise[bank_nb] |= mask;
 	else
-		chip->irq_trig_raise &= ~mask;
+		chip->irq_trig_raise[bank_nb] &= ~mask;
 
 	return 0;
 }
@@ -404,13 +451,13 @@ static struct irq_chip pca953x_irq_chip = {
 	.irq_set_type		= pca953x_irq_set_type,
 };
 
-static u32 pca953x_irq_pending(struct pca953x_chip *chip)
+static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
 {
-	u32 cur_stat;
-	u32 old_stat;
-	u32 pending;
-	u32 trigger;
-	int ret, offset = 0;
+	u8 cur_stat[MAX_BANK];
+	u8 old_stat[MAX_BANK];
+	u8 pendings = 0;
+	u8 trigger[MAX_BANK], triggers = 0;
+	int ret, i, offset = 0;
 
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
@@ -420,45 +467,54 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip)
 		offset = PCA957X_IN;
 		break;
 	}
-	ret = pca953x_read_reg(chip, offset, &cur_stat);
+	ret = pca953x_read_regs(chip, offset, cur_stat);
 	if (ret)
 		return 0;
 
 	/* Remove output pins from the equation */
-	cur_stat &= chip->reg_direction;
+	for (i = 0; i < NBANK(chip); i++)
+		cur_stat[i] &= chip->reg_direction[i];
 
-	old_stat = chip->irq_stat;
-	trigger = (cur_stat ^ old_stat) & chip->irq_mask;
+	memcpy(old_stat, chip->irq_stat, NBANK(chip));
 
-	if (!trigger)
+	for (i = 0; i < NBANK(chip); i++) {
+		trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
+		triggers += trigger[i];
+	}
+
+	if (!triggers)
 		return 0;
 
-	chip->irq_stat = cur_stat;
+	memcpy(chip->irq_stat, cur_stat, NBANK(chip));
 
-	pending = (old_stat & chip->irq_trig_fall) |
-		  (cur_stat & chip->irq_trig_raise);
-	pending &= trigger;
+	for (i = 0; i < NBANK(chip); i++) {
+		pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
+			(cur_stat[i] & chip->irq_trig_raise[i]);
+		pending[i] &= trigger[i];
+		pendings += pending[i];
+	}
 
-	return pending;
+	return pendings;
 }
 
 static irqreturn_t pca953x_irq_handler(int irq, void *devid)
 {
 	struct pca953x_chip *chip = devid;
-	u32 pending;
-	u32 level;
+	u8 pending[MAX_BANK];
+	u8 level;
+	int i;
 
-	pending = pca953x_irq_pending(chip);
-
-	if (!pending)
+	if (!pca953x_irq_pending(chip, pending))
 		return IRQ_HANDLED;
 
-	do {
-		level = __ffs(pending);
-		handle_nested_irq(irq_find_mapping(chip->domain, level));
-
-		pending &= ~(1 << level);
-	} while (pending);
+	for (i = 0; i < NBANK(chip); i++) {
+		do {
+			level = __ffs(pending[i]);
+			handle_nested_irq(irq_find_mapping(chip->domain,
+							level + (BANK_SZ * i)));
+			pending[i] &= ~(1 << level);
+		} while (pending[i]);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -468,8 +524,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 			     int irq_base)
 {
 	struct i2c_client *client = chip->client;
-	int ret, offset = 0;
-	u32 temporary;
+	int ret, i, offset = 0;
 
 	if (irq_base != -1
 			&& (id->driver_data & PCA_INT)) {
@@ -483,8 +538,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 			offset = PCA957X_IN;
 			break;
 		}
-		ret = pca953x_read_reg(chip, offset, &temporary);
-		chip->irq_stat = temporary;
+		ret = pca953x_read_regs(chip, offset, chip->irq_stat);
 		if (ret)
 			goto out_failed;
 
@@ -493,7 +547,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 		 * interrupt.  We have to rely on the previous read for
 		 * this purpose.
 		 */
-		chip->irq_stat &= chip->reg_direction;
+		for (i = 0; i < NBANK(chip); i++)
+			chip->irq_stat[i] &= chip->reg_direction[i];
 		mutex_init(&chip->irq_lock);
 
 		chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1);
@@ -619,18 +674,24 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
 static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
 {
 	int ret;
+	u8 val[MAX_BANK];
 
-	ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
+	ret = pca953x_read_regs(chip, PCA953X_OUTPUT, chip->reg_output);
 	if (ret)
 		goto out;
 
-	ret = pca953x_read_reg(chip, PCA953X_DIRECTION,
-			       &chip->reg_direction);
+	ret = pca953x_read_regs(chip, PCA953X_DIRECTION,
+			       chip->reg_direction);
 	if (ret)
 		goto out;
 
 	/* set platform specific polarity inversion */
-	ret = pca953x_write_reg(chip, PCA953X_INVERT, invert);
+	if (invert)
+		memset(val, 0xFF, NBANK(chip));
+	else
+		memset(val, 0, NBANK(chip));
+
+	ret = pca953x_write_regs(chip, PCA953X_INVERT, val);
 out:
 	return ret;
 }
@@ -638,28 +699,36 @@ out:
 static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
 {
 	int ret;
-	u32 val = 0;
+	u8 val[MAX_BANK];
 
 	/* 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);
+	memset(val, 0, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_PUPD, val);
+	memset(val, 0xFF, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_CFG, val);
+	memset(val, 0, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_OUT, val);
+
+	ret = pca953x_read_regs(chip, PCA957X_IN, val);
 	if (ret)
 		goto out;
-	ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output);
+	ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output);
 	if (ret)
 		goto out;
-	ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction);
+	ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction);
 	if (ret)
 		goto out;
 
 	/* set platform specific polarity inversion */
-	pca953x_write_reg(chip, PCA957X_INVRT, invert);
+	if (invert)
+		memset(val, 0xFF, NBANK(chip));
+	else
+		memset(val, 0, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_INVRT, val);
 
 	/* To enable register 6, 7 to controll pull up and pull down */
-	pca953x_write_reg(chip, PCA957X_BKEN, 0x202);
+	memset(val, 0x02, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_BKEN, val);
 
 	return 0;
 out:
-- 
1.7.9.5

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

* [PATCH V2 2/3] gpio: pca953x: add support for pca9505
  2013-01-07 22:51 ` Gregory CLEMENT
@ 2013-01-07 22:51   ` Gregory CLEMENT
  -1 siblings, 0 replies; 16+ messages in thread
From: Gregory CLEMENT @ 2013-01-07 22:51 UTC (permalink / raw)
  To: Linus Walleij, Grant Likely
  Cc: Maxime Ripard, Andreas Schallenberg, Roland Stigge, Jason Cooper,
	Andrew Lunn, Thomas Petazzoni, Sebastian Hesselbarth,
	linux-arm-kernel, linux-kernel, Gregory CLEMENT

Now that pca953x driver can handle GPIO expanders with more than 32
bits this patch adds the support for the pca9505 which cam with 40
GPIOs.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 drivers/gpio/gpio-pca953x.c |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 544a52f..986200e 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -46,6 +46,7 @@
 #define PCA957X_TYPE		0x2000
 
 static const struct i2c_device_id pca953x_id[] = {
+	{ "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
 	{ "pca9534", 8  | PCA953X_TYPE | PCA_INT, },
 	{ "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
 	{ "pca9536", 4  | PCA953X_TYPE, },
@@ -835,6 +836,7 @@ static int pca953x_remove(struct i2c_client *client)
 }
 
 static const struct of_device_id pca953x_dt_ids[] = {
+	{ .compatible = "nxp,pca9505", },
 	{ .compatible = "nxp,pca9534", },
 	{ .compatible = "nxp,pca9535", },
 	{ .compatible = "nxp,pca9536", },
-- 
1.7.9.5


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

* [PATCH V2 2/3] gpio: pca953x: add support for pca9505
@ 2013-01-07 22:51   ` Gregory CLEMENT
  0 siblings, 0 replies; 16+ messages in thread
From: Gregory CLEMENT @ 2013-01-07 22:51 UTC (permalink / raw)
  To: linux-arm-kernel

Now that pca953x driver can handle GPIO expanders with more than 32
bits this patch adds the support for the pca9505 which cam with 40
GPIOs.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 drivers/gpio/gpio-pca953x.c |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 544a52f..986200e 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -46,6 +46,7 @@
 #define PCA957X_TYPE		0x2000
 
 static const struct i2c_device_id pca953x_id[] = {
+	{ "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
 	{ "pca9534", 8  | PCA953X_TYPE | PCA_INT, },
 	{ "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
 	{ "pca9536", 4  | PCA953X_TYPE, },
@@ -835,6 +836,7 @@ static int pca953x_remove(struct i2c_client *client)
 }
 
 static const struct of_device_id pca953x_dt_ids[] = {
+	{ .compatible = "nxp,pca9505", },
 	{ .compatible = "nxp,pca9534", },
 	{ .compatible = "nxp,pca9535", },
 	{ .compatible = "nxp,pca9536", },
-- 
1.7.9.5

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

* [PATCH V2 3/3] arm: mvebu: enable gpio expander over i2c on Mirabox platform
  2013-01-07 22:51 ` Gregory CLEMENT
@ 2013-01-07 22:51   ` Gregory CLEMENT
  -1 siblings, 0 replies; 16+ messages in thread
From: Gregory CLEMENT @ 2013-01-07 22:51 UTC (permalink / raw)
  To: Linus Walleij, Grant Likely
  Cc: Maxime Ripard, Andreas Schallenberg, Roland Stigge, Jason Cooper,
	Andrew Lunn, Thomas Petazzoni, Sebastian Hesselbarth,
	linux-arm-kernel, linux-kernel, Gregory CLEMENT

The Globalscale Mirabox platform can be connected to the JTAG/GPIO box
through the Multi-IO port. The GPIO box use the NXP PCA9505 I/O port
expansion IC to provide 40-bit parallel input/output GPIOs. This patch
enable the use of this expander on the Mirabox.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 arch/arm/boot/dts/armada-370-mirabox.dts |   10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts
index 3b40713..d9b32d3 100644
--- a/arch/arm/boot/dts/armada-370-mirabox.dts
+++ b/arch/arm/boot/dts/armada-370-mirabox.dts
@@ -52,5 +52,15 @@
 			phy = <&phy1>;
 			phy-mode = "rgmii-id";
 		};
+		i2c@d0011000 {
+			status = "okay";
+			clock-frequency = <100000>;
+			pca9505: pca9505@25 {
+				compatible = "nxp,pca9505";
+				gpio-controller;
+				#gpio-cells = <2>;
+				reg = <0x25>;
+			};
+		};
 	};
 };
-- 
1.7.9.5


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

* [PATCH V2 3/3] arm: mvebu: enable gpio expander over i2c on Mirabox platform
@ 2013-01-07 22:51   ` Gregory CLEMENT
  0 siblings, 0 replies; 16+ messages in thread
From: Gregory CLEMENT @ 2013-01-07 22:51 UTC (permalink / raw)
  To: linux-arm-kernel

The Globalscale Mirabox platform can be connected to the JTAG/GPIO box
through the Multi-IO port. The GPIO box use the NXP PCA9505 I/O port
expansion IC to provide 40-bit parallel input/output GPIOs. This patch
enable the use of this expander on the Mirabox.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 arch/arm/boot/dts/armada-370-mirabox.dts |   10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts
index 3b40713..d9b32d3 100644
--- a/arch/arm/boot/dts/armada-370-mirabox.dts
+++ b/arch/arm/boot/dts/armada-370-mirabox.dts
@@ -52,5 +52,15 @@
 			phy = <&phy1>;
 			phy-mode = "rgmii-id";
 		};
+		i2c at d0011000 {
+			status = "okay";
+			clock-frequency = <100000>;
+			pca9505: pca9505 at 25 {
+				compatible = "nxp,pca9505";
+				gpio-controller;
+				#gpio-cells = <2>;
+				reg = <0x25>;
+			};
+		};
 	};
 };
-- 
1.7.9.5

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

* Re: [PATCH V2 1/3] gpio: pca953x: make the register access by GPIO bank
  2013-01-07 22:51   ` Gregory CLEMENT
@ 2013-01-08  8:32     ` Maxime Ripard
  -1 siblings, 0 replies; 16+ messages in thread
From: Maxime Ripard @ 2013-01-08  8:32 UTC (permalink / raw)
  To: Gregory CLEMENT
  Cc: Linus Walleij, Grant Likely, Andreas Schallenberg, Roland Stigge,
	Jason Cooper, Andrew Lunn, Thomas Petazzoni,
	Sebastian Hesselbarth, linux-arm-kernel, linux-kernel

Hi Gregory,

On 07/01/2013 23:51, Gregory CLEMENT wrote:
> -static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
> +static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
> +				int off)
> +{
> +	int ret;
> +	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
> +	int offset = off / BANK_SZ;
> +
> +	ret = i2c_smbus_read_byte_data(chip->client,
> +				(reg << bank_shift) + offset);
> +	*val = ret;
> +
> +	if (ret < 0) {
> +		dev_err(&chip->client->dev, "failed reading register\n", reg);

This triggers a warning, since you have an argument but nothing corresponding to it in your format string.

>  static irqreturn_t pca953x_irq_handler(int irq, void *devid)
>  {
>  	struct pca953x_chip *chip = devid;
> -	u32 pending;
> -	u32 level;
> +	u8 pending[MAX_BANK];
> +	u8 level;
> +	int i;
>  
> -	pending = pca953x_irq_pending(chip);
> -
> -	if (!pending)
> +	if (!pca953x_irq_pending(chip, pending))
>  		return IRQ_HANDLED;
>  
> -	do {
> -		level = __ffs(pending);
> -		handle_nested_irq(irq_find_mapping(chip->domain, level));
> -
> -		pending &= ~(1 << level);
> -	} while (pending);
> +	for (i = 0; i < NBANK(chip); i++) {
> +		do {
> +			level = __ffs(pending[i]);
> +			handle_nested_irq(irq_find_mapping(chip->domain,
> +							level + (BANK_SZ * i)));
> +			pending[i] &= ~(1 << level);
> +		} while (pending[i]);
> +	}
>  
>  	return IRQ_HANDLED;
>  }

This triggers the following warning when an interrupt is raised:

[   30.773500] ------------[ cut here ]------------
[   30.778843] WARNING: at /home/tmp/linux/kernel/irq/irqdomain.c:137 irq_domain_legacy_revmap+0x2c/0x48()
[   30.788375] Modules linked in:
[   30.791531] [<c0014100>] (unwind_backtrace+0x0/0xf0) from [<c001c878>] (warn_slowpath_common+0x4c/0x64)
[   30.801125] [<c001c878>] (warn_slowpath_common+0x4c/0x64) from [<c001c8ac>] (warn_slowpath_null+0x1c/0x24)
[   30.810968] [<c001c8ac>] (warn_slowpath_null+0x1c/0x24) from [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48)
[   30.821187] [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48) from [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac)
[   30.831656] [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac) from [<c0068688>] (irq_thread+0xd0/0x124)
[   30.841000] [<c0068688>] (irq_thread+0xd0/0x124) from [<c003c238>] (kthread+0xa4/0xb0)
[   30.849125] [<c003c238>] (kthread+0xa4/0xb0) from [<c000ed48>] (ret_from_fork+0x14/0x2c)
[   30.857375] ---[ end trace 09584b7a73100a49 ]---

Maxime

-- 
Maxime Ripard, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* [PATCH V2 1/3] gpio: pca953x: make the register access by GPIO bank
@ 2013-01-08  8:32     ` Maxime Ripard
  0 siblings, 0 replies; 16+ messages in thread
From: Maxime Ripard @ 2013-01-08  8:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Gregory,

On 07/01/2013 23:51, Gregory CLEMENT wrote:
> -static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
> +static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
> +				int off)
> +{
> +	int ret;
> +	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
> +	int offset = off / BANK_SZ;
> +
> +	ret = i2c_smbus_read_byte_data(chip->client,
> +				(reg << bank_shift) + offset);
> +	*val = ret;
> +
> +	if (ret < 0) {
> +		dev_err(&chip->client->dev, "failed reading register\n", reg);

This triggers a warning, since you have an argument but nothing corresponding to it in your format string.

>  static irqreturn_t pca953x_irq_handler(int irq, void *devid)
>  {
>  	struct pca953x_chip *chip = devid;
> -	u32 pending;
> -	u32 level;
> +	u8 pending[MAX_BANK];
> +	u8 level;
> +	int i;
>  
> -	pending = pca953x_irq_pending(chip);
> -
> -	if (!pending)
> +	if (!pca953x_irq_pending(chip, pending))
>  		return IRQ_HANDLED;
>  
> -	do {
> -		level = __ffs(pending);
> -		handle_nested_irq(irq_find_mapping(chip->domain, level));
> -
> -		pending &= ~(1 << level);
> -	} while (pending);
> +	for (i = 0; i < NBANK(chip); i++) {
> +		do {
> +			level = __ffs(pending[i]);
> +			handle_nested_irq(irq_find_mapping(chip->domain,
> +							level + (BANK_SZ * i)));
> +			pending[i] &= ~(1 << level);
> +		} while (pending[i]);
> +	}
>  
>  	return IRQ_HANDLED;
>  }

This triggers the following warning when an interrupt is raised:

[   30.773500] ------------[ cut here ]------------
[   30.778843] WARNING: at /home/tmp/linux/kernel/irq/irqdomain.c:137 irq_domain_legacy_revmap+0x2c/0x48()
[   30.788375] Modules linked in:
[   30.791531] [<c0014100>] (unwind_backtrace+0x0/0xf0) from [<c001c878>] (warn_slowpath_common+0x4c/0x64)
[   30.801125] [<c001c878>] (warn_slowpath_common+0x4c/0x64) from [<c001c8ac>] (warn_slowpath_null+0x1c/0x24)
[   30.810968] [<c001c8ac>] (warn_slowpath_null+0x1c/0x24) from [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48)
[   30.821187] [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48) from [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac)
[   30.831656] [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac) from [<c0068688>] (irq_thread+0xd0/0x124)
[   30.841000] [<c0068688>] (irq_thread+0xd0/0x124) from [<c003c238>] (kthread+0xa4/0xb0)
[   30.849125] [<c003c238>] (kthread+0xa4/0xb0) from [<c000ed48>] (ret_from_fork+0x14/0x2c)
[   30.857375] ---[ end trace 09584b7a73100a49 ]---

Maxime

-- 
Maxime Ripard, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* Re: [PATCH V2 1/3] gpio: pca953x: make the register access by GPIO bank
  2013-01-08  8:32     ` Maxime Ripard
@ 2013-01-08  8:58       ` Gregory CLEMENT
  -1 siblings, 0 replies; 16+ messages in thread
From: Gregory CLEMENT @ 2013-01-08  8:58 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Linus Walleij, Grant Likely, Andreas Schallenberg, Roland Stigge,
	Jason Cooper, Andrew Lunn, Thomas Petazzoni,
	Sebastian Hesselbarth, linux-arm-kernel, linux-kernel

On 01/08/2013 09:32 AM, Maxime Ripard wrote:
> Hi Gregory,

Hi Maxime,

thanks for testing
> 
> On 07/01/2013 23:51, Gregory CLEMENT wrote:
>> -static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
>> +static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
>> +				int off)
>> +{
>> +	int ret;
>> +	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
>> +	int offset = off / BANK_SZ;
>> +
>> +	ret = i2c_smbus_read_byte_data(chip->client,
>> +				(reg << bank_shift) + offset);
>> +	*val = ret;
>> +
>> +	if (ret < 0) {
>> +		dev_err(&chip->client->dev, "failed reading register\n", reg);
> 
> This triggers a warning, since you have an argument but nothing corresponding to it in your format string.

OK this one is easy, I didn't finished to clean up the message.

> 
>>  static irqreturn_t pca953x_irq_handler(int irq, void *devid)
>>  {
>>  	struct pca953x_chip *chip = devid;
>> -	u32 pending;
>> -	u32 level;
>> +	u8 pending[MAX_BANK];
>> +	u8 level;
>> +	int i;
>>  
>> -	pending = pca953x_irq_pending(chip);
>> -
>> -	if (!pending)
>> +	if (!pca953x_irq_pending(chip, pending))
>>  		return IRQ_HANDLED;
>>  
>> -	do {
>> -		level = __ffs(pending);
>> -		handle_nested_irq(irq_find_mapping(chip->domain, level));
>> -
>> -		pending &= ~(1 << level);
>> -	} while (pending);
>> +	for (i = 0; i < NBANK(chip); i++) {
>> +		do {
>> +			level = __ffs(pending[i]);
>> +			handle_nested_irq(irq_find_mapping(chip->domain,
>> +							level + (BANK_SZ * i)));
>> +			pending[i] &= ~(1 << level);
>> +		} while (pending[i]);
>> +	}
>>  
>>  	return IRQ_HANDLED;
>>  }
> 
> This triggers the following warning when an interrupt is raised:
> 
> [   30.773500] ------------[ cut here ]------------
> [   30.778843] WARNING: at /home/tmp/linux/kernel/irq/irqdomain.c:137 irq_domain_legacy_revmap+0x2c/0x48()
> [   30.788375] Modules linked in:
> [   30.791531] [<c0014100>] (unwind_backtrace+0x0/0xf0) from [<c001c878>] (warn_slowpath_common+0x4c/0x64)
> [   30.801125] [<c001c878>] (warn_slowpath_common+0x4c/0x64) from [<c001c8ac>] (warn_slowpath_null+0x1c/0x24)
> [   30.810968] [<c001c8ac>] (warn_slowpath_null+0x1c/0x24) from [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48)
> [   30.821187] [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48) from [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac)
> [   30.831656] [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac) from [<c0068688>] (irq_thread+0xd0/0x124)
> [   30.841000] [<c0068688>] (irq_thread+0xd0/0x124) from [<c003c238>] (kthread+0xa4/0xb0)
> [   30.849125] [<c003c238>] (kthread+0xa4/0xb0) from [<c000ed48>] (ret_from_fork+0x14/0x2c)
> [   30.857375] ---[ end trace 09584b7a73100a49 ]---
> 

Humm it seems that this warning is caused by attempting to use an out of range hwirq.
I need to investigate it more in details.

Expect the IRQ part, is this version is working for your gpio expander?

> Maxime
> 


-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* [PATCH V2 1/3] gpio: pca953x: make the register access by GPIO bank
@ 2013-01-08  8:58       ` Gregory CLEMENT
  0 siblings, 0 replies; 16+ messages in thread
From: Gregory CLEMENT @ 2013-01-08  8:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 01/08/2013 09:32 AM, Maxime Ripard wrote:
> Hi Gregory,

Hi Maxime,

thanks for testing
> 
> On 07/01/2013 23:51, Gregory CLEMENT wrote:
>> -static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
>> +static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
>> +				int off)
>> +{
>> +	int ret;
>> +	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
>> +	int offset = off / BANK_SZ;
>> +
>> +	ret = i2c_smbus_read_byte_data(chip->client,
>> +				(reg << bank_shift) + offset);
>> +	*val = ret;
>> +
>> +	if (ret < 0) {
>> +		dev_err(&chip->client->dev, "failed reading register\n", reg);
> 
> This triggers a warning, since you have an argument but nothing corresponding to it in your format string.

OK this one is easy, I didn't finished to clean up the message.

> 
>>  static irqreturn_t pca953x_irq_handler(int irq, void *devid)
>>  {
>>  	struct pca953x_chip *chip = devid;
>> -	u32 pending;
>> -	u32 level;
>> +	u8 pending[MAX_BANK];
>> +	u8 level;
>> +	int i;
>>  
>> -	pending = pca953x_irq_pending(chip);
>> -
>> -	if (!pending)
>> +	if (!pca953x_irq_pending(chip, pending))
>>  		return IRQ_HANDLED;
>>  
>> -	do {
>> -		level = __ffs(pending);
>> -		handle_nested_irq(irq_find_mapping(chip->domain, level));
>> -
>> -		pending &= ~(1 << level);
>> -	} while (pending);
>> +	for (i = 0; i < NBANK(chip); i++) {
>> +		do {
>> +			level = __ffs(pending[i]);
>> +			handle_nested_irq(irq_find_mapping(chip->domain,
>> +							level + (BANK_SZ * i)));
>> +			pending[i] &= ~(1 << level);
>> +		} while (pending[i]);
>> +	}
>>  
>>  	return IRQ_HANDLED;
>>  }
> 
> This triggers the following warning when an interrupt is raised:
> 
> [   30.773500] ------------[ cut here ]------------
> [   30.778843] WARNING: at /home/tmp/linux/kernel/irq/irqdomain.c:137 irq_domain_legacy_revmap+0x2c/0x48()
> [   30.788375] Modules linked in:
> [   30.791531] [<c0014100>] (unwind_backtrace+0x0/0xf0) from [<c001c878>] (warn_slowpath_common+0x4c/0x64)
> [   30.801125] [<c001c878>] (warn_slowpath_common+0x4c/0x64) from [<c001c8ac>] (warn_slowpath_null+0x1c/0x24)
> [   30.810968] [<c001c8ac>] (warn_slowpath_null+0x1c/0x24) from [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48)
> [   30.821187] [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48) from [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac)
> [   30.831656] [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac) from [<c0068688>] (irq_thread+0xd0/0x124)
> [   30.841000] [<c0068688>] (irq_thread+0xd0/0x124) from [<c003c238>] (kthread+0xa4/0xb0)
> [   30.849125] [<c003c238>] (kthread+0xa4/0xb0) from [<c000ed48>] (ret_from_fork+0x14/0x2c)
> [   30.857375] ---[ end trace 09584b7a73100a49 ]---
> 

Humm it seems that this warning is caused by attempting to use an out of range hwirq.
I need to investigate it more in details.

Expect the IRQ part, is this version is working for your gpio expander?

> Maxime
> 


-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* Re: [PATCH V2 1/3] gpio: pca953x: make the register access by GPIO bank
  2013-01-08  8:58       ` Gregory CLEMENT
@ 2013-01-08  9:00         ` Maxime Ripard
  -1 siblings, 0 replies; 16+ messages in thread
From: Maxime Ripard @ 2013-01-08  9:00 UTC (permalink / raw)
  To: Gregory CLEMENT
  Cc: Linus Walleij, Grant Likely, Andreas Schallenberg, Roland Stigge,
	Jason Cooper, Andrew Lunn, Thomas Petazzoni,
	Sebastian Hesselbarth, linux-arm-kernel, linux-kernel

Hi Gregory,

On 08/01/2013 09:58, Gregory CLEMENT wrote:
> On 01/08/2013 09:32 AM, Maxime Ripard wrote:
>> On 07/01/2013 23:51, Gregory CLEMENT wrote:
>>>  static irqreturn_t pca953x_irq_handler(int irq, void *devid)
>>>  {
>>>  	struct pca953x_chip *chip = devid;
>>> -	u32 pending;
>>> -	u32 level;
>>> +	u8 pending[MAX_BANK];
>>> +	u8 level;
>>> +	int i;
>>>  
>>> -	pending = pca953x_irq_pending(chip);
>>> -
>>> -	if (!pending)
>>> +	if (!pca953x_irq_pending(chip, pending))
>>>  		return IRQ_HANDLED;
>>>  
>>> -	do {
>>> -		level = __ffs(pending);
>>> -		handle_nested_irq(irq_find_mapping(chip->domain, level));
>>> -
>>> -		pending &= ~(1 << level);
>>> -	} while (pending);
>>> +	for (i = 0; i < NBANK(chip); i++) {
>>> +		do {
>>> +			level = __ffs(pending[i]);
>>> +			handle_nested_irq(irq_find_mapping(chip->domain,
>>> +							level + (BANK_SZ * i)));
>>> +			pending[i] &= ~(1 << level);
>>> +		} while (pending[i]);
>>> +	}
>>>  
>>>  	return IRQ_HANDLED;
>>>  }
>>
>> This triggers the following warning when an interrupt is raised:
>>
>> [   30.773500] ------------[ cut here ]------------
>> [   30.778843] WARNING: at /home/tmp/linux/kernel/irq/irqdomain.c:137 irq_domain_legacy_revmap+0x2c/0x48()
>> [   30.788375] Modules linked in:
>> [   30.791531] [<c0014100>] (unwind_backtrace+0x0/0xf0) from [<c001c878>] (warn_slowpath_common+0x4c/0x64)
>> [   30.801125] [<c001c878>] (warn_slowpath_common+0x4c/0x64) from [<c001c8ac>] (warn_slowpath_null+0x1c/0x24)
>> [   30.810968] [<c001c8ac>] (warn_slowpath_null+0x1c/0x24) from [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48)
>> [   30.821187] [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48) from [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac)
>> [   30.831656] [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac) from [<c0068688>] (irq_thread+0xd0/0x124)
>> [   30.841000] [<c0068688>] (irq_thread+0xd0/0x124) from [<c003c238>] (kthread+0xa4/0xb0)
>> [   30.849125] [<c003c238>] (kthread+0xa4/0xb0) from [<c000ed48>] (ret_from_fork+0x14/0x2c)
>> [   30.857375] ---[ end trace 09584b7a73100a49 ]---
>>
> 
> Humm it seems that this warning is caused by attempting to use an out of range hwirq.
> I need to investigate it more in details.
> 
> Expect the IRQ part, is this version is working for your gpio expander?

Yes, it works fine if you leave the interruptions aside.

Maxime

-- 
Maxime Ripard, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* [PATCH V2 1/3] gpio: pca953x: make the register access by GPIO bank
@ 2013-01-08  9:00         ` Maxime Ripard
  0 siblings, 0 replies; 16+ messages in thread
From: Maxime Ripard @ 2013-01-08  9:00 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Gregory,

On 08/01/2013 09:58, Gregory CLEMENT wrote:
> On 01/08/2013 09:32 AM, Maxime Ripard wrote:
>> On 07/01/2013 23:51, Gregory CLEMENT wrote:
>>>  static irqreturn_t pca953x_irq_handler(int irq, void *devid)
>>>  {
>>>  	struct pca953x_chip *chip = devid;
>>> -	u32 pending;
>>> -	u32 level;
>>> +	u8 pending[MAX_BANK];
>>> +	u8 level;
>>> +	int i;
>>>  
>>> -	pending = pca953x_irq_pending(chip);
>>> -
>>> -	if (!pending)
>>> +	if (!pca953x_irq_pending(chip, pending))
>>>  		return IRQ_HANDLED;
>>>  
>>> -	do {
>>> -		level = __ffs(pending);
>>> -		handle_nested_irq(irq_find_mapping(chip->domain, level));
>>> -
>>> -		pending &= ~(1 << level);
>>> -	} while (pending);
>>> +	for (i = 0; i < NBANK(chip); i++) {
>>> +		do {
>>> +			level = __ffs(pending[i]);
>>> +			handle_nested_irq(irq_find_mapping(chip->domain,
>>> +							level + (BANK_SZ * i)));
>>> +			pending[i] &= ~(1 << level);
>>> +		} while (pending[i]);
>>> +	}
>>>  
>>>  	return IRQ_HANDLED;
>>>  }
>>
>> This triggers the following warning when an interrupt is raised:
>>
>> [   30.773500] ------------[ cut here ]------------
>> [   30.778843] WARNING: at /home/tmp/linux/kernel/irq/irqdomain.c:137 irq_domain_legacy_revmap+0x2c/0x48()
>> [   30.788375] Modules linked in:
>> [   30.791531] [<c0014100>] (unwind_backtrace+0x0/0xf0) from [<c001c878>] (warn_slowpath_common+0x4c/0x64)
>> [   30.801125] [<c001c878>] (warn_slowpath_common+0x4c/0x64) from [<c001c8ac>] (warn_slowpath_null+0x1c/0x24)
>> [   30.810968] [<c001c8ac>] (warn_slowpath_null+0x1c/0x24) from [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48)
>> [   30.821187] [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48) from [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac)
>> [   30.831656] [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac) from [<c0068688>] (irq_thread+0xd0/0x124)
>> [   30.841000] [<c0068688>] (irq_thread+0xd0/0x124) from [<c003c238>] (kthread+0xa4/0xb0)
>> [   30.849125] [<c003c238>] (kthread+0xa4/0xb0) from [<c000ed48>] (ret_from_fork+0x14/0x2c)
>> [   30.857375] ---[ end trace 09584b7a73100a49 ]---
>>
> 
> Humm it seems that this warning is caused by attempting to use an out of range hwirq.
> I need to investigate it more in details.
> 
> Expect the IRQ part, is this version is working for your gpio expander?

Yes, it works fine if you leave the interruptions aside.

Maxime

-- 
Maxime Ripard, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* Re: [PATCH V2 1/3] gpio: pca953x: make the register access by GPIO bank
  2013-01-08  8:58       ` Gregory CLEMENT
@ 2013-01-21 23:30         ` Gregory CLEMENT
  -1 siblings, 0 replies; 16+ messages in thread
From: Gregory CLEMENT @ 2013-01-21 23:30 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Linus Walleij, Grant Likely, Andreas Schallenberg, Roland Stigge,
	Jason Cooper, Andrew Lunn, Thomas Petazzoni,
	Sebastian Hesselbarth, linux-arm-kernel, linux-kernel

On 01/08/2013 09:58 AM, Gregory CLEMENT wrote:
> On 01/08/2013 09:32 AM, Maxime Ripard wrote:
>> Hi Gregory,
> 
> Hi Maxime,
> 
> thanks for testing
>>
>> On 07/01/2013 23:51, Gregory CLEMENT wrote:
>>> -static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
>>> +static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
>>> +				int off)
>>> +{
>>> +	int ret;
>>> +	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
>>> +	int offset = off / BANK_SZ;
>>> +
>>> +	ret = i2c_smbus_read_byte_data(chip->client,
>>> +				(reg << bank_shift) + offset);
>>> +	*val = ret;
>>> +
>>> +	if (ret < 0) {
>>> +		dev_err(&chip->client->dev, "failed reading register\n", reg);
>>
>> This triggers a warning, since you have an argument but nothing corresponding to it in your format string.
> 
> OK this one is easy, I didn't finished to clean up the message.
> 
>>
>>>  static irqreturn_t pca953x_irq_handler(int irq, void *devid)
>>>  {
>>>  	struct pca953x_chip *chip = devid;
>>> -	u32 pending;
>>> -	u32 level;
>>> +	u8 pending[MAX_BANK];
>>> +	u8 level;
>>> +	int i;
>>>  
>>> -	pending = pca953x_irq_pending(chip);
>>> -
>>> -	if (!pending)
>>> +	if (!pca953x_irq_pending(chip, pending))
>>>  		return IRQ_HANDLED;
>>>  
>>> -	do {
>>> -		level = __ffs(pending);
>>> -		handle_nested_irq(irq_find_mapping(chip->domain, level));
>>> -
>>> -		pending &= ~(1 << level);
>>> -	} while (pending);
>>> +	for (i = 0; i < NBANK(chip); i++) {
>>> +		do {
>>> +			level = __ffs(pending[i]);
>>> +			handle_nested_irq(irq_find_mapping(chip->domain,
>>> +							level + (BANK_SZ * i)));
>>> +			pending[i] &= ~(1 << level);
>>> +		} while (pending[i]);
>>> +	}
>>>  
>>>  	return IRQ_HANDLED;
>>>  }
>>
>> This triggers the following warning when an interrupt is raised:
>>
>> [   30.773500] ------------[ cut here ]------------
>> [   30.778843] WARNING: at /home/tmp/linux/kernel/irq/irqdomain.c:137 irq_domain_legacy_revmap+0x2c/0x48()
>> [   30.788375] Modules linked in:
>> [   30.791531] [<c0014100>] (unwind_backtrace+0x0/0xf0) from [<c001c878>] (warn_slowpath_common+0x4c/0x64)
>> [   30.801125] [<c001c878>] (warn_slowpath_common+0x4c/0x64) from [<c001c8ac>] (warn_slowpath_null+0x1c/0x24)
>> [   30.810968] [<c001c8ac>] (warn_slowpath_null+0x1c/0x24) from [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48)
>> [   30.821187] [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48) from [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac)
>> [   30.831656] [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac) from [<c0068688>] (irq_thread+0xd0/0x124)
>> [   30.841000] [<c0068688>] (irq_thread+0xd0/0x124) from [<c003c238>] (kthread+0xa4/0xb0)
>> [   30.849125] [<c003c238>] (kthread+0xa4/0xb0) from [<c000ed48>] (ret_from_fork+0x14/0x2c)
>> [   30.857375] ---[ end trace 09584b7a73100a49 ]---
>>
> 
> Humm it seems that this warning is caused by attempting to use an out of range hwirq.
> I need to investigate it more in details.

Unfortunately I didn't receive information on Mirabox to be able to use
interrupt. So I will need you help to debug this part.

Could you try the branch gpio-pca9505-debug  at
https://github.com/MISL-EBU-System-SW/mainline-public.git ?

I suspect that we use a GPIO above 8 to generate the interrupt, am I right?

Thanks,

Gregory

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

* [PATCH V2 1/3] gpio: pca953x: make the register access by GPIO bank
@ 2013-01-21 23:30         ` Gregory CLEMENT
  0 siblings, 0 replies; 16+ messages in thread
From: Gregory CLEMENT @ 2013-01-21 23:30 UTC (permalink / raw)
  To: linux-arm-kernel

On 01/08/2013 09:58 AM, Gregory CLEMENT wrote:
> On 01/08/2013 09:32 AM, Maxime Ripard wrote:
>> Hi Gregory,
> 
> Hi Maxime,
> 
> thanks for testing
>>
>> On 07/01/2013 23:51, Gregory CLEMENT wrote:
>>> -static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
>>> +static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
>>> +				int off)
>>> +{
>>> +	int ret;
>>> +	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
>>> +	int offset = off / BANK_SZ;
>>> +
>>> +	ret = i2c_smbus_read_byte_data(chip->client,
>>> +				(reg << bank_shift) + offset);
>>> +	*val = ret;
>>> +
>>> +	if (ret < 0) {
>>> +		dev_err(&chip->client->dev, "failed reading register\n", reg);
>>
>> This triggers a warning, since you have an argument but nothing corresponding to it in your format string.
> 
> OK this one is easy, I didn't finished to clean up the message.
> 
>>
>>>  static irqreturn_t pca953x_irq_handler(int irq, void *devid)
>>>  {
>>>  	struct pca953x_chip *chip = devid;
>>> -	u32 pending;
>>> -	u32 level;
>>> +	u8 pending[MAX_BANK];
>>> +	u8 level;
>>> +	int i;
>>>  
>>> -	pending = pca953x_irq_pending(chip);
>>> -
>>> -	if (!pending)
>>> +	if (!pca953x_irq_pending(chip, pending))
>>>  		return IRQ_HANDLED;
>>>  
>>> -	do {
>>> -		level = __ffs(pending);
>>> -		handle_nested_irq(irq_find_mapping(chip->domain, level));
>>> -
>>> -		pending &= ~(1 << level);
>>> -	} while (pending);
>>> +	for (i = 0; i < NBANK(chip); i++) {
>>> +		do {
>>> +			level = __ffs(pending[i]);
>>> +			handle_nested_irq(irq_find_mapping(chip->domain,
>>> +							level + (BANK_SZ * i)));
>>> +			pending[i] &= ~(1 << level);
>>> +		} while (pending[i]);
>>> +	}
>>>  
>>>  	return IRQ_HANDLED;
>>>  }
>>
>> This triggers the following warning when an interrupt is raised:
>>
>> [   30.773500] ------------[ cut here ]------------
>> [   30.778843] WARNING: at /home/tmp/linux/kernel/irq/irqdomain.c:137 irq_domain_legacy_revmap+0x2c/0x48()
>> [   30.788375] Modules linked in:
>> [   30.791531] [<c0014100>] (unwind_backtrace+0x0/0xf0) from [<c001c878>] (warn_slowpath_common+0x4c/0x64)
>> [   30.801125] [<c001c878>] (warn_slowpath_common+0x4c/0x64) from [<c001c8ac>] (warn_slowpath_null+0x1c/0x24)
>> [   30.810968] [<c001c8ac>] (warn_slowpath_null+0x1c/0x24) from [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48)
>> [   30.821187] [<c006b5e0>] (irq_domain_legacy_revmap+0x2c/0x48) from [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac)
>> [   30.831656] [<c01c3734>] (pca953x_irq_handler+0x16c/0x1ac) from [<c0068688>] (irq_thread+0xd0/0x124)
>> [   30.841000] [<c0068688>] (irq_thread+0xd0/0x124) from [<c003c238>] (kthread+0xa4/0xb0)
>> [   30.849125] [<c003c238>] (kthread+0xa4/0xb0) from [<c000ed48>] (ret_from_fork+0x14/0x2c)
>> [   30.857375] ---[ end trace 09584b7a73100a49 ]---
>>
> 
> Humm it seems that this warning is caused by attempting to use an out of range hwirq.
> I need to investigate it more in details.

Unfortunately I didn't receive information on Mirabox to be able to use
interrupt. So I will need you help to debug this part.

Could you try the branch gpio-pca9505-debug  at
https://github.com/MISL-EBU-System-SW/mainline-public.git ?

I suspect that we use a GPIO above 8 to generate the interrupt, am I right?

Thanks,

Gregory

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

end of thread, other threads:[~2013-01-21 23:30 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-07 22:51 [PATCH V2 0/3] Add support for gpio expander pca9505 used on Mirabox Gregory CLEMENT
2013-01-07 22:51 ` Gregory CLEMENT
2013-01-07 22:51 ` [PATCH V2 1/3] gpio: pca953x: make the register access by GPIO bank Gregory CLEMENT
2013-01-07 22:51   ` Gregory CLEMENT
2013-01-08  8:32   ` Maxime Ripard
2013-01-08  8:32     ` Maxime Ripard
2013-01-08  8:58     ` Gregory CLEMENT
2013-01-08  8:58       ` Gregory CLEMENT
2013-01-08  9:00       ` Maxime Ripard
2013-01-08  9:00         ` Maxime Ripard
2013-01-21 23:30       ` Gregory CLEMENT
2013-01-21 23:30         ` Gregory CLEMENT
2013-01-07 22:51 ` [PATCH V2 2/3] gpio: pca953x: add support for pca9505 Gregory CLEMENT
2013-01-07 22:51   ` Gregory CLEMENT
2013-01-07 22:51 ` [PATCH V2 3/3] arm: mvebu: enable gpio expander over i2c on Mirabox platform Gregory CLEMENT
2013-01-07 22:51   ` Gregory CLEMENT

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.