gpio: pca953x: Add set_multiple to allow multiple bits to be set in one write.
authorPhil Reid <preid@electromag.com.au>
Fri, 4 Dec 2015 07:52:30 +0000 (15:52 +0800)
committerLinus Walleij <linus.walleij@linaro.org>
Thu, 10 Dec 2015 22:57:43 +0000 (23:57 +0100)
Tested with TCA6408 / TCA6416 devices.

Signed-off-by: Phil Reid <preid@electromag.com.au>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/gpio/gpio-pca953x.c

index 2eaf235..be3e3b9 100644 (file)
@@ -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<NBANK(chip); bank++) {
+               unsigned bankmask = mask[bank/4] >> ((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;