Skip to contentSkip to conversation

gpio: pcf857x: Implement get_multiple/set_multiple methods

PATCH Superseded Radu Rendec 2 participants 3 messages Jan 4, 2023 – Jan 6, 2023 GPIO

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 gpio: pcf857x: Implement get_multiple/set_multiple methods

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.

---
 drivers/gpio/gpio-pcf857x.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)
drivers/gpio/gpio-pcf857x.c +29 -0
index cec2f2c78255..8a8ffeaa8b22 100644
@@ -141,6 +141,21 @@ static int pcf857x_get(struct gpio_chip *chip, unsigned 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 offset, int value)
 {
 	struct pcf857x	*gpio = gpiochip_get_data(chip);
@@ -163,6 +178,18 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned 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;
Signature · 1 line
2.39.0
#1 lore raw
Quoted 17 lines · Radu Rendec

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.

---
 drivers/gpio/gpio-pcf857x.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)
drivers/gpio/gpio-pcf857x.c +0 -0
index cec2f2c78255..8a8ffeaa8b22 100644

drivers/gpio/gpio-pcf857x.c static int pcf857x_get(struct gpio_chip *chip, unsigned offset) · line 148

Quoted 8 lines
drivers/gpio/gpio-pcf857x.c +5 -0
@@ -141,6 +141,21 @@ static int pcf857x_get(struct gpio_chip *chip, unsigned 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);

Ugh, this whitespacing is awful but I get it that you only tried to stay consistent with the rest of the code. Could you add a patch before this one that removes those tabs from local variables? IMO This makes the code less readable, not more. While at it: you can also change all instances of 'unsigned' to 'unsigned int' as per the checkpatch rule.

Otherwise it looks good!

Bart

Quoted 45 lines
drivers/gpio/gpio-pcf857x.c +24 -1
+
+       if (value < 0)
+               return value;
+
+       *bits &= ~*mask;
+       *bits |= value & *mask;
+
+       return 0;
+}
+
 static int pcf857x_output(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct pcf857x  *gpio = gpiochip_get_data(chip);
@@ -163,6 +178,18 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned 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;
--

2.39.0

#2 lore raw
Quoted 15 lines · Bartosz Golaszewski

drivers/gpio/gpio-pcf857x.c static int pcf857x_get(struct gpio_chip *chip, unsigned offset) · line 148

Quoted 6 lines · Radu Rendec
drivers/gpio/gpio-pcf857x.c +5 -0
+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);

Ugh, this whitespacing is awful but I get it that you only tried to stay consistent with the rest of the code. Could you add a patch before this one that removes those tabs from local variables? IMO This makes the code less readable, not more. While at it: you can also change all instances of 'unsigned' to 'unsigned int' as per the checkpatch rule.

Quoted 1 line

Otherwise it looks good!

Thanks for reviewing the patch. Happy to remove those weird tabs. I'm not a fan either, and as you guessed I just tried to stay consistent. It's not just the local variables though, it's also the definition of struct pcf857x and some initialization in pcf857x_probe().

I will send a v2 patch series shortly. If you think it's better to fix the other tabs as well, please just let me know. Thanks!

Radu