Reviewed-by: Glenn Miles <[email protected]>

Thanks,

Glenn

On Thu, 2026-07-09 at 17:23 +0200, Emmanuel Blot wrote:
> The PCA9536 shares the PCA9554 register map and code path but exposes
> only four pins. Add a pca9536 node and check its reset defaults and
> output-to-input reflection are masked to the low nibble.
> 
> Signed-off-by: Emmanuel Blot <[email protected]>
> ---
>  tests/qtest/pca9554-test.c | 70 
> ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 70 insertions(+)
> 
> diff --git a/tests/qtest/pca9554-test.c b/tests/qtest/pca9554-test.c
> index 0da1f3304b..5366e71984 100644
> --- a/tests/qtest/pca9554-test.c
> +++ b/tests/qtest/pca9554-test.c
> @@ -129,6 +129,66 @@ static void test_no_autoincrement(void *obj, void *data,
>      g_assert_cmphex(i2c_get8(dev, PCA9554_POLARITY), ==, 0x33);
>  }
>  
> +/*
> + * The PCA9536 shares the PCA9554 register map but only has four pins, so its
> + * reset defaults and pin logic are masked to the low nibble.
> + */
> +static void test_pca9536_reset_defaults(void *obj, void *data,
> +                                        QGuestAllocator *alloc)
> +{
> +    QI2CDevice *dev = (QI2CDevice *)obj;
> +
> +    g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x0F);
> +    g_assert_cmphex(i2c_get8(dev, PCA9554_OUTPUT), ==, 0x0F);
> +    g_assert_cmphex(i2c_get8(dev, PCA9554_POLARITY), ==, 0x00);
> +    g_assert_cmphex(i2c_get8(dev, PCA9554_CONFIG), ==, 0x0F);
> +}
> +
> +/* Only the four low pins are driven; the upper nibble stays low. */
> +static void test_pca9536_output_drives_input(void *obj, void *data,
> +                                             QGuestAllocator *alloc)
> +{
> +    QI2CDevice *dev = (QI2CDevice *)obj;
> +
> +    i2c_set8(dev, PCA9554_CONFIG, 0x00);
> +
> +    i2c_set8(dev, PCA9554_OUTPUT, 0x0A);
> +    g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x0A);
> +
> +    i2c_set8(dev, PCA9554_OUTPUT, 0x00);
> +    g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x00);
> +}
> +
> +/*
> + * The four upper bits address pins that do not exist on the PCA9536, so 
> writes
> + * to the register map discard them: the writable registers read back with 
> bits
> + * [7:4] cleared, and driving them onto the pins never surfaces in INPUT.
> + */
> +static void test_pca9536_ignores_upper_bits(void *obj, void *data,
> +                                            QGuestAllocator *alloc)
> +{
> +    QI2CDevice *dev = (QI2CDevice *)obj;
> +
> +    /* Bits [7:4] are dropped on write; bits [3:0] survive. */
> +    i2c_set8(dev, PCA9554_OUTPUT, 0xFA);
> +    g_assert_cmphex(i2c_get8(dev, PCA9554_OUTPUT), ==, 0x0A);
> +
> +    i2c_set8(dev, PCA9554_POLARITY, 0xF5);
> +    g_assert_cmphex(i2c_get8(dev, PCA9554_POLARITY), ==, 0x05);
> +
> +    i2c_set8(dev, PCA9554_CONFIG, 0xF3);
> +    g_assert_cmphex(i2c_get8(dev, PCA9554_CONFIG), ==, 0x03);
> +
> +    /*
> +     * With all four pins as outputs, driving 0xFF only affects the low
> +     * nibble.
> +     */
> +    i2c_set8(dev, PCA9554_POLARITY, 0x00);
> +    i2c_set8(dev, PCA9554_CONFIG, 0x00);
> +    i2c_set8(dev, PCA9554_OUTPUT, 0xFF);
> +    g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x0F);
> +}
> +
>  static void pca9554_register_nodes(void)
>  {
>      QOSGraphEdgeOptions opts = {
> @@ -148,6 +208,16 @@ static void pca9554_register_nodes(void)
>      qos_add_test("polarity-with-output", "pca9554", 
> test_polarity_with_output,
>                   NULL);
>      qos_add_test("no-autoincrement", "pca9554", test_no_autoincrement, NULL);
> +
> +    qos_node_create_driver("pca9536", i2c_device_create);
> +    qos_node_consumes("pca9536", "i2c-bus", &opts);
> +
> +    qos_add_test("reset-defaults", "pca9536", test_pca9536_reset_defaults,
> +                 NULL);
> +    qos_add_test("output-drives-input", "pca9536",
> +                 test_pca9536_output_drives_input, NULL);
> +    qos_add_test("ignores-upper-bits", "pca9536",
> +                 test_pca9536_ignores_upper_bits, NULL);
>  }
>  
>  libqos_init(pca9554_register_nodes);
> 


Reply via email to