master
c 856 lines 30.4 KB
Raw
1 /*
2 * QTest testcase for the ADC128D818 ADC
3 *
4 * Copyright (c) 2026 Meta Platforms, Inc. and affiliates.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "qemu/osdep.h"
10 #include "qemu/bitops.h"
11 #include "libqos/i2c.h"
12 #include "libqos/qgraph.h"
13 #include "libqtest-single.h"
14 #include "qobject/qdict.h"
15
16 #define ADC128D818_TEST_ID "adc128d818-test"
17 #define ADC128D818_TEST_ADDR 0x1f
18
19 /* Register addresses */
20 #define REG_CONFIG 0x00
21 #define REG_INT_STATUS 0x01
22 #define REG_INT_MASK 0x03
23 #define REG_CONV_RATE 0x07
24 #define REG_CH_DISABLE 0x08
25 #define REG_ONE_SHOT 0x09
26 #define REG_DEEP_SHUTDOWN 0x0a
27 #define REG_ADV_CONFIG 0x0b
28 #define REG_BUSY_STATUS 0x0c
29
30 /* Channel Reading Registers (16-bit, read-only) */
31 #define REG_CH_READING_BASE 0x20
32
33 /* Limit Registers (8-bit, read/write) */
34 #define REG_LIMIT_BASE 0x2a
35
36 /* ID Registers (read-only) */
37 #define REG_MANUFACTURER_ID 0x3e
38 #define REG_REVISION_ID 0x3f
39
40 /* Configuration Register (0x00) bitfields */
41 #define CONFIG_START BIT(0)
42 #define CONFIG_INT_ENABLE BIT(1)
43 #define CONFIG_INT_CLEAR BIT(3)
44 #define CONFIG_INITIALIZATION BIT(7)
45
46 /* Advanced Configuration Register (0x0b) bitfields */
47 #define ADV_CONFIG_EXT_REF_EN BIT(0)
48 #define ADV_CONFIG_MODE_1 (1 << 1)
49 #define ADV_CONFIG_MODE_2 (2 << 1)
50 #define ADV_CONFIG_MODE_3 (3 << 1)
51
52 /* Number of channels */
53 #define NUM_CHANNELS 8
54
55 /* Internal VREF in mV */
56 #define INTERNAL_VREF_MV 2560
57
58 /* QMP helpers for setting device properties */
59
60 static void qmp_adc128d818_set(const char *property, int value)
61 {
62 QDict *resp;
63
64 resp = qmp("{ 'execute': 'qom-set', 'arguments':"
65 " { 'path': %s, 'property': %s, 'value': %d } }",
66 ADC128D818_TEST_ID, property, value);
67 g_assert(qdict_haskey(resp, "return"));
68 qobject_unref(resp);
69 }
70
71 static int qmp_adc128d818_get(const char *property)
72 {
73 QDict *resp;
74 int ret;
75
76 resp = qmp("{ 'execute': 'qom-get', 'arguments':"
77 " { 'path': %s, 'property': %s } }",
78 ADC128D818_TEST_ID, property);
79 g_assert(qdict_haskey(resp, "return"));
80 ret = qdict_get_int(resp, "return");
81 qobject_unref(resp);
82 return ret;
83 }
84
85 /* Manufacturer and Revision ID registers */
86 static void test_id_registers(void *obj, void *data, QGuestAllocator *alloc)
87 {
88 QI2CDevice *dev = (QI2CDevice *)obj;
89
90 g_assert_cmphex(i2c_get8(dev, REG_MANUFACTURER_ID), ==, 0x01);
91 g_assert_cmphex(i2c_get8(dev, REG_REVISION_ID), ==, 0x09);
92 }
93
94 /* Power-on-reset default values */
95 static void test_defaults(void *obj, void *data, QGuestAllocator *alloc)
96 {
97 QI2CDevice *dev = (QI2CDevice *)obj;
98 unsigned ch;
99
100 g_assert_cmphex(i2c_get8(dev, REG_CONFIG), ==, 0x08);
101 g_assert_cmphex(i2c_get8(dev, REG_INT_STATUS), ==, 0x00);
102 g_assert_cmphex(i2c_get8(dev, REG_INT_MASK), ==, 0x00);
103 g_assert_cmphex(i2c_get8(dev, REG_CONV_RATE), ==, 0x00);
104 g_assert_cmphex(i2c_get8(dev, REG_CH_DISABLE), ==, 0x00);
105 g_assert_cmphex(i2c_get8(dev, REG_DEEP_SHUTDOWN), ==, 0x00);
106 g_assert_cmphex(i2c_get8(dev, REG_ADV_CONFIG), ==, 0x00);
107 g_assert_cmphex(i2c_get8(dev, REG_BUSY_STATUS), ==, 0x02);
108
109 for (ch = 0u; ch < NUM_CHANNELS; ch++) {
110 g_assert_cmphex(i2c_get8(dev, REG_LIMIT_BASE + ch * 2u), ==, 0xFF);
111 g_assert_cmphex(i2c_get8(dev, REG_LIMIT_BASE + ch * 2u + 1u), ==, 0x00);
112 }
113 }
114
115 /* Software reset via INITIALIZATION bit */
116 static void test_soft_reset(void *obj, void *data, QGuestAllocator *alloc)
117 {
118 QI2CDevice *dev = (QI2CDevice *)obj;
119
120 i2c_set8(dev, REG_INT_MASK, 0xAA);
121 i2c_set8(dev, REG_CH_DISABLE, 0x55);
122 i2c_set8(dev, REG_LIMIT_BASE, 0x42);
123
124 g_assert_cmphex(i2c_get8(dev, REG_INT_MASK), ==, 0xAA);
125 g_assert_cmphex(i2c_get8(dev, REG_CH_DISABLE), ==, 0x55);
126 g_assert_cmphex(i2c_get8(dev, REG_LIMIT_BASE), ==, 0x42);
127
128 i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION);
129
130 g_assert_cmphex(i2c_get8(dev, REG_CONFIG), ==, 0x08);
131 g_assert_cmphex(i2c_get8(dev, REG_INT_MASK), ==, 0x00);
132 g_assert_cmphex(i2c_get8(dev, REG_CH_DISABLE), ==, 0x00);
133 g_assert_cmphex(i2c_get8(dev, REG_LIMIT_BASE), ==, 0xFF);
134 g_assert_cmphex(i2c_get8(dev, REG_BUSY_STATUS), ==, 0x02);
135 }
136
137 /* Verify ain property readback via QMP */
138 static void test_ain_property(void *obj, void *data, QGuestAllocator *alloc)
139 {
140 int value;
141
142 qmp_adc128d818_set("ain3", 1500);
143 value = qmp_adc128d818_get("ain3");
144 g_test_message("Set ain3 = 1500 mV, readback = %d mV", value);
145 g_assert_cmpint(value, ==, 1500);
146
147 qmp_adc128d818_set("temperature", 37500);
148 value = qmp_adc128d818_get("temperature");
149 g_test_message("Set temperature = 37500 mC, readback = %d mC", value);
150 g_assert_cmpint(value, ==, 37500);
151 }
152
153 /* Voltage conversion */
154 static void test_voltage_conversion(void *obj, void *data,
155 QGuestAllocator *alloc)
156 {
157 QI2CDevice *dev = (QI2CDevice *)obj;
158 uint16_t reading;
159
160 qmp_adc128d818_set("ain0", 1280);
161 g_test_message("Injected ain0 = 1280 mV");
162 i2c_set8(dev, REG_CONFIG, CONFIG_START);
163
164 reading = i2c_get16(dev, REG_CH_READING_BASE);
165 g_test_message("Read ch0: raw 0x%04x -> %u mV", reading,
166 (reading >> 4u) * INTERNAL_VREF_MV / 4096u);
167 g_assert_cmphex(reading, ==, 0x8000);
168
169 qmp_adc128d818_set("ain1", 2560);
170 g_test_message("Injected ain1 = 2560 mV");
171 reading = i2c_get16(dev, REG_CH_READING_BASE + 1u);
172 g_test_message("Read ch1: raw 0x%04x -> %u mV", reading,
173 (reading >> 4u) * INTERNAL_VREF_MV / 4096u);
174 g_assert_cmphex(reading, ==, 0xFFF0);
175
176 qmp_adc128d818_set("ain2", 0);
177 g_test_message("Injected ain2 = 0 mV");
178 reading = i2c_get16(dev, REG_CH_READING_BASE + 2u);
179 g_test_message("Read ch2: raw 0x%04x -> %u mV", reading,
180 (reading >> 4u) * INTERNAL_VREF_MV / 4096u);
181 g_assert_cmphex(reading, ==, 0x0000);
182 }
183
184 /* Temperature conversion (mode 0, channel 7 = temperature) */
185 static void
186 test_temperature_conversion(void *obj, void *data, QGuestAllocator *alloc)
187 {
188 QI2CDevice *dev = (QI2CDevice *)obj;
189 uint16_t reading;
190
191 qmp_adc128d818_set("temperature", 25000);
192 g_test_message("Injected temperature = 25000 mC (25.0 deg C)");
193 i2c_set8(dev, REG_CONFIG, CONFIG_START);
194
195 reading = i2c_get16(dev, REG_CH_READING_BASE + 7u);
196 g_test_message("Read ch7: raw 0x%04x -> %d mC", reading,
197 (int16_t)(reading & 0xFF80u) * 500 / 128);
198 g_assert_cmphex(reading, ==, 0x1900);
199 }
200
201 /* Channels with distinct voltages */
202 static void test_all_channels(void *obj, void *data, QGuestAllocator *alloc)
203 {
204 QI2CDevice *dev = (QI2CDevice *)obj;
205 static const uint16_t ain_mv[NUM_CHANNELS] = {
206 0, 320, 640, 960, 1280, 1920, 2240, 2560
207 };
208 static const uint16_t expect[NUM_CHANNELS] = {
209 0x0000, 0x2000, 0x4000, 0x6000, 0x8000, 0xC000, 0xE000, 0xFFF0
210 };
211 uint16_t reading;
212 unsigned ch;
213
214 i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION);
215 i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_1);
216
217 for (ch = 0u; ch < NUM_CHANNELS; ch++) {
218 char name[8];
219 snprintf(name, sizeof(name), "ain%u", ch);
220 qmp_adc128d818_set(name, ain_mv[ch]);
221 }
222
223 i2c_set8(dev, REG_CONFIG, CONFIG_START);
224
225 for (ch = 0u; ch < NUM_CHANNELS; ch++) {
226 reading = i2c_get16(dev, REG_CH_READING_BASE + ch);
227 g_test_message("ch%u: ain %u mV -> raw 0x%04x (expect 0x%04x)",
228 ch, ain_mv[ch], reading, expect[ch]);
229 g_assert_cmphex(reading, ==, expect[ch]);
230 }
231 }
232
233 /* Voltage conversion edge cases */
234 static void test_voltage_edges(void *obj, void *data, QGuestAllocator *alloc)
235 {
236 QI2CDevice *dev = (QI2CDevice *)obj;
237 uint16_t reading;
238
239 i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION);
240 i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_1);
241
242 qmp_adc128d818_set("ain0", 3000);
243 i2c_set8(dev, REG_CONFIG, CONFIG_START);
244
245 reading = i2c_get16(dev, REG_CH_READING_BASE);
246 g_test_message("Over-range 3000 mV: raw 0x%04x (expect 0xFFF0)", reading);
247 g_assert_cmphex(reading, ==, 0xFFF0);
248
249 qmp_adc128d818_set("ain1", 1);
250 reading = i2c_get16(dev, REG_CH_READING_BASE + 1u);
251 g_test_message("1 mV: raw 0x%04x (expect 0x0010)", reading);
252 g_assert_cmphex(reading, ==, 0x0010);
253
254 qmp_adc128d818_set("ain2", 640);
255 reading = i2c_get16(dev, REG_CH_READING_BASE + 2u);
256 g_test_message("640 mV (quarter): raw 0x%04x (expect 0x4000)", reading);
257 g_assert_cmphex(reading, ==, 0x4000);
258
259 qmp_adc128d818_set("ain3", 1920);
260 reading = i2c_get16(dev, REG_CH_READING_BASE + 3u);
261 g_test_message("1920 mV (3/4): raw 0x%04x (expect 0xC000)", reading);
262 g_assert_cmphex(reading, ==, 0xC000);
263 }
264
265 /* Temperature conversion edge cases */
266 static void test_temperature_edges(void *obj, void *data,
267 QGuestAllocator *alloc)
268 {
269 QI2CDevice *dev = (QI2CDevice *)obj;
270 uint16_t reading;
271
272 i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION);
273
274 qmp_adc128d818_set("temperature", 0);
275 i2c_set8(dev, REG_CONFIG, CONFIG_START);
276 reading = i2c_get16(dev, REG_CH_READING_BASE + 7u);
277 g_test_message("0 C: raw 0x%04x (expect 0x0000)", reading);
278 g_assert_cmphex(reading, ==, 0x0000);
279
280 qmp_adc128d818_set("temperature", -25000);
281 reading = i2c_get16(dev, REG_CH_READING_BASE + 7u);
282 g_test_message("-25 C: raw 0x%04x (expect 0xE700)", reading);
283 g_assert_cmphex(reading, ==, 0xE700);
284
285 qmp_adc128d818_set("temperature", 127500);
286 reading = i2c_get16(dev, REG_CH_READING_BASE + 7u);
287 g_test_message("+127.5 C: raw 0x%04x (expect 0x7F80)", reading);
288 g_assert_cmphex(reading, ==, 0x7F80);
289
290 qmp_adc128d818_set("temperature", -128000);
291 reading = i2c_get16(dev, REG_CH_READING_BASE + 7u);
292 g_test_message("-128 C: raw 0x%04x (expect 0x8000)", reading);
293 g_assert_cmphex(reading, ==, 0x8000);
294
295 qmp_adc128d818_set("temperature", 200000);
296 reading = i2c_get16(dev, REG_CH_READING_BASE + 7u);
297 g_test_message("200 C (clamped): raw 0x%04x (expect 0x7F80)", reading);
298 g_assert_cmphex(reading, ==, 0x7F80);
299
300 qmp_adc128d818_set("temperature", -200000);
301 reading = i2c_get16(dev, REG_CH_READING_BASE + 7u);
302 g_test_message("-200 C (clamped): raw 0x%04x (expect 0x8000)", reading);
303 g_assert_cmphex(reading, ==, 0x8000);
304 }
305
306 /* External voltage reference */
307 static void test_ext_vref(void *obj, void *data, QGuestAllocator *alloc)
308 {
309 QI2CDevice *dev = (QI2CDevice *)obj;
310 uint16_t reading;
311
312 i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION);
313 i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_1);
314
315 qmp_adc128d818_set("ext-vref-mv", 4096);
316 i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_EXT_REF_EN | ADV_CONFIG_MODE_1);
317
318 qmp_adc128d818_set("ain0", 1000);
319 i2c_set8(dev, REG_CONFIG, CONFIG_START);
320
321 reading = i2c_get16(dev, REG_CH_READING_BASE);
322 g_test_message("1000 mV / 4096 mV VREF: raw 0x%04x (expect 0x3E80)",
323 reading);
324 g_assert_cmphex(reading, ==, 0x3E80);
325
326 qmp_adc128d818_set("ain1", 2048);
327 reading = i2c_get16(dev, REG_CH_READING_BASE + 1u);
328 g_test_message("2048 mV / 4096 mV VREF: raw 0x%04x (expect 0x8000)",
329 reading);
330 g_assert_cmphex(reading, ==, 0x8000);
331 }
332
333 /* Interrupt status set on limit violation; persists while fault remains */
334 static void test_interrupt_status(void *obj, void *data, QGuestAllocator *alloc)
335 {
336 QI2CDevice *dev = (QI2CDevice *)obj;
337 uint8_t status;
338
339 i2c_set8(dev, REG_LIMIT_BASE, 0x10);
340 g_test_message("Set ch0 high limit = 0x10");
341
342 qmp_adc128d818_set("ain0", 2560);
343 g_test_message("Injected ain0 = 2560 mV (exceeds limit)");
344
345 i2c_set8(dev, REG_CONFIG, CONFIG_START | CONFIG_INT_ENABLE);
346
347 status = i2c_get8(dev, REG_INT_STATUS);
348 g_test_message("INT_STATUS = 0x%02x (expect bit 0 set)", status);
349 g_assert_cmphex(status & 0x01u, ==, 0x01);
350
351 status = i2c_get8(dev, REG_INT_STATUS);
352 g_test_message("INT_STATUS after re-read = 0x%02x (expect bit 0 still set)",
353 status);
354 g_assert_cmphex(status & 0x01u, ==, 0x01);
355
356 qmp_adc128d818_set("ain0", 80);
357 g_test_message("Injected ain0 = 80 mV (within limit)");
358 status = i2c_get8(dev, REG_INT_STATUS);
359 g_test_message("INT_STATUS after fault cleared = 0x%02x "
360 "(expect bit 0 clear)", status);
361 g_assert_cmphex(status & 0x01u, ==, 0x00);
362 }
363
364 /* INT_CLEAR stops the round-robin monitoring loop */
365 static void test_int_clear(void *obj, void *data, QGuestAllocator *alloc)
366 {
367 QI2CDevice *dev = (QI2CDevice *)obj;
368 uint8_t status;
369
370 i2c_set8(dev, REG_LIMIT_BASE, 0x10);
371 qmp_adc128d818_set("ain0", 2560);
372
373 i2c_set8(dev, REG_CONFIG,
374 CONFIG_START | CONFIG_INT_ENABLE | CONFIG_INT_CLEAR);
375 status = i2c_get8(dev, REG_INT_STATUS);
376 g_test_message("INT_STATUS with INT_CLEAR set = 0x%02x (expect 0x00)",
377 status);
378 g_assert_cmphex(status, ==, 0x00);
379
380 i2c_set8(dev, REG_CONFIG, CONFIG_START | CONFIG_INT_ENABLE);
381 status = i2c_get8(dev, REG_INT_STATUS);
382 g_test_message("INT_STATUS after INT_CLEAR cleared = 0x%02x (expect bit 0)",
383 status);
384 g_assert_cmphex(status & 0x01u, ==, 0x01);
385 }
386
387 /* Low-limit interrupt triggers correctly */
388 static void test_low_limit(void *obj, void *data, QGuestAllocator *alloc)
389 {
390 QI2CDevice *dev = (QI2CDevice *)obj;
391 uint8_t status;
392
393 i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION);
394
395 i2c_set8(dev, REG_LIMIT_BASE + 3u, 0x80);
396 g_test_message("Set ch1 low limit = 0x80");
397
398 i2c_set8(dev, REG_LIMIT_BASE + 5u, 0x80);
399 g_test_message("Set ch2 low limit = 0x80");
400
401 qmp_adc128d818_set("ain1", 640);
402 qmp_adc128d818_set("ain2", 1280);
403 qmp_adc128d818_set("ain0", 1280);
404 i2c_set8(dev, REG_CONFIG, CONFIG_START | CONFIG_INT_ENABLE);
405
406 status = i2c_get8(dev, REG_INT_STATUS);
407 g_test_message("INT_STATUS = 0x%02x (expect bits 1 and 2 set)", status);
408 g_assert_cmphex(status & 0x02u, ==, 0x02);
409 g_assert_cmphex(status & 0x04u, ==, 0x04);
410
411 g_assert_cmphex(status & 0x01u, ==, 0x00);
412 }
413
414 /* Temperature high-limit interrupt with hysteresis */
415 static void test_temp_hysteresis(void *obj, void *data,
416 QGuestAllocator *alloc)
417 {
418 QI2CDevice *dev = (QI2CDevice *)obj;
419 uint8_t status;
420
421 i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION);
422
423 i2c_set8(dev, REG_LIMIT_BASE + 7u * 2u, 0x32);
424 i2c_set8(dev, REG_LIMIT_BASE + 7u * 2u + 1u, 0x28);
425
426 qmp_adc128d818_set("temperature", 25000);
427 i2c_set8(dev, REG_CONFIG, CONFIG_START);
428
429 status = i2c_get8(dev, REG_INT_STATUS);
430 g_test_message("25 C: INT_STATUS = 0x%02x (temp bit expect clear)", status);
431 g_assert_cmphex(status & 0x80u, ==, 0x00);
432
433 qmp_adc128d818_set("temperature", 55000);
434 status = i2c_get8(dev, REG_INT_STATUS);
435 g_test_message("55 C: INT_STATUS = 0x%02x (temp bit expect set)", status);
436 g_assert_cmphex(status & 0x80u, ==, 0x80);
437
438 qmp_adc128d818_set("temperature", 45000);
439 status = i2c_get8(dev, REG_INT_STATUS);
440 g_test_message("45 C (hysteresis): INT_STATUS = 0x%02x "
441 "(temp bit expect set)", status);
442 g_assert_cmphex(status & 0x80u, ==, 0x80);
443
444 qmp_adc128d818_set("temperature", 35000);
445 status = i2c_get8(dev, REG_INT_STATUS);
446 g_test_message("35 C: INT_STATUS = 0x%02x (temp bit expect clear)", status);
447 g_assert_cmphex(status & 0x80u, ==, 0x00);
448 }
449
450 /* Channel disable prevents conversion */
451 static void test_channel_disable(void *obj, void *data, QGuestAllocator *alloc)
452 {
453 QI2CDevice *dev = (QI2CDevice *)obj;
454 uint16_t reading;
455
456 i2c_set8(dev, REG_CH_DISABLE, 0x01);
457 g_test_message("Disabled channel 0");
458
459 qmp_adc128d818_set("ain0", 1280);
460 g_test_message("Injected ain0 = 1280 mV (disabled)");
461 i2c_set8(dev, REG_CONFIG, CONFIG_START);
462
463 reading = i2c_get16(dev, REG_CH_READING_BASE);
464 g_test_message("Read ch0 (disabled): raw 0x%04x", reading);
465 g_assert_cmphex(reading, ==, 0x0000);
466
467 qmp_adc128d818_set("ain1", 1280);
468 g_test_message("Injected ain1 = 1280 mV (enabled)");
469 reading = i2c_get16(dev, REG_CH_READING_BASE + 1u);
470 g_test_message("Read ch1 (enabled): raw 0x%04x -> %u mV", reading,
471 (reading >> 4u) * INTERNAL_VREF_MV / 4096u);
472 g_assert_cmphex(reading, ==, 0x8000);
473 }
474
475 /* One-shot conversion in shutdown mode */
476 static void test_one_shot(void *obj, void *data, QGuestAllocator *alloc)
477 {
478 QI2CDevice *dev = (QI2CDevice *)obj;
479 uint16_t reading;
480
481 qmp_adc128d818_set("ain0", 1280);
482 g_test_message("Injected ain0 = 1280 mV (device stopped)");
483
484 reading = i2c_get16(dev, REG_CH_READING_BASE);
485 g_test_message("Read ch0 before one-shot: raw 0x%04x", reading);
486 g_assert_cmphex(reading, ==, 0x0000);
487
488 g_assert_cmphex(i2c_get8(dev, REG_ONE_SHOT), ==, 0x00);
489
490 i2c_set8(dev, REG_ONE_SHOT, 0x00);
491 g_test_message("Triggered one-shot conversion with value 0x00");
492
493 reading = i2c_get16(dev, REG_CH_READING_BASE);
494 g_test_message("Read ch0 after one-shot: raw 0x%04x -> %u mV", reading,
495 (reading >> 4u) * INTERNAL_VREF_MV / 4096u);
496 g_assert_cmphex(reading, ==, 0x8000);
497 }
498
499 /* Mode 1 makes channel 7 a voltage input instead of temperature */
500 static void test_mode_selection(void *obj, void *data, QGuestAllocator *alloc)
501 {
502 QI2CDevice *dev = (QI2CDevice *)obj;
503 uint16_t reading;
504
505 i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_1);
506 g_test_message("Set mode 1 (all voltage channels)");
507
508 qmp_adc128d818_set("ain7", 1280);
509 qmp_adc128d818_set("temperature", 50000);
510 g_test_message("Injected ain7 = 1280 mV, temperature = 50000 mC");
511
512 i2c_set8(dev, REG_CONFIG, CONFIG_START);
513
514 reading = i2c_get16(dev, REG_CH_READING_BASE + 7u);
515 g_test_message("Read ch7 (mode 1): raw 0x%04x -> %u mV", reading,
516 (reading >> 4u) * INTERNAL_VREF_MV / 4096u);
517 g_assert_cmphex(reading, ==, 0x8000);
518 }
519
520 /* Mode 2 - 4 pseudo-differential pairs */
521 static void test_mode2_diff(void *obj, void *data, QGuestAllocator *alloc)
522 {
523 QI2CDevice *dev = (QI2CDevice *)obj;
524 uint16_t reading;
525
526 i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_2);
527 g_test_message("Set mode 2 (4 pseudo-differential pairs)");
528
529 qmp_adc128d818_set("ain0", 2000);
530 qmp_adc128d818_set("ain1", 720);
531 i2c_set8(dev, REG_CONFIG, CONFIG_START);
532
533 reading = i2c_get16(dev, REG_CH_READING_BASE);
534 g_test_message("Pair 0 (IN0-IN1): raw 0x%04x (expect 0x8000)", reading);
535 g_assert_cmphex(reading, ==, 0x8000);
536
537 qmp_adc128d818_set("ain3", 1920);
538 qmp_adc128d818_set("ain2", 640);
539
540 reading = i2c_get16(dev, REG_CH_READING_BASE + 1u);
541 g_test_message("Pair 1 (IN3-IN2): raw 0x%04x (expect 0x8000)", reading);
542 g_assert_cmphex(reading, ==, 0x8000);
543
544 qmp_adc128d818_set("ain4", 1500);
545 qmp_adc128d818_set("ain5", 220);
546
547 reading = i2c_get16(dev, REG_CH_READING_BASE + 2u);
548 g_test_message("Pair 2 (IN4-IN5): raw 0x%04x (expect 0x8000)", reading);
549 g_assert_cmphex(reading, ==, 0x8000);
550
551 qmp_adc128d818_set("ain7", 2560);
552 qmp_adc128d818_set("ain6", 1280);
553
554 reading = i2c_get16(dev, REG_CH_READING_BASE + 3u);
555 g_test_message("Pair 3 (IN7-IN6): raw 0x%04x (expect 0x8000)", reading);
556 g_assert_cmphex(reading, ==, 0x8000);
557
558 reading = i2c_get16(dev, REG_CH_READING_BASE + 4u);
559 g_test_message("Reserved ch4: raw 0x%04x (expect 0x0000)", reading);
560 g_assert_cmphex(reading, ==, 0x0000);
561
562 qmp_adc128d818_set("ain0", 500);
563 qmp_adc128d818_set("ain1", 1000);
564
565 reading = i2c_get16(dev, REG_CH_READING_BASE);
566 g_test_message("Pair 0 negative dV: raw 0x%04x (expect 0x0000)", reading);
567 g_assert_cmphex(reading, ==, 0x0000);
568 }
569
570 /* Mode 3 - 4 single-ended + 2 pseudo-differential pairs */
571 static void test_mode3_mixed(void *obj, void *data, QGuestAllocator *alloc)
572 {
573 QI2CDevice *dev = (QI2CDevice *)obj;
574 uint16_t reading;
575
576 i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_3);
577 g_test_message("Set mode 3 (4 single-ended + 2 differential)");
578
579 qmp_adc128d818_set("ain0", 1280);
580 i2c_set8(dev, REG_CONFIG, CONFIG_START);
581
582 reading = i2c_get16(dev, REG_CH_READING_BASE);
583 g_test_message("Ch0 single-ended: raw 0x%04x (expect 0x8000)", reading);
584 g_assert_cmphex(reading, ==, 0x8000);
585
586 qmp_adc128d818_set("ain4", 1500);
587 qmp_adc128d818_set("ain5", 220);
588
589 reading = i2c_get16(dev, REG_CH_READING_BASE + 4u);
590 g_test_message("Ch4 diff (IN4-IN5): raw 0x%04x (expect 0x8000)", reading);
591 g_assert_cmphex(reading, ==, 0x8000);
592
593 qmp_adc128d818_set("ain7", 2560);
594 qmp_adc128d818_set("ain6", 1280);
595
596 reading = i2c_get16(dev, REG_CH_READING_BASE + 5u);
597 g_test_message("Ch5 diff (IN7-IN6): raw 0x%04x (expect 0x8000)", reading);
598 g_assert_cmphex(reading, ==, 0x8000);
599
600 reading = i2c_get16(dev, REG_CH_READING_BASE + 6u);
601 g_test_message("Reserved ch6: raw 0x%04x (expect 0x0000)", reading);
602 g_assert_cmphex(reading, ==, 0x0000);
603
604 qmp_adc128d818_set("temperature", 25000);
605
606 reading = i2c_get16(dev, REG_CH_READING_BASE + 7u);
607 g_test_message("Ch7 temperature: raw 0x%04x (expect 0x1900)", reading);
608 g_assert_cmphex(reading, ==, 0x1900);
609 }
610
611 /* Mode change resets channel readings and interrupt status */
612 static void test_mode_change_reset(void *obj, void *data,
613 QGuestAllocator *alloc)
614 {
615 QI2CDevice *dev = (QI2CDevice *)obj;
616 uint16_t reading;
617 uint8_t status;
618
619 qmp_adc128d818_set("ain0", 1280);
620 i2c_set8(dev, REG_CONFIG, CONFIG_START);
621
622 reading = i2c_get16(dev, REG_CH_READING_BASE);
623 g_test_message("Before mode change, ch0: raw 0x%04x", reading);
624 g_assert_cmphex(reading, !=, 0x0000);
625
626 i2c_set8(dev, REG_CONFIG, 0x00);
627 i2c_set8(dev, REG_LIMIT_BASE, 0x10);
628 qmp_adc128d818_set("ain0", 2560);
629 i2c_set8(dev, REG_CONFIG, CONFIG_START);
630
631 i2c_set8(dev, REG_CONFIG, 0x00);
632 i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_2);
633
634 reading = i2c_get16(dev, REG_CH_READING_BASE);
635 g_test_message("After mode change, ch0: raw 0x%04x (expect 0x0000)",
636 reading);
637 g_assert_cmphex(reading, ==, 0x0000);
638
639 status = i2c_get8(dev, REG_INT_STATUS);
640 g_test_message("After mode change, INT_STATUS: 0x%02x (expect 0x00)",
641 status);
642 g_assert_cmphex(status, ==, 0x00);
643
644 g_assert_cmphex(i2c_get8(dev, REG_LIMIT_BASE), ==, 0x10);
645 g_test_message("Limit register preserved after mode change");
646 }
647
648 /* QOM property changes trigger correct differential conversion */
649 static void test_diff_qom_trigger(void *obj, void *data,
650 QGuestAllocator *alloc)
651 {
652 QI2CDevice *dev = (QI2CDevice *)obj;
653 uint16_t reading;
654
655 i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION);
656 i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_2);
657
658 qmp_adc128d818_set("ain0", 0);
659 qmp_adc128d818_set("ain1", 0);
660 qmp_adc128d818_set("ain2", 0);
661 qmp_adc128d818_set("ain3", 0);
662 i2c_set8(dev, REG_CONFIG, CONFIG_START);
663
664 qmp_adc128d818_set("ain0", 2000);
665 reading = i2c_get16(dev, REG_CH_READING_BASE);
666 g_test_message("After ain0=2000, ain1=0: pair0 = 0x%04x (expect 0xC800)",
667 reading);
668 g_assert_cmphex(reading, ==, 0xC800);
669
670 qmp_adc128d818_set("ain1", 720);
671 reading = i2c_get16(dev, REG_CH_READING_BASE);
672 g_test_message("After ain1=720: pair0 = 0x%04x (expect 0x8000)", reading);
673 g_assert_cmphex(reading, ==, 0x8000);
674
675 qmp_adc128d818_set("ain3", 1920);
676 qmp_adc128d818_set("ain2", 640);
677 reading = i2c_get16(dev, REG_CH_READING_BASE + 1u);
678 g_test_message("Pair 1 (IN3-IN2) via QOM: 0x%04x (expect 0x8000)", reading);
679 g_assert_cmphex(reading, ==, 0x8000);
680 }
681
682 /* One-shot conversion works in deep shutdown */
683 static void test_deep_shutdown(void *obj, void *data, QGuestAllocator *alloc)
684 {
685 QI2CDevice *dev = (QI2CDevice *)obj;
686 uint16_t reading;
687
688 i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION);
689
690 qmp_adc128d818_set("ain0", 1280);
691 i2c_set8(dev, REG_CONFIG, CONFIG_START);
692 reading = i2c_get16(dev, REG_CH_READING_BASE);
693 g_assert_cmphex(reading, ==, 0x8000);
694
695 i2c_set8(dev, REG_DEEP_SHUTDOWN, 0x01);
696 g_test_message("DEEP_SHUTDOWN write while running rejected");
697 g_assert_cmphex(i2c_get8(dev, REG_DEEP_SHUTDOWN), ==, 0x00);
698
699 i2c_set8(dev, REG_CONFIG, 0x00);
700 i2c_set8(dev, REG_DEEP_SHUTDOWN, 0x01);
701 qmp_adc128d818_set("ain0", 0);
702
703 reading = i2c_get16(dev, REG_CH_READING_BASE);
704 g_test_message("Deep shutdown, no one-shot: raw 0x%04x (expect 0x8000)",
705 reading);
706 g_assert_cmphex(reading, ==, 0x8000);
707
708 i2c_set8(dev, REG_ONE_SHOT, 0x01);
709 reading = i2c_get16(dev, REG_CH_READING_BASE);
710 g_test_message("Deep shutdown one-shot: raw 0x%04x (expect 0x0000)",
711 reading);
712 g_assert_cmphex(reading, ==, 0x0000);
713
714 g_assert_cmphex(i2c_get8(dev, REG_DEEP_SHUTDOWN), ==, 0x01);
715
716 i2c_set8(dev, REG_DEEP_SHUTDOWN, 0x00);
717 qmp_adc128d818_set("ain0", 1280);
718 i2c_set8(dev, REG_ONE_SHOT, 0x01);
719 reading = i2c_get16(dev, REG_CH_READING_BASE);
720 g_test_message("After exit shutdown: raw 0x%04x (expect 0x8000)", reading);
721 g_assert_cmphex(reading, ==, 0x8000);
722 }
723
724 /* BUSY_STATUS NOT_READY clears after first conversion */
725 static void test_busy_status(void *obj, void *data, QGuestAllocator *alloc)
726 {
727 QI2CDevice *dev = (QI2CDevice *)obj;
728
729 i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION);
730
731 g_assert_cmphex(i2c_get8(dev, REG_BUSY_STATUS) & 0x02, ==, 0x02);
732 g_test_message("After reset: BUSY_STATUS = 0x%02x (NOT_READY set)",
733 i2c_get8(dev, REG_BUSY_STATUS));
734
735 qmp_adc128d818_set("ain0", 0);
736 i2c_set8(dev, REG_CONFIG, CONFIG_START);
737
738 g_assert_cmphex(i2c_get8(dev, REG_BUSY_STATUS) & 0x02, ==, 0x00);
739 g_test_message("After conversion: BUSY_STATUS = 0x%02x (NOT_READY cleared)",
740 i2c_get8(dev, REG_BUSY_STATUS));
741 }
742
743 /* Programming Channel Disable resets channel readings */
744 static void test_chan_disable_clears(void *obj, void *data,
745 QGuestAllocator *alloc)
746 {
747 QI2CDevice *dev = (QI2CDevice *)obj;
748 uint16_t reading;
749
750 i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION);
751
752 qmp_adc128d818_set("ain0", 1280);
753 i2c_set8(dev, REG_CONFIG, CONFIG_START);
754 g_assert_cmphex(i2c_get16(dev, REG_CH_READING_BASE), ==, 0x8000);
755
756 i2c_set8(dev, REG_CONFIG, 0x00);
757 i2c_set8(dev, REG_CH_DISABLE, 0x02);
758 reading = i2c_get16(dev, REG_CH_READING_BASE);
759 g_test_message("After CH_DISABLE write: ch0 raw 0x%04x (expect 0x0000)",
760 reading);
761 g_assert_cmphex(reading, ==, 0x0000);
762 }
763
764 /* Programming Advanced Configuration always resets channel readings */
765 static void test_adv_config_clears(void *obj, void *data,
766 QGuestAllocator *alloc)
767 {
768 QI2CDevice *dev = (QI2CDevice *)obj;
769 uint16_t reading;
770
771 i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION);
772
773 qmp_adc128d818_set("ain0", 1280);
774 i2c_set8(dev, REG_CONFIG, CONFIG_START);
775 g_assert_cmphex(i2c_get16(dev, REG_CH_READING_BASE), ==, 0x8000);
776
777 i2c_set8(dev, REG_CONFIG, 0x00);
778 i2c_set8(dev, REG_ADV_CONFIG, 0x00);
779 reading = i2c_get16(dev, REG_CH_READING_BASE);
780 g_test_message("After same-mode ADV_CONFIG: ch0 0x%04x (expect 0x0000)",
781 reading);
782 g_assert_cmphex(reading, ==, 0x0000);
783
784 i2c_set8(dev, REG_CONFIG, CONFIG_START);
785 g_assert_cmphex(i2c_get16(dev, REG_CH_READING_BASE), ==, 0x8000);
786 i2c_set8(dev, REG_CONFIG, 0x00);
787 qmp_adc128d818_set("ext-vref-mv", 4096);
788 i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_EXT_REF_EN);
789 reading = i2c_get16(dev, REG_CH_READING_BASE);
790 g_test_message("After ext-vref toggle: ch0 0x%04x (expect 0x0000)",
791 reading);
792 g_assert_cmphex(reading, ==, 0x0000);
793 }
794
795 /* Conversion Rate register may only be programmed while in shutdown */
796 static void test_conv_rate(void *obj, void *data, QGuestAllocator *alloc)
797 {
798 QI2CDevice *dev = (QI2CDevice *)obj;
799
800 i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION);
801
802 i2c_set8(dev, REG_CONV_RATE, 0x01);
803 g_assert_cmphex(i2c_get8(dev, REG_CONV_RATE), ==, 0x01);
804
805 i2c_set8(dev, REG_CONFIG, CONFIG_START);
806 i2c_set8(dev, REG_CONV_RATE, 0x00);
807 g_test_message("CONV_RATE while running: 0x%02x (expect unchanged 0x01)",
808 i2c_get8(dev, REG_CONV_RATE));
809 g_assert_cmphex(i2c_get8(dev, REG_CONV_RATE), ==, 0x01);
810 }
811
812 static void adc128d818_register_nodes(void)
813 {
814 QOSGraphEdgeOptions opts = {
815 .extra_device_opts = "id=" ADC128D818_TEST_ID
816 ",address=0x1f"
817 };
818 add_qi2c_address(&opts, &(QI2CAddress) { ADC128D818_TEST_ADDR });
819
820 qos_node_create_driver("adc128d818", i2c_device_create);
821 qos_node_consumes("adc128d818", "i2c-bus", &opts);
822
823 qos_add_test("id-registers", "adc128d818", test_id_registers, NULL);
824 qos_add_test("defaults", "adc128d818", test_defaults, NULL);
825 qos_add_test("soft-reset", "adc128d818", test_soft_reset, NULL);
826 qos_add_test("ain-property", "adc128d818", test_ain_property, NULL);
827 qos_add_test("voltage-conversion", "adc128d818", test_voltage_conversion,
828 NULL);
829 qos_add_test("temperature-conversion", "adc128d818",
830 test_temperature_conversion, NULL);
831 qos_add_test("all-channels", "adc128d818", test_all_channels, NULL);
832 qos_add_test("voltage-edges", "adc128d818", test_voltage_edges, NULL);
833 qos_add_test("temperature-edges", "adc128d818", test_temperature_edges,
834 NULL);
835 qos_add_test("ext-vref", "adc128d818", test_ext_vref, NULL);
836 qos_add_test("interrupt-status", "adc128d818", test_interrupt_status, NULL);
837 qos_add_test("int-clear", "adc128d818", test_int_clear, NULL);
838 qos_add_test("low-limit", "adc128d818", test_low_limit, NULL);
839 qos_add_test("temp-hysteresis", "adc128d818", test_temp_hysteresis, NULL);
840 qos_add_test("channel-disable", "adc128d818", test_channel_disable, NULL);
841 qos_add_test("one-shot", "adc128d818", test_one_shot, NULL);
842 qos_add_test("mode-selection", "adc128d818", test_mode_selection, NULL);
843 qos_add_test("mode2-diff", "adc128d818", test_mode2_diff, NULL);
844 qos_add_test("mode3-mixed", "adc128d818", test_mode3_mixed, NULL);
845 qos_add_test("mode-change-reset", "adc128d818", test_mode_change_reset,
846 NULL);
847 qos_add_test("diff-qom-trigger", "adc128d818", test_diff_qom_trigger, NULL);
848 qos_add_test("deep-shutdown", "adc128d818", test_deep_shutdown, NULL);
849 qos_add_test("busy-status", "adc128d818", test_busy_status, NULL);
850 qos_add_test("chan-disable-clears", "adc128d818", test_chan_disable_clears,
851 NULL);
852 qos_add_test("adv-config-clears", "adc128d818", test_adv_config_clears,
853 NULL);
854 qos_add_test("conv-rate", "adc128d818", test_conv_rate, NULL);
855 }
856 libqos_init(adc128d818_register_nodes);