From b4818afeacbd81821f89a89951471cffcb6a65e0 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Fri, 4 Dec 2015 15:52:30 +0800 Subject: [PATCH] gpio: pca953x: Add set_multiple to allow multiple bits to be set in one write. Tested with TCA6408 / TCA6416 devices. Signed-off-by: Phil Reid Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 2eaf235a39e5..be3e3b903ff0 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -350,6 +350,43 @@ exit: mutex_unlock(&chip->i2c_lock); } + +static void pca953x_gpio_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) +{ + struct pca953x_chip *chip = to_pca(gc); + u8 reg_val[MAX_BANK]; + int ret, offset = 0; + int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); + int bank; + + switch (chip->chip_type) { + case PCA953X_TYPE: + offset = PCA953X_OUTPUT; + break; + case PCA957X_TYPE: + offset = PCA957X_OUT; + break; + } + + memcpy(reg_val, chip->reg_output, NBANK(chip)); + mutex_lock(&chip->i2c_lock); + for(bank=0; bank> ((bank % 4) * 8); + if(bankmask) { + unsigned bankval = bits[bank/4] >> ((bank % 4) * 8); + reg_val[bank] = (reg_val[bank] & ~bankmask) | bankval; + } + } + ret = i2c_smbus_write_i2c_block_data(chip->client, offset << bank_shift, NBANK(chip), reg_val); + if (ret) + goto exit; + + memcpy(chip->reg_output, reg_val, NBANK(chip)); +exit: + mutex_unlock(&chip->i2c_lock); +} + static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) { struct gpio_chip *gc; @@ -360,6 +397,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->direction_output = pca953x_gpio_direction_output; gc->get = pca953x_gpio_get_value; gc->set = pca953x_gpio_set_value; + gc->set_multiple = pca953x_gpio_set_multiple; gc->can_sleep = true; gc->base = chip->gpio_start;