xref: /qemu/hw/sensor/adm1272.c (revision c93488f16b70debc0c168b4117531623b03d6bf0)
1*c93488f1STitus Rwantare /*
2*c93488f1STitus Rwantare  * Analog Devices ADM1272 High Voltage Positive Hot Swap Controller and Digital
3*c93488f1STitus Rwantare  * Power Monitor with PMBus
4*c93488f1STitus Rwantare  *
5*c93488f1STitus Rwantare  * Copyright 2021 Google LLC
6*c93488f1STitus Rwantare  *
7*c93488f1STitus Rwantare  * SPDX-License-Identifier: GPL-2.0-or-later
8*c93488f1STitus Rwantare  */
9*c93488f1STitus Rwantare 
10*c93488f1STitus Rwantare #include "qemu/osdep.h"
11*c93488f1STitus Rwantare #include <string.h>
12*c93488f1STitus Rwantare #include "hw/i2c/pmbus_device.h"
13*c93488f1STitus Rwantare #include "hw/irq.h"
14*c93488f1STitus Rwantare #include "migration/vmstate.h"
15*c93488f1STitus Rwantare #include "qapi/error.h"
16*c93488f1STitus Rwantare #include "qapi/visitor.h"
17*c93488f1STitus Rwantare #include "qemu/log.h"
18*c93488f1STitus Rwantare #include "qemu/module.h"
19*c93488f1STitus Rwantare 
20*c93488f1STitus Rwantare #define TYPE_ADM1272 "adm1272"
21*c93488f1STitus Rwantare #define ADM1272(obj) OBJECT_CHECK(ADM1272State, (obj), TYPE_ADM1272)
22*c93488f1STitus Rwantare 
23*c93488f1STitus Rwantare #define ADM1272_RESTART_TIME            0xCC
24*c93488f1STitus Rwantare #define ADM1272_MFR_PEAK_IOUT           0xD0
25*c93488f1STitus Rwantare #define ADM1272_MFR_PEAK_VIN            0xD1
26*c93488f1STitus Rwantare #define ADM1272_MFR_PEAK_VOUT           0xD2
27*c93488f1STitus Rwantare #define ADM1272_MFR_PMON_CONTROL        0xD3
28*c93488f1STitus Rwantare #define ADM1272_MFR_PMON_CONFIG         0xD4
29*c93488f1STitus Rwantare #define ADM1272_MFR_ALERT1_CONFIG       0xD5
30*c93488f1STitus Rwantare #define ADM1272_MFR_ALERT2_CONFIG       0xD6
31*c93488f1STitus Rwantare #define ADM1272_MFR_PEAK_TEMPERATURE    0xD7
32*c93488f1STitus Rwantare #define ADM1272_MFR_DEVICE_CONFIG       0xD8
33*c93488f1STitus Rwantare #define ADM1272_MFR_POWER_CYCLE         0xD9
34*c93488f1STitus Rwantare #define ADM1272_MFR_PEAK_PIN            0xDA
35*c93488f1STitus Rwantare #define ADM1272_MFR_READ_PIN_EXT        0xDB
36*c93488f1STitus Rwantare #define ADM1272_MFR_READ_EIN_EXT        0xDC
37*c93488f1STitus Rwantare 
38*c93488f1STitus Rwantare #define ADM1272_HYSTERESIS_LOW          0xF2
39*c93488f1STitus Rwantare #define ADM1272_HYSTERESIS_HIGH         0xF3
40*c93488f1STitus Rwantare #define ADM1272_STATUS_HYSTERESIS       0xF4
41*c93488f1STitus Rwantare #define ADM1272_STATUS_GPIO             0xF5
42*c93488f1STitus Rwantare #define ADM1272_STRT_UP_IOUT_LIM        0xF6
43*c93488f1STitus Rwantare 
44*c93488f1STitus Rwantare /* Defaults */
45*c93488f1STitus Rwantare #define ADM1272_OPERATION_DEFAULT       0x80
46*c93488f1STitus Rwantare #define ADM1272_CAPABILITY_DEFAULT      0xB0
47*c93488f1STitus Rwantare #define ADM1272_CAPABILITY_NO_PEC       0x30
48*c93488f1STitus Rwantare #define ADM1272_DIRECT_MODE             0x40
49*c93488f1STitus Rwantare #define ADM1272_HIGH_LIMIT_DEFAULT      0x0FFF
50*c93488f1STitus Rwantare #define ADM1272_PIN_OP_DEFAULT          0x7FFF
51*c93488f1STitus Rwantare #define ADM1272_PMBUS_REVISION_DEFAULT  0x22
52*c93488f1STitus Rwantare #define ADM1272_MFR_ID_DEFAULT          "ADI"
53*c93488f1STitus Rwantare #define ADM1272_MODEL_DEFAULT           "ADM1272-A1"
54*c93488f1STitus Rwantare #define ADM1272_MFR_DEFAULT_REVISION    "25"
55*c93488f1STitus Rwantare #define ADM1272_DEFAULT_DATE            "160301"
56*c93488f1STitus Rwantare #define ADM1272_RESTART_TIME_DEFAULT    0x64
57*c93488f1STitus Rwantare #define ADM1272_PMON_CONTROL_DEFAULT    0x1
58*c93488f1STitus Rwantare #define ADM1272_PMON_CONFIG_DEFAULT     0x3F35
59*c93488f1STitus Rwantare #define ADM1272_DEVICE_CONFIG_DEFAULT   0x8
60*c93488f1STitus Rwantare #define ADM1272_HYSTERESIS_HIGH_DEFAULT     0xFFFF
61*c93488f1STitus Rwantare #define ADM1272_STRT_UP_IOUT_LIM_DEFAULT    0x000F
62*c93488f1STitus Rwantare #define ADM1272_VOLT_DEFAULT            12000
63*c93488f1STitus Rwantare #define ADM1272_IOUT_DEFAULT            25000
64*c93488f1STitus Rwantare #define ADM1272_PWR_DEFAULT             300  /* 12V 25A */
65*c93488f1STitus Rwantare #define ADM1272_SHUNT                   300 /* micro-ohms */
66*c93488f1STitus Rwantare #define ADM1272_VOLTAGE_COEFF_DEFAULT   1
67*c93488f1STitus Rwantare #define ADM1272_CURRENT_COEFF_DEFAULT   3
68*c93488f1STitus Rwantare #define ADM1272_PWR_COEFF_DEFAULT       7
69*c93488f1STitus Rwantare #define ADM1272_IOUT_OFFSET             0x5000
70*c93488f1STitus Rwantare #define ADM1272_IOUT_OFFSET             0x5000
71*c93488f1STitus Rwantare 
72*c93488f1STitus Rwantare 
73*c93488f1STitus Rwantare typedef struct ADM1272State {
74*c93488f1STitus Rwantare     PMBusDevice parent;
75*c93488f1STitus Rwantare 
76*c93488f1STitus Rwantare     uint64_t ein_ext;
77*c93488f1STitus Rwantare     uint32_t pin_ext;
78*c93488f1STitus Rwantare     uint8_t restart_time;
79*c93488f1STitus Rwantare 
80*c93488f1STitus Rwantare     uint16_t peak_vin;
81*c93488f1STitus Rwantare     uint16_t peak_vout;
82*c93488f1STitus Rwantare     uint16_t peak_iout;
83*c93488f1STitus Rwantare     uint16_t peak_temperature;
84*c93488f1STitus Rwantare     uint16_t peak_pin;
85*c93488f1STitus Rwantare 
86*c93488f1STitus Rwantare     uint8_t pmon_control;
87*c93488f1STitus Rwantare     uint16_t pmon_config;
88*c93488f1STitus Rwantare     uint16_t alert1_config;
89*c93488f1STitus Rwantare     uint16_t alert2_config;
90*c93488f1STitus Rwantare     uint16_t device_config;
91*c93488f1STitus Rwantare 
92*c93488f1STitus Rwantare     uint16_t hysteresis_low;
93*c93488f1STitus Rwantare     uint16_t hysteresis_high;
94*c93488f1STitus Rwantare     uint8_t status_hysteresis;
95*c93488f1STitus Rwantare     uint8_t status_gpio;
96*c93488f1STitus Rwantare 
97*c93488f1STitus Rwantare     uint16_t strt_up_iout_lim;
98*c93488f1STitus Rwantare 
99*c93488f1STitus Rwantare } ADM1272State;
100*c93488f1STitus Rwantare 
101*c93488f1STitus Rwantare static const PMBusCoefficients adm1272_coefficients[] = {
102*c93488f1STitus Rwantare     [0] = { 6770, 0, -2 },        /* voltage, vrange 60V */
103*c93488f1STitus Rwantare     [1] = { 4062, 0, -2 },        /* voltage, vrange 100V */
104*c93488f1STitus Rwantare     [2] = { 1326, 20480, -1 },    /* current, vsense range 15mV */
105*c93488f1STitus Rwantare     [3] = { 663, 20480, -1 },     /* current, vsense range 30mV */
106*c93488f1STitus Rwantare     [4] = { 3512, 0, -2 },        /* power, vrange 60V, irange 15mV */
107*c93488f1STitus Rwantare     [5] = { 21071, 0, -3 },       /* power, vrange 100V, irange 15mV */
108*c93488f1STitus Rwantare     [6] = { 17561, 0, -3 },       /* power, vrange 60V, irange 30mV */
109*c93488f1STitus Rwantare     [7] = { 10535, 0, -3 },       /* power, vrange 100V, irange 30mV */
110*c93488f1STitus Rwantare     [8] = { 42, 31871, -1 },      /* temperature */
111*c93488f1STitus Rwantare };
112*c93488f1STitus Rwantare 
113*c93488f1STitus Rwantare static void adm1272_check_limits(ADM1272State *s)
114*c93488f1STitus Rwantare {
115*c93488f1STitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(s);
116*c93488f1STitus Rwantare 
117*c93488f1STitus Rwantare     pmbus_check_limits(pmdev);
118*c93488f1STitus Rwantare 
119*c93488f1STitus Rwantare     if (pmdev->pages[0].read_vout > s->peak_vout) {
120*c93488f1STitus Rwantare         s->peak_vout = pmdev->pages[0].read_vout;
121*c93488f1STitus Rwantare     }
122*c93488f1STitus Rwantare 
123*c93488f1STitus Rwantare     if (pmdev->pages[0].read_vin > s->peak_vin) {
124*c93488f1STitus Rwantare         s->peak_vin = pmdev->pages[0].read_vin;
125*c93488f1STitus Rwantare     }
126*c93488f1STitus Rwantare 
127*c93488f1STitus Rwantare     if (pmdev->pages[0].read_iout > s->peak_iout) {
128*c93488f1STitus Rwantare         s->peak_iout = pmdev->pages[0].read_iout;
129*c93488f1STitus Rwantare     }
130*c93488f1STitus Rwantare 
131*c93488f1STitus Rwantare     if (pmdev->pages[0].read_temperature_1 > s->peak_temperature) {
132*c93488f1STitus Rwantare         s->peak_temperature = pmdev->pages[0].read_temperature_1;
133*c93488f1STitus Rwantare     }
134*c93488f1STitus Rwantare 
135*c93488f1STitus Rwantare     if (pmdev->pages[0].read_pin > s->peak_pin) {
136*c93488f1STitus Rwantare         s->peak_pin = pmdev->pages[0].read_pin;
137*c93488f1STitus Rwantare     }
138*c93488f1STitus Rwantare }
139*c93488f1STitus Rwantare 
140*c93488f1STitus Rwantare static uint16_t adm1272_millivolts_to_direct(uint32_t value)
141*c93488f1STitus Rwantare {
142*c93488f1STitus Rwantare     PMBusCoefficients c = adm1272_coefficients[ADM1272_VOLTAGE_COEFF_DEFAULT];
143*c93488f1STitus Rwantare     c.b = c.b * 1000;
144*c93488f1STitus Rwantare     c.R = c.R - 3;
145*c93488f1STitus Rwantare     return pmbus_data2direct_mode(c, value);
146*c93488f1STitus Rwantare }
147*c93488f1STitus Rwantare 
148*c93488f1STitus Rwantare static uint32_t adm1272_direct_to_millivolts(uint16_t value)
149*c93488f1STitus Rwantare {
150*c93488f1STitus Rwantare     PMBusCoefficients c = adm1272_coefficients[ADM1272_VOLTAGE_COEFF_DEFAULT];
151*c93488f1STitus Rwantare     c.b = c.b * 1000;
152*c93488f1STitus Rwantare     c.R = c.R - 3;
153*c93488f1STitus Rwantare     return pmbus_direct_mode2data(c, value);
154*c93488f1STitus Rwantare }
155*c93488f1STitus Rwantare 
156*c93488f1STitus Rwantare static uint16_t adm1272_milliamps_to_direct(uint32_t value)
157*c93488f1STitus Rwantare {
158*c93488f1STitus Rwantare     PMBusCoefficients c = adm1272_coefficients[ADM1272_CURRENT_COEFF_DEFAULT];
159*c93488f1STitus Rwantare     /* Y = (m * r_sense * x - b) * 10^R */
160*c93488f1STitus Rwantare     c.m = c.m * ADM1272_SHUNT / 1000; /* micro-ohms */
161*c93488f1STitus Rwantare     c.b = c.b * 1000;
162*c93488f1STitus Rwantare     c.R = c.R - 3;
163*c93488f1STitus Rwantare     return pmbus_data2direct_mode(c, value);
164*c93488f1STitus Rwantare }
165*c93488f1STitus Rwantare 
166*c93488f1STitus Rwantare static uint32_t adm1272_direct_to_milliamps(uint16_t value)
167*c93488f1STitus Rwantare {
168*c93488f1STitus Rwantare     PMBusCoefficients c = adm1272_coefficients[ADM1272_CURRENT_COEFF_DEFAULT];
169*c93488f1STitus Rwantare     c.m = c.m * ADM1272_SHUNT / 1000;
170*c93488f1STitus Rwantare     c.b = c.b * 1000;
171*c93488f1STitus Rwantare     c.R = c.R - 3;
172*c93488f1STitus Rwantare     return pmbus_direct_mode2data(c, value);
173*c93488f1STitus Rwantare }
174*c93488f1STitus Rwantare 
175*c93488f1STitus Rwantare static uint16_t adm1272_watts_to_direct(uint32_t value)
176*c93488f1STitus Rwantare {
177*c93488f1STitus Rwantare     PMBusCoefficients c = adm1272_coefficients[ADM1272_PWR_COEFF_DEFAULT];
178*c93488f1STitus Rwantare     c.m = c.m * ADM1272_SHUNT / 1000;
179*c93488f1STitus Rwantare     return pmbus_data2direct_mode(c, value);
180*c93488f1STitus Rwantare }
181*c93488f1STitus Rwantare 
182*c93488f1STitus Rwantare static uint32_t adm1272_direct_to_watts(uint16_t value)
183*c93488f1STitus Rwantare {
184*c93488f1STitus Rwantare     PMBusCoefficients c = adm1272_coefficients[ADM1272_PWR_COEFF_DEFAULT];
185*c93488f1STitus Rwantare     c.m = c.m * ADM1272_SHUNT / 1000;
186*c93488f1STitus Rwantare     return pmbus_direct_mode2data(c, value);
187*c93488f1STitus Rwantare }
188*c93488f1STitus Rwantare 
189*c93488f1STitus Rwantare static void adm1272_exit_reset(Object *obj)
190*c93488f1STitus Rwantare {
191*c93488f1STitus Rwantare     ADM1272State *s = ADM1272(obj);
192*c93488f1STitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
193*c93488f1STitus Rwantare 
194*c93488f1STitus Rwantare     pmdev->page = 0;
195*c93488f1STitus Rwantare     pmdev->pages[0].operation = ADM1272_OPERATION_DEFAULT;
196*c93488f1STitus Rwantare 
197*c93488f1STitus Rwantare 
198*c93488f1STitus Rwantare     pmdev->capability = ADM1272_CAPABILITY_NO_PEC;
199*c93488f1STitus Rwantare     pmdev->pages[0].revision = ADM1272_PMBUS_REVISION_DEFAULT;
200*c93488f1STitus Rwantare     pmdev->pages[0].vout_mode = ADM1272_DIRECT_MODE;
201*c93488f1STitus Rwantare     pmdev->pages[0].vout_ov_warn_limit = ADM1272_HIGH_LIMIT_DEFAULT;
202*c93488f1STitus Rwantare     pmdev->pages[0].vout_uv_warn_limit = 0;
203*c93488f1STitus Rwantare     pmdev->pages[0].iout_oc_warn_limit = ADM1272_HIGH_LIMIT_DEFAULT;
204*c93488f1STitus Rwantare     pmdev->pages[0].ot_fault_limit = ADM1272_HIGH_LIMIT_DEFAULT;
205*c93488f1STitus Rwantare     pmdev->pages[0].ot_warn_limit = ADM1272_HIGH_LIMIT_DEFAULT;
206*c93488f1STitus Rwantare     pmdev->pages[0].vin_ov_warn_limit = ADM1272_HIGH_LIMIT_DEFAULT;
207*c93488f1STitus Rwantare     pmdev->pages[0].vin_uv_warn_limit = 0;
208*c93488f1STitus Rwantare     pmdev->pages[0].pin_op_warn_limit = ADM1272_PIN_OP_DEFAULT;
209*c93488f1STitus Rwantare 
210*c93488f1STitus Rwantare     pmdev->pages[0].status_word = 0;
211*c93488f1STitus Rwantare     pmdev->pages[0].status_vout = 0;
212*c93488f1STitus Rwantare     pmdev->pages[0].status_iout = 0;
213*c93488f1STitus Rwantare     pmdev->pages[0].status_input = 0;
214*c93488f1STitus Rwantare     pmdev->pages[0].status_temperature = 0;
215*c93488f1STitus Rwantare     pmdev->pages[0].status_mfr_specific = 0;
216*c93488f1STitus Rwantare 
217*c93488f1STitus Rwantare     pmdev->pages[0].read_vin
218*c93488f1STitus Rwantare         = adm1272_millivolts_to_direct(ADM1272_VOLT_DEFAULT);
219*c93488f1STitus Rwantare     pmdev->pages[0].read_vout
220*c93488f1STitus Rwantare         = adm1272_millivolts_to_direct(ADM1272_VOLT_DEFAULT);
221*c93488f1STitus Rwantare     pmdev->pages[0].read_iout
222*c93488f1STitus Rwantare         = adm1272_milliamps_to_direct(ADM1272_IOUT_DEFAULT);
223*c93488f1STitus Rwantare     pmdev->pages[0].read_temperature_1 = 0;
224*c93488f1STitus Rwantare     pmdev->pages[0].read_pin = adm1272_watts_to_direct(ADM1272_PWR_DEFAULT);
225*c93488f1STitus Rwantare     pmdev->pages[0].revision = ADM1272_PMBUS_REVISION_DEFAULT;
226*c93488f1STitus Rwantare     pmdev->pages[0].mfr_id = ADM1272_MFR_ID_DEFAULT;
227*c93488f1STitus Rwantare     pmdev->pages[0].mfr_model = ADM1272_MODEL_DEFAULT;
228*c93488f1STitus Rwantare     pmdev->pages[0].mfr_revision = ADM1272_MFR_DEFAULT_REVISION;
229*c93488f1STitus Rwantare     pmdev->pages[0].mfr_date = ADM1272_DEFAULT_DATE;
230*c93488f1STitus Rwantare 
231*c93488f1STitus Rwantare     s->pin_ext = 0;
232*c93488f1STitus Rwantare     s->ein_ext = 0;
233*c93488f1STitus Rwantare     s->restart_time = ADM1272_RESTART_TIME_DEFAULT;
234*c93488f1STitus Rwantare 
235*c93488f1STitus Rwantare     s->peak_vin = 0;
236*c93488f1STitus Rwantare     s->peak_vout = 0;
237*c93488f1STitus Rwantare     s->peak_iout = 0;
238*c93488f1STitus Rwantare     s->peak_temperature = 0;
239*c93488f1STitus Rwantare     s->peak_pin = 0;
240*c93488f1STitus Rwantare 
241*c93488f1STitus Rwantare     s->pmon_control = ADM1272_PMON_CONTROL_DEFAULT;
242*c93488f1STitus Rwantare     s->pmon_config = ADM1272_PMON_CONFIG_DEFAULT;
243*c93488f1STitus Rwantare     s->alert1_config = 0;
244*c93488f1STitus Rwantare     s->alert2_config = 0;
245*c93488f1STitus Rwantare     s->device_config = ADM1272_DEVICE_CONFIG_DEFAULT;
246*c93488f1STitus Rwantare 
247*c93488f1STitus Rwantare     s->hysteresis_low = 0;
248*c93488f1STitus Rwantare     s->hysteresis_high = ADM1272_HYSTERESIS_HIGH_DEFAULT;
249*c93488f1STitus Rwantare     s->status_hysteresis = 0;
250*c93488f1STitus Rwantare     s->status_gpio = 0;
251*c93488f1STitus Rwantare 
252*c93488f1STitus Rwantare     s->strt_up_iout_lim = ADM1272_STRT_UP_IOUT_LIM_DEFAULT;
253*c93488f1STitus Rwantare }
254*c93488f1STitus Rwantare 
255*c93488f1STitus Rwantare static uint8_t adm1272_read_byte(PMBusDevice *pmdev)
256*c93488f1STitus Rwantare {
257*c93488f1STitus Rwantare     ADM1272State *s = ADM1272(pmdev);
258*c93488f1STitus Rwantare 
259*c93488f1STitus Rwantare     switch (pmdev->code) {
260*c93488f1STitus Rwantare     case ADM1272_RESTART_TIME:
261*c93488f1STitus Rwantare         pmbus_send8(pmdev, s->restart_time);
262*c93488f1STitus Rwantare         break;
263*c93488f1STitus Rwantare 
264*c93488f1STitus Rwantare     case ADM1272_MFR_PEAK_IOUT:
265*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->peak_iout);
266*c93488f1STitus Rwantare         break;
267*c93488f1STitus Rwantare 
268*c93488f1STitus Rwantare     case ADM1272_MFR_PEAK_VIN:
269*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->peak_vin);
270*c93488f1STitus Rwantare         break;
271*c93488f1STitus Rwantare 
272*c93488f1STitus Rwantare     case ADM1272_MFR_PEAK_VOUT:
273*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->peak_vout);
274*c93488f1STitus Rwantare         break;
275*c93488f1STitus Rwantare 
276*c93488f1STitus Rwantare     case ADM1272_MFR_PMON_CONTROL:
277*c93488f1STitus Rwantare         pmbus_send8(pmdev, s->pmon_control);
278*c93488f1STitus Rwantare         break;
279*c93488f1STitus Rwantare 
280*c93488f1STitus Rwantare     case ADM1272_MFR_PMON_CONFIG:
281*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->pmon_config);
282*c93488f1STitus Rwantare         break;
283*c93488f1STitus Rwantare 
284*c93488f1STitus Rwantare     case ADM1272_MFR_ALERT1_CONFIG:
285*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->alert1_config);
286*c93488f1STitus Rwantare         break;
287*c93488f1STitus Rwantare 
288*c93488f1STitus Rwantare     case ADM1272_MFR_ALERT2_CONFIG:
289*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->alert2_config);
290*c93488f1STitus Rwantare         break;
291*c93488f1STitus Rwantare 
292*c93488f1STitus Rwantare     case ADM1272_MFR_PEAK_TEMPERATURE:
293*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->peak_temperature);
294*c93488f1STitus Rwantare         break;
295*c93488f1STitus Rwantare 
296*c93488f1STitus Rwantare     case ADM1272_MFR_DEVICE_CONFIG:
297*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->device_config);
298*c93488f1STitus Rwantare         break;
299*c93488f1STitus Rwantare 
300*c93488f1STitus Rwantare     case ADM1272_MFR_PEAK_PIN:
301*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->peak_pin);
302*c93488f1STitus Rwantare         break;
303*c93488f1STitus Rwantare 
304*c93488f1STitus Rwantare     case ADM1272_MFR_READ_PIN_EXT:
305*c93488f1STitus Rwantare         pmbus_send32(pmdev, s->pin_ext);
306*c93488f1STitus Rwantare         break;
307*c93488f1STitus Rwantare 
308*c93488f1STitus Rwantare     case ADM1272_MFR_READ_EIN_EXT:
309*c93488f1STitus Rwantare         pmbus_send64(pmdev, s->ein_ext);
310*c93488f1STitus Rwantare         break;
311*c93488f1STitus Rwantare 
312*c93488f1STitus Rwantare     case ADM1272_HYSTERESIS_LOW:
313*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->hysteresis_low);
314*c93488f1STitus Rwantare         break;
315*c93488f1STitus Rwantare 
316*c93488f1STitus Rwantare     case ADM1272_HYSTERESIS_HIGH:
317*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->hysteresis_high);
318*c93488f1STitus Rwantare         break;
319*c93488f1STitus Rwantare 
320*c93488f1STitus Rwantare     case ADM1272_STATUS_HYSTERESIS:
321*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->status_hysteresis);
322*c93488f1STitus Rwantare         break;
323*c93488f1STitus Rwantare 
324*c93488f1STitus Rwantare     case ADM1272_STATUS_GPIO:
325*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->status_gpio);
326*c93488f1STitus Rwantare         break;
327*c93488f1STitus Rwantare 
328*c93488f1STitus Rwantare     case ADM1272_STRT_UP_IOUT_LIM:
329*c93488f1STitus Rwantare         pmbus_send16(pmdev, s->strt_up_iout_lim);
330*c93488f1STitus Rwantare         break;
331*c93488f1STitus Rwantare 
332*c93488f1STitus Rwantare     default:
333*c93488f1STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
334*c93488f1STitus Rwantare                       "%s: reading from unsupported register: 0x%02x\n",
335*c93488f1STitus Rwantare                       __func__, pmdev->code);
336*c93488f1STitus Rwantare         return 0xFF;
337*c93488f1STitus Rwantare         break;
338*c93488f1STitus Rwantare     }
339*c93488f1STitus Rwantare 
340*c93488f1STitus Rwantare     return 0;
341*c93488f1STitus Rwantare }
342*c93488f1STitus Rwantare 
343*c93488f1STitus Rwantare static int adm1272_write_data(PMBusDevice *pmdev, const uint8_t *buf,
344*c93488f1STitus Rwantare                               uint8_t len)
345*c93488f1STitus Rwantare {
346*c93488f1STitus Rwantare     ADM1272State *s = ADM1272(pmdev);
347*c93488f1STitus Rwantare 
348*c93488f1STitus Rwantare     if (len == 0) {
349*c93488f1STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__);
350*c93488f1STitus Rwantare         return -1;
351*c93488f1STitus Rwantare     }
352*c93488f1STitus Rwantare 
353*c93488f1STitus Rwantare     pmdev->code = buf[0]; /* PMBus command code */
354*c93488f1STitus Rwantare 
355*c93488f1STitus Rwantare     if (len == 1) {
356*c93488f1STitus Rwantare         return 0;
357*c93488f1STitus Rwantare     }
358*c93488f1STitus Rwantare 
359*c93488f1STitus Rwantare     /* Exclude command code from buffer */
360*c93488f1STitus Rwantare     buf++;
361*c93488f1STitus Rwantare     len--;
362*c93488f1STitus Rwantare 
363*c93488f1STitus Rwantare     switch (pmdev->code) {
364*c93488f1STitus Rwantare 
365*c93488f1STitus Rwantare     case ADM1272_RESTART_TIME:
366*c93488f1STitus Rwantare         s->restart_time = pmbus_receive8(pmdev);
367*c93488f1STitus Rwantare         break;
368*c93488f1STitus Rwantare 
369*c93488f1STitus Rwantare     case ADM1272_MFR_PMON_CONTROL:
370*c93488f1STitus Rwantare         s->pmon_control = pmbus_receive8(pmdev);
371*c93488f1STitus Rwantare         break;
372*c93488f1STitus Rwantare 
373*c93488f1STitus Rwantare     case ADM1272_MFR_PMON_CONFIG:
374*c93488f1STitus Rwantare         s->pmon_config = pmbus_receive16(pmdev);
375*c93488f1STitus Rwantare         break;
376*c93488f1STitus Rwantare 
377*c93488f1STitus Rwantare     case ADM1272_MFR_ALERT1_CONFIG:
378*c93488f1STitus Rwantare         s->alert1_config = pmbus_receive16(pmdev);
379*c93488f1STitus Rwantare         break;
380*c93488f1STitus Rwantare 
381*c93488f1STitus Rwantare     case ADM1272_MFR_ALERT2_CONFIG:
382*c93488f1STitus Rwantare         s->alert2_config = pmbus_receive16(pmdev);
383*c93488f1STitus Rwantare         break;
384*c93488f1STitus Rwantare 
385*c93488f1STitus Rwantare     case ADM1272_MFR_DEVICE_CONFIG:
386*c93488f1STitus Rwantare         s->device_config = pmbus_receive16(pmdev);
387*c93488f1STitus Rwantare         break;
388*c93488f1STitus Rwantare 
389*c93488f1STitus Rwantare     case ADM1272_MFR_POWER_CYCLE:
390*c93488f1STitus Rwantare         adm1272_exit_reset((Object *)s);
391*c93488f1STitus Rwantare         break;
392*c93488f1STitus Rwantare 
393*c93488f1STitus Rwantare     case ADM1272_HYSTERESIS_LOW:
394*c93488f1STitus Rwantare         s->hysteresis_low = pmbus_receive16(pmdev);
395*c93488f1STitus Rwantare         break;
396*c93488f1STitus Rwantare 
397*c93488f1STitus Rwantare     case ADM1272_HYSTERESIS_HIGH:
398*c93488f1STitus Rwantare         s->hysteresis_high = pmbus_receive16(pmdev);
399*c93488f1STitus Rwantare         break;
400*c93488f1STitus Rwantare 
401*c93488f1STitus Rwantare     case ADM1272_STRT_UP_IOUT_LIM:
402*c93488f1STitus Rwantare         s->strt_up_iout_lim = pmbus_receive16(pmdev);
403*c93488f1STitus Rwantare         adm1272_check_limits(s);
404*c93488f1STitus Rwantare         break;
405*c93488f1STitus Rwantare 
406*c93488f1STitus Rwantare     default:
407*c93488f1STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
408*c93488f1STitus Rwantare                       "%s: writing to unsupported register: 0x%02x\n",
409*c93488f1STitus Rwantare                       __func__, pmdev->code);
410*c93488f1STitus Rwantare         break;
411*c93488f1STitus Rwantare     }
412*c93488f1STitus Rwantare     return 0;
413*c93488f1STitus Rwantare }
414*c93488f1STitus Rwantare 
415*c93488f1STitus Rwantare static void adm1272_get(Object *obj, Visitor *v, const char *name, void *opaque,
416*c93488f1STitus Rwantare                         Error **errp)
417*c93488f1STitus Rwantare {
418*c93488f1STitus Rwantare     uint16_t value;
419*c93488f1STitus Rwantare 
420*c93488f1STitus Rwantare     if (strcmp(name, "vin") == 0 || strcmp(name, "vout") == 0) {
421*c93488f1STitus Rwantare         value = adm1272_direct_to_millivolts(*(uint16_t *)opaque);
422*c93488f1STitus Rwantare     } else if (strcmp(name, "iout") == 0) {
423*c93488f1STitus Rwantare         value = adm1272_direct_to_milliamps(*(uint16_t *)opaque);
424*c93488f1STitus Rwantare     } else if (strcmp(name, "pin") == 0) {
425*c93488f1STitus Rwantare         value = adm1272_direct_to_watts(*(uint16_t *)opaque);
426*c93488f1STitus Rwantare     } else {
427*c93488f1STitus Rwantare         value = *(uint16_t *)opaque;
428*c93488f1STitus Rwantare     }
429*c93488f1STitus Rwantare 
430*c93488f1STitus Rwantare     visit_type_uint16(v, name, &value, errp);
431*c93488f1STitus Rwantare }
432*c93488f1STitus Rwantare 
433*c93488f1STitus Rwantare static void adm1272_set(Object *obj, Visitor *v, const char *name, void *opaque,
434*c93488f1STitus Rwantare                         Error **errp)
435*c93488f1STitus Rwantare {
436*c93488f1STitus Rwantare     ADM1272State *s = ADM1272(obj);
437*c93488f1STitus Rwantare     uint16_t *internal = opaque;
438*c93488f1STitus Rwantare     uint16_t value;
439*c93488f1STitus Rwantare 
440*c93488f1STitus Rwantare     if (!visit_type_uint16(v, name, &value, errp)) {
441*c93488f1STitus Rwantare         return;
442*c93488f1STitus Rwantare     }
443*c93488f1STitus Rwantare 
444*c93488f1STitus Rwantare     if (strcmp(name, "vin") == 0 || strcmp(name, "vout") == 0) {
445*c93488f1STitus Rwantare         *internal = adm1272_millivolts_to_direct(value);
446*c93488f1STitus Rwantare     } else if (strcmp(name, "iout") == 0) {
447*c93488f1STitus Rwantare         *internal = adm1272_milliamps_to_direct(value);
448*c93488f1STitus Rwantare     } else if (strcmp(name, "pin") == 0) {
449*c93488f1STitus Rwantare         *internal = adm1272_watts_to_direct(value);
450*c93488f1STitus Rwantare     } else {
451*c93488f1STitus Rwantare         *internal = value;
452*c93488f1STitus Rwantare     }
453*c93488f1STitus Rwantare 
454*c93488f1STitus Rwantare     adm1272_check_limits(s);
455*c93488f1STitus Rwantare }
456*c93488f1STitus Rwantare 
457*c93488f1STitus Rwantare static const VMStateDescription vmstate_adm1272 = {
458*c93488f1STitus Rwantare     .name = "ADM1272",
459*c93488f1STitus Rwantare     .version_id = 0,
460*c93488f1STitus Rwantare     .minimum_version_id = 0,
461*c93488f1STitus Rwantare     .fields = (VMStateField[]){
462*c93488f1STitus Rwantare         VMSTATE_PMBUS_DEVICE(parent, ADM1272State),
463*c93488f1STitus Rwantare         VMSTATE_UINT64(ein_ext, ADM1272State),
464*c93488f1STitus Rwantare         VMSTATE_UINT32(pin_ext, ADM1272State),
465*c93488f1STitus Rwantare         VMSTATE_UINT8(restart_time, ADM1272State),
466*c93488f1STitus Rwantare 
467*c93488f1STitus Rwantare         VMSTATE_UINT16(peak_vin, ADM1272State),
468*c93488f1STitus Rwantare         VMSTATE_UINT16(peak_vout, ADM1272State),
469*c93488f1STitus Rwantare         VMSTATE_UINT16(peak_iout, ADM1272State),
470*c93488f1STitus Rwantare         VMSTATE_UINT16(peak_temperature, ADM1272State),
471*c93488f1STitus Rwantare         VMSTATE_UINT16(peak_pin, ADM1272State),
472*c93488f1STitus Rwantare 
473*c93488f1STitus Rwantare         VMSTATE_UINT8(pmon_control, ADM1272State),
474*c93488f1STitus Rwantare         VMSTATE_UINT16(pmon_config, ADM1272State),
475*c93488f1STitus Rwantare         VMSTATE_UINT16(alert1_config, ADM1272State),
476*c93488f1STitus Rwantare         VMSTATE_UINT16(alert2_config, ADM1272State),
477*c93488f1STitus Rwantare         VMSTATE_UINT16(device_config, ADM1272State),
478*c93488f1STitus Rwantare 
479*c93488f1STitus Rwantare         VMSTATE_UINT16(hysteresis_low, ADM1272State),
480*c93488f1STitus Rwantare         VMSTATE_UINT16(hysteresis_high, ADM1272State),
481*c93488f1STitus Rwantare         VMSTATE_UINT8(status_hysteresis, ADM1272State),
482*c93488f1STitus Rwantare         VMSTATE_UINT8(status_gpio, ADM1272State),
483*c93488f1STitus Rwantare 
484*c93488f1STitus Rwantare         VMSTATE_UINT16(strt_up_iout_lim, ADM1272State),
485*c93488f1STitus Rwantare         VMSTATE_END_OF_LIST()
486*c93488f1STitus Rwantare     }
487*c93488f1STitus Rwantare };
488*c93488f1STitus Rwantare 
489*c93488f1STitus Rwantare static void adm1272_init(Object *obj)
490*c93488f1STitus Rwantare {
491*c93488f1STitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
492*c93488f1STitus Rwantare     uint64_t flags = PB_HAS_VOUT_MODE | PB_HAS_VOUT | PB_HAS_VIN | PB_HAS_IOUT |
493*c93488f1STitus Rwantare                      PB_HAS_PIN | PB_HAS_TEMPERATURE | PB_HAS_MFR_INFO;
494*c93488f1STitus Rwantare 
495*c93488f1STitus Rwantare     pmbus_page_config(pmdev, 0, flags);
496*c93488f1STitus Rwantare 
497*c93488f1STitus Rwantare     object_property_add(obj, "vin", "uint16",
498*c93488f1STitus Rwantare                         adm1272_get,
499*c93488f1STitus Rwantare                         adm1272_set, NULL, &pmdev->pages[0].read_vin);
500*c93488f1STitus Rwantare 
501*c93488f1STitus Rwantare     object_property_add(obj, "vout", "uint16",
502*c93488f1STitus Rwantare                         adm1272_get,
503*c93488f1STitus Rwantare                         adm1272_set, NULL, &pmdev->pages[0].read_vout);
504*c93488f1STitus Rwantare 
505*c93488f1STitus Rwantare     object_property_add(obj, "iout", "uint16",
506*c93488f1STitus Rwantare                         adm1272_get,
507*c93488f1STitus Rwantare                         adm1272_set, NULL, &pmdev->pages[0].read_iout);
508*c93488f1STitus Rwantare 
509*c93488f1STitus Rwantare     object_property_add(obj, "pin", "uint16",
510*c93488f1STitus Rwantare                         adm1272_get,
511*c93488f1STitus Rwantare                         adm1272_set, NULL, &pmdev->pages[0].read_pin);
512*c93488f1STitus Rwantare 
513*c93488f1STitus Rwantare }
514*c93488f1STitus Rwantare 
515*c93488f1STitus Rwantare static void adm1272_class_init(ObjectClass *klass, void *data)
516*c93488f1STitus Rwantare {
517*c93488f1STitus Rwantare     ResettableClass *rc = RESETTABLE_CLASS(klass);
518*c93488f1STitus Rwantare     DeviceClass *dc = DEVICE_CLASS(klass);
519*c93488f1STitus Rwantare     PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass);
520*c93488f1STitus Rwantare 
521*c93488f1STitus Rwantare     dc->desc = "Analog Devices ADM1272 Hot Swap controller";
522*c93488f1STitus Rwantare     dc->vmsd = &vmstate_adm1272;
523*c93488f1STitus Rwantare     k->write_data = adm1272_write_data;
524*c93488f1STitus Rwantare     k->receive_byte = adm1272_read_byte;
525*c93488f1STitus Rwantare     k->device_num_pages = 1;
526*c93488f1STitus Rwantare 
527*c93488f1STitus Rwantare     rc->phases.exit = adm1272_exit_reset;
528*c93488f1STitus Rwantare }
529*c93488f1STitus Rwantare 
530*c93488f1STitus Rwantare static const TypeInfo adm1272_info = {
531*c93488f1STitus Rwantare     .name = TYPE_ADM1272,
532*c93488f1STitus Rwantare     .parent = TYPE_PMBUS_DEVICE,
533*c93488f1STitus Rwantare     .instance_size = sizeof(ADM1272State),
534*c93488f1STitus Rwantare     .instance_init = adm1272_init,
535*c93488f1STitus Rwantare     .class_init = adm1272_class_init,
536*c93488f1STitus Rwantare };
537*c93488f1STitus Rwantare 
538*c93488f1STitus Rwantare static void adm1272_register_types(void)
539*c93488f1STitus Rwantare {
540*c93488f1STitus Rwantare     type_register_static(&adm1272_info);
541*c93488f1STitus Rwantare }
542*c93488f1STitus Rwantare 
543*c93488f1STitus Rwantare type_init(adm1272_register_types)
544