[PATCH 3/4] gpio: kempld: Add support for get/set multiple

From: Alban Bedel

Date: Wed Mar 11 2026 - 10:32:17 EST


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@xxxxxxxxxx>
---
drivers/gpio/gpio-kempld.c | 60 ++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)

diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c
index 2263de77d40e9..7dd94ff6f2df4 100644
--- a/drivers/gpio/gpio-kempld.c
+++ b/drivers/gpio/gpio-kempld.c
@@ -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");
--
2.39.5