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