All of lore.kernel.org
 help / color / mirror / Atom feed
From: Titus Rwantare <titusr@google.com>
To: f4bug@amsat.org, minyard@acm.org
Cc: qemu-arm@nongnu.org, qemu-devel@nongnu.org, venture@google.com,
	 Titus Rwantare <titusr@google.com>, Hao Wu <wuhaotsh@google.com>
Subject: [PATCH 3/5] hw/sensor: add Intersil ISL69260 device model
Date: Thu,  6 Jan 2022 23:09:34 +0000	[thread overview]
Message-ID: <20220106230936.417020-4-titusr@google.com> (raw)
In-Reply-To: <20220106230936.417020-1-titusr@google.com>

Signed-off-by: Titus Rwantare <titusr@google.com>
Reviewed-by: Hao Wu <wuhaotsh@google.com>
---
 MAINTAINERS                   |   3 +
 hw/arm/Kconfig                |   1 +
 hw/sensor/Kconfig             |   5 +
 hw/sensor/isl_pmbus.c         | 210 +++++++++++++++++++
 hw/sensor/meson.build         |   1 +
 include/hw/sensor/isl_pmbus.h |  50 +++++
 tests/qtest/isl_pmbus-test.c  | 381 ++++++++++++++++++++++++++++++++++
 tests/qtest/meson.build       |   1 +
 8 files changed, 652 insertions(+)
 create mode 100644 hw/sensor/isl_pmbus.c
 create mode 100644 include/hw/sensor/isl_pmbus.h
 create mode 100644 tests/qtest/isl_pmbus-test.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6349e3da1f..156c5812a8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3034,10 +3034,13 @@ M: Titus Rwantare <titusr@google.com>
 S: Maintained
 F: hw/i2c/pmbus_device.c
 F: hw/sensor/adm1272.c
+F: hw/sensor/isl_pmbus.c
 F: hw/sensor/max34451.c
 F: include/hw/i2c/pmbus_device.h
+F: include/hw/sensor/isl_pmbus.h
 F: tests/qtest/adm1272-test.c
 F: tests/qtest/max34451-test.c
+F: tests/qtest/isl_pmbus-test.c
 
 Firmware schema specifications
 M: Philippe Mathieu-Daudé <f4bug@amsat.org>
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index e652590943..019099df96 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -393,6 +393,7 @@ config NPCM7XX
     select SMBUS
     select AT24C  # EEPROM
     select MAX34451
+    select ISL_PMBUS
     select PL310  # cache controller
     select PMBUS
     select SERIAL
diff --git a/hw/sensor/Kconfig b/hw/sensor/Kconfig
index 9c8a049b06..f935d9cccb 100644
--- a/hw/sensor/Kconfig
+++ b/hw/sensor/Kconfig
@@ -21,3 +21,8 @@ config ADM1272
 config MAX34451
     bool
     depends on I2C
+
+config ISL_PMBUS
+    bool
+    depends on I2C
+
diff --git a/hw/sensor/isl_pmbus.c b/hw/sensor/isl_pmbus.c
new file mode 100644
index 0000000000..8cc7220a57
--- /dev/null
+++ b/hw/sensor/isl_pmbus.c
@@ -0,0 +1,210 @@
+/*
+ * PMBus device for Renesas Digital Multiphase Voltage Regulators
+ *
+ * Copyright 2021 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sensor/isl_pmbus.h"
+#include "hw/qdev-properties.h"
+#include "qapi/visitor.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+
+static uint8_t isl_pmbus_read_byte(PMBusDevice *pmdev)
+{
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "%s: reading from unsupported register: 0x%02x\n",
+                  __func__, pmdev->code);
+    return 0xFF;
+}
+
+static int isl_pmbus_write_data(PMBusDevice *pmdev, const uint8_t *buf,
+                              uint8_t len)
+{
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "%s: write to unsupported register: 0x%02x\n",
+                  __func__, pmdev->code);
+    return 0xFF;
+}
+
+/* TODO: Implement coefficients support in pmbus_device.c for qmp */
+static void isl_pmbus_get(Object *obj, Visitor *v, const char *name,
+                                     void *opaque, Error **errp)
+{
+    visit_type_uint16(v, name, (uint16_t *)opaque, errp);
+}
+
+static void isl_pmbus_set(Object *obj, Visitor *v, const char *name,
+                                 void *opaque, Error **errp)
+{
+    PMBusDevice *pmdev = PMBUS_DEVICE(obj);
+    uint16_t *internal = opaque;
+    uint16_t value;
+    if (!visit_type_uint16(v, name, &value, errp)) {
+        return;
+    }
+
+    *internal = value;
+    pmbus_check_limits(pmdev);
+}
+
+static void isl_pmbus_exit_reset(Object *obj)
+{
+    PMBusDevice *pmdev = PMBUS_DEVICE(obj);
+
+    pmdev->page = 0;
+    pmdev->capability = ISL_CAPABILITY_DEFAULT;
+    for (int i = 0; i < pmdev->num_pages; i++) {
+        pmdev->pages[i].operation = ISL_OPERATION_DEFAULT;
+        pmdev->pages[i].on_off_config = ISL_ON_OFF_CONFIG_DEFAULT;
+        pmdev->pages[i].vout_mode = ISL_VOUT_MODE_DEFAULT;
+        pmdev->pages[i].vout_command = ISL_VOUT_COMMAND_DEFAULT;
+        pmdev->pages[i].vout_max = ISL_VOUT_MAX_DEFAULT;
+        pmdev->pages[i].vout_margin_high = ISL_VOUT_MARGIN_HIGH_DEFAULT;
+        pmdev->pages[i].vout_margin_low = ISL_VOUT_MARGIN_LOW_DEFAULT;
+        pmdev->pages[i].vout_transition_rate = ISL_VOUT_TRANSITION_RATE_DEFAULT;
+        pmdev->pages[i].vout_ov_fault_limit = ISL_VOUT_OV_FAULT_LIMIT_DEFAULT;
+        pmdev->pages[i].ot_fault_limit = ISL_OT_FAULT_LIMIT_DEFAULT;
+        pmdev->pages[i].ot_warn_limit = ISL_OT_WARN_LIMIT_DEFAULT;
+        pmdev->pages[i].vin_ov_warn_limit = ISL_VIN_OV_WARN_LIMIT_DEFAULT;
+        pmdev->pages[i].vin_uv_warn_limit = ISL_VIN_UV_WARN_LIMIT_DEFAULT;
+        pmdev->pages[i].iin_oc_fault_limit = ISL_IIN_OC_FAULT_LIMIT_DEFAULT;
+        pmdev->pages[i].ton_delay = ISL_TON_DELAY_DEFAULT;
+        pmdev->pages[i].ton_rise = ISL_TON_RISE_DEFAULT;
+        pmdev->pages[i].toff_fall = ISL_TOFF_FALL_DEFAULT;
+        pmdev->pages[i].revision = ISL_REVISION_DEFAULT;
+
+        pmdev->pages[i].read_vout = ISL_READ_VOUT_DEFAULT;
+        pmdev->pages[i].read_iout = ISL_READ_IOUT_DEFAULT;
+        pmdev->pages[i].read_pout = ISL_READ_POUT_DEFAULT;
+        pmdev->pages[i].read_vin = ISL_READ_VIN_DEFAULT;
+        pmdev->pages[i].read_iin = ISL_READ_IIN_DEFAULT;
+        pmdev->pages[i].read_pin = ISL_READ_PIN_DEFAULT;
+        pmdev->pages[i].read_temperature_1 = ISL_READ_TEMP_DEFAULT;
+        pmdev->pages[i].read_temperature_2 = ISL_READ_TEMP_DEFAULT;
+        pmdev->pages[i].read_temperature_3 = ISL_READ_TEMP_DEFAULT;
+    }
+}
+
+static void isl_pmbus_add_props(Object *obj, uint64_t *flags, uint8_t pages)
+{
+    PMBusDevice *pmdev = PMBUS_DEVICE(obj);
+    for (int i = 0; i < pages; i++) {
+        if (flags[i] & PB_HAS_VIN) {
+            object_property_add(obj, "vin[*]", "uint16",
+                                isl_pmbus_get,
+                                isl_pmbus_set,
+                                NULL, &pmdev->pages[i].read_vin);
+        }
+
+        if (flags[i] & PB_HAS_VOUT) {
+            object_property_add(obj, "vout[*]", "uint16",
+                                isl_pmbus_get,
+                                isl_pmbus_set,
+                                NULL, &pmdev->pages[i].read_vout);
+        }
+
+        if (flags[i] & PB_HAS_IIN) {
+            object_property_add(obj, "iin[*]", "uint16",
+                                isl_pmbus_get,
+                                isl_pmbus_set,
+                                NULL, &pmdev->pages[i].read_iin);
+        }
+
+        if (flags[i] & PB_HAS_IOUT) {
+            object_property_add(obj, "iout[*]", "uint16",
+                                isl_pmbus_get,
+                                isl_pmbus_set,
+                                NULL, &pmdev->pages[i].read_iout);
+        }
+
+        if (flags[i] & PB_HAS_PIN) {
+            object_property_add(obj, "pin[*]", "uint16",
+                                isl_pmbus_get,
+                                isl_pmbus_set,
+                                NULL, &pmdev->pages[i].read_pin);
+        }
+
+        if (flags[i] & PB_HAS_POUT) {
+            object_property_add(obj, "pout[*]", "uint16",
+                                isl_pmbus_get,
+                                isl_pmbus_set,
+                                NULL, &pmdev->pages[i].read_pout);
+        }
+
+        if (flags[i] & PB_HAS_TEMPERATURE) {
+            object_property_add(obj, "temp1[*]", "uint16",
+                                isl_pmbus_get,
+                                isl_pmbus_set,
+                                NULL, &pmdev->pages[i].read_temperature_1);
+        }
+
+        if (flags[i] & PB_HAS_TEMP2) {
+            object_property_add(obj, "temp2[*]", "uint16",
+                                isl_pmbus_get,
+                                isl_pmbus_set,
+                                NULL, &pmdev->pages[i].read_temperature_2);
+        }
+
+        if (flags[i] & PB_HAS_TEMP3) {
+            object_property_add(obj, "temp3[*]", "uint16",
+                                isl_pmbus_get,
+                                isl_pmbus_set,
+                                NULL, &pmdev->pages[i].read_temperature_3);
+        }
+    }
+}
+
+static void raa22xx_init(Object *obj)
+{
+    PMBusDevice *pmdev = PMBUS_DEVICE(obj);
+    uint64_t flags[2];
+
+    flags[0] = PB_HAS_VIN | PB_HAS_VOUT | PB_HAS_VOUT_MODE |
+               PB_HAS_VOUT_RATING | PB_HAS_VOUT_MARGIN | PB_HAS_IIN |
+               PB_HAS_IOUT | PB_HAS_PIN | PB_HAS_POUT | PB_HAS_TEMPERATURE |
+               PB_HAS_TEMP2 | PB_HAS_TEMP3 | PB_HAS_STATUS_MFR_SPECIFIC;
+    flags[1] = PB_HAS_IIN | PB_HAS_PIN | PB_HAS_TEMPERATURE | PB_HAS_TEMP3 |
+               PB_HAS_VOUT | PB_HAS_VOUT_MODE | PB_HAS_VOUT_MARGIN |
+               PB_HAS_VOUT_RATING | PB_HAS_IOUT | PB_HAS_POUT |
+               PB_HAS_STATUS_MFR_SPECIFIC;
+
+    pmbus_page_config(pmdev, 0, flags[0]);
+    pmbus_page_config(pmdev, 1, flags[1]);
+    isl_pmbus_add_props(obj, flags, 2);
+}
+
+static void isl_pmbus_class_init(ObjectClass *klass, void *data, uint8_t pages)
+{
+    PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass);
+    k->write_data = isl_pmbus_write_data;
+    k->receive_byte = isl_pmbus_read_byte;
+    k->device_num_pages = pages;
+}
+
+static void isl69260_class_init(ObjectClass *klass, void *data)
+{
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->desc = "Renesas ISL69260 Digital Multiphase Voltage Regulator";
+    rc->phases.exit = isl_pmbus_exit_reset;
+    isl_pmbus_class_init(klass, data, 2);
+}
+
+static const TypeInfo isl69260_info = {
+    .name = TYPE_ISL69260,
+    .parent = TYPE_PMBUS_DEVICE,
+    .instance_size = sizeof(ISLState),
+    .instance_init = raa22xx_init,
+    .class_init = isl69260_class_init,
+};
+
+static void isl_pmbus_register_types(void)
+{
+    type_register_static(&isl69260_info);
+}
+
+type_init(isl_pmbus_register_types)
diff --git a/hw/sensor/meson.build b/hw/sensor/meson.build
index 059c4ca935..d511994d0c 100644
--- a/hw/sensor/meson.build
+++ b/hw/sensor/meson.build
@@ -4,3 +4,4 @@ softmmu_ss.add(when: 'CONFIG_DPS310', if_true: files('dps310.c'))
 softmmu_ss.add(when: 'CONFIG_EMC141X', if_true: files('emc141x.c'))
 softmmu_ss.add(when: 'CONFIG_ADM1272', if_true: files('adm1272.c'))
 softmmu_ss.add(when: 'CONFIG_MAX34451', if_true: files('max34451.c'))
+softmmu_ss.add(when: 'CONFIG_ISL_PMBUS', if_true: files('isl_pmbus.c'))
diff --git a/include/hw/sensor/isl_pmbus.h b/include/hw/sensor/isl_pmbus.h
new file mode 100644
index 0000000000..8115aaa698
--- /dev/null
+++ b/include/hw/sensor/isl_pmbus.h
@@ -0,0 +1,50 @@
+/*
+ * PMBus device for Renesas Digital Multiphase Voltage Regulators
+ *
+ * Copyright 2022 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_MISC_ISL_PMBUS_H
+#define HW_MISC_ISL_PMBUS_H
+
+#include "hw/i2c/pmbus_device.h"
+#include "qom/object.h"
+
+#define TYPE_ISL69260   "isl69260"
+
+struct ISLState {
+    PMBusDevice parent;
+};
+
+OBJECT_DECLARE_SIMPLE_TYPE(ISLState, ISL69260)
+
+#define ISL_CAPABILITY_DEFAULT                 0x40
+#define ISL_OPERATION_DEFAULT                  0x80
+#define ISL_ON_OFF_CONFIG_DEFAULT              0x16
+#define ISL_VOUT_MODE_DEFAULT                  0x40
+#define ISL_VOUT_COMMAND_DEFAULT               0x0384
+#define ISL_VOUT_MAX_DEFAULT                   0x08FC
+#define ISL_VOUT_MARGIN_HIGH_DEFAULT           0x0640
+#define ISL_VOUT_MARGIN_LOW_DEFAULT            0xFA
+#define ISL_VOUT_TRANSITION_RATE_DEFAULT       0x64
+#define ISL_VOUT_OV_FAULT_LIMIT_DEFAULT        0x076C
+#define ISL_OT_FAULT_LIMIT_DEFAULT             0x7D
+#define ISL_OT_WARN_LIMIT_DEFAULT              0x07D0
+#define ISL_VIN_OV_WARN_LIMIT_DEFAULT          0x36B0
+#define ISL_VIN_UV_WARN_LIMIT_DEFAULT          0x1F40
+#define ISL_IIN_OC_FAULT_LIMIT_DEFAULT         0x32
+#define ISL_TON_DELAY_DEFAULT                  0x14
+#define ISL_TON_RISE_DEFAULT                   0x01F4
+#define ISL_TOFF_FALL_DEFAULT                  0x01F4
+#define ISL_REVISION_DEFAULT                   0x33
+#define ISL_READ_VOUT_DEFAULT                  1000
+#define ISL_READ_IOUT_DEFAULT                  40
+#define ISL_READ_POUT_DEFAULT                  4
+#define ISL_READ_TEMP_DEFAULT                  25
+#define ISL_READ_VIN_DEFAULT                   1100
+#define ISL_READ_IIN_DEFAULT                   40
+#define ISL_READ_PIN_DEFAULT                   4
+
+#endif
diff --git a/tests/qtest/isl_pmbus-test.c b/tests/qtest/isl_pmbus-test.c
new file mode 100644
index 0000000000..3e956f912c
--- /dev/null
+++ b/tests/qtest/isl_pmbus-test.c
@@ -0,0 +1,381 @@
+/*
+ * QTests for the ISL_PMBUS digital voltage regulators
+ *
+ * Copyright 2021 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "qemu/osdep.h"
+#include <math.h>
+#include "hw/i2c/pmbus_device.h"
+#include "hw/sensor/isl_pmbus.h"
+#include "libqtest-single.h"
+#include "libqos/qgraph.h"
+#include "libqos/i2c.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qnum.h"
+#include "qemu/bitops.h"
+
+#define TEST_ID "isl_pmbus-test"
+#define TEST_ADDR (0x43)
+
+static uint16_t qmp_isl_pmbus_get(const char *id, const char *property)
+{
+    QDict *response;
+    uint64_t ret;
+
+    response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, "
+                   "'property': %s } }", id, property);
+    g_assert(qdict_haskey(response, "return"));
+    ret = qnum_get_uint(qobject_to(QNum, qdict_get(response, "return")));
+    qobject_unref(response);
+    return ret;
+}
+
+static void qmp_isl_pmbus_set(const char *id,
+                            const char *property,
+                            uint16_t value)
+{
+    QDict *response;
+
+    response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
+                   "'property': %s, 'value': %u } }", id, property, value);
+    g_assert(qdict_haskey(response, "return"));
+    qobject_unref(response);
+}
+
+/* PMBus commands are little endian vs i2c_set16 in i2c.h which is big endian */
+static uint16_t isl_pmbus_i2c_get16(QI2CDevice *i2cdev, uint8_t reg)
+{
+    uint8_t resp[2];
+    i2c_read_block(i2cdev, reg, resp, sizeof(resp));
+    return (resp[1] << 8) | resp[0];
+}
+
+/* PMBus commands are little endian vs i2c_set16 in i2c.h which is big endian */
+static void isl_pmbus_i2c_set16(QI2CDevice *i2cdev, uint8_t reg, uint16_t value)
+{
+    uint8_t data[2];
+
+    data[0] = value & 255;
+    data[1] = value >> 8;
+    i2c_write_block(i2cdev, reg, data, sizeof(data));
+}
+
+static void test_defaults(void *obj, void *data, QGuestAllocator *alloc)
+{
+    uint16_t value, i2c_value;
+    QI2CDevice *i2cdev = (QI2CDevice *)obj;
+
+    value = qmp_isl_pmbus_get(TEST_ID, "vout[0]");
+    g_assert_cmpuint(value, ==, ISL_READ_VOUT_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_IOUT);
+    g_assert_cmpuint(i2c_value, ==, ISL_READ_IOUT_DEFAULT);
+
+    value = qmp_isl_pmbus_get(TEST_ID, "pout[0]");
+    g_assert_cmpuint(value, ==, ISL_READ_POUT_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_VIN);
+    g_assert_cmpuint(i2c_value, ==, ISL_READ_VIN_DEFAULT);
+
+    value = qmp_isl_pmbus_get(TEST_ID, "iin[0]");
+    g_assert_cmpuint(value, ==, ISL_READ_IIN_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_PIN);
+    g_assert_cmpuint(i2c_value, ==, ISL_READ_PIN_DEFAULT);
+
+    value = qmp_isl_pmbus_get(TEST_ID, "temp1[0]");
+    g_assert_cmpuint(value, ==, ISL_READ_TEMP_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_2);
+    g_assert_cmpuint(i2c_value, ==, ISL_READ_TEMP_DEFAULT);
+
+    i2c_value = i2c_get8(i2cdev, PMBUS_CAPABILITY);
+    g_assert_cmphex(i2c_value, ==, ISL_CAPABILITY_DEFAULT);
+
+    i2c_value = i2c_get8(i2cdev, PMBUS_OPERATION);
+    g_assert_cmphex(i2c_value, ==, ISL_OPERATION_DEFAULT);
+
+    i2c_value = i2c_get8(i2cdev, PMBUS_ON_OFF_CONFIG);
+    g_assert_cmphex(i2c_value, ==, ISL_ON_OFF_CONFIG_DEFAULT);
+
+    i2c_value = i2c_get8(i2cdev, PMBUS_VOUT_MODE);
+    g_assert_cmphex(i2c_value, ==, ISL_VOUT_MODE_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_COMMAND);
+    g_assert_cmphex(i2c_value, ==, ISL_VOUT_COMMAND_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_MAX);
+    g_assert_cmphex(i2c_value, ==, ISL_VOUT_MAX_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_MARGIN_HIGH);
+    g_assert_cmphex(i2c_value, ==, ISL_VOUT_MARGIN_HIGH_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_MARGIN_LOW);
+    g_assert_cmphex(i2c_value, ==, ISL_VOUT_MARGIN_LOW_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_TRANSITION_RATE);
+    g_assert_cmphex(i2c_value, ==, ISL_VOUT_TRANSITION_RATE_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_OV_FAULT_LIMIT);
+    g_assert_cmphex(i2c_value, ==, ISL_VOUT_OV_FAULT_LIMIT_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_OT_FAULT_LIMIT);
+    g_assert_cmphex(i2c_value, ==, ISL_OT_FAULT_LIMIT_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_OT_WARN_LIMIT);
+    g_assert_cmphex(i2c_value, ==, ISL_OT_WARN_LIMIT_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VIN_OV_WARN_LIMIT);
+    g_assert_cmphex(i2c_value, ==, ISL_VIN_OV_WARN_LIMIT_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VIN_UV_WARN_LIMIT);
+    g_assert_cmphex(i2c_value, ==, ISL_VIN_UV_WARN_LIMIT_DEFAULT);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_IIN_OC_FAULT_LIMIT);
+    g_assert_cmphex(i2c_value, ==, ISL_IIN_OC_FAULT_LIMIT_DEFAULT);
+
+    i2c_value = i2c_get8(i2cdev, PMBUS_REVISION);
+    g_assert_cmphex(i2c_value, ==, ISL_REVISION_DEFAULT);
+}
+
+/* test qmp access */
+static void test_tx_rx(void *obj, void *data, QGuestAllocator *alloc)
+{
+    uint16_t i2c_value, value;
+    QI2CDevice *i2cdev = (QI2CDevice *)obj;
+
+    qmp_isl_pmbus_set(TEST_ID, "vin[0]", 200);
+    value = qmp_isl_pmbus_get(TEST_ID, "vin[0]");
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_VIN);
+    g_assert_cmpuint(value, ==, i2c_value);
+
+    qmp_isl_pmbus_set(TEST_ID, "vout[0]", 2500);
+    value = qmp_isl_pmbus_get(TEST_ID, "vout[0]");
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_VOUT);
+    g_assert_cmpuint(value, ==, i2c_value);
+
+    qmp_isl_pmbus_set(TEST_ID, "iin[0]", 300);
+    value = qmp_isl_pmbus_get(TEST_ID, "iin[0]");
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_IIN);
+    g_assert_cmpuint(value, ==, i2c_value);
+
+    qmp_isl_pmbus_set(TEST_ID, "iout[0]", 310);
+    value = qmp_isl_pmbus_get(TEST_ID, "iout[0]");
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_IOUT);
+    g_assert_cmpuint(value, ==, i2c_value);
+
+    qmp_isl_pmbus_set(TEST_ID, "pin[0]", 100);
+    value = qmp_isl_pmbus_get(TEST_ID, "pin[0]");
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_PIN);
+    g_assert_cmpuint(value, ==, i2c_value);
+
+    qmp_isl_pmbus_set(TEST_ID, "pout[0]", 95);
+    value = qmp_isl_pmbus_get(TEST_ID, "pout[0]");
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_POUT);
+    g_assert_cmpuint(value, ==, i2c_value);
+
+    qmp_isl_pmbus_set(TEST_ID, "temp1[0]", 26);
+    value = qmp_isl_pmbus_get(TEST_ID, "temp1[0]");
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_1);
+    g_assert_cmpuint(value, ==, i2c_value);
+
+    qmp_isl_pmbus_set(TEST_ID, "temp2[0]", 27);
+    value = qmp_isl_pmbus_get(TEST_ID, "temp2[0]");
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_2);
+    g_assert_cmpuint(value, ==, i2c_value);
+
+    qmp_isl_pmbus_set(TEST_ID, "temp3[0]", 28);
+    value = qmp_isl_pmbus_get(TEST_ID, "temp3[0]");
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_3);
+    g_assert_cmpuint(value, ==, i2c_value);
+
+}
+
+/* test r/w registers */
+static void test_rw_regs(void *obj, void *data, QGuestAllocator *alloc)
+{
+    uint16_t i2c_value;
+    QI2CDevice *i2cdev = (QI2CDevice *)obj;
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VOUT_COMMAND, 0x1234);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_COMMAND);
+    g_assert_cmphex(i2c_value, ==, 0x1234);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VOUT_TRIM, 0x4567);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_TRIM);
+    g_assert_cmphex(i2c_value, ==, 0x4567);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VOUT_MAX, 0x9876);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_MAX);
+    g_assert_cmphex(i2c_value, ==, 0x9876);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VOUT_MARGIN_HIGH, 0xABCD);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_MARGIN_HIGH);
+    g_assert_cmphex(i2c_value, ==, 0xABCD);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VOUT_MARGIN_LOW, 0xA1B2);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_MARGIN_LOW);
+    g_assert_cmphex(i2c_value, ==, 0xA1B2);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VOUT_TRANSITION_RATE, 0xDEF1);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_TRANSITION_RATE);
+    g_assert_cmphex(i2c_value, ==, 0xDEF1);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VOUT_DROOP, 0x5678);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_DROOP);
+    g_assert_cmphex(i2c_value, ==, 0x5678);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VOUT_MIN, 0x1234);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_MIN);
+    g_assert_cmphex(i2c_value, ==, 0x1234);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VOUT_OV_FAULT_LIMIT, 0x2345);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_OV_FAULT_LIMIT);
+    g_assert_cmphex(i2c_value, ==, 0x2345);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VOUT_UV_FAULT_LIMIT, 0xFA12);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VOUT_UV_FAULT_LIMIT);
+    g_assert_cmphex(i2c_value, ==, 0xFA12);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_OT_FAULT_LIMIT, 0xF077);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_OT_FAULT_LIMIT);
+    g_assert_cmphex(i2c_value, ==, 0xF077);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_OT_WARN_LIMIT, 0x7137);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_OT_WARN_LIMIT);
+    g_assert_cmphex(i2c_value, ==, 0x7137);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VIN_OV_FAULT_LIMIT, 0x3456);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VIN_OV_FAULT_LIMIT);
+    g_assert_cmphex(i2c_value, ==, 0x3456);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VIN_UV_FAULT_LIMIT, 0xBADA);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_VIN_UV_FAULT_LIMIT);
+    g_assert_cmphex(i2c_value, ==, 0xBADA);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_IIN_OC_FAULT_LIMIT, 0xB1B0);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_IIN_OC_FAULT_LIMIT);
+    g_assert_cmphex(i2c_value, ==, 0xB1B0);
+
+    i2c_set8(i2cdev, PMBUS_PAGE, 2);
+    i2c_value = i2c_get8(i2cdev, PMBUS_PAGE);
+    g_assert_cmphex(i2c_value, ==, 2);
+
+    i2c_set8(i2cdev, PMBUS_OPERATION, 0xA);
+    i2c_value = i2c_get8(i2cdev, PMBUS_OPERATION);
+    g_assert_cmphex(i2c_value, ==, 0xA);
+
+    i2c_set8(i2cdev, PMBUS_ON_OFF_CONFIG, 0x42);
+    i2c_value = i2c_get8(i2cdev, PMBUS_ON_OFF_CONFIG);
+    g_assert_cmphex(i2c_value, ==, 0x42);
+}
+
+/* test read-only registers */
+static void test_ro_regs(void *obj, void *data, QGuestAllocator *alloc)
+{
+    uint16_t i2c_init_value, i2c_value;
+    QI2CDevice *i2cdev = (QI2CDevice *)obj;
+
+    i2c_init_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_VIN);
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_READ_VIN, 0xBEEF);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_VIN);
+    g_assert_cmphex(i2c_init_value, ==, i2c_value);
+
+    i2c_init_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_IIN);
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_READ_IIN, 0xB00F);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_IIN);
+    g_assert_cmphex(i2c_init_value, ==, i2c_value);
+
+    i2c_init_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_VOUT);
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_READ_VOUT, 0x1234);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_VOUT);
+    g_assert_cmphex(i2c_init_value, ==, i2c_value);
+
+    i2c_init_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_IOUT);
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_READ_IOUT, 0x6547);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_IOUT);
+    g_assert_cmphex(i2c_init_value, ==, i2c_value);
+
+    i2c_init_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_1);
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_READ_TEMPERATURE_1, 0x1597);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_1);
+    g_assert_cmphex(i2c_init_value, ==, i2c_value);
+
+    i2c_init_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_2);
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_READ_TEMPERATURE_2, 0x1897);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_2);
+    g_assert_cmphex(i2c_init_value, ==, i2c_value);
+
+    i2c_init_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_3);
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_READ_TEMPERATURE_3, 0x1007);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_3);
+    g_assert_cmphex(i2c_init_value, ==, i2c_value);
+
+    i2c_init_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_PIN);
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_READ_PIN, 0xDEAD);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_PIN);
+    g_assert_cmphex(i2c_init_value, ==, i2c_value);
+
+    i2c_init_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_POUT);
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_READ_POUT, 0xD00D);
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_READ_POUT);
+    g_assert_cmphex(i2c_init_value, ==, i2c_value);
+}
+
+/* test voltage fault handling */
+static void test_voltage_faults(void *obj, void *data, QGuestAllocator *alloc)
+{
+    uint16_t i2c_value;
+    uint8_t i2c_byte;
+    QI2CDevice *i2cdev = (QI2CDevice *)obj;
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VOUT_OV_WARN_LIMIT, 5000);
+    qmp_isl_pmbus_set(TEST_ID, "vout[0]", 5100);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_STATUS_WORD);
+    i2c_byte = i2c_get8(i2cdev, PMBUS_STATUS_VOUT);
+    g_assert_true((i2c_value & PB_STATUS_VOUT) != 0);
+    g_assert_true((i2c_byte & PB_STATUS_VOUT_OV_WARN) != 0);
+
+    qmp_isl_pmbus_set(TEST_ID, "vout[0]", 4500);
+    i2c_set8(i2cdev, PMBUS_CLEAR_FAULTS, 0);
+    i2c_byte = i2c_get8(i2cdev, PMBUS_STATUS_VOUT);
+    g_assert_true((i2c_byte & PB_STATUS_VOUT_OV_WARN) == 0);
+
+    isl_pmbus_i2c_set16(i2cdev, PMBUS_VOUT_UV_WARN_LIMIT, 4600);
+
+    i2c_value = isl_pmbus_i2c_get16(i2cdev, PMBUS_STATUS_WORD);
+    i2c_byte = i2c_get8(i2cdev, PMBUS_STATUS_VOUT);
+    g_assert_true((i2c_value & PB_STATUS_VOUT) != 0);
+    g_assert_true((i2c_byte & PB_STATUS_VOUT_UV_WARN) != 0);
+
+}
+
+static void isl_pmbus_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "id=" TEST_ID ",address=0x43"
+    };
+    add_qi2c_address(&opts, &(QI2CAddress) { TEST_ADDR });
+
+    qos_node_create_driver("isl69260", i2c_device_create);
+    qos_node_consumes("isl69260", "i2c-bus", &opts);
+
+    qos_add_test("test_defaults", "isl69260", test_defaults, NULL);
+    qos_add_test("test_tx_rx", "isl69260", test_tx_rx, NULL);
+    qos_add_test("test_rw_regs", "isl69260", test_rw_regs, NULL);
+    qos_add_test("test_ro_regs", "isl69260", test_ro_regs, NULL);
+    qos_add_test("test_ov_faults", "isl69260", test_voltage_faults, NULL);
+}
+libqos_init(isl_pmbus_register_nodes);
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 37e1eaa449..7a580d6d9f 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -242,6 +242,7 @@ qos_test_ss.add(
   'eepro100-test.c',
   'es1370-test.c',
   'ipoctal232-test.c',
+  'isl_pmbus-test.c',
   'max34451-test.c',
   'megasas-test.c',
   'ne2000-test.c',
-- 
2.34.1.448.ga2b2bfdf31-goog



  parent reply	other threads:[~2022-01-06 23:22 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-06 23:09 [PATCH 0/5] Fixups for PMBus and new sensors Titus Rwantare
2022-01-06 23:09 ` [PATCH 1/5] hw/i2c: pmbus updates Titus Rwantare
2022-01-27 19:36   ` Peter Maydell
2022-01-06 23:09 ` [PATCH 2/5] hw/i2c: Added linear mode translation for pmbus devices Titus Rwantare
2022-01-07 14:42   ` Philippe Mathieu-Daudé
2022-01-06 23:09 ` Titus Rwantare [this message]
2022-01-27 19:39   ` [PATCH 3/5] hw/sensor: add Intersil ISL69260 device model Peter Maydell
2022-01-27 20:54     ` Titus Rwantare
2022-01-28 10:34       ` Peter Maydell
2022-01-06 23:09 ` [PATCH 4/5] hw/sensor: add Renesas raa229004 PMBus device Titus Rwantare
2022-01-06 23:09 ` [PATCH 5/5] hw/misc: add Renesas raa228000 device Titus Rwantare
2022-02-24 18:58 ` [PATCH 0/5] Fixups for PMBus and new sensors Patrick Venture
2022-02-24 19:13   ` Corey Minyard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220106230936.417020-4-titusr@google.com \
    --to=titusr@google.com \
    --cc=f4bug@amsat.org \
    --cc=minyard@acm.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=venture@google.com \
    --cc=wuhaotsh@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.