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];
>  }
>  
> 


Reply via email to