@samitouri / QOSamiQemu / commits / 0e96438679

tests/qtest: pca9555: test output-to-input reflection and pull-ups

Add tests covering the pin I/O semantics of the expander: output-driven pins reflected in the input register, the pull-up seen on input-configured pins, and the independence of the two 8-bit ports. Signed-off-by: Emmanuel Blot <emmanuel.blot@free.fr> Reviewed-by: Glenn Miles <milesg@linux.ibm.com> Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-11-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater <clg@redhat.com>

Emmanuel Blot committed Jul 9, 2026 at 17:23 UTC 0e964386792dcd40e6657155db8545a814eefa4b
1 file changed +75
tests/qtest/pca9555-test.c
+75
@@ -28,6 +28,77 @@ static void test_reset_defaults(void *obj, void *data, QGuestAllocator *alloc)
28 g_assert_cmphex(i2c_get8(dev, PCA9535_CONFIG1), ==, 0xFF);
29 }
30
31 +/*
32 + * When a pin is configured as output and driven low (output=0, config=0),
33 + * the input register should reflect 0 for that pin.
34 + * When driven high (output=1, config=0), input should reflect 1.
35 + * When configured as input (config=1), PCA5555 pull-up makes it read 1.
36 + */
37 +static void test_output_drives_input(void *obj, void *data,
38 + QGuestAllocator *alloc)
39 +{
40 + QI2CDevice *dev = (QI2CDevice *)obj;
41 +
42 + i2c_set8(dev, PCA9535_CONFIG0, 0xF0);
43 + i2c_set8(dev, PCA9535_OUTPUT0, 0xFA);
44 +
45 + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0xFA);
46 +
47 + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT1), ==, 0xFF);
48 +
49 + i2c_set8(dev, PCA9535_CONFIG0, 0x00);
50 + i2c_set8(dev, PCA9535_OUTPUT0, 0x00);
51 + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0x00);
52 +
53 + i2c_set8(dev, PCA9535_OUTPUT0, 0xFF);
54 + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0xFF);
55 +}
56 +
57 +/*
58 + * When all pins are inputs (config=0xFF) and no external driver,
59 + * PCA9555 pull-ups should make the input register read all ones.
60 + * Switching a pin to output mode with output=0 should drive it low.
61 + */
62 +static void test_input_pullup(void *obj, void *data, QGuestAllocator *alloc)
63 +{
64 + QI2CDevice *dev = (QI2CDevice *)obj;
65 +
66 + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0xFF);
67 + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT1), ==, 0xFF);
68 +
69 + i2c_set8(dev, PCA9535_OUTPUT0, 0x00);
70 + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0xFF);
71 +
72 + i2c_set8(dev, PCA9535_CONFIG0, 0x00);
73 + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0x00);
74 +}
75 +
76 +/*
77 + * Test that both ports are independent: changing port 0 registers
78 + * should not affect port 1 and vice versa.
79 + */
80 +static void test_port_independence(void *obj, void *data,
81 + QGuestAllocator *alloc)
82 +{
83 + QI2CDevice *dev = (QI2CDevice *)obj;
84 +
85 + i2c_set8(dev, PCA9535_CONFIG0, 0x00);
86 + i2c_set8(dev, PCA9535_OUTPUT0, 0x00);
87 +
88 + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0x00);
89 + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT1), ==, 0xFF);
90 + g_assert_cmphex(i2c_get8(dev, PCA9535_CONFIG1), ==, 0xFF);
91 + g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT1), ==, 0xFF);
92 +
93 + i2c_set8(dev, PCA9535_CONFIG1, 0x00);
94 + i2c_set8(dev, PCA9535_OUTPUT1, 0xAA);
95 +
96 + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0x00);
97 + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT1), ==, 0xAA);
98 + g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT0), ==, 0x00);
99 + g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT1), ==, 0xAA);
100 +}
101 +
102 static void pca9555_register_nodes(void)
103 {
104 QOSGraphEdgeOptions opts = {
@@ -39,6 +110,10 @@ static void pca9555_register_nodes(void)
110 qos_node_consumes("pca9555", "i2c-bus", &opts);
111
112 qos_add_test("reset-defaults", "pca9555", test_reset_defaults, NULL);
113 + qos_add_test("output-drives-input", "pca9555", test_output_drives_input,
114 + NULL);
115 + qos_add_test("input-pullup", "pca9555", test_input_pullup, NULL);
116 + qos_add_test("port-independence", "pca9555", test_port_independence, NULL);
117 }
118
119 libqos_init(pca9555_register_nodes);