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