123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775 |
- /*
- * Maxim MAX34451 PMBus 16-Channel V/I monitor and 12-Channel Sequencer/Marginer
- *
- * Copyright 2021 Google LLC
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
- #include "qemu/osdep.h"
- #include "hw/i2c/pmbus_device.h"
- #include "hw/irq.h"
- #include "migration/vmstate.h"
- #include "qapi/error.h"
- #include "qapi/visitor.h"
- #include "qemu/log.h"
- #include "qemu/module.h"
- #define TYPE_MAX34451 "max34451"
- #define MAX34451(obj) OBJECT_CHECK(MAX34451State, (obj), TYPE_MAX34451)
- #define MAX34451_MFR_MODE 0xD1
- #define MAX34451_MFR_PSEN_CONFIG 0xD2
- #define MAX34451_MFR_VOUT_PEAK 0xD4
- #define MAX34451_MFR_IOUT_PEAK 0xD5
- #define MAX34451_MFR_TEMPERATURE_PEAK 0xD6
- #define MAX34451_MFR_VOUT_MIN 0xD7
- #define MAX34451_MFR_NV_LOG_CONFIG 0xD8
- #define MAX34451_MFR_FAULT_RESPONSE 0xD9
- #define MAX34451_MFR_FAULT_RETRY 0xDA
- #define MAX34451_MFR_NV_FAULT_LOG 0xDC
- #define MAX34451_MFR_TIME_COUNT 0xDD
- #define MAX34451_MFR_MARGIN_CONFIG 0xDF
- #define MAX34451_MFR_FW_SERIAL 0xE0
- #define MAX34451_MFR_IOUT_AVG 0xE2
- #define MAX34451_MFR_CHANNEL_CONFIG 0xE4
- #define MAX34451_MFR_TON_SEQ_MAX 0xE6
- #define MAX34451_MFR_PWM_CONFIG 0xE7
- #define MAX34451_MFR_SEQ_CONFIG 0xE8
- #define MAX34451_MFR_STORE_ALL 0xEE
- #define MAX34451_MFR_RESTORE_ALL 0xEF
- #define MAX34451_MFR_TEMP_SENSOR_CONFIG 0xF0
- #define MAX34451_MFR_STORE_SINGLE 0xFC
- #define MAX34451_MFR_CRC 0xFE
- #define MAX34451_NUM_MARGINED_PSU 12
- #define MAX34451_NUM_PWR_DEVICES 16
- #define MAX34451_NUM_TEMP_DEVICES 5
- #define MAX34451_NUM_PAGES 21
- #define DEFAULT_OP_ON 0x80
- #define DEFAULT_CAPABILITY 0x20
- #define DEFAULT_ON_OFF_CONFIG 0x1a
- #define DEFAULT_VOUT_MODE 0x40
- #define DEFAULT_TEMPERATURE 2500
- #define DEFAULT_SCALE 0x7FFF
- #define DEFAULT_OV_LIMIT 0x7FFF
- #define DEFAULT_OC_LIMIT 0x7FFF
- #define DEFAULT_OT_LIMIT 0x7FFF
- #define DEFAULT_VMIN 0x7FFF
- #define DEFAULT_TON_FAULT_LIMIT 0xFFFF
- #define DEFAULT_CHANNEL_CONFIG 0x20
- #define DEFAULT_TEXT 0x3130313031303130
- /**
- * MAX34451State:
- * @code: The command code received
- * @page: Each page corresponds to a device monitored by the Max 34451
- * The page register determines the available commands depending on device
- ___________________________________________________________________________
- | 0 | Power supply monitored by RS0, controlled by PSEN0, and |
- | | margined with PWM0. |
- |_______|___________________________________________________________________|
- | 1 | Power supply monitored by RS1, controlled by PSEN1, and |
- | | margined with PWM1. |
- |_______|___________________________________________________________________|
- | 2 | Power supply monitored by RS2, controlled by PSEN2, and |
- | | margined with PWM2. |
- |_______|___________________________________________________________________|
- | 3 | Power supply monitored by RS3, controlled by PSEN3, and |
- | | margined with PWM3. |
- |_______|___________________________________________________________________|
- | 4 | Power supply monitored by RS4, controlled by PSEN4, and |
- | | margined with PWM4. |
- |_______|___________________________________________________________________|
- | 5 | Power supply monitored by RS5, controlled by PSEN5, and |
- | | margined with PWM5. |
- |_______|___________________________________________________________________|
- | 6 | Power supply monitored by RS6, controlled by PSEN6, and |
- | | margined with PWM6. |
- |_______|___________________________________________________________________|
- | 7 | Power supply monitored by RS7, controlled by PSEN7, and |
- | | margined with PWM7. |
- |_______|___________________________________________________________________|
- | 8 | Power supply monitored by RS8, controlled by PSEN8, and |
- | | optionally margined by OUT0 of external DS4424 at I2C address A0h.|
- |_______|___________________________________________________________________|
- | 9 | Power supply monitored by RS9, controlled by PSEN9, and |
- | | optionally margined by OUT1 of external DS4424 at I2C address A0h.|
- |_______|___________________________________________________________________|
- | 10 | Power supply monitored by RS10, controlled by PSEN10, and |
- | | optionally margined by OUT2 of external DS4424 at I2C address A0h.|
- |_______|___________________________________________________________________|
- | 11 | Power supply monitored by RS11, controlled by PSEN11, and |
- | | optionally margined by OUT3 of external DS4424 at I2C address A0h.|
- |_______|___________________________________________________________________|
- | 12 | ADC channel 12 (monitors voltage or current) or GPI. |
- |_______|___________________________________________________________________|
- | 13 | ADC channel 13 (monitors voltage or current) or GPI. |
- |_______|___________________________________________________________________|
- | 14 | ADC channel 14 (monitors voltage or current) or GPI. |
- |_______|___________________________________________________________________|
- | 15 | ADC channel 15 (monitors voltage or current) or GPI. |
- |_______|___________________________________________________________________|
- | 16 | Internal temperature sensor. |
- |_______|___________________________________________________________________|
- | 17 | External DS75LV temperature sensor with I2C address 90h. |
- |_______|___________________________________________________________________|
- | 18 | External DS75LV temperature sensor with I2C address 92h. |
- |_______|___________________________________________________________________|
- | 19 | External DS75LV temperature sensor with I2C address 94h. |
- |_______|___________________________________________________________________|
- | 20 | External DS75LV temperature sensor with I2C address 96h. |
- |_______|___________________________________________________________________|
- | 21=E2=80=93254| Reserved. |
- |_______|___________________________________________________________________|
- | 255 | Applies to all pages. |
- |_______|___________________________________________________________________|
- *
- * @operation: Turn on and off power supplies
- * @on_off_config: Configure the power supply on and off transition behaviour
- * @write_protect: protect against changes to the device's memory
- * @vout_margin_high: the voltage when OPERATION is set to margin high
- * @vout_margin_low: the voltage when OPERATION is set to margin low
- * @vout_scale: scale ADC reading to actual device reading if different
- * @iout_cal_gain: set ratio of the voltage at the ADC input to sensed current
- */
- typedef struct MAX34451State {
- PMBusDevice parent;
- uint16_t power_good_on[MAX34451_NUM_PWR_DEVICES];
- uint16_t power_good_off[MAX34451_NUM_PWR_DEVICES];
- uint16_t ton_delay[MAX34451_NUM_MARGINED_PSU];
- uint16_t ton_max_fault_limit[MAX34451_NUM_MARGINED_PSU];
- uint16_t toff_delay[MAX34451_NUM_MARGINED_PSU];
- uint8_t status_mfr_specific[MAX34451_NUM_PWR_DEVICES];
- /* Manufacturer specific function */
- uint64_t mfr_location;
- uint64_t mfr_date;
- uint64_t mfr_serial;
- uint16_t mfr_mode;
- uint32_t psen_config[MAX34451_NUM_MARGINED_PSU];
- uint16_t vout_peak[MAX34451_NUM_PWR_DEVICES];
- uint16_t iout_peak[MAX34451_NUM_PWR_DEVICES];
- uint16_t temperature_peak[MAX34451_NUM_TEMP_DEVICES];
- uint16_t vout_min[MAX34451_NUM_PWR_DEVICES];
- uint16_t nv_log_config;
- uint32_t fault_response[MAX34451_NUM_PWR_DEVICES];
- uint16_t fault_retry;
- uint32_t fault_log;
- uint32_t time_count;
- uint16_t margin_config[MAX34451_NUM_MARGINED_PSU];
- uint16_t fw_serial;
- uint16_t iout_avg[MAX34451_NUM_PWR_DEVICES];
- uint16_t channel_config[MAX34451_NUM_PWR_DEVICES];
- uint16_t ton_seq_max[MAX34451_NUM_MARGINED_PSU];
- uint32_t pwm_config[MAX34451_NUM_MARGINED_PSU];
- uint32_t seq_config[MAX34451_NUM_MARGINED_PSU];
- uint16_t temp_sensor_config[MAX34451_NUM_TEMP_DEVICES];
- uint16_t store_single;
- uint16_t crc;
- } MAX34451State;
- static void max34451_check_limits(MAX34451State *s)
- {
- PMBusDevice *pmdev = PMBUS_DEVICE(s);
- pmbus_check_limits(pmdev);
- for (int i = 0; i < MAX34451_NUM_PWR_DEVICES; i++) {
- if (pmdev->pages[i].read_vout == 0) { /* PSU disabled */
- continue;
- }
- if (pmdev->pages[i].read_vout > s->vout_peak[i]) {
- s->vout_peak[i] = pmdev->pages[i].read_vout;
- }
- if (pmdev->pages[i].read_vout < s->vout_min[i]) {
- s->vout_min[i] = pmdev->pages[i].read_vout;
- }
- if (pmdev->pages[i].read_iout > s->iout_peak[i]) {
- s->iout_peak[i] = pmdev->pages[i].read_iout;
- }
- }
- for (int i = 0; i < MAX34451_NUM_TEMP_DEVICES; i++) {
- if (pmdev->pages[i + 16].read_temperature_1 > s->temperature_peak[i]) {
- s->temperature_peak[i] = pmdev->pages[i + 16].read_temperature_1;
- }
- }
- }
- static uint8_t max34451_read_byte(PMBusDevice *pmdev)
- {
- MAX34451State *s = MAX34451(pmdev);
- switch (pmdev->code) {
- case PMBUS_POWER_GOOD_ON:
- if (pmdev->page < 16) {
- pmbus_send16(pmdev, s->power_good_on[pmdev->page]);
- }
- break;
- case PMBUS_POWER_GOOD_OFF:
- if (pmdev->page < 16) {
- pmbus_send16(pmdev, s->power_good_off[pmdev->page]);
- }
- break;
- case PMBUS_TON_DELAY:
- if (pmdev->page < 12) {
- pmbus_send16(pmdev, s->ton_delay[pmdev->page]);
- }
- break;
- case PMBUS_TON_MAX_FAULT_LIMIT:
- if (pmdev->page < 12) {
- pmbus_send16(pmdev, s->ton_max_fault_limit[pmdev->page]);
- }
- break;
- case PMBUS_TOFF_DELAY:
- if (pmdev->page < 12) {
- pmbus_send16(pmdev, s->toff_delay[pmdev->page]);
- }
- break;
- case PMBUS_STATUS_MFR_SPECIFIC:
- if (pmdev->page < 16) {
- pmbus_send8(pmdev, s->status_mfr_specific[pmdev->page]);
- }
- break;
- case PMBUS_MFR_ID:
- pmbus_send8(pmdev, 0x4d); /* Maxim */
- break;
- case PMBUS_MFR_MODEL:
- pmbus_send8(pmdev, 0x59);
- break;
- case PMBUS_MFR_LOCATION:
- pmbus_send64(pmdev, s->mfr_location);
- break;
- case PMBUS_MFR_DATE:
- pmbus_send64(pmdev, s->mfr_date);
- break;
- case PMBUS_MFR_SERIAL:
- pmbus_send64(pmdev, s->mfr_serial);
- break;
- case MAX34451_MFR_MODE:
- pmbus_send16(pmdev, s->mfr_mode);
- break;
- case MAX34451_MFR_PSEN_CONFIG:
- if (pmdev->page < 12) {
- pmbus_send32(pmdev, s->psen_config[pmdev->page]);
- }
- break;
- case MAX34451_MFR_VOUT_PEAK:
- if (pmdev->page < 16) {
- pmbus_send16(pmdev, s->vout_peak[pmdev->page]);
- }
- break;
- case MAX34451_MFR_IOUT_PEAK:
- if (pmdev->page < 16) {
- pmbus_send16(pmdev, s->iout_peak[pmdev->page]);
- }
- break;
- case MAX34451_MFR_TEMPERATURE_PEAK:
- if (15 < pmdev->page && pmdev->page < 21) {
- pmbus_send16(pmdev, s->temperature_peak[pmdev->page % 16]);
- } else {
- pmbus_send16(pmdev, s->temperature_peak[0]);
- }
- break;
- case MAX34451_MFR_VOUT_MIN:
- if (pmdev->page < 16) {
- pmbus_send16(pmdev, s->vout_min[pmdev->page]);
- }
- break;
- case MAX34451_MFR_NV_LOG_CONFIG:
- pmbus_send16(pmdev, s->nv_log_config);
- break;
- case MAX34451_MFR_FAULT_RESPONSE:
- if (pmdev->page < 16) {
- pmbus_send32(pmdev, s->fault_response[pmdev->page]);
- }
- break;
- case MAX34451_MFR_FAULT_RETRY:
- pmbus_send32(pmdev, s->fault_retry);
- break;
- case MAX34451_MFR_NV_FAULT_LOG:
- pmbus_send32(pmdev, s->fault_log);
- break;
- case MAX34451_MFR_TIME_COUNT:
- pmbus_send32(pmdev, s->time_count);
- break;
- case MAX34451_MFR_MARGIN_CONFIG:
- if (pmdev->page < 12) {
- pmbus_send16(pmdev, s->margin_config[pmdev->page]);
- }
- break;
- case MAX34451_MFR_FW_SERIAL:
- if (pmdev->page == 255) {
- pmbus_send16(pmdev, 1); /* Firmware revision */
- }
- break;
- case MAX34451_MFR_IOUT_AVG:
- if (pmdev->page < 16) {
- pmbus_send16(pmdev, s->iout_avg[pmdev->page]);
- }
- break;
- case MAX34451_MFR_CHANNEL_CONFIG:
- if (pmdev->page < 16) {
- pmbus_send16(pmdev, s->channel_config[pmdev->page]);
- }
- break;
- case MAX34451_MFR_TON_SEQ_MAX:
- if (pmdev->page < 12) {
- pmbus_send16(pmdev, s->ton_seq_max[pmdev->page]);
- }
- break;
- case MAX34451_MFR_PWM_CONFIG:
- if (pmdev->page < 12) {
- pmbus_send32(pmdev, s->pwm_config[pmdev->page]);
- }
- break;
- case MAX34451_MFR_SEQ_CONFIG:
- if (pmdev->page < 12) {
- pmbus_send32(pmdev, s->seq_config[pmdev->page]);
- }
- break;
- case MAX34451_MFR_TEMP_SENSOR_CONFIG:
- if (15 < pmdev->page && pmdev->page < 21) {
- pmbus_send32(pmdev, s->temp_sensor_config[pmdev->page % 16]);
- }
- break;
- case MAX34451_MFR_STORE_SINGLE:
- pmbus_send32(pmdev, s->store_single);
- break;
- case MAX34451_MFR_CRC:
- pmbus_send32(pmdev, s->crc);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: reading from unsupported register: 0x%02x\n",
- __func__, pmdev->code);
- break;
- }
- return 0xFF;
- }
- static int max34451_write_data(PMBusDevice *pmdev, const uint8_t *buf,
- uint8_t len)
- {
- MAX34451State *s = MAX34451(pmdev);
- if (len == 0) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__);
- return -1;
- }
- pmdev->code = buf[0]; /* PMBus command code */
- if (len == 1) {
- return 0;
- }
- /* Exclude command code from buffer */
- buf++;
- len--;
- uint8_t index = pmdev->page;
- switch (pmdev->code) {
- case MAX34451_MFR_STORE_ALL:
- case MAX34451_MFR_RESTORE_ALL:
- case MAX34451_MFR_STORE_SINGLE:
- /*
- * TODO: hardware behaviour is to move the contents of volatile
- * memory to non-volatile memory.
- */
- break;
- case PMBUS_POWER_GOOD_ON: /* R/W word */
- if (pmdev->page < MAX34451_NUM_PWR_DEVICES) {
- s->power_good_on[pmdev->page] = pmbus_receive16(pmdev);
- }
- break;
- case PMBUS_POWER_GOOD_OFF: /* R/W word */
- if (pmdev->page < MAX34451_NUM_PWR_DEVICES) {
- s->power_good_off[pmdev->page] = pmbus_receive16(pmdev);
- }
- break;
- case PMBUS_TON_DELAY: /* R/W word */
- if (pmdev->page < 12) {
- s->ton_delay[pmdev->page] = pmbus_receive16(pmdev);
- }
- break;
- case PMBUS_TON_MAX_FAULT_LIMIT: /* R/W word */
- if (pmdev->page < 12) {
- s->ton_max_fault_limit[pmdev->page]
- = pmbus_receive16(pmdev);
- }
- break;
- case PMBUS_TOFF_DELAY: /* R/W word */
- if (pmdev->page < 12) {
- s->toff_delay[pmdev->page] = pmbus_receive16(pmdev);
- }
- break;
- case PMBUS_MFR_LOCATION: /* R/W 64 */
- s->mfr_location = pmbus_receive64(pmdev);
- break;
- case PMBUS_MFR_DATE: /* R/W 64 */
- s->mfr_date = pmbus_receive64(pmdev);
- break;
- case PMBUS_MFR_SERIAL: /* R/W 64 */
- s->mfr_serial = pmbus_receive64(pmdev);
- break;
- case MAX34451_MFR_MODE: /* R/W word */
- s->mfr_mode = pmbus_receive16(pmdev);
- break;
- case MAX34451_MFR_PSEN_CONFIG: /* R/W 32 */
- if (pmdev->page < 12) {
- s->psen_config[pmdev->page] = pmbus_receive32(pmdev);
- }
- break;
- case MAX34451_MFR_VOUT_PEAK: /* R/W word */
- if (pmdev->page < 16) {
- s->vout_peak[pmdev->page] = pmbus_receive16(pmdev);
- }
- break;
- case MAX34451_MFR_IOUT_PEAK: /* R/W word */
- if (pmdev->page < 16) {
- s->iout_peak[pmdev->page] = pmbus_receive16(pmdev);
- }
- break;
- case MAX34451_MFR_TEMPERATURE_PEAK: /* R/W word */
- if (15 < pmdev->page && pmdev->page < 21) {
- s->temperature_peak[pmdev->page % 16]
- = pmbus_receive16(pmdev);
- }
- break;
- case MAX34451_MFR_VOUT_MIN: /* R/W word */
- if (pmdev->page < 16) {
- s->vout_min[pmdev->page] = pmbus_receive16(pmdev);
- }
- break;
- case MAX34451_MFR_NV_LOG_CONFIG: /* R/W word */
- s->nv_log_config = pmbus_receive16(pmdev);
- break;
- case MAX34451_MFR_FAULT_RESPONSE: /* R/W 32 */
- if (pmdev->page < 16) {
- s->fault_response[pmdev->page] = pmbus_receive32(pmdev);
- }
- break;
- case MAX34451_MFR_FAULT_RETRY: /* R/W word */
- s->fault_retry = pmbus_receive16(pmdev);
- break;
- case MAX34451_MFR_TIME_COUNT: /* R/W 32 */
- s->time_count = pmbus_receive32(pmdev);
- break;
- case MAX34451_MFR_MARGIN_CONFIG: /* R/W word */
- if (pmdev->page < 12) {
- s->margin_config[pmdev->page] = pmbus_receive16(pmdev);
- }
- break;
- case MAX34451_MFR_CHANNEL_CONFIG: /* R/W word */
- if (pmdev->page < 16) {
- s->channel_config[pmdev->page] = pmbus_receive16(pmdev);
- }
- break;
- case MAX34451_MFR_TON_SEQ_MAX: /* R/W word */
- if (pmdev->page < 12) {
- s->ton_seq_max[pmdev->page] = pmbus_receive16(pmdev);
- }
- break;
- case MAX34451_MFR_PWM_CONFIG: /* R/W 32 */
- if (pmdev->page < 12) {
- s->pwm_config[pmdev->page] = pmbus_receive32(pmdev);
- }
- break;
- case MAX34451_MFR_SEQ_CONFIG: /* R/W 32 */
- if (pmdev->page < 12) {
- s->seq_config[pmdev->page] = pmbus_receive32(pmdev);
- }
- break;
- case MAX34451_MFR_TEMP_SENSOR_CONFIG: /* R/W word */
- if (15 < pmdev->page && pmdev->page < 21) {
- s->temp_sensor_config[pmdev->page % 16]
- = pmbus_receive16(pmdev);
- }
- break;
- case MAX34451_MFR_CRC: /* R/W word */
- s->crc = pmbus_receive16(pmdev);
- break;
- case MAX34451_MFR_NV_FAULT_LOG:
- case MAX34451_MFR_FW_SERIAL:
- case MAX34451_MFR_IOUT_AVG:
- /* Read only commands */
- pmdev->pages[index].status_word |= PMBUS_STATUS_CML;
- pmdev->pages[index].status_cml |= PB_CML_FAULT_INVALID_DATA;
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: writing to read-only register 0x%02x\n",
- __func__, pmdev->code);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: writing to unsupported register: 0x%02x\n",
- __func__, pmdev->code);
- break;
- }
- return 0;
- }
- static void max34451_get(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
- {
- visit_type_uint16(v, name, (uint16_t *)opaque, errp);
- }
- static void max34451_set(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
- {
- MAX34451State *s = MAX34451(obj);
- uint16_t *internal = opaque;
- uint16_t value;
- if (!visit_type_uint16(v, name, &value, errp)) {
- return;
- }
- *internal = value;
- max34451_check_limits(s);
- }
- /* used to init uint16_t arrays */
- static inline void *memset_word(void *s, uint16_t c, size_t n)
- {
- size_t i;
- uint16_t *p = s;
- for (i = 0; i < n; i++) {
- p[i] = c;
- }
- return s;
- }
- static void max34451_exit_reset(Object *obj)
- {
- PMBusDevice *pmdev = PMBUS_DEVICE(obj);
- MAX34451State *s = MAX34451(obj);
- pmdev->capability = DEFAULT_CAPABILITY;
- for (int i = 0; i < MAX34451_NUM_PAGES; i++) {
- pmdev->pages[i].operation = DEFAULT_OP_ON;
- pmdev->pages[i].on_off_config = DEFAULT_ON_OFF_CONFIG;
- pmdev->pages[i].revision = 0x11;
- pmdev->pages[i].vout_mode = DEFAULT_VOUT_MODE;
- }
- for (int i = 0; i < MAX34451_NUM_PWR_DEVICES; i++) {
- pmdev->pages[i].vout_scale_monitor = DEFAULT_SCALE;
- pmdev->pages[i].vout_ov_fault_limit = DEFAULT_OV_LIMIT;
- pmdev->pages[i].vout_ov_warn_limit = DEFAULT_OV_LIMIT;
- pmdev->pages[i].iout_oc_warn_limit = DEFAULT_OC_LIMIT;
- pmdev->pages[i].iout_oc_fault_limit = DEFAULT_OC_LIMIT;
- }
- for (int i = 0; i < MAX34451_NUM_MARGINED_PSU; i++) {
- pmdev->pages[i].ton_max_fault_limit = DEFAULT_TON_FAULT_LIMIT;
- }
- for (int i = 16; i < MAX34451_NUM_TEMP_DEVICES + 16; i++) {
- pmdev->pages[i].read_temperature_1 = DEFAULT_TEMPERATURE;
- pmdev->pages[i].ot_warn_limit = DEFAULT_OT_LIMIT;
- pmdev->pages[i].ot_fault_limit = DEFAULT_OT_LIMIT;
- }
- memset_word(s->ton_max_fault_limit, DEFAULT_TON_FAULT_LIMIT,
- MAX34451_NUM_MARGINED_PSU);
- memset_word(s->channel_config, DEFAULT_CHANNEL_CONFIG,
- MAX34451_NUM_PWR_DEVICES);
- memset_word(s->vout_min, DEFAULT_VMIN, MAX34451_NUM_PWR_DEVICES);
- s->mfr_location = DEFAULT_TEXT;
- s->mfr_date = DEFAULT_TEXT;
- s->mfr_serial = DEFAULT_TEXT;
- }
- static const VMStateDescription vmstate_max34451 = {
- .name = TYPE_MAX34451,
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (VMStateField[]){
- VMSTATE_PMBUS_DEVICE(parent, MAX34451State),
- VMSTATE_UINT16_ARRAY(power_good_on, MAX34451State,
- MAX34451_NUM_PWR_DEVICES),
- VMSTATE_UINT16_ARRAY(power_good_off, MAX34451State,
- MAX34451_NUM_PWR_DEVICES),
- VMSTATE_UINT16_ARRAY(ton_delay, MAX34451State,
- MAX34451_NUM_MARGINED_PSU),
- VMSTATE_UINT16_ARRAY(ton_max_fault_limit, MAX34451State,
- MAX34451_NUM_MARGINED_PSU),
- VMSTATE_UINT16_ARRAY(toff_delay, MAX34451State,
- MAX34451_NUM_MARGINED_PSU),
- VMSTATE_UINT8_ARRAY(status_mfr_specific, MAX34451State,
- MAX34451_NUM_PWR_DEVICES),
- VMSTATE_UINT64(mfr_location, MAX34451State),
- VMSTATE_UINT64(mfr_date, MAX34451State),
- VMSTATE_UINT64(mfr_serial, MAX34451State),
- VMSTATE_UINT16(mfr_mode, MAX34451State),
- VMSTATE_UINT32_ARRAY(psen_config, MAX34451State,
- MAX34451_NUM_MARGINED_PSU),
- VMSTATE_UINT16_ARRAY(vout_peak, MAX34451State,
- MAX34451_NUM_PWR_DEVICES),
- VMSTATE_UINT16_ARRAY(iout_peak, MAX34451State,
- MAX34451_NUM_PWR_DEVICES),
- VMSTATE_UINT16_ARRAY(temperature_peak, MAX34451State,
- MAX34451_NUM_TEMP_DEVICES),
- VMSTATE_UINT16_ARRAY(vout_min, MAX34451State, MAX34451_NUM_PWR_DEVICES),
- VMSTATE_UINT16(nv_log_config, MAX34451State),
- VMSTATE_UINT32_ARRAY(fault_response, MAX34451State,
- MAX34451_NUM_PWR_DEVICES),
- VMSTATE_UINT16(fault_retry, MAX34451State),
- VMSTATE_UINT32(fault_log, MAX34451State),
- VMSTATE_UINT32(time_count, MAX34451State),
- VMSTATE_UINT16_ARRAY(margin_config, MAX34451State,
- MAX34451_NUM_MARGINED_PSU),
- VMSTATE_UINT16(fw_serial, MAX34451State),
- VMSTATE_UINT16_ARRAY(iout_avg, MAX34451State, MAX34451_NUM_PWR_DEVICES),
- VMSTATE_UINT16_ARRAY(channel_config, MAX34451State,
- MAX34451_NUM_PWR_DEVICES),
- VMSTATE_UINT16_ARRAY(ton_seq_max, MAX34451State,
- MAX34451_NUM_MARGINED_PSU),
- VMSTATE_UINT32_ARRAY(pwm_config, MAX34451State,
- MAX34451_NUM_MARGINED_PSU),
- VMSTATE_UINT32_ARRAY(seq_config, MAX34451State,
- MAX34451_NUM_MARGINED_PSU),
- VMSTATE_UINT16_ARRAY(temp_sensor_config, MAX34451State,
- MAX34451_NUM_TEMP_DEVICES),
- VMSTATE_UINT16(store_single, MAX34451State),
- VMSTATE_UINT16(crc, MAX34451State),
- VMSTATE_END_OF_LIST()
- }
- };
- static void max34451_init(Object *obj)
- {
- PMBusDevice *pmdev = PMBUS_DEVICE(obj);
- uint64_t psu_flags = PB_HAS_VOUT | PB_HAS_IOUT | PB_HAS_VOUT_MODE |
- PB_HAS_IOUT_GAIN;
- for (int i = 0; i < MAX34451_NUM_PWR_DEVICES; i++) {
- pmbus_page_config(pmdev, i, psu_flags);
- }
- for (int i = 0; i < MAX34451_NUM_MARGINED_PSU; i++) {
- pmbus_page_config(pmdev, i, psu_flags | PB_HAS_VOUT_MARGIN);
- }
- for (int i = 16; i < MAX34451_NUM_TEMP_DEVICES + 16; i++) {
- pmbus_page_config(pmdev, i, PB_HAS_TEMPERATURE | PB_HAS_VOUT_MODE);
- }
- /* get and set the voltage in millivolts, max is 32767 mV */
- for (int i = 0; i < MAX34451_NUM_PWR_DEVICES; i++) {
- object_property_add(obj, "vout[*]", "uint16",
- max34451_get,
- max34451_set, NULL, &pmdev->pages[i].read_vout);
- }
- /*
- * get and set the temperature of the internal temperature sensor in
- * centidegrees Celcius i.e.: 2500 -> 25.00 C, max is 327.67 C
- */
- for (int i = 0; i < MAX34451_NUM_TEMP_DEVICES; i++) {
- object_property_add(obj, "temperature[*]", "uint16",
- max34451_get,
- max34451_set,
- NULL,
- &pmdev->pages[i + 16].read_temperature_1);
- }
- }
- static void max34451_class_init(ObjectClass *klass, void *data)
- {
- ResettableClass *rc = RESETTABLE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
- PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass);
- dc->desc = "Maxim MAX34451 16-Channel V/I monitor";
- dc->vmsd = &vmstate_max34451;
- k->write_data = max34451_write_data;
- k->receive_byte = max34451_read_byte;
- k->device_num_pages = MAX34451_NUM_PAGES;
- rc->phases.exit = max34451_exit_reset;
- }
- static const TypeInfo max34451_info = {
- .name = TYPE_MAX34451,
- .parent = TYPE_PMBUS_DEVICE,
- .instance_size = sizeof(MAX34451State),
- .instance_init = max34451_init,
- .class_init = max34451_class_init,
- };
- static void max34451_register_types(void)
- {
- type_register_static(&max34451_info);
- }
- type_init(max34451_register_types)
|