Implement .get_multiple and .set_multiple to allow reading or setting
multiple pins simultaneously. Pins in the same bank will all be switched at
the same time, improving synchronization and performances.

Signed-off-by: Alexandre Belloni <alexandre.bell...@bootlin.com>
---
 drivers/pinctrl/pinctrl-at91-pio4.c | 60 +++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c 
b/drivers/pinctrl/pinctrl-at91-pio4.c
index d6de4d360cd4..488a302a60d4 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -328,6 +328,35 @@ static int atmel_gpio_get(struct gpio_chip *chip, unsigned 
offset)
        return !!(reg & BIT(pin->line));
 }
 
+static int atmel_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+                                  unsigned long *bits)
+{
+       struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
+       unsigned int bank;
+
+       bitmap_zero(bits, atmel_pioctrl->npins);
+
+       for (bank = 0; bank < atmel_pioctrl->nbanks; bank++) {
+               unsigned int word = bank;
+               unsigned int offset = 0;
+               unsigned int reg;
+
+#if ATMEL_PIO_NPINS_PER_BANK != BITS_PER_LONG
+               word = BIT_WORD(bank * ATMEL_PIO_NPINS_PER_BANK);
+               offset = bank * ATMEL_PIO_NPINS_PER_BANK % BITS_PER_LONG;
+#endif
+               if (!mask[word])
+                       continue;
+
+               reg = atmel_gpio_read(atmel_pioctrl, bank, ATMEL_PIO_PDSR);
+               bits[word] |= mask[word] & (reg << offset);
+
+               pr_err("ABE: %d %08x\n", bank, bits[word]);
+       }
+
+       return 0;
+}
+
 static int atmel_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
                                       int value)
 {
@@ -358,11 +387,42 @@ static void atmel_gpio_set(struct gpio_chip *chip, 
unsigned offset, int val)
                         BIT(pin->line));
 }
 
+static void atmel_gpio_set_multiple(struct gpio_chip *chip, unsigned long 
*mask,
+                                   unsigned long *bits)
+{
+       struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
+       unsigned int bank;
+
+       for (bank = 0; bank < atmel_pioctrl->nbanks; bank++) {
+               unsigned int bitmask;
+               unsigned int word = bank;
+
+#if ATMEL_PIO_NPINS_PER_BANK != BITS_PER_LONG
+               word = BIT_WORD(bank * ATMEL_PIO_NPINS_PER_BANK);
+#endif
+               if (!mask[word])
+                       continue;
+
+               bitmask = mask[word] & bits[word];
+               atmel_gpio_write(atmel_pioctrl, bank, ATMEL_PIO_SODR, bitmask);
+
+               bitmask = mask[word] & ~bits[word];
+               atmel_gpio_write(atmel_pioctrl, bank, ATMEL_PIO_CODR, bitmask);
+
+#if ATMEL_PIO_NPINS_PER_BANK != BITS_PER_LONG
+               mask[word] >>= ATMEL_PIO_NPINS_PER_BANK;
+               bits[word] >>= ATMEL_PIO_NPINS_PER_BANK;
+#endif
+       }
+}
+
 static struct gpio_chip atmel_gpio_chip = {
        .direction_input        = atmel_gpio_direction_input,
        .get                    = atmel_gpio_get,
+       .get_multiple           = atmel_gpio_get_multiple,
        .direction_output       = atmel_gpio_direction_output,
        .set                    = atmel_gpio_set,
+       .set_multiple           = atmel_gpio_set_multiple,
        .to_irq                 = atmel_gpio_to_irq,
        .base                   = 0,
 };
-- 
2.21.0

Reply via email to