From: Alban Bedel Date: Wed, 11 Mar 2026 14:31:19 +0000 (+0100) Subject: gpio: kempld: Add support for get/set multiple X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2443c2e1223bda4dcef5563d0154df6a72969922;p=thirdparty%2Fkernel%2Flinux.git gpio: kempld: Add support for get/set multiple 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 Link: https://patch.msgid.link/20260311143120.2179347-4-alban.bedel@lht.dlh.de Signed-off-by: Bartosz Golaszewski --- 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");