xref: /qemu/hw/sensor/max34451.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
17215456aSTitus Rwantare /*
27215456aSTitus Rwantare  * Maxim MAX34451 PMBus 16-Channel V/I monitor and 12-Channel Sequencer/Marginer
37215456aSTitus Rwantare  *
47215456aSTitus Rwantare  * Copyright 2021 Google LLC
57215456aSTitus Rwantare  *
67215456aSTitus Rwantare  * SPDX-License-Identifier: GPL-2.0-or-later
77215456aSTitus Rwantare  */
87215456aSTitus Rwantare 
97215456aSTitus Rwantare #include "qemu/osdep.h"
107215456aSTitus Rwantare #include "hw/i2c/pmbus_device.h"
117215456aSTitus Rwantare #include "hw/irq.h"
127215456aSTitus Rwantare #include "migration/vmstate.h"
137215456aSTitus Rwantare #include "qapi/error.h"
147215456aSTitus Rwantare #include "qapi/visitor.h"
157215456aSTitus Rwantare #include "qemu/log.h"
167215456aSTitus Rwantare #include "qemu/module.h"
177215456aSTitus Rwantare 
187215456aSTitus Rwantare #define TYPE_MAX34451 "max34451"
197215456aSTitus Rwantare #define MAX34451(obj) OBJECT_CHECK(MAX34451State, (obj), TYPE_MAX34451)
207215456aSTitus Rwantare 
217215456aSTitus Rwantare #define MAX34451_MFR_MODE               0xD1
227215456aSTitus Rwantare #define MAX34451_MFR_PSEN_CONFIG        0xD2
237215456aSTitus Rwantare #define MAX34451_MFR_VOUT_PEAK          0xD4
247215456aSTitus Rwantare #define MAX34451_MFR_IOUT_PEAK          0xD5
257215456aSTitus Rwantare #define MAX34451_MFR_TEMPERATURE_PEAK   0xD6
267215456aSTitus Rwantare #define MAX34451_MFR_VOUT_MIN           0xD7
277215456aSTitus Rwantare #define MAX34451_MFR_NV_LOG_CONFIG      0xD8
287215456aSTitus Rwantare #define MAX34451_MFR_FAULT_RESPONSE     0xD9
297215456aSTitus Rwantare #define MAX34451_MFR_FAULT_RETRY        0xDA
307215456aSTitus Rwantare #define MAX34451_MFR_NV_FAULT_LOG       0xDC
317215456aSTitus Rwantare #define MAX34451_MFR_TIME_COUNT         0xDD
327215456aSTitus Rwantare #define MAX34451_MFR_MARGIN_CONFIG      0xDF
337215456aSTitus Rwantare #define MAX34451_MFR_FW_SERIAL          0xE0
347215456aSTitus Rwantare #define MAX34451_MFR_IOUT_AVG           0xE2
357215456aSTitus Rwantare #define MAX34451_MFR_CHANNEL_CONFIG     0xE4
367215456aSTitus Rwantare #define MAX34451_MFR_TON_SEQ_MAX        0xE6
377215456aSTitus Rwantare #define MAX34451_MFR_PWM_CONFIG         0xE7
387215456aSTitus Rwantare #define MAX34451_MFR_SEQ_CONFIG         0xE8
397215456aSTitus Rwantare #define MAX34451_MFR_STORE_ALL          0xEE
407215456aSTitus Rwantare #define MAX34451_MFR_RESTORE_ALL        0xEF
417215456aSTitus Rwantare #define MAX34451_MFR_TEMP_SENSOR_CONFIG 0xF0
427215456aSTitus Rwantare #define MAX34451_MFR_STORE_SINGLE       0xFC
437215456aSTitus Rwantare #define MAX34451_MFR_CRC                0xFE
447215456aSTitus Rwantare 
457215456aSTitus Rwantare #define MAX34451_NUM_MARGINED_PSU       12
467215456aSTitus Rwantare #define MAX34451_NUM_PWR_DEVICES        16
477215456aSTitus Rwantare #define MAX34451_NUM_TEMP_DEVICES       5
487215456aSTitus Rwantare #define MAX34451_NUM_PAGES              21
497215456aSTitus Rwantare 
507215456aSTitus Rwantare #define DEFAULT_OP_ON                   0x80
517215456aSTitus Rwantare #define DEFAULT_CAPABILITY              0x20
527215456aSTitus Rwantare #define DEFAULT_ON_OFF_CONFIG           0x1a
537215456aSTitus Rwantare #define DEFAULT_VOUT_MODE               0x40
547215456aSTitus Rwantare #define DEFAULT_TEMPERATURE             2500
557215456aSTitus Rwantare #define DEFAULT_SCALE                   0x7FFF
567215456aSTitus Rwantare #define DEFAULT_OV_LIMIT                0x7FFF
577215456aSTitus Rwantare #define DEFAULT_OC_LIMIT                0x7FFF
587215456aSTitus Rwantare #define DEFAULT_OT_LIMIT                0x7FFF
597215456aSTitus Rwantare #define DEFAULT_VMIN                    0x7FFF
607215456aSTitus Rwantare #define DEFAULT_TON_FAULT_LIMIT         0xFFFF
617215456aSTitus Rwantare #define DEFAULT_CHANNEL_CONFIG          0x20
627215456aSTitus Rwantare #define DEFAULT_TEXT                    0x3130313031303130
637215456aSTitus Rwantare 
647215456aSTitus Rwantare /**
657215456aSTitus Rwantare  * MAX34451State:
667215456aSTitus Rwantare  * @code: The command code received
677215456aSTitus Rwantare  * @page: Each page corresponds to a device monitored by the Max 34451
687215456aSTitus Rwantare  * The page register determines the available commands depending on device
697215456aSTitus Rwantare   ___________________________________________________________________________
707215456aSTitus Rwantare  |   0   |  Power supply monitored by RS0, controlled by PSEN0, and          |
717215456aSTitus Rwantare  |       |  margined with PWM0.                                              |
727215456aSTitus Rwantare  |_______|___________________________________________________________________|
737215456aSTitus Rwantare  |   1   |  Power supply monitored by RS1, controlled by PSEN1, and          |
747215456aSTitus Rwantare  |       |  margined with PWM1.                                              |
757215456aSTitus Rwantare  |_______|___________________________________________________________________|
767215456aSTitus Rwantare  |   2   |  Power supply monitored by RS2, controlled by PSEN2, and          |
777215456aSTitus Rwantare  |       |  margined with PWM2.                                              |
787215456aSTitus Rwantare  |_______|___________________________________________________________________|
797215456aSTitus Rwantare  |   3   |  Power supply monitored by RS3, controlled by PSEN3, and          |
807215456aSTitus Rwantare  |       |  margined with PWM3.                                              |
817215456aSTitus Rwantare  |_______|___________________________________________________________________|
827215456aSTitus Rwantare  |   4   |  Power supply monitored by RS4, controlled by PSEN4, and          |
837215456aSTitus Rwantare  |       |  margined with PWM4.                                              |
847215456aSTitus Rwantare  |_______|___________________________________________________________________|
857215456aSTitus Rwantare  |   5   |  Power supply monitored by RS5, controlled by PSEN5, and          |
867215456aSTitus Rwantare  |       |  margined with PWM5.                                              |
877215456aSTitus Rwantare  |_______|___________________________________________________________________|
887215456aSTitus Rwantare  |   6   |  Power supply monitored by RS6, controlled by PSEN6, and          |
897215456aSTitus Rwantare  |       |  margined with PWM6.                                              |
907215456aSTitus Rwantare  |_______|___________________________________________________________________|
917215456aSTitus Rwantare  |   7   |  Power supply monitored by RS7, controlled by PSEN7, and          |
927215456aSTitus Rwantare  |       |  margined with PWM7.                                              |
937215456aSTitus Rwantare  |_______|___________________________________________________________________|
947215456aSTitus Rwantare  |   8   |  Power supply monitored by RS8, controlled by PSEN8, and          |
957215456aSTitus Rwantare  |       | optionally margined by OUT0 of external DS4424 at I2C address A0h.|
967215456aSTitus Rwantare  |_______|___________________________________________________________________|
977215456aSTitus Rwantare  |   9   |  Power supply monitored by RS9, controlled by PSEN9, and          |
987215456aSTitus Rwantare  |       | optionally margined by OUT1 of external DS4424 at I2C address A0h.|
997215456aSTitus Rwantare  |_______|___________________________________________________________________|
1007215456aSTitus Rwantare  |   10  |  Power supply monitored by RS10, controlled by PSEN10, and        |
1017215456aSTitus Rwantare  |       | optionally margined by OUT2 of external DS4424 at I2C address A0h.|
1027215456aSTitus Rwantare  |_______|___________________________________________________________________|
1037215456aSTitus Rwantare  |   11  |  Power supply monitored by RS11, controlled by PSEN11, and        |
1047215456aSTitus Rwantare  |       | optionally margined by OUT3 of external DS4424 at I2C address A0h.|
1057215456aSTitus Rwantare  |_______|___________________________________________________________________|
1067215456aSTitus Rwantare  |   12  |  ADC channel 12 (monitors voltage or current) or GPI.             |
1077215456aSTitus Rwantare  |_______|___________________________________________________________________|
1087215456aSTitus Rwantare  |   13  |  ADC channel 13 (monitors voltage or current) or GPI.             |
1097215456aSTitus Rwantare  |_______|___________________________________________________________________|
1107215456aSTitus Rwantare  |   14  |  ADC channel 14 (monitors voltage or current) or GPI.             |
1117215456aSTitus Rwantare  |_______|___________________________________________________________________|
1127215456aSTitus Rwantare  |   15  |  ADC channel 15 (monitors voltage or current) or GPI.             |
1137215456aSTitus Rwantare  |_______|___________________________________________________________________|
1147215456aSTitus Rwantare  |   16  |  Internal temperature sensor.                                     |
1157215456aSTitus Rwantare  |_______|___________________________________________________________________|
1167215456aSTitus Rwantare  |   17  |  External DS75LV temperature sensor with I2C address 90h.         |
1177215456aSTitus Rwantare  |_______|___________________________________________________________________|
1187215456aSTitus Rwantare  |   18  |  External DS75LV temperature sensor with I2C address 92h.         |
1197215456aSTitus Rwantare  |_______|___________________________________________________________________|
1207215456aSTitus Rwantare  |   19  |  External DS75LV temperature sensor with I2C address 94h.         |
1217215456aSTitus Rwantare  |_______|___________________________________________________________________|
1227215456aSTitus Rwantare  |   20  |  External DS75LV temperature sensor with I2C address 96h.         |
1237215456aSTitus Rwantare  |_______|___________________________________________________________________|
1247215456aSTitus Rwantare  | 21=E2=80=93254|  Reserved.                                                        |
1257215456aSTitus Rwantare  |_______|___________________________________________________________________|
1267215456aSTitus Rwantare  |   255 |  Applies to all pages.                                            |
1277215456aSTitus Rwantare  |_______|___________________________________________________________________|
1287215456aSTitus Rwantare  *
1297215456aSTitus Rwantare  * @operation: Turn on and off power supplies
1307215456aSTitus Rwantare  * @on_off_config: Configure the power supply on and off transition behaviour
1317215456aSTitus Rwantare  * @write_protect: protect against changes to the device's memory
1327215456aSTitus Rwantare  * @vout_margin_high: the voltage when OPERATION is set to margin high
1337215456aSTitus Rwantare  * @vout_margin_low: the voltage when OPERATION is set to margin low
1347215456aSTitus Rwantare  * @vout_scale: scale ADC reading to actual device reading if different
1357215456aSTitus Rwantare  * @iout_cal_gain: set ratio of the voltage at the ADC input to sensed current
1367215456aSTitus Rwantare  */
1377215456aSTitus Rwantare typedef struct MAX34451State {
1387215456aSTitus Rwantare     PMBusDevice parent;
1397215456aSTitus Rwantare 
1407215456aSTitus Rwantare     uint16_t power_good_on[MAX34451_NUM_PWR_DEVICES];
1417215456aSTitus Rwantare     uint16_t power_good_off[MAX34451_NUM_PWR_DEVICES];
1427215456aSTitus Rwantare     uint16_t ton_delay[MAX34451_NUM_MARGINED_PSU];
1437215456aSTitus Rwantare     uint16_t ton_max_fault_limit[MAX34451_NUM_MARGINED_PSU];
1447215456aSTitus Rwantare     uint16_t toff_delay[MAX34451_NUM_MARGINED_PSU];
1457215456aSTitus Rwantare     uint8_t status_mfr_specific[MAX34451_NUM_PWR_DEVICES];
1467215456aSTitus Rwantare     /* Manufacturer specific function */
1477215456aSTitus Rwantare     uint64_t mfr_location;
1487215456aSTitus Rwantare     uint64_t mfr_date;
1497215456aSTitus Rwantare     uint64_t mfr_serial;
1507215456aSTitus Rwantare     uint16_t mfr_mode;
1517215456aSTitus Rwantare     uint32_t psen_config[MAX34451_NUM_MARGINED_PSU];
1527215456aSTitus Rwantare     uint16_t vout_peak[MAX34451_NUM_PWR_DEVICES];
1537215456aSTitus Rwantare     uint16_t iout_peak[MAX34451_NUM_PWR_DEVICES];
1547215456aSTitus Rwantare     uint16_t temperature_peak[MAX34451_NUM_TEMP_DEVICES];
1557215456aSTitus Rwantare     uint16_t vout_min[MAX34451_NUM_PWR_DEVICES];
1567215456aSTitus Rwantare     uint16_t nv_log_config;
1577215456aSTitus Rwantare     uint32_t fault_response[MAX34451_NUM_PWR_DEVICES];
1587215456aSTitus Rwantare     uint16_t fault_retry;
1597215456aSTitus Rwantare     uint32_t fault_log;
1607215456aSTitus Rwantare     uint32_t time_count;
1617215456aSTitus Rwantare     uint16_t margin_config[MAX34451_NUM_MARGINED_PSU];
1627215456aSTitus Rwantare     uint16_t fw_serial;
1637215456aSTitus Rwantare     uint16_t iout_avg[MAX34451_NUM_PWR_DEVICES];
1647215456aSTitus Rwantare     uint16_t channel_config[MAX34451_NUM_PWR_DEVICES];
1657215456aSTitus Rwantare     uint16_t ton_seq_max[MAX34451_NUM_MARGINED_PSU];
1667215456aSTitus Rwantare     uint32_t pwm_config[MAX34451_NUM_MARGINED_PSU];
1677215456aSTitus Rwantare     uint32_t seq_config[MAX34451_NUM_MARGINED_PSU];
1687215456aSTitus Rwantare     uint16_t temp_sensor_config[MAX34451_NUM_TEMP_DEVICES];
1697215456aSTitus Rwantare     uint16_t store_single;
1707215456aSTitus Rwantare     uint16_t crc;
1717215456aSTitus Rwantare } MAX34451State;
1727215456aSTitus Rwantare 
1737215456aSTitus Rwantare 
max34451_check_limits(MAX34451State * s)1747215456aSTitus Rwantare static void max34451_check_limits(MAX34451State *s)
1757215456aSTitus Rwantare {
1767215456aSTitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(s);
1777215456aSTitus Rwantare 
1787215456aSTitus Rwantare     pmbus_check_limits(pmdev);
1797215456aSTitus Rwantare 
1807215456aSTitus Rwantare     for (int i = 0; i < MAX34451_NUM_PWR_DEVICES; i++) {
1817215456aSTitus Rwantare         if (pmdev->pages[i].read_vout == 0) { /* PSU disabled */
1827215456aSTitus Rwantare             continue;
1837215456aSTitus Rwantare         }
1847215456aSTitus Rwantare 
1857215456aSTitus Rwantare         if (pmdev->pages[i].read_vout > s->vout_peak[i]) {
1867215456aSTitus Rwantare             s->vout_peak[i] = pmdev->pages[i].read_vout;
1877215456aSTitus Rwantare         }
1887215456aSTitus Rwantare 
1897215456aSTitus Rwantare         if (pmdev->pages[i].read_vout < s->vout_min[i]) {
1907215456aSTitus Rwantare             s->vout_min[i] = pmdev->pages[i].read_vout;
1917215456aSTitus Rwantare         }
1927215456aSTitus Rwantare 
1937215456aSTitus Rwantare         if (pmdev->pages[i].read_iout > s->iout_peak[i]) {
1947215456aSTitus Rwantare             s->iout_peak[i] = pmdev->pages[i].read_iout;
1957215456aSTitus Rwantare         }
1967215456aSTitus Rwantare     }
1977215456aSTitus Rwantare 
1987215456aSTitus Rwantare     for (int i = 0; i < MAX34451_NUM_TEMP_DEVICES; i++) {
1997215456aSTitus Rwantare         if (pmdev->pages[i + 16].read_temperature_1 > s->temperature_peak[i]) {
2007215456aSTitus Rwantare             s->temperature_peak[i] = pmdev->pages[i + 16].read_temperature_1;
2017215456aSTitus Rwantare         }
2027215456aSTitus Rwantare     }
2037215456aSTitus Rwantare }
2047215456aSTitus Rwantare 
max34451_read_byte(PMBusDevice * pmdev)2057215456aSTitus Rwantare static uint8_t max34451_read_byte(PMBusDevice *pmdev)
2067215456aSTitus Rwantare {
2077215456aSTitus Rwantare     MAX34451State *s = MAX34451(pmdev);
2087215456aSTitus Rwantare     switch (pmdev->code) {
2097215456aSTitus Rwantare 
2107215456aSTitus Rwantare     case PMBUS_POWER_GOOD_ON:
2117215456aSTitus Rwantare         if (pmdev->page < 16) {
2127215456aSTitus Rwantare             pmbus_send16(pmdev, s->power_good_on[pmdev->page]);
2137215456aSTitus Rwantare         }
2147215456aSTitus Rwantare         break;
2157215456aSTitus Rwantare 
2167215456aSTitus Rwantare     case PMBUS_POWER_GOOD_OFF:
2177215456aSTitus Rwantare         if (pmdev->page < 16) {
2187215456aSTitus Rwantare             pmbus_send16(pmdev, s->power_good_off[pmdev->page]);
2197215456aSTitus Rwantare         }
2207215456aSTitus Rwantare         break;
2217215456aSTitus Rwantare 
2227215456aSTitus Rwantare     case PMBUS_TON_DELAY:
2237215456aSTitus Rwantare         if (pmdev->page < 12) {
2247215456aSTitus Rwantare             pmbus_send16(pmdev, s->ton_delay[pmdev->page]);
2257215456aSTitus Rwantare         }
2267215456aSTitus Rwantare         break;
2277215456aSTitus Rwantare 
2287215456aSTitus Rwantare     case PMBUS_TON_MAX_FAULT_LIMIT:
2297215456aSTitus Rwantare         if (pmdev->page < 12) {
2307215456aSTitus Rwantare             pmbus_send16(pmdev, s->ton_max_fault_limit[pmdev->page]);
2317215456aSTitus Rwantare         }
2327215456aSTitus Rwantare         break;
2337215456aSTitus Rwantare 
2347215456aSTitus Rwantare     case PMBUS_TOFF_DELAY:
2357215456aSTitus Rwantare         if (pmdev->page < 12) {
2367215456aSTitus Rwantare             pmbus_send16(pmdev, s->toff_delay[pmdev->page]);
2377215456aSTitus Rwantare         }
2387215456aSTitus Rwantare         break;
2397215456aSTitus Rwantare 
2407215456aSTitus Rwantare     case PMBUS_STATUS_MFR_SPECIFIC:
2417215456aSTitus Rwantare         if (pmdev->page < 16) {
2427215456aSTitus Rwantare             pmbus_send8(pmdev, s->status_mfr_specific[pmdev->page]);
2437215456aSTitus Rwantare         }
2447215456aSTitus Rwantare         break;
2457215456aSTitus Rwantare 
2467215456aSTitus Rwantare     case PMBUS_MFR_ID:
2477215456aSTitus Rwantare         pmbus_send8(pmdev, 0x4d); /* Maxim */
2487215456aSTitus Rwantare         break;
2497215456aSTitus Rwantare 
2507215456aSTitus Rwantare     case PMBUS_MFR_MODEL:
2517215456aSTitus Rwantare         pmbus_send8(pmdev, 0x59);
2527215456aSTitus Rwantare         break;
2537215456aSTitus Rwantare 
2547215456aSTitus Rwantare     case PMBUS_MFR_LOCATION:
2557215456aSTitus Rwantare         pmbus_send64(pmdev, s->mfr_location);
2567215456aSTitus Rwantare         break;
2577215456aSTitus Rwantare 
2587215456aSTitus Rwantare     case PMBUS_MFR_DATE:
2597215456aSTitus Rwantare         pmbus_send64(pmdev, s->mfr_date);
2607215456aSTitus Rwantare         break;
2617215456aSTitus Rwantare 
2627215456aSTitus Rwantare     case PMBUS_MFR_SERIAL:
2637215456aSTitus Rwantare         pmbus_send64(pmdev, s->mfr_serial);
2647215456aSTitus Rwantare         break;
2657215456aSTitus Rwantare 
2667215456aSTitus Rwantare     case MAX34451_MFR_MODE:
2677215456aSTitus Rwantare         pmbus_send16(pmdev, s->mfr_mode);
2687215456aSTitus Rwantare         break;
2697215456aSTitus Rwantare 
2707215456aSTitus Rwantare     case MAX34451_MFR_PSEN_CONFIG:
2717215456aSTitus Rwantare         if (pmdev->page < 12) {
2727215456aSTitus Rwantare             pmbus_send32(pmdev, s->psen_config[pmdev->page]);
2737215456aSTitus Rwantare         }
2747215456aSTitus Rwantare         break;
2757215456aSTitus Rwantare 
2767215456aSTitus Rwantare     case MAX34451_MFR_VOUT_PEAK:
2777215456aSTitus Rwantare         if (pmdev->page < 16) {
2787215456aSTitus Rwantare             pmbus_send16(pmdev, s->vout_peak[pmdev->page]);
2797215456aSTitus Rwantare         }
2807215456aSTitus Rwantare         break;
2817215456aSTitus Rwantare 
2827215456aSTitus Rwantare     case MAX34451_MFR_IOUT_PEAK:
2837215456aSTitus Rwantare         if (pmdev->page < 16) {
2847215456aSTitus Rwantare             pmbus_send16(pmdev, s->iout_peak[pmdev->page]);
2857215456aSTitus Rwantare         }
2867215456aSTitus Rwantare         break;
2877215456aSTitus Rwantare 
2887215456aSTitus Rwantare     case MAX34451_MFR_TEMPERATURE_PEAK:
2897215456aSTitus Rwantare         if (15 < pmdev->page && pmdev->page < 21) {
2907215456aSTitus Rwantare             pmbus_send16(pmdev, s->temperature_peak[pmdev->page % 16]);
2917215456aSTitus Rwantare         } else {
2927215456aSTitus Rwantare             pmbus_send16(pmdev, s->temperature_peak[0]);
2937215456aSTitus Rwantare         }
2947215456aSTitus Rwantare         break;
2957215456aSTitus Rwantare 
2967215456aSTitus Rwantare     case MAX34451_MFR_VOUT_MIN:
2977215456aSTitus Rwantare         if (pmdev->page < 16) {
2987215456aSTitus Rwantare             pmbus_send16(pmdev, s->vout_min[pmdev->page]);
2997215456aSTitus Rwantare         }
3007215456aSTitus Rwantare         break;
3017215456aSTitus Rwantare 
3027215456aSTitus Rwantare     case MAX34451_MFR_NV_LOG_CONFIG:
3037215456aSTitus Rwantare         pmbus_send16(pmdev, s->nv_log_config);
3047215456aSTitus Rwantare         break;
3057215456aSTitus Rwantare 
3067215456aSTitus Rwantare     case MAX34451_MFR_FAULT_RESPONSE:
3077215456aSTitus Rwantare         if (pmdev->page < 16) {
3087215456aSTitus Rwantare             pmbus_send32(pmdev, s->fault_response[pmdev->page]);
3097215456aSTitus Rwantare         }
3107215456aSTitus Rwantare         break;
3117215456aSTitus Rwantare 
3127215456aSTitus Rwantare     case MAX34451_MFR_FAULT_RETRY:
3137215456aSTitus Rwantare         pmbus_send32(pmdev, s->fault_retry);
3147215456aSTitus Rwantare         break;
3157215456aSTitus Rwantare 
3167215456aSTitus Rwantare     case MAX34451_MFR_NV_FAULT_LOG:
3177215456aSTitus Rwantare         pmbus_send32(pmdev, s->fault_log);
3187215456aSTitus Rwantare         break;
3197215456aSTitus Rwantare 
3207215456aSTitus Rwantare     case MAX34451_MFR_TIME_COUNT:
3217215456aSTitus Rwantare         pmbus_send32(pmdev, s->time_count);
3227215456aSTitus Rwantare         break;
3237215456aSTitus Rwantare 
3247215456aSTitus Rwantare     case MAX34451_MFR_MARGIN_CONFIG:
3257215456aSTitus Rwantare         if (pmdev->page < 12) {
3267215456aSTitus Rwantare             pmbus_send16(pmdev, s->margin_config[pmdev->page]);
3277215456aSTitus Rwantare         }
3287215456aSTitus Rwantare         break;
3297215456aSTitus Rwantare 
3307215456aSTitus Rwantare     case MAX34451_MFR_FW_SERIAL:
3317215456aSTitus Rwantare         if (pmdev->page == 255) {
3327215456aSTitus Rwantare             pmbus_send16(pmdev, 1); /* Firmware revision */
3337215456aSTitus Rwantare         }
3347215456aSTitus Rwantare         break;
3357215456aSTitus Rwantare 
3367215456aSTitus Rwantare     case MAX34451_MFR_IOUT_AVG:
3377215456aSTitus Rwantare         if (pmdev->page < 16) {
3387215456aSTitus Rwantare             pmbus_send16(pmdev, s->iout_avg[pmdev->page]);
3397215456aSTitus Rwantare         }
3407215456aSTitus Rwantare         break;
3417215456aSTitus Rwantare 
3427215456aSTitus Rwantare     case MAX34451_MFR_CHANNEL_CONFIG:
3437215456aSTitus Rwantare         if (pmdev->page < 16) {
3447215456aSTitus Rwantare             pmbus_send16(pmdev, s->channel_config[pmdev->page]);
3457215456aSTitus Rwantare         }
3467215456aSTitus Rwantare         break;
3477215456aSTitus Rwantare 
3487215456aSTitus Rwantare     case MAX34451_MFR_TON_SEQ_MAX:
3497215456aSTitus Rwantare         if (pmdev->page < 12) {
3507215456aSTitus Rwantare             pmbus_send16(pmdev, s->ton_seq_max[pmdev->page]);
3517215456aSTitus Rwantare         }
3527215456aSTitus Rwantare         break;
3537215456aSTitus Rwantare 
3547215456aSTitus Rwantare     case MAX34451_MFR_PWM_CONFIG:
3557215456aSTitus Rwantare         if (pmdev->page < 12) {
3567215456aSTitus Rwantare             pmbus_send32(pmdev, s->pwm_config[pmdev->page]);
3577215456aSTitus Rwantare         }
3587215456aSTitus Rwantare         break;
3597215456aSTitus Rwantare 
3607215456aSTitus Rwantare     case MAX34451_MFR_SEQ_CONFIG:
3617215456aSTitus Rwantare         if (pmdev->page < 12) {
3627215456aSTitus Rwantare             pmbus_send32(pmdev, s->seq_config[pmdev->page]);
3637215456aSTitus Rwantare         }
3647215456aSTitus Rwantare         break;
3657215456aSTitus Rwantare 
3667215456aSTitus Rwantare     case MAX34451_MFR_TEMP_SENSOR_CONFIG:
3677215456aSTitus Rwantare         if (15 < pmdev->page && pmdev->page < 21) {
3687215456aSTitus Rwantare             pmbus_send32(pmdev, s->temp_sensor_config[pmdev->page % 16]);
3697215456aSTitus Rwantare         }
3707215456aSTitus Rwantare         break;
3717215456aSTitus Rwantare 
3727215456aSTitus Rwantare     case MAX34451_MFR_STORE_SINGLE:
3737215456aSTitus Rwantare         pmbus_send32(pmdev, s->store_single);
3747215456aSTitus Rwantare         break;
3757215456aSTitus Rwantare 
3767215456aSTitus Rwantare     case MAX34451_MFR_CRC:
3777215456aSTitus Rwantare         pmbus_send32(pmdev, s->crc);
3787215456aSTitus Rwantare         break;
3797215456aSTitus Rwantare 
3807215456aSTitus Rwantare     default:
3817215456aSTitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
3827215456aSTitus Rwantare                       "%s: reading from unsupported register: 0x%02x\n",
3837215456aSTitus Rwantare                       __func__, pmdev->code);
3847215456aSTitus Rwantare         break;
3857215456aSTitus Rwantare     }
3867215456aSTitus Rwantare     return 0xFF;
3877215456aSTitus Rwantare }
3887215456aSTitus Rwantare 
max34451_write_data(PMBusDevice * pmdev,const uint8_t * buf,uint8_t len)3897215456aSTitus Rwantare static int max34451_write_data(PMBusDevice *pmdev, const uint8_t *buf,
3907215456aSTitus Rwantare                                uint8_t len)
3917215456aSTitus Rwantare {
3927215456aSTitus Rwantare     MAX34451State *s = MAX34451(pmdev);
3937215456aSTitus Rwantare 
3947215456aSTitus Rwantare     if (len == 0) {
3957215456aSTitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__);
3967215456aSTitus Rwantare         return -1;
3977215456aSTitus Rwantare     }
3987215456aSTitus Rwantare 
3997215456aSTitus Rwantare     pmdev->code = buf[0]; /* PMBus command code */
4007215456aSTitus Rwantare 
4017215456aSTitus Rwantare     if (len == 1) {
4027215456aSTitus Rwantare         return 0;
4037215456aSTitus Rwantare     }
4047215456aSTitus Rwantare 
4057215456aSTitus Rwantare     /* Exclude command code from buffer */
4067215456aSTitus Rwantare     buf++;
4077215456aSTitus Rwantare     len--;
4087215456aSTitus Rwantare     uint8_t index = pmdev->page;
4097215456aSTitus Rwantare 
4107215456aSTitus Rwantare     switch (pmdev->code) {
4117215456aSTitus Rwantare     case MAX34451_MFR_STORE_ALL:
4127215456aSTitus Rwantare     case MAX34451_MFR_RESTORE_ALL:
4137215456aSTitus Rwantare     case MAX34451_MFR_STORE_SINGLE:
4147215456aSTitus Rwantare         /*
4157215456aSTitus Rwantare          * TODO: hardware behaviour is to move the contents of volatile
4167215456aSTitus Rwantare          * memory to non-volatile memory.
4177215456aSTitus Rwantare          */
4187215456aSTitus Rwantare         break;
4197215456aSTitus Rwantare 
4207215456aSTitus Rwantare     case PMBUS_POWER_GOOD_ON: /* R/W word */
4217215456aSTitus Rwantare         if (pmdev->page < MAX34451_NUM_PWR_DEVICES) {
4227215456aSTitus Rwantare             s->power_good_on[pmdev->page] = pmbus_receive16(pmdev);
4237215456aSTitus Rwantare         }
4247215456aSTitus Rwantare         break;
4257215456aSTitus Rwantare 
4267215456aSTitus Rwantare     case PMBUS_POWER_GOOD_OFF: /* R/W word */
4277215456aSTitus Rwantare         if (pmdev->page < MAX34451_NUM_PWR_DEVICES) {
4287215456aSTitus Rwantare             s->power_good_off[pmdev->page] = pmbus_receive16(pmdev);
4297215456aSTitus Rwantare         }
4307215456aSTitus Rwantare         break;
4317215456aSTitus Rwantare 
4327215456aSTitus Rwantare     case PMBUS_TON_DELAY: /* R/W word */
4337215456aSTitus Rwantare         if (pmdev->page < 12) {
4347215456aSTitus Rwantare             s->ton_delay[pmdev->page] = pmbus_receive16(pmdev);
4357215456aSTitus Rwantare         }
4367215456aSTitus Rwantare         break;
4377215456aSTitus Rwantare 
4387215456aSTitus Rwantare     case PMBUS_TON_MAX_FAULT_LIMIT: /* R/W word */
4397215456aSTitus Rwantare         if (pmdev->page < 12) {
4407215456aSTitus Rwantare             s->ton_max_fault_limit[pmdev->page]
4417215456aSTitus Rwantare                 = pmbus_receive16(pmdev);
4427215456aSTitus Rwantare         }
4437215456aSTitus Rwantare         break;
4447215456aSTitus Rwantare 
4457215456aSTitus Rwantare     case PMBUS_TOFF_DELAY: /* R/W word */
4467215456aSTitus Rwantare         if (pmdev->page < 12) {
4477215456aSTitus Rwantare             s->toff_delay[pmdev->page] = pmbus_receive16(pmdev);
4487215456aSTitus Rwantare         }
4497215456aSTitus Rwantare         break;
4507215456aSTitus Rwantare 
4517215456aSTitus Rwantare     case PMBUS_MFR_LOCATION: /* R/W 64 */
4527215456aSTitus Rwantare         s->mfr_location = pmbus_receive64(pmdev);
4537215456aSTitus Rwantare         break;
4547215456aSTitus Rwantare 
4557215456aSTitus Rwantare     case PMBUS_MFR_DATE: /* R/W 64 */
4567215456aSTitus Rwantare         s->mfr_date = pmbus_receive64(pmdev);
4577215456aSTitus Rwantare         break;
4587215456aSTitus Rwantare 
4597215456aSTitus Rwantare     case PMBUS_MFR_SERIAL: /* R/W 64 */
4607215456aSTitus Rwantare         s->mfr_serial = pmbus_receive64(pmdev);
4617215456aSTitus Rwantare         break;
4627215456aSTitus Rwantare 
4637215456aSTitus Rwantare     case MAX34451_MFR_MODE: /* R/W word */
4647215456aSTitus Rwantare          s->mfr_mode = pmbus_receive16(pmdev);
4657215456aSTitus Rwantare         break;
4667215456aSTitus Rwantare 
4677215456aSTitus Rwantare     case MAX34451_MFR_PSEN_CONFIG: /* R/W 32 */
4687215456aSTitus Rwantare         if (pmdev->page < 12) {
4697215456aSTitus Rwantare             s->psen_config[pmdev->page] = pmbus_receive32(pmdev);
4707215456aSTitus Rwantare         }
4717215456aSTitus Rwantare         break;
4727215456aSTitus Rwantare 
4737215456aSTitus Rwantare     case MAX34451_MFR_VOUT_PEAK: /* R/W word */
4747215456aSTitus Rwantare         if (pmdev->page < 16) {
4757215456aSTitus Rwantare             s->vout_peak[pmdev->page] = pmbus_receive16(pmdev);
4767215456aSTitus Rwantare         }
4777215456aSTitus Rwantare         break;
4787215456aSTitus Rwantare 
4797215456aSTitus Rwantare     case MAX34451_MFR_IOUT_PEAK: /* R/W word */
4807215456aSTitus Rwantare         if (pmdev->page < 16) {
4817215456aSTitus Rwantare             s->iout_peak[pmdev->page] = pmbus_receive16(pmdev);
4827215456aSTitus Rwantare         }
4837215456aSTitus Rwantare         break;
4847215456aSTitus Rwantare 
4857215456aSTitus Rwantare     case MAX34451_MFR_TEMPERATURE_PEAK: /* R/W word */
4867215456aSTitus Rwantare         if (15 < pmdev->page && pmdev->page < 21) {
4877215456aSTitus Rwantare             s->temperature_peak[pmdev->page % 16]
4887215456aSTitus Rwantare                 = pmbus_receive16(pmdev);
4897215456aSTitus Rwantare         }
4907215456aSTitus Rwantare         break;
4917215456aSTitus Rwantare 
4927215456aSTitus Rwantare     case MAX34451_MFR_VOUT_MIN: /* R/W word */
4937215456aSTitus Rwantare         if (pmdev->page < 16) {
4947215456aSTitus Rwantare             s->vout_min[pmdev->page] = pmbus_receive16(pmdev);
4957215456aSTitus Rwantare         }
4967215456aSTitus Rwantare         break;
4977215456aSTitus Rwantare 
4987215456aSTitus Rwantare     case MAX34451_MFR_NV_LOG_CONFIG: /* R/W word */
4997215456aSTitus Rwantare          s->nv_log_config = pmbus_receive16(pmdev);
5007215456aSTitus Rwantare         break;
5017215456aSTitus Rwantare 
5027215456aSTitus Rwantare     case MAX34451_MFR_FAULT_RESPONSE: /* R/W 32 */
5037215456aSTitus Rwantare         if (pmdev->page < 16) {
5047215456aSTitus Rwantare             s->fault_response[pmdev->page] = pmbus_receive32(pmdev);
5057215456aSTitus Rwantare         }
5067215456aSTitus Rwantare         break;
5077215456aSTitus Rwantare 
5087215456aSTitus Rwantare     case MAX34451_MFR_FAULT_RETRY: /* R/W word */
5097215456aSTitus Rwantare         s->fault_retry = pmbus_receive16(pmdev);
5107215456aSTitus Rwantare         break;
5117215456aSTitus Rwantare 
5127215456aSTitus Rwantare     case MAX34451_MFR_TIME_COUNT: /* R/W 32 */
5137215456aSTitus Rwantare         s->time_count = pmbus_receive32(pmdev);
5147215456aSTitus Rwantare         break;
5157215456aSTitus Rwantare 
5167215456aSTitus Rwantare     case MAX34451_MFR_MARGIN_CONFIG: /* R/W word */
5177215456aSTitus Rwantare         if (pmdev->page < 12) {
5187215456aSTitus Rwantare             s->margin_config[pmdev->page] = pmbus_receive16(pmdev);
5197215456aSTitus Rwantare         }
5207215456aSTitus Rwantare         break;
5217215456aSTitus Rwantare 
5227215456aSTitus Rwantare     case MAX34451_MFR_CHANNEL_CONFIG: /* R/W word */
5237215456aSTitus Rwantare         if (pmdev->page < 16) {
5247215456aSTitus Rwantare             s->channel_config[pmdev->page] = pmbus_receive16(pmdev);
5257215456aSTitus Rwantare         }
5267215456aSTitus Rwantare         break;
5277215456aSTitus Rwantare 
5287215456aSTitus Rwantare     case MAX34451_MFR_TON_SEQ_MAX: /* R/W word */
5297215456aSTitus Rwantare         if (pmdev->page < 12) {
5307215456aSTitus Rwantare             s->ton_seq_max[pmdev->page] = pmbus_receive16(pmdev);
5317215456aSTitus Rwantare         }
5327215456aSTitus Rwantare         break;
5337215456aSTitus Rwantare 
5347215456aSTitus Rwantare     case MAX34451_MFR_PWM_CONFIG: /* R/W 32 */
5357215456aSTitus Rwantare         if (pmdev->page < 12) {
5367215456aSTitus Rwantare             s->pwm_config[pmdev->page] = pmbus_receive32(pmdev);
5377215456aSTitus Rwantare         }
5387215456aSTitus Rwantare         break;
5397215456aSTitus Rwantare 
5407215456aSTitus Rwantare     case MAX34451_MFR_SEQ_CONFIG:  /* R/W 32 */
5417215456aSTitus Rwantare         if (pmdev->page < 12) {
5427215456aSTitus Rwantare             s->seq_config[pmdev->page] = pmbus_receive32(pmdev);
5437215456aSTitus Rwantare         }
5447215456aSTitus Rwantare         break;
5457215456aSTitus Rwantare 
5467215456aSTitus Rwantare     case MAX34451_MFR_TEMP_SENSOR_CONFIG:  /* R/W word */
5477215456aSTitus Rwantare         if (15 < pmdev->page && pmdev->page < 21) {
5487215456aSTitus Rwantare             s->temp_sensor_config[pmdev->page % 16]
5497215456aSTitus Rwantare                 = pmbus_receive16(pmdev);
5507215456aSTitus Rwantare         }
5517215456aSTitus Rwantare         break;
5527215456aSTitus Rwantare 
5537215456aSTitus Rwantare     case MAX34451_MFR_CRC: /* R/W word */
5547215456aSTitus Rwantare         s->crc = pmbus_receive16(pmdev);
5557215456aSTitus Rwantare         break;
5567215456aSTitus Rwantare 
5577215456aSTitus Rwantare     case MAX34451_MFR_NV_FAULT_LOG:
5587215456aSTitus Rwantare     case MAX34451_MFR_FW_SERIAL:
5597215456aSTitus Rwantare     case MAX34451_MFR_IOUT_AVG:
5607215456aSTitus Rwantare         /* Read only commands */
5617215456aSTitus Rwantare         pmdev->pages[index].status_word |= PMBUS_STATUS_CML;
5627215456aSTitus Rwantare         pmdev->pages[index].status_cml |= PB_CML_FAULT_INVALID_DATA;
5637215456aSTitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
5647215456aSTitus Rwantare                       "%s: writing to read-only register 0x%02x\n",
5657215456aSTitus Rwantare                       __func__, pmdev->code);
5667215456aSTitus Rwantare         break;
5677215456aSTitus Rwantare 
5687215456aSTitus Rwantare     default:
5697215456aSTitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
5707215456aSTitus Rwantare                       "%s: writing to unsupported register: 0x%02x\n",
5717215456aSTitus Rwantare                       __func__, pmdev->code);
5727215456aSTitus Rwantare         break;
5737215456aSTitus Rwantare     }
5747215456aSTitus Rwantare 
5757215456aSTitus Rwantare     return 0;
5767215456aSTitus Rwantare }
5777215456aSTitus Rwantare 
max34451_get(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)5787215456aSTitus Rwantare static void max34451_get(Object *obj, Visitor *v, const char *name,
5797215456aSTitus Rwantare                                      void *opaque, Error **errp)
5807215456aSTitus Rwantare {
5817215456aSTitus Rwantare     visit_type_uint16(v, name, (uint16_t *)opaque, errp);
5827215456aSTitus Rwantare }
5837215456aSTitus Rwantare 
max34451_set(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)5847215456aSTitus Rwantare static void max34451_set(Object *obj, Visitor *v, const char *name,
5857215456aSTitus Rwantare                                  void *opaque, Error **errp)
5867215456aSTitus Rwantare {
5877215456aSTitus Rwantare     MAX34451State *s = MAX34451(obj);
5887215456aSTitus Rwantare     uint16_t *internal = opaque;
5897215456aSTitus Rwantare     uint16_t value;
5907215456aSTitus Rwantare     if (!visit_type_uint16(v, name, &value, errp)) {
5917215456aSTitus Rwantare         return;
5927215456aSTitus Rwantare     }
5937215456aSTitus Rwantare 
5947215456aSTitus Rwantare     *internal = value;
5957215456aSTitus Rwantare     max34451_check_limits(s);
5967215456aSTitus Rwantare }
5977215456aSTitus Rwantare 
5987215456aSTitus Rwantare /* used to init uint16_t arrays */
memset_word(void * s,uint16_t c,size_t n)5997215456aSTitus Rwantare static inline void *memset_word(void *s, uint16_t c, size_t n)
6007215456aSTitus Rwantare {
6017215456aSTitus Rwantare     size_t i;
6027215456aSTitus Rwantare     uint16_t *p = s;
6037215456aSTitus Rwantare 
6047215456aSTitus Rwantare     for (i = 0; i < n; i++) {
6057215456aSTitus Rwantare         p[i] = c;
6067215456aSTitus Rwantare     }
6077215456aSTitus Rwantare 
6087215456aSTitus Rwantare     return s;
6097215456aSTitus Rwantare }
6107215456aSTitus Rwantare 
max34451_exit_reset(Object * obj,ResetType type)611ad80e367SPeter Maydell static void max34451_exit_reset(Object *obj, ResetType type)
6127215456aSTitus Rwantare {
6137215456aSTitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
6147215456aSTitus Rwantare     MAX34451State *s = MAX34451(obj);
6157215456aSTitus Rwantare     pmdev->capability = DEFAULT_CAPABILITY;
6167215456aSTitus Rwantare 
6177215456aSTitus Rwantare     for (int i = 0; i < MAX34451_NUM_PAGES; i++) {
6187215456aSTitus Rwantare         pmdev->pages[i].operation = DEFAULT_OP_ON;
6197215456aSTitus Rwantare         pmdev->pages[i].on_off_config = DEFAULT_ON_OFF_CONFIG;
6207215456aSTitus Rwantare         pmdev->pages[i].revision = 0x11;
6217215456aSTitus Rwantare         pmdev->pages[i].vout_mode = DEFAULT_VOUT_MODE;
6227215456aSTitus Rwantare     }
6237215456aSTitus Rwantare 
6247215456aSTitus Rwantare     for (int i = 0; i < MAX34451_NUM_PWR_DEVICES; i++) {
6257215456aSTitus Rwantare         pmdev->pages[i].vout_scale_monitor = DEFAULT_SCALE;
6267215456aSTitus Rwantare         pmdev->pages[i].vout_ov_fault_limit = DEFAULT_OV_LIMIT;
6277215456aSTitus Rwantare         pmdev->pages[i].vout_ov_warn_limit = DEFAULT_OV_LIMIT;
6287215456aSTitus Rwantare         pmdev->pages[i].iout_oc_warn_limit = DEFAULT_OC_LIMIT;
6297215456aSTitus Rwantare         pmdev->pages[i].iout_oc_fault_limit = DEFAULT_OC_LIMIT;
6307215456aSTitus Rwantare     }
6317215456aSTitus Rwantare 
6327215456aSTitus Rwantare     for (int i = 0; i < MAX34451_NUM_MARGINED_PSU; i++) {
6337215456aSTitus Rwantare         pmdev->pages[i].ton_max_fault_limit = DEFAULT_TON_FAULT_LIMIT;
6347215456aSTitus Rwantare     }
6357215456aSTitus Rwantare 
6367215456aSTitus Rwantare     for (int i = 16; i < MAX34451_NUM_TEMP_DEVICES + 16; i++) {
6377215456aSTitus Rwantare         pmdev->pages[i].read_temperature_1 = DEFAULT_TEMPERATURE;
6387215456aSTitus Rwantare         pmdev->pages[i].ot_warn_limit = DEFAULT_OT_LIMIT;
6397215456aSTitus Rwantare         pmdev->pages[i].ot_fault_limit = DEFAULT_OT_LIMIT;
6407215456aSTitus Rwantare     }
6417215456aSTitus Rwantare 
6427215456aSTitus Rwantare     memset_word(s->ton_max_fault_limit, DEFAULT_TON_FAULT_LIMIT,
6437215456aSTitus Rwantare                 MAX34451_NUM_MARGINED_PSU);
6447215456aSTitus Rwantare     memset_word(s->channel_config, DEFAULT_CHANNEL_CONFIG,
6457215456aSTitus Rwantare                 MAX34451_NUM_PWR_DEVICES);
6467215456aSTitus Rwantare     memset_word(s->vout_min, DEFAULT_VMIN, MAX34451_NUM_PWR_DEVICES);
6477215456aSTitus Rwantare 
6487215456aSTitus Rwantare     s->mfr_location = DEFAULT_TEXT;
6497215456aSTitus Rwantare     s->mfr_date = DEFAULT_TEXT;
6507215456aSTitus Rwantare     s->mfr_serial = DEFAULT_TEXT;
6517215456aSTitus Rwantare }
6527215456aSTitus Rwantare 
6537215456aSTitus Rwantare static const VMStateDescription vmstate_max34451 = {
6547215456aSTitus Rwantare     .name = TYPE_MAX34451,
6557215456aSTitus Rwantare     .version_id = 0,
6567215456aSTitus Rwantare     .minimum_version_id = 0,
657af10fff2SRichard Henderson     .fields = (const VMStateField[]){
6587215456aSTitus Rwantare         VMSTATE_PMBUS_DEVICE(parent, MAX34451State),
6597215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(power_good_on, MAX34451State,
6607215456aSTitus Rwantare                              MAX34451_NUM_PWR_DEVICES),
6617215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(power_good_off, MAX34451State,
6627215456aSTitus Rwantare                              MAX34451_NUM_PWR_DEVICES),
6637215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(ton_delay, MAX34451State,
6647215456aSTitus Rwantare                              MAX34451_NUM_MARGINED_PSU),
6657215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(ton_max_fault_limit, MAX34451State,
6667215456aSTitus Rwantare                              MAX34451_NUM_MARGINED_PSU),
6677215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(toff_delay, MAX34451State,
6687215456aSTitus Rwantare                              MAX34451_NUM_MARGINED_PSU),
6697215456aSTitus Rwantare         VMSTATE_UINT8_ARRAY(status_mfr_specific, MAX34451State,
6707215456aSTitus Rwantare                              MAX34451_NUM_PWR_DEVICES),
6717215456aSTitus Rwantare         VMSTATE_UINT64(mfr_location, MAX34451State),
6727215456aSTitus Rwantare         VMSTATE_UINT64(mfr_date, MAX34451State),
6737215456aSTitus Rwantare         VMSTATE_UINT64(mfr_serial, MAX34451State),
6747215456aSTitus Rwantare         VMSTATE_UINT16(mfr_mode, MAX34451State),
6757215456aSTitus Rwantare         VMSTATE_UINT32_ARRAY(psen_config, MAX34451State,
6767215456aSTitus Rwantare                              MAX34451_NUM_MARGINED_PSU),
6777215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(vout_peak, MAX34451State,
6787215456aSTitus Rwantare                              MAX34451_NUM_PWR_DEVICES),
6797215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(iout_peak, MAX34451State,
6807215456aSTitus Rwantare                              MAX34451_NUM_PWR_DEVICES),
6817215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(temperature_peak, MAX34451State,
6827215456aSTitus Rwantare                              MAX34451_NUM_TEMP_DEVICES),
6837215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(vout_min, MAX34451State, MAX34451_NUM_PWR_DEVICES),
6847215456aSTitus Rwantare         VMSTATE_UINT16(nv_log_config, MAX34451State),
6857215456aSTitus Rwantare         VMSTATE_UINT32_ARRAY(fault_response, MAX34451State,
6867215456aSTitus Rwantare                              MAX34451_NUM_PWR_DEVICES),
6877215456aSTitus Rwantare         VMSTATE_UINT16(fault_retry, MAX34451State),
6887215456aSTitus Rwantare         VMSTATE_UINT32(fault_log, MAX34451State),
6897215456aSTitus Rwantare         VMSTATE_UINT32(time_count, MAX34451State),
6907215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(margin_config, MAX34451State,
6917215456aSTitus Rwantare                              MAX34451_NUM_MARGINED_PSU),
6927215456aSTitus Rwantare         VMSTATE_UINT16(fw_serial, MAX34451State),
6937215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(iout_avg, MAX34451State, MAX34451_NUM_PWR_DEVICES),
6947215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(channel_config, MAX34451State,
6957215456aSTitus Rwantare                              MAX34451_NUM_PWR_DEVICES),
6967215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(ton_seq_max, MAX34451State,
6977215456aSTitus Rwantare                              MAX34451_NUM_MARGINED_PSU),
6987215456aSTitus Rwantare         VMSTATE_UINT32_ARRAY(pwm_config, MAX34451State,
6997215456aSTitus Rwantare                              MAX34451_NUM_MARGINED_PSU),
7007215456aSTitus Rwantare         VMSTATE_UINT32_ARRAY(seq_config, MAX34451State,
7017215456aSTitus Rwantare                              MAX34451_NUM_MARGINED_PSU),
7027215456aSTitus Rwantare         VMSTATE_UINT16_ARRAY(temp_sensor_config, MAX34451State,
7037215456aSTitus Rwantare                              MAX34451_NUM_TEMP_DEVICES),
7047215456aSTitus Rwantare         VMSTATE_UINT16(store_single, MAX34451State),
7057215456aSTitus Rwantare         VMSTATE_UINT16(crc, MAX34451State),
7067215456aSTitus Rwantare         VMSTATE_END_OF_LIST()
7077215456aSTitus Rwantare     }
7087215456aSTitus Rwantare };
7097215456aSTitus Rwantare 
max34451_init(Object * obj)7107215456aSTitus Rwantare static void max34451_init(Object *obj)
7117215456aSTitus Rwantare {
7127215456aSTitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
7137215456aSTitus Rwantare     uint64_t psu_flags = PB_HAS_VOUT | PB_HAS_IOUT | PB_HAS_VOUT_MODE |
7147215456aSTitus Rwantare                          PB_HAS_IOUT_GAIN;
7157215456aSTitus Rwantare 
7167215456aSTitus Rwantare     for (int i = 0; i < MAX34451_NUM_PWR_DEVICES; i++) {
7177215456aSTitus Rwantare         pmbus_page_config(pmdev, i, psu_flags);
7187215456aSTitus Rwantare     }
7197215456aSTitus Rwantare 
7207215456aSTitus Rwantare     for (int i = 0; i < MAX34451_NUM_MARGINED_PSU; i++) {
7217215456aSTitus Rwantare         pmbus_page_config(pmdev, i, psu_flags | PB_HAS_VOUT_MARGIN);
7227215456aSTitus Rwantare     }
7237215456aSTitus Rwantare 
7247215456aSTitus Rwantare     for (int i = 16; i < MAX34451_NUM_TEMP_DEVICES + 16; i++) {
7257215456aSTitus Rwantare         pmbus_page_config(pmdev, i, PB_HAS_TEMPERATURE | PB_HAS_VOUT_MODE);
7267215456aSTitus Rwantare     }
7277215456aSTitus Rwantare 
7287215456aSTitus Rwantare     /* get and set the voltage in millivolts, max is 32767 mV */
7297215456aSTitus Rwantare     for (int i = 0; i < MAX34451_NUM_PWR_DEVICES; i++) {
7307215456aSTitus Rwantare         object_property_add(obj, "vout[*]", "uint16",
7317215456aSTitus Rwantare                             max34451_get,
7327215456aSTitus Rwantare                             max34451_set, NULL, &pmdev->pages[i].read_vout);
7337215456aSTitus Rwantare     }
7347215456aSTitus Rwantare 
7357215456aSTitus Rwantare     /*
7367215456aSTitus Rwantare      * get and set the temperature of the internal temperature sensor in
7378fa21b80SMichael Tokarev      * centidegrees Celsius i.e.: 2500 -> 25.00 C, max is 327.67 C
7387215456aSTitus Rwantare      */
7397215456aSTitus Rwantare     for (int i = 0; i < MAX34451_NUM_TEMP_DEVICES; i++) {
7407215456aSTitus Rwantare         object_property_add(obj, "temperature[*]", "uint16",
7417215456aSTitus Rwantare                             max34451_get,
7427215456aSTitus Rwantare                             max34451_set,
7437215456aSTitus Rwantare                             NULL,
7447215456aSTitus Rwantare                             &pmdev->pages[i + 16].read_temperature_1);
7457215456aSTitus Rwantare     }
7467215456aSTitus Rwantare 
7477215456aSTitus Rwantare }
7487215456aSTitus Rwantare 
max34451_class_init(ObjectClass * klass,const void * data)749*12d1a768SPhilippe Mathieu-Daudé static void max34451_class_init(ObjectClass *klass, const void *data)
7507215456aSTitus Rwantare {
7517215456aSTitus Rwantare     ResettableClass *rc = RESETTABLE_CLASS(klass);
7527215456aSTitus Rwantare     DeviceClass *dc = DEVICE_CLASS(klass);
7537215456aSTitus Rwantare     PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass);
7547215456aSTitus Rwantare     dc->desc = "Maxim MAX34451 16-Channel V/I monitor";
7557215456aSTitus Rwantare     dc->vmsd = &vmstate_max34451;
7567215456aSTitus Rwantare     k->write_data = max34451_write_data;
7577215456aSTitus Rwantare     k->receive_byte = max34451_read_byte;
7587215456aSTitus Rwantare     k->device_num_pages = MAX34451_NUM_PAGES;
7597215456aSTitus Rwantare     rc->phases.exit = max34451_exit_reset;
7607215456aSTitus Rwantare }
7617215456aSTitus Rwantare 
7627215456aSTitus Rwantare static const TypeInfo max34451_info = {
7637215456aSTitus Rwantare     .name = TYPE_MAX34451,
7647215456aSTitus Rwantare     .parent = TYPE_PMBUS_DEVICE,
7657215456aSTitus Rwantare     .instance_size = sizeof(MAX34451State),
7667215456aSTitus Rwantare     .instance_init = max34451_init,
7677215456aSTitus Rwantare     .class_init = max34451_class_init,
7687215456aSTitus Rwantare };
7697215456aSTitus Rwantare 
max34451_register_types(void)7707215456aSTitus Rwantare static void max34451_register_types(void)
7717215456aSTitus Rwantare {
7727215456aSTitus Rwantare     type_register_static(&max34451_info);
7737215456aSTitus Rwantare }
7747215456aSTitus Rwantare 
7757215456aSTitus Rwantare type_init(max34451_register_types)
776