diff options
author | Axel Lin <axel.lin@ingics.com> | 2016-03-23 19:49:41 +0800 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2016-03-31 15:14:37 +0200 |
commit | 6e66a6599a813abfc9ebe2e295c9d557c434812a (patch) | |
tree | c91ccdb0443c7e07a3f207eb56cf730da31ca27d /drivers/gpio/gpio-tpic2810.c | |
parent | 18fb0a981e18b91c6eb1a00f8b06f2fb5be2e9aa (diff) | |
download | linux-6e66a6599a813abfc9ebe2e295c9d557c434812a.tar.gz linux-6e66a6599a813abfc9ebe2e295c9d557c434812a.tar.bz2 linux-6e66a6599a813abfc9ebe2e295c9d557c434812a.zip |
gpio: tpic2810: Make sure cached buffer has consistent status with h/w status
i2c_smbus_write_byte_data() can fail. To ensure the
cached buffer has consistent status with h/w status, don't
update the cached gpio->buffer if write fails.
Also refactor the code a bit by adding a tpic2810_set_mask_bits()
helper and use it to simplify the code.
Signed-off-by: Axel Lin <axel.lin@ingics.com>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpio-tpic2810.c')
-rw-r--r-- | drivers/gpio/gpio-tpic2810.c | 35 |
1 files changed, 15 insertions, 20 deletions
diff --git a/drivers/gpio/gpio-tpic2810.c b/drivers/gpio/gpio-tpic2810.c index 9f020aa4b067..cace79c1b70a 100644 --- a/drivers/gpio/gpio-tpic2810.c +++ b/drivers/gpio/gpio-tpic2810.c @@ -57,39 +57,34 @@ static int tpic2810_direction_output(struct gpio_chip *chip, return 0; } -static void tpic2810_set(struct gpio_chip *chip, unsigned offset, int value) +static void tpic2810_set_mask_bits(struct gpio_chip *chip, u8 mask, u8 bits) { struct tpic2810 *gpio = gpiochip_get_data(chip); + u8 buffer; + int err; mutex_lock(&gpio->lock); - if (value) - gpio->buffer |= BIT(offset); - else - gpio->buffer &= ~BIT(offset); + buffer = gpio->buffer & ~mask; + buffer |= (mask & bits); - i2c_smbus_write_byte_data(gpio->client, TPIC2810_WS_COMMAND, - gpio->buffer); + err = i2c_smbus_write_byte_data(gpio->client, TPIC2810_WS_COMMAND, + buffer); + if (!err) + gpio->buffer = buffer; mutex_unlock(&gpio->lock); } +static void tpic2810_set(struct gpio_chip *chip, unsigned offset, int value) +{ + tpic2810_set_mask_bits(chip, BIT(offset), value ? BIT(offset) : 0); +} + static void tpic2810_set_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits) { - struct tpic2810 *gpio = gpiochip_get_data(chip); - - mutex_lock(&gpio->lock); - - /* clear bits under mask */ - gpio->buffer &= ~(*mask); - /* set bits under mask */ - gpio->buffer |= ((*mask) & (*bits)); - - i2c_smbus_write_byte_data(gpio->client, TPIC2810_WS_COMMAND, - gpio->buffer); - - mutex_unlock(&gpio->lock); + tpic2810_set_mask_bits(chip, *mask, *bits); } static struct gpio_chip template_chip = { |