diff mbox

gpio: 74x164: Implement gpiochip.set_multiple()

Message ID 1457968758-22670-1-git-send-email-geert+renesas@glider.be
State New
Headers show

Commit Message

Geert Uytterhoeven March 14, 2016, 3:19 p.m. UTC
This allows to set multiple outputs using a single SPI transfer.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/gpio/gpio-74x164.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

Comments

Phil Reid March 15, 2016, 4:04 a.m. UTC | #1
On 14/03/2016 11:19 PM, Geert Uytterhoeven wrote:
> This allows to set multiple outputs using a single SPI transfer.
>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>

Reviewed-by: Phil Reid <preid@electromag.com.au>


I do have a general question about GPIO drivers.
pca953x does not update the cached data unless the write operation
was successful. Which I folowed with the implement of set_multiple.
However a number of other drivers update regardless.
eg chip->buffer is updated even if the write_config fails.

What is the preferred approach?

> ---
>   drivers/gpio/gpio-74x164.c | 24 ++++++++++++++++++++++++
>   1 file changed, 24 insertions(+)
>
> diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
> index c81224ff2dca988b..62291a81c97f7140 100644
> --- a/drivers/gpio/gpio-74x164.c
> +++ b/drivers/gpio/gpio-74x164.c
> @@ -75,6 +75,29 @@ static void gen_74x164_set_value(struct gpio_chip *gc,
>   	mutex_unlock(&chip->lock);
>   }
>
> +static void gen_74x164_set_multiple(struct gpio_chip *gc, unsigned long *mask,
> +				    unsigned long *bits)
> +{
> +	struct gen_74x164_chip *chip = gpiochip_get_data(gc);
> +	unsigned int i, idx, shift;
> +	u8 bank, bankmask;
> +
> +	mutex_lock(&chip->lock);
> +	for (i = 0, bank = chip->registers - 1; i < chip->registers;
> +	     i++, bank--) {
> +		idx = i / sizeof(*mask);
> +		shift = i % sizeof(*mask) * BITS_PER_BYTE;
> +		bankmask = mask[idx] >> shift;
> +		if (!bankmask)
> +			continue;
> +
> +		chip->buffer[bank] &= ~bankmask;
> +		chip->buffer[bank] |= bankmask & (bits[idx] >> shift);
> +	}
> +	__gen_74x164_write_config(chip);
> +	mutex_unlock(&chip->lock);
> +}
> +
>   static int gen_74x164_direction_output(struct gpio_chip *gc,
>   		unsigned offset, int val)
>   {
> @@ -114,6 +137,7 @@ static int gen_74x164_probe(struct spi_device *spi)
>   	chip->gpio_chip.direction_output = gen_74x164_direction_output;
>   	chip->gpio_chip.get = gen_74x164_get_value;
>   	chip->gpio_chip.set = gen_74x164_set_value;
> +	chip->gpio_chip.set_multiple = gen_74x164_set_multiple;
>   	chip->gpio_chip.base = -1;
>
>   	chip->registers = nregs;
>
Linus Walleij March 22, 2016, 10:54 a.m. UTC | #2
On Mon, Mar 14, 2016 at 4:19 PM, Geert Uytterhoeven
<geert+renesas@glider.be> wrote:

> This allows to set multiple outputs using a single SPI transfer.
>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>

Patch applied for v4.7 with Phil's Review tag.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij March 22, 2016, 10:56 a.m. UTC | #3
On Tue, Mar 15, 2016 at 5:04 AM, Phil Reid <preid@electromag.com.au> wrote:

> pca953x does not update the cached data unless the write operation
> was successful. Which I folowed with the implement of set_multiple.
> However a number of other drivers update regardless.
> eg chip->buffer is updated even if the write_config fails.
>
> What is the preferred approach?

Obviously the other drivers are buggy and need to be fixed.
It can't be too many since the number of drivers with failable
write operations aren's so many. (And I guess they seldom fail
so it's not a big real world problem.) But it should be fixed.

Add Axel Lin to the thread, he's awesome at finding semantic
bugs.

Patches accepted :)

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
index c81224ff2dca988b..62291a81c97f7140 100644
--- a/drivers/gpio/gpio-74x164.c
+++ b/drivers/gpio/gpio-74x164.c
@@ -75,6 +75,29 @@  static void gen_74x164_set_value(struct gpio_chip *gc,
 	mutex_unlock(&chip->lock);
 }
 
+static void gen_74x164_set_multiple(struct gpio_chip *gc, unsigned long *mask,
+				    unsigned long *bits)
+{
+	struct gen_74x164_chip *chip = gpiochip_get_data(gc);
+	unsigned int i, idx, shift;
+	u8 bank, bankmask;
+
+	mutex_lock(&chip->lock);
+	for (i = 0, bank = chip->registers - 1; i < chip->registers;
+	     i++, bank--) {
+		idx = i / sizeof(*mask);
+		shift = i % sizeof(*mask) * BITS_PER_BYTE;
+		bankmask = mask[idx] >> shift;
+		if (!bankmask)
+			continue;
+
+		chip->buffer[bank] &= ~bankmask;
+		chip->buffer[bank] |= bankmask & (bits[idx] >> shift);
+	}
+	__gen_74x164_write_config(chip);
+	mutex_unlock(&chip->lock);
+}
+
 static int gen_74x164_direction_output(struct gpio_chip *gc,
 		unsigned offset, int val)
 {
@@ -114,6 +137,7 @@  static int gen_74x164_probe(struct spi_device *spi)
 	chip->gpio_chip.direction_output = gen_74x164_direction_output;
 	chip->gpio_chip.get = gen_74x164_get_value;
 	chip->gpio_chip.set = gen_74x164_set_value;
+	chip->gpio_chip.set_multiple = gen_74x164_set_multiple;
 	chip->gpio_chip.base = -1;
 
 	chip->registers = nregs;