qemu/tests/qtest/adm1272-test.c
<<
>>
Prefs
   1/*
   2 * QTests for the ADM1272 hotswap controller
   3 *
   4 * Copyright 2021 Google LLC
   5 *
   6 * SPDX-License-Identifier: GPL-2.0-or-later
   7 */
   8
   9#include "qemu/osdep.h"
  10#include <math.h>
  11#include "hw/i2c/pmbus_device.h"
  12#include "libqtest-single.h"
  13#include "libqos/qgraph.h"
  14#include "libqos/i2c.h"
  15#include "qapi/qmp/qdict.h"
  16#include "qapi/qmp/qnum.h"
  17#include "qemu/bitops.h"
  18
  19#define TEST_ID "adm1272-test"
  20#define TEST_ADDR (0x10)
  21
  22#define ADM1272_RESTART_TIME            0xCC
  23#define ADM1272_MFR_PEAK_IOUT           0xD0
  24#define ADM1272_MFR_PEAK_VIN            0xD1
  25#define ADM1272_MFR_PEAK_VOUT           0xD2
  26#define ADM1272_MFR_PMON_CONTROL        0xD3
  27#define ADM1272_MFR_PMON_CONFIG         0xD4
  28#define ADM1272_MFR_ALERT1_CONFIG       0xD5
  29#define ADM1272_MFR_ALERT2_CONFIG       0xD6
  30#define ADM1272_MFR_PEAK_TEMPERATURE    0xD7
  31#define ADM1272_MFR_DEVICE_CONFIG       0xD8
  32#define ADM1272_MFR_POWER_CYCLE         0xD9
  33#define ADM1272_MFR_PEAK_PIN            0xDA
  34#define ADM1272_MFR_READ_PIN_EXT        0xDB
  35#define ADM1272_MFR_READ_EIN_EXT        0xDC
  36
  37#define ADM1272_HYSTERESIS_LOW          0xF2
  38#define ADM1272_HYSTERESIS_HIGH         0xF3
  39#define ADM1272_STATUS_HYSTERESIS       0xF4
  40#define ADM1272_STATUS_GPIO             0xF5
  41#define ADM1272_STRT_UP_IOUT_LIM        0xF6
  42
  43/* Defaults */
  44#define ADM1272_OPERATION_DEFAULT       0x80
  45#define ADM1272_CAPABILITY_DEFAULT      0xB0
  46#define ADM1272_CAPABILITY_NO_PEC       0x30
  47#define ADM1272_DIRECT_MODE             0x40
  48#define ADM1272_HIGH_LIMIT_DEFAULT      0x0FFF
  49#define ADM1272_PIN_OP_DEFAULT          0x7FFF
  50#define ADM1272_PMBUS_REVISION_DEFAULT  0x22
  51#define ADM1272_MFR_ID_DEFAULT          "ADI"
  52#define ADM1272_MODEL_DEFAULT           "ADM1272-A1"
  53#define ADM1272_MFR_DEFAULT_REVISION    "25"
  54#define ADM1272_DEFAULT_DATE            "160301"
  55#define ADM1272_RESTART_TIME_DEFAULT    0x64
  56#define ADM1272_PMON_CONTROL_DEFAULT    0x1
  57#define ADM1272_PMON_CONFIG_DEFAULT     0x3F35
  58#define ADM1272_DEVICE_CONFIG_DEFAULT   0x8
  59#define ADM1272_HYSTERESIS_HIGH_DEFAULT     0xFFFF
  60#define ADM1272_STRT_UP_IOUT_LIM_DEFAULT    0x000F
  61#define ADM1272_VOLT_DEFAULT            12000
  62#define ADM1272_IOUT_DEFAULT            25000
  63#define ADM1272_PWR_DEFAULT             300  /* 12V 25A */
  64#define ADM1272_SHUNT                   300 /* micro-ohms */
  65#define ADM1272_VOLTAGE_COEFF_DEFAULT   1
  66#define ADM1272_CURRENT_COEFF_DEFAULT   3
  67#define ADM1272_PWR_COEFF_DEFAULT       7
  68#define ADM1272_IOUT_OFFSET             0x5000
  69#define ADM1272_IOUT_OFFSET             0x5000
  70
  71static const PMBusCoefficients adm1272_coefficients[] = {
  72    [0] = { 6770, 0, -2 },       /* voltage, vrange 60V */
  73    [1] = { 4062, 0, -2 },       /* voltage, vrange 100V */
  74    [2] = { 1326, 20480, -1 },   /* current, vsense range 15mV */
  75    [3] = { 663, 20480, -1 },    /* current, vsense range 30mV */
  76    [4] = { 3512, 0, -2 },       /* power, vrange 60V, irange 15mV */
  77    [5] = { 21071, 0, -3 },      /* power, vrange 100V, irange 15mV */
  78    [6] = { 17561, 0, -3 },      /* power, vrange 60V, irange 30mV */
  79    [7] = { 10535, 0, -3 },      /* power, vrange 100V, irange 30mV */
  80    [8] = { 42, 31871, -1 },     /* temperature */
  81};
  82
  83uint16_t pmbus_data2direct_mode(PMBusCoefficients c, uint32_t value)
  84{
  85    /* R is usually negative to fit large readings into 16 bits */
  86    uint16_t y = (c.m * value + c.b) * pow(10, c.R);
  87    return y;
  88}
  89
  90uint32_t pmbus_direct_mode2data(PMBusCoefficients c, uint16_t value)
  91{
  92    /* X = (Y * 10^-R - b) / m */
  93    uint32_t x = (value / pow(10, c.R) - c.b) / c.m;
  94    return x;
  95}
  96
  97
  98static uint16_t adm1272_millivolts_to_direct(uint32_t value)
  99{
 100    PMBusCoefficients c = adm1272_coefficients[ADM1272_VOLTAGE_COEFF_DEFAULT];
 101    c.b = c.b * 1000;
 102    c.R = c.R - 3;
 103    return pmbus_data2direct_mode(c, value);
 104}
 105
 106static uint32_t adm1272_direct_to_millivolts(uint16_t value)
 107{
 108    PMBusCoefficients c = adm1272_coefficients[ADM1272_VOLTAGE_COEFF_DEFAULT];
 109    c.b = c.b * 1000;
 110    c.R = c.R - 3;
 111    return pmbus_direct_mode2data(c, value);
 112}
 113
 114static uint16_t adm1272_milliamps_to_direct(uint32_t value)
 115{
 116    PMBusCoefficients c = adm1272_coefficients[ADM1272_CURRENT_COEFF_DEFAULT];
 117    /* Y = (m * r_sense * x - b) * 10^R */
 118    c.m = c.m * ADM1272_SHUNT / 1000; /* micro-ohms */
 119    c.b = c.b * 1000;
 120    c.R = c.R - 3;
 121    return pmbus_data2direct_mode(c, value);
 122}
 123
 124static uint32_t adm1272_direct_to_milliamps(uint16_t value)
 125{
 126    PMBusCoefficients c = adm1272_coefficients[ADM1272_CURRENT_COEFF_DEFAULT];
 127    c.m = c.m * ADM1272_SHUNT / 1000;
 128    c.b = c.b * 1000;
 129    c.R = c.R - 3;
 130    return pmbus_direct_mode2data(c, value);
 131}
 132
 133static uint16_t adm1272_watts_to_direct(uint32_t value)
 134{
 135    PMBusCoefficients c = adm1272_coefficients[ADM1272_PWR_COEFF_DEFAULT];
 136    c.m = c.m * ADM1272_SHUNT / 1000;
 137    return pmbus_data2direct_mode(c, value);
 138}
 139
 140static uint32_t adm1272_direct_to_watts(uint16_t value)
 141{
 142    PMBusCoefficients c = adm1272_coefficients[ADM1272_PWR_COEFF_DEFAULT];
 143    c.m = c.m * ADM1272_SHUNT / 1000;
 144    return pmbus_direct_mode2data(c, value);
 145}
 146
 147static uint16_t qmp_adm1272_get(const char *id, const char *property)
 148{
 149    QDict *response;
 150    uint64_t ret;
 151
 152    response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, "
 153                   "'property': %s } }", id, property);
 154    g_assert(qdict_haskey(response, "return"));
 155    ret = qnum_get_uint(qobject_to(QNum, qdict_get(response, "return")));
 156    qobject_unref(response);
 157    return ret;
 158}
 159
 160static void qmp_adm1272_set(const char *id,
 161                            const char *property,
 162                            uint16_t value)
 163{
 164    QDict *response;
 165
 166    response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
 167                   "'property': %s, 'value': %u } }", id, property, value);
 168    g_assert(qdict_haskey(response, "return"));
 169    qobject_unref(response);
 170}
 171
 172/* PMBus commands are little endian vs i2c_set16 in i2c.h which is big endian */
 173static uint16_t adm1272_i2c_get16(QI2CDevice *i2cdev, uint8_t reg)
 174{
 175    uint8_t resp[2];
 176    i2c_read_block(i2cdev, reg, resp, sizeof(resp));
 177    return (resp[1] << 8) | resp[0];
 178}
 179
 180/* PMBus commands are little endian vs i2c_set16 in i2c.h which is big endian */
 181static void adm1272_i2c_set16(QI2CDevice *i2cdev, uint8_t reg, uint16_t value)
 182{
 183    uint8_t data[2];
 184
 185    data[0] = value & 255;
 186    data[1] = value >> 8;
 187    i2c_write_block(i2cdev, reg, data, sizeof(data));
 188}
 189
 190static void test_defaults(void *obj, void *data, QGuestAllocator *alloc)
 191{
 192    uint16_t value, i2c_value;
 193    int16_t err;
 194    QI2CDevice *i2cdev = (QI2CDevice *)obj;
 195    value = qmp_adm1272_get(TEST_ID, "vout");
 196    err = ADM1272_VOLT_DEFAULT - value;
 197    g_assert_cmpuint(abs(err), <, ADM1272_VOLT_DEFAULT / 20);
 198
 199    i2c_value = i2c_get8(i2cdev, PMBUS_OPERATION);
 200    g_assert_cmphex(i2c_value, ==, ADM1272_OPERATION_DEFAULT);
 201
 202    i2c_value = i2c_get8(i2cdev, PMBUS_VOUT_MODE);
 203    g_assert_cmphex(i2c_value, ==, ADM1272_DIRECT_MODE);
 204
 205    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VOUT_OV_WARN_LIMIT);
 206    g_assert_cmphex(i2c_value, ==, ADM1272_HIGH_LIMIT_DEFAULT);
 207
 208    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VOUT_UV_WARN_LIMIT);
 209    g_assert_cmphex(i2c_value, ==, 0);
 210
 211    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_IOUT_OC_WARN_LIMIT);
 212    g_assert_cmphex(i2c_value, ==, ADM1272_HIGH_LIMIT_DEFAULT);
 213
 214    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_OT_FAULT_LIMIT);
 215    g_assert_cmphex(i2c_value, ==, ADM1272_HIGH_LIMIT_DEFAULT);
 216
 217    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_OT_WARN_LIMIT);
 218    g_assert_cmphex(i2c_value, ==, ADM1272_HIGH_LIMIT_DEFAULT);
 219
 220    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VIN_OV_WARN_LIMIT);
 221    g_assert_cmphex(i2c_value, ==, ADM1272_HIGH_LIMIT_DEFAULT);
 222
 223    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VIN_UV_WARN_LIMIT);
 224    g_assert_cmphex(i2c_value, ==, 0);
 225
 226    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_PIN_OP_WARN_LIMIT);
 227    g_assert_cmphex(i2c_value, ==, ADM1272_PIN_OP_DEFAULT);
 228
 229    i2c_value = i2c_get8(i2cdev, PMBUS_REVISION);
 230    g_assert_cmphex(i2c_value, ==, ADM1272_PMBUS_REVISION_DEFAULT);
 231
 232    i2c_value = i2c_get8(i2cdev, ADM1272_MFR_PMON_CONTROL);
 233    g_assert_cmphex(i2c_value, ==, ADM1272_PMON_CONTROL_DEFAULT);
 234
 235    i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_MFR_PMON_CONFIG);
 236    g_assert_cmphex(i2c_value, ==, ADM1272_PMON_CONFIG_DEFAULT);
 237
 238    i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_MFR_DEVICE_CONFIG);
 239    g_assert_cmphex(i2c_value, ==, ADM1272_DEVICE_CONFIG_DEFAULT);
 240
 241    i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_HYSTERESIS_HIGH);
 242    g_assert_cmphex(i2c_value, ==, ADM1272_HYSTERESIS_HIGH_DEFAULT);
 243
 244    i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_STRT_UP_IOUT_LIM);
 245    g_assert_cmphex(i2c_value, ==, ADM1272_STRT_UP_IOUT_LIM_DEFAULT);
 246}
 247
 248/* test qmp access */
 249static void test_tx_rx(void *obj, void *data, QGuestAllocator *alloc)
 250{
 251    uint16_t i2c_value, value, i2c_voltage, i2c_pwr, lossy_value;
 252    QI2CDevice *i2cdev = (QI2CDevice *)obj;
 253
 254    /* converting to direct mode is lossy - we generate the same loss here */
 255    lossy_value =
 256        adm1272_direct_to_millivolts(adm1272_millivolts_to_direct(1000));
 257    qmp_adm1272_set(TEST_ID, "vin", 1000);
 258    value = qmp_adm1272_get(TEST_ID, "vin");
 259    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_VIN);
 260    i2c_voltage = adm1272_direct_to_millivolts(i2c_value);
 261    g_assert_cmpuint(value, ==, i2c_voltage);
 262    g_assert_cmpuint(i2c_voltage, ==, lossy_value);
 263
 264    lossy_value =
 265        adm1272_direct_to_millivolts(adm1272_millivolts_to_direct(1500));
 266    qmp_adm1272_set(TEST_ID, "vout", 1500);
 267    value = qmp_adm1272_get(TEST_ID, "vout");
 268    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_VOUT);
 269    i2c_voltage = adm1272_direct_to_millivolts(i2c_value);
 270    g_assert_cmpuint(value, ==, i2c_voltage);
 271    g_assert_cmpuint(i2c_voltage, ==, lossy_value);
 272
 273    lossy_value =
 274        adm1272_direct_to_milliamps(adm1272_milliamps_to_direct(1600));
 275    qmp_adm1272_set(TEST_ID, "iout", 1600);
 276    value = qmp_adm1272_get(TEST_ID, "iout");
 277    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_IOUT);
 278    i2c_value = adm1272_direct_to_milliamps(i2c_value);
 279    g_assert_cmphex(value, ==, i2c_value);
 280    g_assert_cmphex(i2c_value, ==, lossy_value);
 281
 282    lossy_value =
 283        adm1272_direct_to_watts(adm1272_watts_to_direct(320));
 284    qmp_adm1272_set(TEST_ID, "pin", 320);
 285    value = qmp_adm1272_get(TEST_ID, "pin");
 286    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_PIN);
 287    i2c_pwr = adm1272_direct_to_watts(i2c_value);
 288    g_assert_cmphex(value, ==, i2c_pwr);
 289    g_assert_cmphex(i2c_pwr, ==, lossy_value);
 290}
 291
 292/* test r/w registers */
 293static void test_rw_regs(void *obj, void *data, QGuestAllocator *alloc)
 294{
 295    uint16_t i2c_value;
 296    QI2CDevice *i2cdev = (QI2CDevice *)obj;
 297
 298    adm1272_i2c_set16(i2cdev, PMBUS_VOUT_OV_WARN_LIMIT, 0xABCD);
 299    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VOUT_OV_WARN_LIMIT);
 300    g_assert_cmphex(i2c_value, ==, 0xABCD);
 301
 302    adm1272_i2c_set16(i2cdev, PMBUS_VOUT_UV_WARN_LIMIT, 0xCDEF);
 303    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VOUT_UV_WARN_LIMIT);
 304    g_assert_cmphex(i2c_value, ==, 0xCDEF);
 305
 306    adm1272_i2c_set16(i2cdev, PMBUS_IOUT_OC_WARN_LIMIT, 0x1234);
 307    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_IOUT_OC_WARN_LIMIT);
 308    g_assert_cmphex(i2c_value, ==, 0x1234);
 309
 310    adm1272_i2c_set16(i2cdev, PMBUS_OT_FAULT_LIMIT, 0x5678);
 311    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_OT_FAULT_LIMIT);
 312    g_assert_cmphex(i2c_value, ==, 0x5678);
 313
 314    adm1272_i2c_set16(i2cdev, PMBUS_OT_WARN_LIMIT, 0xABDC);
 315    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_OT_WARN_LIMIT);
 316    g_assert_cmphex(i2c_value, ==, 0xABDC);
 317
 318    adm1272_i2c_set16(i2cdev, PMBUS_VIN_OV_WARN_LIMIT, 0xCDEF);
 319    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VIN_OV_WARN_LIMIT);
 320    g_assert_cmphex(i2c_value, ==, 0xCDEF);
 321
 322    adm1272_i2c_set16(i2cdev, PMBUS_VIN_UV_WARN_LIMIT, 0x2345);
 323    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VIN_UV_WARN_LIMIT);
 324    g_assert_cmphex(i2c_value, ==, 0x2345);
 325
 326    i2c_set8(i2cdev, ADM1272_RESTART_TIME, 0xF8);
 327    i2c_value = i2c_get8(i2cdev, ADM1272_RESTART_TIME);
 328    g_assert_cmphex(i2c_value, ==, 0xF8);
 329
 330    i2c_set8(i2cdev, ADM1272_MFR_PMON_CONTROL, 0);
 331    i2c_value = i2c_get8(i2cdev, ADM1272_MFR_PMON_CONTROL);
 332    g_assert_cmpuint(i2c_value, ==, 0);
 333
 334    adm1272_i2c_set16(i2cdev, ADM1272_MFR_PMON_CONFIG, 0xDEF0);
 335    i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_MFR_PMON_CONFIG);
 336    g_assert_cmphex(i2c_value, ==, 0xDEF0);
 337
 338    adm1272_i2c_set16(i2cdev, ADM1272_MFR_ALERT1_CONFIG, 0x0123);
 339    i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_MFR_ALERT1_CONFIG);
 340    g_assert_cmphex(i2c_value, ==, 0x0123);
 341
 342    adm1272_i2c_set16(i2cdev, ADM1272_MFR_ALERT2_CONFIG, 0x9876);
 343    i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_MFR_ALERT2_CONFIG);
 344    g_assert_cmphex(i2c_value, ==, 0x9876);
 345
 346    adm1272_i2c_set16(i2cdev, ADM1272_MFR_DEVICE_CONFIG, 0x3456);
 347    i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_MFR_DEVICE_CONFIG);
 348    g_assert_cmphex(i2c_value, ==, 0x3456);
 349
 350    adm1272_i2c_set16(i2cdev, ADM1272_HYSTERESIS_LOW, 0xCABA);
 351    i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_HYSTERESIS_LOW);
 352    g_assert_cmphex(i2c_value, ==, 0xCABA);
 353
 354    adm1272_i2c_set16(i2cdev, ADM1272_HYSTERESIS_HIGH, 0x6789);
 355    i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_HYSTERESIS_HIGH);
 356    g_assert_cmphex(i2c_value, ==, 0x6789);
 357
 358    adm1272_i2c_set16(i2cdev, ADM1272_STRT_UP_IOUT_LIM, 0x9876);
 359    i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_STRT_UP_IOUT_LIM);
 360    g_assert_cmphex(i2c_value, ==, 0x9876);
 361
 362    adm1272_i2c_set16(i2cdev, PMBUS_OPERATION, 0xA);
 363    i2c_value = i2c_get8(i2cdev, PMBUS_OPERATION);
 364    g_assert_cmphex(i2c_value, ==, 0xA);
 365}
 366
 367/* test read-only registers */
 368static void test_ro_regs(void *obj, void *data, QGuestAllocator *alloc)
 369{
 370    uint16_t i2c_init_value, i2c_value;
 371    QI2CDevice *i2cdev = (QI2CDevice *)obj;
 372
 373    i2c_init_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_VIN);
 374    adm1272_i2c_set16(i2cdev, PMBUS_READ_VIN, 0xBEEF);
 375    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_VIN);
 376    g_assert_cmphex(i2c_init_value, ==, i2c_value);
 377
 378    i2c_init_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_VOUT);
 379    adm1272_i2c_set16(i2cdev, PMBUS_READ_VOUT, 0x1234);
 380    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_VOUT);
 381    g_assert_cmphex(i2c_init_value, ==, i2c_value);
 382
 383    i2c_init_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_IOUT);
 384    adm1272_i2c_set16(i2cdev, PMBUS_READ_IOUT, 0x6547);
 385    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_IOUT);
 386    g_assert_cmphex(i2c_init_value, ==, i2c_value);
 387
 388    i2c_init_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_1);
 389    adm1272_i2c_set16(i2cdev, PMBUS_READ_TEMPERATURE_1, 0x1597);
 390    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_1);
 391    g_assert_cmphex(i2c_init_value, ==, i2c_value);
 392
 393    i2c_init_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_PIN);
 394    adm1272_i2c_set16(i2cdev, PMBUS_READ_PIN, 0xDEAD);
 395    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_PIN);
 396    g_assert_cmphex(i2c_init_value, ==, i2c_value);
 397}
 398
 399/* test voltage fault handling */
 400static void test_voltage_faults(void *obj, void *data, QGuestAllocator *alloc)
 401{
 402    uint16_t i2c_value;
 403    uint8_t i2c_byte;
 404    QI2CDevice *i2cdev = (QI2CDevice *)obj;
 405
 406    adm1272_i2c_set16(i2cdev, PMBUS_VOUT_OV_WARN_LIMIT,
 407                      adm1272_millivolts_to_direct(5000));
 408    qmp_adm1272_set(TEST_ID, "vout", 5100);
 409
 410    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_STATUS_WORD);
 411    i2c_byte = i2c_get8(i2cdev, PMBUS_STATUS_VOUT);
 412    g_assert_true((i2c_value & PB_STATUS_VOUT) != 0);
 413    g_assert_true((i2c_byte & PB_STATUS_VOUT_OV_WARN) != 0);
 414
 415    qmp_adm1272_set(TEST_ID, "vout", 4500);
 416    i2c_set8(i2cdev, PMBUS_CLEAR_FAULTS, 0);
 417    i2c_byte = i2c_get8(i2cdev, PMBUS_STATUS_VOUT);
 418    g_assert_true((i2c_byte & PB_STATUS_VOUT_OV_WARN) == 0);
 419
 420    adm1272_i2c_set16(i2cdev, PMBUS_VOUT_UV_WARN_LIMIT,
 421                      adm1272_millivolts_to_direct(4600));
 422    i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_STATUS_WORD);
 423    i2c_byte = i2c_get8(i2cdev, PMBUS_STATUS_VOUT);
 424    g_assert_true((i2c_value & PB_STATUS_VOUT) != 0);
 425    g_assert_true((i2c_byte & PB_STATUS_VOUT_UV_WARN) != 0);
 426
 427}
 428
 429static void adm1272_register_nodes(void)
 430{
 431    QOSGraphEdgeOptions opts = {
 432        .extra_device_opts = "id=" TEST_ID ",address=0x10"
 433    };
 434    add_qi2c_address(&opts, &(QI2CAddress) { TEST_ADDR });
 435
 436    qos_node_create_driver("adm1272", i2c_device_create);
 437    qos_node_consumes("adm1272", "i2c-bus", &opts);
 438
 439    qos_add_test("test_defaults", "adm1272", test_defaults, NULL);
 440    qos_add_test("test_tx_rx", "adm1272", test_tx_rx, NULL);
 441    qos_add_test("test_rw_regs", "adm1272", test_rw_regs, NULL);
 442    qos_add_test("test_ro_regs", "adm1272", test_ro_regs, NULL);
 443    qos_add_test("test_ov_faults", "adm1272", test_voltage_faults, NULL);
 444}
 445libqos_init(adm1272_register_nodes);
 446