tests/qtest: pca9555: test auto-increment and command wrapping
Add tests for the I2C command protocol of the GPIO variant: the auto-increment that toggles bit 0 within a register pair on reads and writes, and the 3-bit command wrapping that aliases out-of-range register addresses back into the register window. 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-13-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater <clg@redhat.com>
Emmanuel Blot committed
Jul 9, 2026 at 17:23 UTC
f43ee338662b02827c61c033fcc35be68eae952c
1 file changed
+88
tests/qtest/pca9555-test.c
+88
@@ -139,6 +139,87 @@ static void test_polarity_with_output(void *obj, void *data,
139
g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT0), ==, 0xA5);
140
}
141
142
+/*
143
+ * The PCA9555 auto-increments by toggling bit 0 of the command pointer
144
+ * within a register pair. Reading two bytes from INPUT0 should yield
145
+ * INPUT0 then INPUT1.
146
+ */
147
+static void test_auto_increment_read(void *obj, void *data,
148
+ QGuestAllocator *alloc)
149
+{
150
+ QI2CDevice *dev = (QI2CDevice *)obj;
151
+ uint8_t buf[2];
152
+
153
+ i2c_set8(dev, PCA9535_CONFIG0, 0x00);
154
+ i2c_set8(dev, PCA9535_CONFIG1, 0x00);
155
+ i2c_set8(dev, PCA9535_OUTPUT0, 0xAA);
156
+ i2c_set8(dev, PCA9535_OUTPUT1, 0x55);
157
+
158
+ i2c_read_block(dev, PCA9535_INPUT0, buf, 2);
159
+ g_assert_cmphex(buf[0], ==, 0xAA);
160
+ g_assert_cmphex(buf[1], ==, 0x55);
161
+
162
+ i2c_read_block(dev, PCA9535_OUTPUT0, buf, 2);
163
+ g_assert_cmphex(buf[0], ==, 0xAA);
164
+ g_assert_cmphex(buf[1], ==, 0x55);
165
+}
166
+
167
+/*
168
+ * Auto-increment write: writing two data bytes after a command byte
169
+ * should write to port 0 then port 1 of the addressed register pair.
170
+ */
171
+static void test_auto_increment_write(void *obj, void *data,
172
+ QGuestAllocator *alloc)
173
+{
174
+ QI2CDevice *dev = (QI2CDevice *)obj;
175
+ uint8_t buf[2];
176
+
177
+ buf[0] = 0x12;
178
+ buf[1] = 0x34;
179
+ i2c_write_block(dev, PCA9535_OUTPUT0, buf, 2);
180
+
181
+ g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT0), ==, 0x12);
182
+ g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT1), ==, 0x34);
183
+
184
+ buf[0] = 0x0F;
185
+ buf[1] = 0xF0;
186
+ i2c_write_block(dev, PCA9535_CONFIG0, buf, 2);
187
+
188
+ g_assert_cmphex(i2c_get8(dev, PCA9535_CONFIG0), ==, 0x0F);
189
+ g_assert_cmphex(i2c_get8(dev, PCA9535_CONFIG1), ==, 0xF0);
190
+}
191
+
192
+/*
193
+ * Auto-increment toggles within the pair: starting from port 1 should
194
+ * wrap back to port 0 (toggle bit 0).
195
+ */
196
+static void test_auto_increment_toggle(void *obj, void *data,
197
+ QGuestAllocator *alloc)
198
+{
199
+ QI2CDevice *dev = (QI2CDevice *)obj;
200
+ uint8_t buf[2];
201
+
202
+ i2c_set8(dev, PCA9535_OUTPUT0, 0xAA);
203
+ i2c_set8(dev, PCA9535_OUTPUT1, 0x55);
204
+
205
+ i2c_read_block(dev, PCA9535_OUTPUT1, buf, 2);
206
+ g_assert_cmphex(buf[0], ==, 0x55);
207
+ g_assert_cmphex(buf[1], ==, 0xAA);
208
+}
209
+
210
+/*
211
+ * Verify the command byte wraps at 3 bits: register addresses
212
+ * beyond 7 should alias to the same register (bits [2:0] only).
213
+ */
214
+static void test_command_wrapping(void *obj, void *data, QGuestAllocator *alloc)
215
+{
216
+ QI2CDevice *dev = (QI2CDevice *)obj;
217
+
218
+ i2c_set8(dev, PCA9535_OUTPUT0, 0x42);
219
+
220
+ g_assert_cmphex(i2c_get8(dev, 0x0A), ==, 0x42);
221
+}
222
+
223
static void pca9555_register_nodes(void)
224
{
225
QOSGraphEdgeOptions opts = {
@@ -158,6 +239,13 @@ static void pca9555_register_nodes(void)
239
NULL);
240
qos_add_test("polarity-with-output", "pca9555", test_polarity_with_output,
241
NULL);
242
+ qos_add_test("auto-increment-read", "pca9555", test_auto_increment_read,
243
+ NULL);
244
+ qos_add_test("auto-increment-write", "pca9555", test_auto_increment_write,
245
+ NULL);
246
+ qos_add_test("auto-increment-toggle", "pca9555", test_auto_increment_toggle,
247
+ NULL);
248
+ qos_add_test("command-wrapping", "pca9555", test_command_wrapping, NULL);
249
}
250
251
libqos_init(pca9555_register_nodes);