gpio: pcf857x: Implement get_multiple/set_multiple methods
authorRadu Rendec <radu.rendec@gmail.com>
Fri, 6 Jan 2023 16:04:19 +0000 (11:04 -0500)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Mon, 30 Jan 2023 14:55:29 +0000 (15:55 +0100)
This change allows the GPIO core to read/change multiple pins in a
single driver call and subsequent I2C transfer. It helps a lot with
PCF857x devices, since their I2C protocol always reads/changes all
existing pins anyway. Therefore, when the GPIO client code does a bulk
operation on multiple pins, the driver makes a single I2C transfer.

Signed-off-by: Radu Rendec <radu.rendec@gmail.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
drivers/gpio/gpio-pcf857x.c

index 1026973..d9db878 100644 (file)
@@ -141,6 +141,21 @@ static int pcf857x_get(struct gpio_chip *chip, unsigned int offset)
        return (value < 0) ? value : !!(value & (1 << offset));
 }
 
+static int pcf857x_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+                               unsigned long *bits)
+{
+       struct pcf857x *gpio = gpiochip_get_data(chip);
+       int value = gpio->read(gpio->client);
+
+       if (value < 0)
+               return value;
+
+       *bits &= ~*mask;
+       *bits |= value & *mask;
+
+       return 0;
+}
+
 static int pcf857x_output(struct gpio_chip *chip, unsigned int offset, int value)
 {
        struct pcf857x *gpio = gpiochip_get_data(chip);
@@ -163,6 +178,18 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned int offset, int value)
        pcf857x_output(chip, offset, value);
 }
 
+static void pcf857x_set_multiple(struct gpio_chip *chip, unsigned long *mask,
+                                unsigned long *bits)
+{
+       struct pcf857x *gpio = gpiochip_get_data(chip);
+
+       mutex_lock(&gpio->lock);
+       gpio->out &= ~*mask;
+       gpio->out |= *bits & *mask;
+       gpio->write(gpio->client, gpio->out);
+       mutex_unlock(&gpio->lock);
+}
+
 /*-------------------------------------------------------------------------*/
 
 static irqreturn_t pcf857x_irq(int irq, void *data)
@@ -275,7 +302,9 @@ static int pcf857x_probe(struct i2c_client *client)
        gpio->chip.parent               = &client->dev;
        gpio->chip.owner                = THIS_MODULE;
        gpio->chip.get                  = pcf857x_get;
+       gpio->chip.get_multiple         = pcf857x_get_multiple;
        gpio->chip.set                  = pcf857x_set;
+       gpio->chip.set_multiple         = pcf857x_set_multiple;
        gpio->chip.direction_input      = pcf857x_input;
        gpio->chip.direction_output     = pcf857x_output;
        gpio->chip.ngpio                = id->driver_data;