Reviewed-by: Glenn Miles <[email protected]> Thanks,
Glenn On Thu, 2026-07-09 at 17:23 +0200, Emmanuel Blot wrote: > The PCA9535 polarity inversion register inverts the value read back from > the input port for every pin, regardless of its direction, and does not > affect the output drive or the physical pin level. > > Store the raw pin level in the input register and apply the polarity > inversion when the input port is read, instead of XORing it into the > stored value of output-configured pins only. The interrupt output now > reflects the raw pin level, matching the datasheet. > > Signed-off-by: Emmanuel Blot <[email protected]> > --- > hw/gpio/pca9552.c | 25 ++++++++++++++++++------- > 1 file changed, 18 insertions(+), 7 deletions(-) > > diff --git a/hw/gpio/pca9552.c b/hw/gpio/pca9552.c > index 66f699bf6a..24f6465415 100644 > --- a/hw/gpio/pca9552.c > +++ b/hw/gpio/pca9552.c > @@ -167,9 +167,12 @@ static void pca955x_update_pin_input(PCA955xState *s) > /* PCA9535: Simple GPIO behavior */ > uint8_t config_reg = PCA9535_CONFIG0 + (i / 8); > uint8_t output_reg = PCA9535_OUTPUT0 + (i / 8); > - uint8_t polarity_reg = PCA9535_POLARITY0 + (i / 8); > > - /* Check if pin is configured as input */ > + /* > + * The input register holds the raw pin logic level; the > + * polarity inversion register is only applied when the input > + * port is read (see pca955x_read()). > + */ > if (s->regs[config_reg] & bit_mask) { > /* Input mode - reflect external state */ > if (s->ext_state[i] == PCA9552_PIN_LOW) { > @@ -179,12 +182,8 @@ static void pca955x_update_pin_input(PCA955xState *s) > } > } else { > /* Output mode - reflect output register value */ > - uint8_t output_bit = s->regs[output_reg] & bit_mask; > - uint8_t polarity_bit = s->regs[polarity_reg] & bit_mask; > - > - /* Apply polarity inversion if set */ > s->regs[input_reg] = (s->regs[input_reg] & ~bit_mask) | > - ((output_bit ^ polarity_bit) & bit_mask); > + (s->regs[output_reg] & bit_mask); > } > } > > @@ -206,6 +205,18 @@ static uint8_t pca955x_read(PCA955xState *s, uint8_t reg) > return 0xFF; > } > > + /* > + * On the GPIO variants, reading an input port returns the raw pin > + * levels XORed with the polarity inversion register, as specified by > + * the datasheet. > + */ > + if (!k->has_led_support && > + (reg == PCA9535_INPUT0 || reg == PCA9535_INPUT1)) { > + uint8_t polarity_reg = PCA9535_POLARITY0 + (reg - PCA9535_INPUT0); > + > + return s->regs[reg] ^ s->regs[polarity_reg]; > + } > + > return s->regs[reg]; > } > >
