Message ID | 20200330195018.27494-2-u.kleine-koenig@pengutronix.de |
---|---|
State | New |
Headers | show |
Series | gpio: pca953x: fix handling of automatic address incrementing | expand |
On Mon, Mar 30, 2020 at 09:50:17PM +0200, Uwe Kleine-König wrote: > Some of the chips supported by the pca953x driver need the most > significant bit in the address word set to automatically increment the > address pointer on subsequent reads and writes (example: PCA9505). With > this bit unset the same register is read multiple times on a multi-byte > read sequence. Other chips must not have this bit set and autoincrement > always (example: PCA9555). > > Up to now this AI bit was interpreted to be part of the address, which > resulted in inconsistent regmap caching when a register was written with > AI set and then read without it. This happened for the PCA9505 in > pca953x_gpio_set_multiple() where pca953x_read_regs() bulk read from the > cache for registers 0x8-0xc and then wrote to registers 0x88-0x8c. (Side > note: reading 5 values from offset 0x8 yiels OP0 5 times because AI must > be set to get OP0-OP4, which is another bug that is resolved here as a > by-product.) The same problem happens when calls to gpio_set_value() and > gpio_set_array_value() were mixed. > > With this patch the AI bit is always set for chips that support it. This > works as there are no code locations that make use of the behaviour with > AI unset (for the chips that support it). > > Note that the call to pca953x_setup_gpio() had to be done a bit earlier > to make the NBANK macro work. > > The history of this bug is a bit complicated. Commit b32cecb46bdc > ("gpio: pca953x: Extract the register address mangling to single > function") changed which chips and functions are affected. Commit > 3b00691cc46a ("gpio: pca953x: hack to fix 24 bit gpio expanders") used > some duct tape to make the driver at least appear to work. Commit > 49427232764d ("gpio: pca953x: Perform basic regmap conversion") > introduced the caching. Commit b4818afeacbd ("gpio: pca953x: Add > set_multiple to allow multiple bits to be set in one write.") introduced > the .set_multiple() callback which didn't work for chips that need the > AI bit which was fixed later for some chips in 8958262af3fb ("gpio: > pca953x: Repair multi-byte IO address increment on PCA9575"). So I'm > sorry, I don't know which commit I should pick for a Fixes: line. > Tags were applied to both patches. Just to elaborate here as well that I have tested on PCA9555 (GPIO mode + IRQ mode) and since it doesn't use AI, I haven't found any regressions. Tested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> > Tested-by: Marcel Gudert <m.gudert@eckelmann.de> > Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> > --- > drivers/gpio/gpio-pca953x.c | 44 +++++++++++++++++++++++-------------- > 1 file changed, 28 insertions(+), 16 deletions(-) > > diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c > index 5638b4e5355f..8168558299c2 100644 > --- a/drivers/gpio/gpio-pca953x.c > +++ b/drivers/gpio/gpio-pca953x.c > @@ -307,8 +307,22 @@ static const struct regmap_config pca953x_i2c_regmap = { > .volatile_reg = pca953x_volatile_register, > > .cache_type = REGCACHE_RBTREE, > - /* REVISIT: should be 0x7f but some 24 bit chips use REG_ADDR_AI */ > - .max_register = 0xff, > + .max_register = 0x7f, > +}; > + > +static const struct regmap_config pca953x_ai_i2c_regmap = { > + .reg_bits = 8, > + .val_bits = 8, > + > + .read_flag_mask = REG_ADDR_AI, > + .write_flag_mask = REG_ADDR_AI, > + > + .readable_reg = pca953x_readable_register, > + .writeable_reg = pca953x_writeable_register, > + .volatile_reg = pca953x_volatile_register, > + > + .cache_type = REGCACHE_RBTREE, > + .max_register = 0x7f, > }; > > static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off, > @@ -319,18 +333,6 @@ static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off, > int pinctrl = (reg & PCAL_PINCTRL_MASK) << 1; > u8 regaddr = pinctrl | addr | (off / BANK_SZ); > > - /* Single byte read doesn't need AI bit set. */ > - if (!addrinc) > - return regaddr; > - > - /* Chips with 24 and more GPIOs always support Auto Increment */ > - if (write && NBANK(chip) > 2) > - regaddr |= REG_ADDR_AI; > - > - /* PCA9575 needs address-increment on multi-byte writes */ > - if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) > - regaddr |= REG_ADDR_AI; > - > return regaddr; > } > > @@ -863,6 +865,7 @@ static int pca953x_probe(struct i2c_client *client, > int ret; > u32 invert = 0; > struct regulator *reg; > + const struct regmap_config *regmap_config; > > chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); > if (chip == NULL) > @@ -925,7 +928,17 @@ static int pca953x_probe(struct i2c_client *client, > > i2c_set_clientdata(client, chip); > > - chip->regmap = devm_regmap_init_i2c(client, &pca953x_i2c_regmap); > + pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK); > + > + if (NBANK(chip) > 2 || PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) { > + dev_info(&client->dev, "using AI\n"); > + regmap_config = &pca953x_ai_i2c_regmap; > + } else { > + dev_info(&client->dev, "using no AI\n"); > + regmap_config = &pca953x_i2c_regmap; > + } > + > + chip->regmap = devm_regmap_init_i2c(client, regmap_config); > if (IS_ERR(chip->regmap)) { > ret = PTR_ERR(chip->regmap); > goto err_exit; > @@ -956,7 +969,6 @@ static int pca953x_probe(struct i2c_client *client, > /* initialize cached registers from their original values. > * we can't share this chip with another i2c master. > */ > - pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK); > > if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) { > chip->regs = &pca953x_regs; > -- > 2.26.0.rc2 >
On Mon, Mar 30, 2020 at 09:50:17PM +0200, Uwe Kleine-König wrote: ... > The history of this bug is a bit complicated. Commit b32cecb46bdc > ("gpio: pca953x: Extract the register address mangling to single > function") changed which chips and functions are affected. Commit > 3b00691cc46a ("gpio: pca953x: hack to fix 24 bit gpio expanders") used > some duct tape to make the driver at least appear to work. Commit > 49427232764d ("gpio: pca953x: Perform basic regmap conversion") > introduced the caching. Commit b4818afeacbd ("gpio: pca953x: Add > set_multiple to allow multiple bits to be set in one write.") introduced > the .set_multiple() callback which didn't work for chips that need the > AI bit which was fixed later for some chips in 8958262af3fb ("gpio: > pca953x: Repair multi-byte IO address increment on PCA9575"). So I'm > sorry, I don't know which commit I should pick for a Fixes: line. It's allowed to put more, but I rather utilize Depends-on for that. So, something like Fixes: b4818afeacbd ... Depends-on: 8958262af3fb ...
Hello, obviously I failed to Cc: the gpio maintainers. Should I resend because of that? On Tue, Mar 31, 2020 at 01:07:59PM +0300, Andy Shevchenko wrote: > On Mon, Mar 30, 2020 at 09:50:17PM +0200, Uwe Kleine-König wrote: > > ... > > > The history of this bug is a bit complicated. Commit b32cecb46bdc > > ("gpio: pca953x: Extract the register address mangling to single > > function") changed which chips and functions are affected. Commit > > 3b00691cc46a ("gpio: pca953x: hack to fix 24 bit gpio expanders") used > > some duct tape to make the driver at least appear to work. Commit > > 49427232764d ("gpio: pca953x: Perform basic regmap conversion") > > introduced the caching. Commit b4818afeacbd ("gpio: pca953x: Add > > set_multiple to allow multiple bits to be set in one write.") introduced > > the .set_multiple() callback which didn't work for chips that need the > > AI bit which was fixed later for some chips in 8958262af3fb ("gpio: > > pca953x: Repair multi-byte IO address increment on PCA9575"). So I'm > > sorry, I don't know which commit I should pick for a Fixes: line. > > It's allowed to put more, but I rather utilize Depends-on for that. > > So, something like > > Fixes: b4818afeacbd ... > Depends-on: 8958262af3fb ... I don't know what is best here. Using Fixes: b4818afeacbd ("gpio: pca953x: Add set_multiple to allow multiple bits to be set in one write.") seems sensible. Not sure which commits are sensible to list in Depends-on lines. I tend to just don't list any and then backport on request of the stable maintainers iff and when application to older versions failed. Linus/Bartosz: Do you care for application of the tags according to your taste? Best regards Uwe
On Tue, Apr 14, 2020 at 12:15:45PM +0200, Uwe Kleine-König wrote: > Hello, > > obviously I failed to Cc: the gpio maintainers. Should I resend because > of that? I guess it's better to do because of - this, - v5.7-rc1 is out, makes sense to rebase. ... > > So, something like > > > > Fixes: b4818afeacbd ... > > Depends-on: 8958262af3fb ... > > I don't know what is best here. Using > > Fixes: b4818afeacbd ("gpio: pca953x: Add set_multiple to allow multiple bits to be set in one write.") > > seems sensible. Not sure which commits are sensible to list in > Depends-on lines. I tend to just don't list any and then backport on > request of the stable maintainers iff and when application to older > versions failed. Depends-on, in my opinion, is good to have to show at least one significant dependency for the fix.
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 5638b4e5355f..8168558299c2 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -307,8 +307,22 @@ static const struct regmap_config pca953x_i2c_regmap = { .volatile_reg = pca953x_volatile_register, .cache_type = REGCACHE_RBTREE, - /* REVISIT: should be 0x7f but some 24 bit chips use REG_ADDR_AI */ - .max_register = 0xff, + .max_register = 0x7f, +}; + +static const struct regmap_config pca953x_ai_i2c_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .read_flag_mask = REG_ADDR_AI, + .write_flag_mask = REG_ADDR_AI, + + .readable_reg = pca953x_readable_register, + .writeable_reg = pca953x_writeable_register, + .volatile_reg = pca953x_volatile_register, + + .cache_type = REGCACHE_RBTREE, + .max_register = 0x7f, }; static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off, @@ -319,18 +333,6 @@ static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off, int pinctrl = (reg & PCAL_PINCTRL_MASK) << 1; u8 regaddr = pinctrl | addr | (off / BANK_SZ); - /* Single byte read doesn't need AI bit set. */ - if (!addrinc) - return regaddr; - - /* Chips with 24 and more GPIOs always support Auto Increment */ - if (write && NBANK(chip) > 2) - regaddr |= REG_ADDR_AI; - - /* PCA9575 needs address-increment on multi-byte writes */ - if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) - regaddr |= REG_ADDR_AI; - return regaddr; } @@ -863,6 +865,7 @@ static int pca953x_probe(struct i2c_client *client, int ret; u32 invert = 0; struct regulator *reg; + const struct regmap_config *regmap_config; chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) @@ -925,7 +928,17 @@ static int pca953x_probe(struct i2c_client *client, i2c_set_clientdata(client, chip); - chip->regmap = devm_regmap_init_i2c(client, &pca953x_i2c_regmap); + pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK); + + if (NBANK(chip) > 2 || PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) { + dev_info(&client->dev, "using AI\n"); + regmap_config = &pca953x_ai_i2c_regmap; + } else { + dev_info(&client->dev, "using no AI\n"); + regmap_config = &pca953x_i2c_regmap; + } + + chip->regmap = devm_regmap_init_i2c(client, regmap_config); if (IS_ERR(chip->regmap)) { ret = PTR_ERR(chip->regmap); goto err_exit; @@ -956,7 +969,6 @@ static int pca953x_probe(struct i2c_client *client, /* initialize cached registers from their original values. * we can't share this chip with another i2c master. */ - pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK); if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) { chip->regs = &pca953x_regs;