tests/qtest: adc128d818: test operating modes and power control
Cover advanced-configuration mode selection (single-ended, pseudo-differential pairs, and mixed) and the reset of readings on reconfiguration, plus channel disable, one-shot conversion, deep shutdown, BUSY_STATUS lifecycle, and conversion-rate gating. Signed-off-by: Emmanuel Blot <emmanuel.blot@free.fr> Link: https://lore.kernel.org/qemu-devel/20260707091609.97759-6-emmanuel.blot@free.fr Signed-off-by: Cédric Le Goater <clg@redhat.com>
Emmanuel Blot committed
Jul 7, 2026 at 11:15 UTC
41bea707fef524b5457742d1786bece491d681d8
1 file changed
+377
tests/qtest/adc128d818-test.c
+377
@@ -447,6 +447,368 @@ static void test_temp_hysteresis(void *obj, void *data,
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 = {
@@ -475,5 +837,20 @@ static void adc128d818_register_nodes(void)
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);