[PATCH 7/8] hw/sensor: adm1266: expose vout_mode over QMP

Titus Rwantare <[email protected]> Wed, 29 Jul 2026 23:13:22 +0000
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <[email protected]>
The vout_mode registers can now be adjusted to allow a wider value range
in read_vout.
vout_mode is per pmbus page, therefore vout_mode[n] will affect
read_vout[n].

Signed-off-by: Titus Rwantare <[email protected]>
---
 hw/sensor/adm1266.c        |  8 ++++++++
 tests/qtest/adm1266-test.c | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/hw/sensor/adm1266.c b/hw/sensor/adm1266.c
index 80960dc1c4..1464307971 100644
--- a/hw/sensor/adm1266.c
+++ b/hw/sensor/adm1266.c
@@ -271,6 +271,8 @@ static void adm1266_get(Object *obj, Visitor *v, const char *name, void *opaque,
         sscanf(name, "vout[%u]", &index);
         mode = (PMBusVoutMode *)&pmdev->pages[index].vout_mode;
         value = pmbus_linear_mode2milliunits(*(uint16_t *)opaque, mode->exp);
+    } else if (strncmp(name, "vout_mode", 9) == 0) {
+        value = *(uint8_t *)opaque;
     } else {
         value = *(uint16_t *)opaque;
     }
@@ -293,6 +295,8 @@ static void adm1266_set(Object *obj, Visitor *v, const char *name, void *opaque,
         sscanf(name, "vout[%u]", &index);
         mode = (PMBusVoutMode *)&pmdev->pages[index].vout_mode;
         *internal = pmbus_milliunits2linear_mode(value, mode->exp);
+    } else if (strncmp(name, "vout_mode", 9) == 0) {
+        *(uint8_t *)opaque = value;
     } else {
         *internal = value;
     }
@@ -321,6 +325,10 @@ static void adm1266_init(Object *obj)
         object_property_add(obj, "vout[*]", "uint32",
                             adm1266_get,
                             adm1266_set, NULL, &pmdev->pages[i].read_vout);
+
+        object_property_add(obj, "vout_mode[*]", "uint32",
+                            adm1266_get,
+                            adm1266_set, NULL, &pmdev->pages[i].vout_mode);
     }
 }
 
diff --git a/tests/qtest/adm1266-test.c b/tests/qtest/adm1266-test.c
index fd3d8079b6..9cdd206c3f 100644
--- a/tests/qtest/adm1266-test.c
+++ b/tests/qtest/adm1266-test.c
@@ -186,6 +186,40 @@ static void test_vout_mode_exponent(void *obj, void *data,
     }
 }
 
+static void test_vout_mode_qmp(void *obj, void *data,
+                                    QGuestAllocator *alloc)
+{
+    uint16_t i2c_value, value, expected;
+    QI2CDevice *i2cdev = (QI2CDevice *)obj;
+    ADM1266VoutMode m;
+    char *path;
+
+    /* set a different exponent per page and a different value */
+    for (int i = 0; i < ADM1266_NUM_PAGES; i++) {
+        expected = 1000 * (i * 2);
+        m.mode.exp = i - 14;
+        path = g_strdup_printf("vout_mode[%d]", i);
+        qmp_adm1266_set(TEST_ID, path, m.raw);
+        path = g_strdup_printf("vout[%d]", i);
+        qmp_adm1266_set(TEST_ID, path, expected);
+    }
+
+    for (int i = 0; i < ADM1266_NUM_PAGES; i++) {
+        i2c_set8(i2cdev, PMBUS_PAGE, i);
+        expected = 1000 * (i * 2);
+        /* check correct value from i2c*/
+        m.raw = i2c_get8(i2cdev, PMBUS_VOUT_MODE);
+        i2c_value = bswap16(i2c_get16(i2cdev, PMBUS_READ_VOUT));
+        i2c_value = adm1266_linear_mode2milliunits(i2c_value, m.mode.exp);
+        g_assert_cmpuint(i2c_value, ==, expected);
+
+        /* check correct value from qmp*/
+        path = g_strdup_printf("vout[%d]", i);
+        value = qmp_adm1266_get(TEST_ID, path);
+        g_assert_cmpuint(value, ==, expected);
+    }
+}
+
 static void test_vout_clamp_to_max(void *obj, void *data,
                                    QGuestAllocator *alloc)
 {
@@ -278,6 +312,7 @@ static void adm1266_register_nodes(void)
                     test_vout_mode_exponent, NULL);
     qos_add_test("test_vout_clamp_to_max", "adm1266",
                     test_vout_clamp_to_max, NULL);
+    qos_add_test("test_vout_mode_qmp", "adm1266", test_vout_mode_qmp, NULL);
 }
 
 libqos_init(adm1266_register_nodes);
-- 
2.55.0.508.g3f0d502094-goog