gpio: gpio-pca953x, Add get_multiple function
PATCH 1/1 gpio: gpio-pca953x, Add get_multiple function
Implement a get_multiple function for gpio-pca953x. If a driver leaves get_multiple unimplemented then gpio_chip_get_multiple() in gpiolib.c takes care of it by calling chip->get() as needed. For i2c chips this is very inefficient. For example if you do an 8-bit read then instead of a single i2c transaction there are 8 transactions reading the same byte!
This has been tested with max7312 chips on a 5.2 kernel.
--- drivers/gpio/gpio-pca953x.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+)
drivers/gpio/gpio-pca953x.c +37 -0
@@ -114,6 +114,7 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);#define MAX_BANK 5#define BANK_SZ 8 +#define BANK_SFT 3/* ilog2(BANK_SZ) */ #define NBANK (chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ)
@@ -451,6 +452,41 @@ static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off)return !!(reg_val & bit); } +static int pca953x_gpio_get_multiple (struct gpio_chip *gc, +unsigned long *mask,unsigned long *bits) +{ +struct pca953x_chip *chip =gpiochip_get_data (gc); +unsigned int reg_val; +int offset, value, i, ret =0 ; +u8 inreg; + +/* Force offset outside the range of i so that +* at least the first relevant register is read +*/ + offset = gc->ngpio; +for_each_set_bit (i, mask, gc->ngpio) { +/* whenever i goes into a new bank update inreg +* and read the register +*/ +if ((offset >>BANK_SFT ) != (i >>BANK_SFT )) { + offset = i; + inreg =pca953x_recalc_addr (chip, chip->regs->input, + offset, true, false); +mutex_lock (&chip->i2c_lock); + ret =regmap_read (chip->regmap, inreg, ®_val); +mutex_unlock (&chip->i2c_lock); +if (ret <0 ) +return ret; + } +/* reg_val is relative to the last read byte, +* so only shift the relative bits +*/ + value = (reg_val >> (i %8 )) &0x01 ; +__assign_bit (i, bits, value); + } +return ret; +} +static void pca953x_gpio_set_multiple (struct gpio_chip *gc,unsigned long *mask,unsigned long *bits) {
@@ -547,6 +583,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->get = pca953x_gpio_get_value; gc->set = pca953x_gpio_set_value; gc->get_direction = pca953x_gpio_get_direction; + gc->get_multiple = pca953x_gpio_get_multiple; gc->set_multiple = pca953x_gpio_set_multiple; gc->set_config = pca953x_gpio_set_config; gc->can_sleep = true;
Signature · 1 line
2.17.1
pon., 6 kwi 2020 o 18:53 Paul Thomas <[email protected]> napisał(a):
Quoted 8 lines
Implement a
get_multiplefunction for gpio-pca953x. If a driver leavesget_multipleunimplemented thengpio_chip_get_multiple()ingpiolib.ctakes care of it by callingchip->get()as needed. For i2c chips this is very inefficient. For example if you do an 8-bit read then instead of a single i2c transaction there are 8 transactions reading the same byte!
Quoted 4 lines
This has been tested with max7312 chips on a 5.2 kernel.
Signed-off-by Paul Thomas <[email protected]>---
Hi, this doesn't apply on top of current master. Can you rebase it on top of v5.7-rc1 and resend?
Bart
Quoted 2 lines
Hi, this doesn't apply on top of current master. Can you rebase it on top of v5.7-rc1 and resend?
Yeah, I saw that. I'll resend it.
-Paul
Quoted 2 lines
Bart