tests/qtest: pca9554: test output-to-input reflection and pull-ups
Check that a pin configured as output drives its OUTPUT register level onto the pin (push-pull) as reflected by the INPUT register, and that a pin configured as input floats high through its pull-up. 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-20-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater <clg@redhat.com>
Emmanuel Blot committed
Jul 9, 2026 at 17:23 UTC
e5f73c36dbf0f52e1006d907d5ef283c9c01b52c
1 file changed
+45
tests/qtest/pca9554-test.c
+45
@@ -25,6 +25,48 @@ static void test_reset_defaults(void *obj, void *data, QGuestAllocator *alloc)
25
g_assert_cmphex(i2c_get8(dev, PCA9554_CONFIG), ==, 0xFF);
26
}
27
28
+/*
29
+ * A pin configured as output (config=0) drives its OUTPUT register level onto
30
+ * the pin (push-pull), which the INPUT register reflects. A pin configured as
31
+ * input (config=1) floats high through its pull-up.
32
+ */
33
+static void test_output_drives_input(void *obj, void *data,
34
+ QGuestAllocator *alloc)
35
+{
36
+ QI2CDevice *dev = (QI2CDevice *)obj;
37
+
38
+ /* Low nibble output, high nibble input (pull-up). */
39
+ i2c_set8(dev, PCA9554_CONFIG, 0xF0);
40
+ i2c_set8(dev, PCA9554_OUTPUT, 0xFA);
41
+ g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0xFA);
42
+
43
+ /* All outputs, driven low then high. */
44
+ i2c_set8(dev, PCA9554_CONFIG, 0x00);
45
+ i2c_set8(dev, PCA9554_OUTPUT, 0x00);
46
+ g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x00);
47
+
48
+ i2c_set8(dev, PCA9554_OUTPUT, 0xFF);
49
+ g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0xFF);
50
+}
51
+
52
+/*
53
+ * With all pins configured as inputs the pull-ups make the INPUT register read
54
+ * all ones regardless of the OUTPUT register; switching a pin to output with
55
+ * output=0 drives it low.
56
+ */
57
+static void test_input_pullup(void *obj, void *data, QGuestAllocator *alloc)
58
+{
59
+ QI2CDevice *dev = (QI2CDevice *)obj;
60
+
61
+ g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0xFF);
62
+
63
+ i2c_set8(dev, PCA9554_OUTPUT, 0x00);
64
+ g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0xFF);
65
+
66
+ i2c_set8(dev, PCA9554_CONFIG, 0x00);
67
+ g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x00);
68
+}
69
+
70
static void pca9554_register_nodes(void)
71
{
72
QOSGraphEdgeOptions opts = {
@@ -36,6 +78,9 @@ static void pca9554_register_nodes(void)
78
qos_node_consumes("pca9554", "i2c-bus", &opts);
79
80
qos_add_test("reset-defaults", "pca9554", test_reset_defaults, NULL);
81
+ qos_add_test("output-drives-input", "pca9554", test_output_drives_input,
82
+ NULL);
83
+ qos_add_test("input-pullup", "pca9554", test_input_pullup, NULL);
84
}
85
86
libqos_init(pca9554_register_nodes);