@samitouri / QOSamiQemu / commits / 41bea707fe

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