Reviewed-by: Glenn Miles <[email protected]> Thanks,
Glenn On Thu, 2026-07-09 at 17:23 +0200, Emmanuel Blot wrote: > The PCA9552 shares its device model with the PCA9535/PCA9555 GPIO > expanders but decodes registers differently. Add tests for the behaviour > that is specific to the LED variant and diverges from the PCA9555: > > - the power-on reset defaults of the prescaler, PWM and LED-selector > registers; > - the prescaler/PWM registers (2-5), which are OUTPUT/POLARITY on the > PCA9555, as plain read/write storage; > - the auto-increment, which only advances when the AI command bit is set > and wraps modulo the full 10-register map (rather than toggling bit 0 > within a register pair); > - the 4-bit command decode, where an out-of-range register reads back > 0xFF instead of aliasing into the register window. > > Signed-off-by: Emmanuel Blot <[email protected]> > --- > tests/qtest/pca9552-test.c | 76 > ++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 76 insertions(+) > > diff --git a/tests/qtest/pca9552-test.c b/tests/qtest/pca9552-test.c > index 74749576923..3718dfbd227 100644 > --- a/tests/qtest/pca9552-test.c > +++ b/tests/qtest/pca9552-test.c > @@ -77,6 +77,76 @@ static void send_and_receive(void *obj, void *data, > QGuestAllocator *alloc) > g_assert_cmphex(value, ==, 0xEF); > } > > +/* Verify the power-on reset defaults. */ > +static void test_reset_defaults(void *obj, void *data, QGuestAllocator > *alloc) > +{ > + QI2CDevice *i2cdev = (QI2CDevice *)obj; > + > + /* Prescalers, PWM duty cycles and LED selectors (all LEDs off) */ > + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_PSC0), ==, 0xFF); > + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_PWM0), ==, 0x80); > + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_PSC1), ==, 0xFF); > + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_PWM1), ==, 0x80); > + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_LS0), ==, 0x55); > + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_LS1), ==, 0x55); > + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_LS2), ==, 0x55); > + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_LS3), ==, 0x55); > + > + /* All LEDs off, so every pin floats high through its pull-up */ > + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_INPUT0), ==, 0xFF); > + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_INPUT1), ==, 0xFF); > +} > + > +/* > + * The PCA9552 only advances the command pointer when the AI bit is set, and > + * it wraps modulo the full 10-register map. > + */ > +static void test_autoinc_requires_ai_bit(void *obj, void *data, > + QGuestAllocator *alloc) > +{ > + QI2CDevice *i2cdev = (QI2CDevice *)obj; > + uint8_t reg; > + uint8_t resp; > + > + /* > + * With the AI bit, reading from LS3 (register 9) rolls over to INPUT0 > + * (register 0), not to a sibling in a register pair. All LEDs are off > + * after reset so the input ports read 0xFF. > + */ > + reg = PCA9552_LS3 | PCA9552_AUTOINC; > + qi2c_send(i2cdev, ®, 1); > + qi2c_recv(i2cdev, &resp, 1); /* LS3 */ > + g_assert_cmphex(resp, ==, 0x55); > + qi2c_recv(i2cdev, &resp, 1); /* wraps to INPUT0 */ > + g_assert_cmphex(resp, ==, 0xFF); > + qi2c_recv(i2cdev, &resp, 1); /* INPUT1 */ > + g_assert_cmphex(resp, ==, 0xFF); > + > + /* > + * Without the AI bit the pointer must not advance: repeated reads keep > + * returning the same register. > + */ > + i2c_set8(i2cdev, PCA9552_LS0, 0x54); > + reg = PCA9552_LS0; > + qi2c_send(i2cdev, ®, 1); > + qi2c_recv(i2cdev, &resp, 1); > + g_assert_cmphex(resp, ==, 0x54); > + qi2c_recv(i2cdev, &resp, 1); > + g_assert_cmphex(resp, ==, 0x54); > +} > + > +/* > + * The PCA9552 decodes a 4-bit command and has no register past LS3 (9), so > + * addressing register 0x0A reads back 0xFF. > + */ > +static void test_command_out_of_range(void *obj, void *data, > + QGuestAllocator *alloc) > +{ > + QI2CDevice *i2cdev = (QI2CDevice *)obj; > + > + g_assert_cmphex(i2c_get8(i2cdev, 0x0A), ==, 0xFF); > +} > + > static void pca9552_register_nodes(void) > { > QOSGraphEdgeOptions opts = { > @@ -89,5 +159,11 @@ static void pca9552_register_nodes(void) > > qos_add_test("tx-rx", "pca9552", send_and_receive, NULL); > qos_add_test("rx-autoinc", "pca9552", receive_autoinc, NULL); > + qos_add_test("reset-defaults", "pca9552", test_reset_defaults, NULL); > + qos_add_test("autoinc-requires-ai-bit", "pca9552", > + test_autoinc_requires_ai_bit, NULL); > + qos_add_test("command-out-of-range", "pca9552", > test_command_out_of_range, > + NULL); > } > + > libqos_init(pca9552_register_nodes); >
