]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
gpio: kempld: Add support for get/set multiple
authorAlban Bedel <alban.bedel@lht.dlh.de>
Wed, 11 Mar 2026 14:31:19 +0000 (15:31 +0100)
committerBartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Mon, 16 Mar 2026 09:05:33 +0000 (10:05 +0100)
As the bus accesses are quiet slow with this device, supporting the
get/set multiple API can help with performences. The implementation
tries to keep the number of bus access to a minimum by checking
the mask to only read or write the needed bytes.

Signed-off-by: Alban Bedel <alban.bedel@lht.dlh.de>
Link: https://patch.msgid.link/20260311143120.2179347-4-alban.bedel@lht.dlh.de
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
drivers/gpio/gpio-kempld.c

index 2263de77d40e962b266120126e4133d382ef0a3c..7dd94ff6f2df40bb8653ab504d3390240c6324d6 100644 (file)
@@ -65,6 +65,33 @@ static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset)
        return !!kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL, offset);
 }
 
+static int kempld_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+                                   unsigned long *bits)
+{
+       struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
+       struct kempld_device_data *pld = gpio->pld;
+       u8 reg = KEMPLD_GPIO_LVL;
+       unsigned int shift;
+
+       bits[0] &= ~mask[0];
+
+       kempld_get_mutex(pld);
+
+       /* Try to reduce to a single 8 bits access if possible */
+       for (shift = 0; shift < gpio->chip.ngpio; shift += 8, reg++) {
+               unsigned long msk = (mask[0] >> shift) & 0xff;
+
+               if (!msk)
+                       continue;
+
+               bits[0] |= (kempld_read8(pld, reg) & msk) << shift;
+       }
+
+       kempld_release_mutex(pld);
+
+       return 0;
+}
+
 static int kempld_gpio_set(struct gpio_chip *chip, unsigned int offset,
                           int value)
 {
@@ -78,6 +105,37 @@ static int kempld_gpio_set(struct gpio_chip *chip, unsigned int offset,
        return 0;
 }
 
+static int kempld_gpio_set_multiple(struct gpio_chip *chip,
+                                   unsigned long *mask, unsigned long *bits)
+{
+       struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
+       struct kempld_device_data *pld = gpio->pld;
+       u8 reg = gpio->out_lvl_reg;
+       unsigned int shift;
+
+       kempld_get_mutex(pld);
+
+       /* Try to reduce to a single 8 bits access if possible */
+       for (shift = 0; shift < gpio->chip.ngpio; shift += 8, reg++) {
+               u8 val, msk = mask[0] >> shift;
+
+               if (!msk)
+                       continue;
+
+               if (msk != 0xFF)
+                       val = kempld_read8(pld, reg) & ~msk;
+               else
+                       val = 0;
+
+               val |= (bits[0] >> shift) & msk;
+               kempld_write8(pld, reg, val);
+       }
+
+       kempld_release_mutex(pld);
+
+       return 0;
+}
+
 static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
        struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
@@ -180,7 +238,9 @@ static int kempld_gpio_probe(struct platform_device *pdev)
        chip->direction_output = kempld_gpio_direction_output;
        chip->get_direction = kempld_gpio_get_direction;
        chip->get = kempld_gpio_get;
+       chip->get_multiple = kempld_gpio_get_multiple;
        chip->set = kempld_gpio_set;
+       chip->set_multiple = kempld_gpio_set_multiple;
        chip->ngpio = kempld_gpio_pincount(pld);
        if (chip->ngpio == 0) {
                dev_err(dev, "No GPIO pins detected\n");