@samitouri / QOSamiQemu / commits / f43ee33866

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);