xref: /qemu/hw/i2c/pmbus_device.c (revision 8fa21b80268ef7944f0344af9462b0ab812ba7bd) !
13746d5c1STitus Rwantare /*
23746d5c1STitus Rwantare  * PMBus wrapper over SMBus
33746d5c1STitus Rwantare  *
43746d5c1STitus Rwantare  * Copyright 2021 Google LLC
53746d5c1STitus Rwantare  *
63746d5c1STitus Rwantare  * SPDX-License-Identifier: GPL-2.0-or-later
73746d5c1STitus Rwantare  */
83746d5c1STitus Rwantare 
93746d5c1STitus Rwantare #include "qemu/osdep.h"
103746d5c1STitus Rwantare #include <math.h>
113746d5c1STitus Rwantare #include "hw/i2c/pmbus_device.h"
123746d5c1STitus Rwantare #include "migration/vmstate.h"
133746d5c1STitus Rwantare #include "qemu/module.h"
143746d5c1STitus Rwantare #include "qemu/log.h"
153746d5c1STitus Rwantare 
163746d5c1STitus Rwantare uint16_t pmbus_data2direct_mode(PMBusCoefficients c, uint32_t value)
173746d5c1STitus Rwantare {
183746d5c1STitus Rwantare     /* R is usually negative to fit large readings into 16 bits */
193746d5c1STitus Rwantare     uint16_t y = (c.m * value + c.b) * pow(10, c.R);
203746d5c1STitus Rwantare     return y;
213746d5c1STitus Rwantare }
223746d5c1STitus Rwantare 
233746d5c1STitus Rwantare uint32_t pmbus_direct_mode2data(PMBusCoefficients c, uint16_t value)
243746d5c1STitus Rwantare {
253746d5c1STitus Rwantare     /* X = (Y * 10^-R - b) / m */
263746d5c1STitus Rwantare     uint32_t x = (value / pow(10, c.R) - c.b) / c.m;
273746d5c1STitus Rwantare     return x;
283746d5c1STitus Rwantare }
293746d5c1STitus Rwantare 
30648a4882SShengtan Mao uint16_t pmbus_data2linear_mode(uint16_t value, int exp)
31648a4882SShengtan Mao {
32648a4882SShengtan Mao     /* L = D * 2^(-e) */
33648a4882SShengtan Mao     if (exp < 0) {
34648a4882SShengtan Mao         return value << (-exp);
35648a4882SShengtan Mao     }
36648a4882SShengtan Mao     return value >> exp;
37648a4882SShengtan Mao }
38648a4882SShengtan Mao 
39648a4882SShengtan Mao uint16_t pmbus_linear_mode2data(uint16_t value, int exp)
40648a4882SShengtan Mao {
41648a4882SShengtan Mao     /* D = L * 2^e */
42648a4882SShengtan Mao     if (exp < 0) {
43648a4882SShengtan Mao         return value >> (-exp);
44648a4882SShengtan Mao     }
45648a4882SShengtan Mao     return value << exp;
46648a4882SShengtan Mao }
47648a4882SShengtan Mao 
483746d5c1STitus Rwantare void pmbus_send(PMBusDevice *pmdev, const uint8_t *data, uint16_t len)
493746d5c1STitus Rwantare {
503746d5c1STitus Rwantare     if (pmdev->out_buf_len + len > SMBUS_DATA_MAX_LEN) {
513746d5c1STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
523746d5c1STitus Rwantare                       "PMBus device tried to send too much data");
533746d5c1STitus Rwantare         len = 0;
543746d5c1STitus Rwantare     }
553746d5c1STitus Rwantare 
563746d5c1STitus Rwantare     for (int i = len - 1; i >= 0; i--) {
573746d5c1STitus Rwantare         pmdev->out_buf[i + pmdev->out_buf_len] = data[len - i - 1];
583746d5c1STitus Rwantare     }
593746d5c1STitus Rwantare     pmdev->out_buf_len += len;
603746d5c1STitus Rwantare }
613746d5c1STitus Rwantare 
623746d5c1STitus Rwantare /* Internal only, convert unsigned ints to the little endian bus */
633746d5c1STitus Rwantare static void pmbus_send_uint(PMBusDevice *pmdev, uint64_t data, uint8_t size)
643746d5c1STitus Rwantare {
653746d5c1STitus Rwantare     uint8_t bytes[8];
663746d5c1STitus Rwantare     g_assert(size <= 8);
673746d5c1STitus Rwantare 
683746d5c1STitus Rwantare     for (int i = 0; i < size; i++) {
693746d5c1STitus Rwantare         bytes[i] = data & 0xFF;
703746d5c1STitus Rwantare         data = data >> 8;
713746d5c1STitus Rwantare     }
723746d5c1STitus Rwantare     pmbus_send(pmdev, bytes, size);
733746d5c1STitus Rwantare }
743746d5c1STitus Rwantare 
753746d5c1STitus Rwantare void pmbus_send8(PMBusDevice *pmdev, uint8_t data)
763746d5c1STitus Rwantare {
773746d5c1STitus Rwantare     pmbus_send_uint(pmdev, data, 1);
783746d5c1STitus Rwantare }
793746d5c1STitus Rwantare 
803746d5c1STitus Rwantare void pmbus_send16(PMBusDevice *pmdev, uint16_t data)
813746d5c1STitus Rwantare {
823746d5c1STitus Rwantare     pmbus_send_uint(pmdev, data, 2);
833746d5c1STitus Rwantare }
843746d5c1STitus Rwantare 
853746d5c1STitus Rwantare void pmbus_send32(PMBusDevice *pmdev, uint32_t data)
863746d5c1STitus Rwantare {
873746d5c1STitus Rwantare     pmbus_send_uint(pmdev, data, 4);
883746d5c1STitus Rwantare }
893746d5c1STitus Rwantare 
903746d5c1STitus Rwantare void pmbus_send64(PMBusDevice *pmdev, uint64_t data)
913746d5c1STitus Rwantare {
923746d5c1STitus Rwantare     pmbus_send_uint(pmdev, data, 8);
933746d5c1STitus Rwantare }
943746d5c1STitus Rwantare 
953746d5c1STitus Rwantare void pmbus_send_string(PMBusDevice *pmdev, const char *data)
963746d5c1STitus Rwantare {
9795bf3418STitus Rwantare     if (!data) {
9895bf3418STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
9995bf3418STitus Rwantare                       "%s: %s: uninitialised read from 0x%02x\n",
10095bf3418STitus Rwantare                       __func__, DEVICE(pmdev)->canonical_path, pmdev->code);
10195bf3418STitus Rwantare         return;
10295bf3418STitus Rwantare     }
10395bf3418STitus Rwantare 
1043746d5c1STitus Rwantare     size_t len = strlen(data);
1053746d5c1STitus Rwantare     g_assert(len > 0);
1063746d5c1STitus Rwantare     g_assert(len + pmdev->out_buf_len < SMBUS_DATA_MAX_LEN);
1073746d5c1STitus Rwantare     pmdev->out_buf[len + pmdev->out_buf_len] = len;
1083746d5c1STitus Rwantare 
1093746d5c1STitus Rwantare     for (int i = len - 1; i >= 0; i--) {
1103746d5c1STitus Rwantare         pmdev->out_buf[i + pmdev->out_buf_len] = data[len - 1 - i];
1113746d5c1STitus Rwantare     }
1123746d5c1STitus Rwantare     pmdev->out_buf_len += len + 1;
1133746d5c1STitus Rwantare }
1143746d5c1STitus Rwantare 
1153746d5c1STitus Rwantare 
11678fdfc59STitus Rwantare static uint64_t pmbus_receive_uint(PMBusDevice *pmdev)
1173746d5c1STitus Rwantare {
1183746d5c1STitus Rwantare     uint64_t ret = 0;
1193746d5c1STitus Rwantare 
1203746d5c1STitus Rwantare     /* Exclude command code from return value */
12178fdfc59STitus Rwantare     pmdev->in_buf++;
12278fdfc59STitus Rwantare     pmdev->in_buf_len--;
1233746d5c1STitus Rwantare 
12478fdfc59STitus Rwantare     for (int i = pmdev->in_buf_len - 1; i >= 0; i--) {
12578fdfc59STitus Rwantare         ret = ret << 8 | pmdev->in_buf[i];
1263746d5c1STitus Rwantare     }
1273746d5c1STitus Rwantare     return ret;
1283746d5c1STitus Rwantare }
1293746d5c1STitus Rwantare 
1303746d5c1STitus Rwantare uint8_t pmbus_receive8(PMBusDevice *pmdev)
1313746d5c1STitus Rwantare {
1323746d5c1STitus Rwantare     if (pmdev->in_buf_len - 1 != 1) {
1333746d5c1STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
1343746d5c1STitus Rwantare                       "%s: length mismatch. Expected 1 byte, got %d bytes\n",
1353746d5c1STitus Rwantare                       __func__, pmdev->in_buf_len - 1);
1363746d5c1STitus Rwantare     }
13778fdfc59STitus Rwantare     return pmbus_receive_uint(pmdev);
1383746d5c1STitus Rwantare }
1393746d5c1STitus Rwantare 
1403746d5c1STitus Rwantare uint16_t pmbus_receive16(PMBusDevice *pmdev)
1413746d5c1STitus Rwantare {
1423746d5c1STitus Rwantare     if (pmdev->in_buf_len - 1 != 2) {
1433746d5c1STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
1443746d5c1STitus Rwantare                       "%s: length mismatch. Expected 2 bytes, got %d bytes\n",
1453746d5c1STitus Rwantare                       __func__, pmdev->in_buf_len - 1);
1463746d5c1STitus Rwantare     }
14778fdfc59STitus Rwantare     return pmbus_receive_uint(pmdev);
1483746d5c1STitus Rwantare }
1493746d5c1STitus Rwantare 
1503746d5c1STitus Rwantare uint32_t pmbus_receive32(PMBusDevice *pmdev)
1513746d5c1STitus Rwantare {
1523746d5c1STitus Rwantare     if (pmdev->in_buf_len - 1 != 4) {
1533746d5c1STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
1543746d5c1STitus Rwantare                       "%s: length mismatch. Expected 4 bytes, got %d bytes\n",
1553746d5c1STitus Rwantare                       __func__, pmdev->in_buf_len - 1);
1563746d5c1STitus Rwantare     }
15778fdfc59STitus Rwantare     return pmbus_receive_uint(pmdev);
1583746d5c1STitus Rwantare }
1593746d5c1STitus Rwantare 
1603746d5c1STitus Rwantare uint64_t pmbus_receive64(PMBusDevice *pmdev)
1613746d5c1STitus Rwantare {
1623746d5c1STitus Rwantare     if (pmdev->in_buf_len - 1 != 8) {
1633746d5c1STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
1643746d5c1STitus Rwantare                       "%s: length mismatch. Expected 8 bytes, got %d bytes\n",
1653746d5c1STitus Rwantare                       __func__, pmdev->in_buf_len - 1);
1663746d5c1STitus Rwantare     }
16778fdfc59STitus Rwantare     return pmbus_receive_uint(pmdev);
1683746d5c1STitus Rwantare }
1693746d5c1STitus Rwantare 
1703746d5c1STitus Rwantare static uint8_t pmbus_out_buf_pop(PMBusDevice *pmdev)
1713746d5c1STitus Rwantare {
1723746d5c1STitus Rwantare     if (pmdev->out_buf_len == 0) {
1733746d5c1STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
1743746d5c1STitus Rwantare                       "%s: tried to read from empty buffer",
1753746d5c1STitus Rwantare                       __func__);
17638870253STitus Rwantare         return PMBUS_ERR_BYTE;
1773746d5c1STitus Rwantare     }
1783746d5c1STitus Rwantare     uint8_t data = pmdev->out_buf[pmdev->out_buf_len - 1];
1793746d5c1STitus Rwantare     pmdev->out_buf_len--;
1803746d5c1STitus Rwantare     return data;
1813746d5c1STitus Rwantare }
1823746d5c1STitus Rwantare 
1833746d5c1STitus Rwantare static void pmbus_quick_cmd(SMBusDevice *smd, uint8_t read)
1843746d5c1STitus Rwantare {
1853746d5c1STitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(smd);
1863746d5c1STitus Rwantare     PMBusDeviceClass *pmdc = PMBUS_DEVICE_GET_CLASS(pmdev);
1873746d5c1STitus Rwantare 
1883746d5c1STitus Rwantare     if (pmdc->quick_cmd) {
1893746d5c1STitus Rwantare         pmdc->quick_cmd(pmdev, read);
1903746d5c1STitus Rwantare     }
1913746d5c1STitus Rwantare }
1923746d5c1STitus Rwantare 
193f0e4588fSPhilippe Mathieu-Daudé static uint8_t pmbus_pages_num(PMBusDevice *pmdev)
194f0e4588fSPhilippe Mathieu-Daudé {
195f0e4588fSPhilippe Mathieu-Daudé     const PMBusDeviceClass *k = PMBUS_DEVICE_GET_CLASS(pmdev);
196f0e4588fSPhilippe Mathieu-Daudé 
197f0e4588fSPhilippe Mathieu-Daudé     /* some PMBus devices don't use the PAGE command, so they get 1 page */
198f0e4588fSPhilippe Mathieu-Daudé     return k->device_num_pages ? : 1;
199f0e4588fSPhilippe Mathieu-Daudé }
200f0e4588fSPhilippe Mathieu-Daudé 
2013746d5c1STitus Rwantare static void pmbus_pages_alloc(PMBusDevice *pmdev)
2023746d5c1STitus Rwantare {
203f0e4588fSPhilippe Mathieu-Daudé     pmdev->num_pages = pmbus_pages_num(pmdev);
204f0e4588fSPhilippe Mathieu-Daudé     pmdev->pages = g_new0(PMBusPage, pmdev->num_pages);
2053746d5c1STitus Rwantare }
2063746d5c1STitus Rwantare 
2073746d5c1STitus Rwantare void pmbus_check_limits(PMBusDevice *pmdev)
2083746d5c1STitus Rwantare {
2093746d5c1STitus Rwantare     for (int i = 0; i < pmdev->num_pages; i++) {
2103746d5c1STitus Rwantare         if ((pmdev->pages[i].operation & PB_OP_ON) == 0) {
2113746d5c1STitus Rwantare             continue;   /* don't check powered off devices */
2123746d5c1STitus Rwantare         }
2133746d5c1STitus Rwantare 
2143746d5c1STitus Rwantare         if (pmdev->pages[i].read_vout > pmdev->pages[i].vout_ov_fault_limit) {
2153746d5c1STitus Rwantare             pmdev->pages[i].status_word |= PB_STATUS_VOUT;
2163746d5c1STitus Rwantare             pmdev->pages[i].status_vout |= PB_STATUS_VOUT_OV_FAULT;
2173746d5c1STitus Rwantare         }
2183746d5c1STitus Rwantare 
2193746d5c1STitus Rwantare         if (pmdev->pages[i].read_vout > pmdev->pages[i].vout_ov_warn_limit) {
2203746d5c1STitus Rwantare             pmdev->pages[i].status_word |= PB_STATUS_VOUT;
2213746d5c1STitus Rwantare             pmdev->pages[i].status_vout |= PB_STATUS_VOUT_OV_WARN;
2223746d5c1STitus Rwantare         }
2233746d5c1STitus Rwantare 
2243746d5c1STitus Rwantare         if (pmdev->pages[i].read_vout < pmdev->pages[i].vout_uv_warn_limit) {
2253746d5c1STitus Rwantare             pmdev->pages[i].status_word |= PB_STATUS_VOUT;
2263746d5c1STitus Rwantare             pmdev->pages[i].status_vout |= PB_STATUS_VOUT_UV_WARN;
2273746d5c1STitus Rwantare         }
2283746d5c1STitus Rwantare 
2293746d5c1STitus Rwantare         if (pmdev->pages[i].read_vout < pmdev->pages[i].vout_uv_fault_limit) {
2303746d5c1STitus Rwantare             pmdev->pages[i].status_word |= PB_STATUS_VOUT;
2313746d5c1STitus Rwantare             pmdev->pages[i].status_vout |= PB_STATUS_VOUT_UV_FAULT;
2323746d5c1STitus Rwantare         }
2333746d5c1STitus Rwantare 
2343746d5c1STitus Rwantare         if (pmdev->pages[i].read_vin > pmdev->pages[i].vin_ov_warn_limit) {
2353746d5c1STitus Rwantare             pmdev->pages[i].status_word |= PB_STATUS_INPUT;
2363746d5c1STitus Rwantare             pmdev->pages[i].status_input |= PB_STATUS_INPUT_VIN_OV_WARN;
2373746d5c1STitus Rwantare         }
2383746d5c1STitus Rwantare 
2393746d5c1STitus Rwantare         if (pmdev->pages[i].read_vin < pmdev->pages[i].vin_uv_warn_limit) {
2403746d5c1STitus Rwantare             pmdev->pages[i].status_word |= PB_STATUS_INPUT;
2413746d5c1STitus Rwantare             pmdev->pages[i].status_input |= PB_STATUS_INPUT_VIN_UV_WARN;
2423746d5c1STitus Rwantare         }
2433746d5c1STitus Rwantare 
2443746d5c1STitus Rwantare         if (pmdev->pages[i].read_iout > pmdev->pages[i].iout_oc_warn_limit) {
2453746d5c1STitus Rwantare             pmdev->pages[i].status_word |= PB_STATUS_IOUT_POUT;
2463746d5c1STitus Rwantare             pmdev->pages[i].status_iout |= PB_STATUS_IOUT_OC_WARN;
2473746d5c1STitus Rwantare         }
2483746d5c1STitus Rwantare 
2493746d5c1STitus Rwantare         if (pmdev->pages[i].read_iout > pmdev->pages[i].iout_oc_fault_limit) {
2503746d5c1STitus Rwantare             pmdev->pages[i].status_word |= PB_STATUS_IOUT_POUT;
2513746d5c1STitus Rwantare             pmdev->pages[i].status_iout |= PB_STATUS_IOUT_OC_FAULT;
2523746d5c1STitus Rwantare         }
2533746d5c1STitus Rwantare 
2543746d5c1STitus Rwantare         if (pmdev->pages[i].read_pin > pmdev->pages[i].pin_op_warn_limit) {
2553746d5c1STitus Rwantare             pmdev->pages[i].status_word |= PB_STATUS_INPUT;
2563746d5c1STitus Rwantare             pmdev->pages[i].status_input |= PB_STATUS_INPUT_PIN_OP_WARN;
2573746d5c1STitus Rwantare         }
2583746d5c1STitus Rwantare 
2593746d5c1STitus Rwantare         if (pmdev->pages[i].read_temperature_1
2603746d5c1STitus Rwantare                 > pmdev->pages[i].ot_fault_limit) {
2613746d5c1STitus Rwantare             pmdev->pages[i].status_word |= PB_STATUS_TEMPERATURE;
2623746d5c1STitus Rwantare             pmdev->pages[i].status_temperature |= PB_STATUS_OT_FAULT;
2633746d5c1STitus Rwantare         }
2643746d5c1STitus Rwantare 
2653746d5c1STitus Rwantare         if (pmdev->pages[i].read_temperature_1
2663746d5c1STitus Rwantare                 > pmdev->pages[i].ot_warn_limit) {
2673746d5c1STitus Rwantare             pmdev->pages[i].status_word |= PB_STATUS_TEMPERATURE;
2683746d5c1STitus Rwantare             pmdev->pages[i].status_temperature |= PB_STATUS_OT_WARN;
2693746d5c1STitus Rwantare         }
2703746d5c1STitus Rwantare     }
2713746d5c1STitus Rwantare }
2723746d5c1STitus Rwantare 
273d272d141SPeter Delevoryas void pmbus_idle(PMBusDevice *pmdev)
274d272d141SPeter Delevoryas {
275d272d141SPeter Delevoryas     pmdev->code = PMBUS_IDLE_STATE;
276d272d141SPeter Delevoryas }
277d272d141SPeter Delevoryas 
27838870253STitus Rwantare /* assert the status_cml error upon receipt of malformed command */
27938870253STitus Rwantare static void pmbus_cml_error(PMBusDevice *pmdev)
28038870253STitus Rwantare {
28138870253STitus Rwantare     for (int i = 0; i < pmdev->num_pages; i++) {
28238870253STitus Rwantare         pmdev->pages[i].status_word |= PMBUS_STATUS_CML;
28338870253STitus Rwantare         pmdev->pages[i].status_cml |= PB_CML_FAULT_INVALID_CMD;
28438870253STitus Rwantare     }
28538870253STitus Rwantare }
28638870253STitus Rwantare 
2873746d5c1STitus Rwantare static uint8_t pmbus_receive_byte(SMBusDevice *smd)
2883746d5c1STitus Rwantare {
2893746d5c1STitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(smd);
2903746d5c1STitus Rwantare     PMBusDeviceClass *pmdc = PMBUS_DEVICE_GET_CLASS(pmdev);
29138870253STitus Rwantare     uint8_t ret = PMBUS_ERR_BYTE;
29238870253STitus Rwantare     uint8_t index;
2933746d5c1STitus Rwantare 
2943746d5c1STitus Rwantare     if (pmdev->out_buf_len != 0) {
2953746d5c1STitus Rwantare         ret = pmbus_out_buf_pop(pmdev);
2963746d5c1STitus Rwantare         return ret;
2973746d5c1STitus Rwantare     }
2983746d5c1STitus Rwantare 
29938870253STitus Rwantare     /*
30038870253STitus Rwantare      * Reading from all pages will return the value from page 0,
301dd0b3271SMaheswara Kurapati      * means that all subsequent commands are to be applied to all output.
30238870253STitus Rwantare      */
30338870253STitus Rwantare     if (pmdev->page == PB_ALL_PAGES) {
30438870253STitus Rwantare         index = 0;
30538870253STitus Rwantare     } else if (pmdev->page > pmdev->num_pages - 1) {
30638870253STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
30738870253STitus Rwantare                       "%s: page %d is out of range\n",
30838870253STitus Rwantare                       __func__, pmdev->page);
30938870253STitus Rwantare         pmbus_cml_error(pmdev);
31038870253STitus Rwantare         return PMBUS_ERR_BYTE;
31138870253STitus Rwantare     } else {
31238870253STitus Rwantare         index = pmdev->page;
31338870253STitus Rwantare     }
31438870253STitus Rwantare 
3153746d5c1STitus Rwantare     switch (pmdev->code) {
3163746d5c1STitus Rwantare     case PMBUS_PAGE:
3173746d5c1STitus Rwantare         pmbus_send8(pmdev, pmdev->page);
3183746d5c1STitus Rwantare         break;
3193746d5c1STitus Rwantare 
3203746d5c1STitus Rwantare     case PMBUS_OPERATION:                 /* R/W byte */
3213746d5c1STitus Rwantare         pmbus_send8(pmdev, pmdev->pages[index].operation);
3223746d5c1STitus Rwantare         break;
3233746d5c1STitus Rwantare 
3243746d5c1STitus Rwantare     case PMBUS_ON_OFF_CONFIG:             /* R/W byte */
3253746d5c1STitus Rwantare         pmbus_send8(pmdev, pmdev->pages[index].on_off_config);
3263746d5c1STitus Rwantare         break;
3273746d5c1STitus Rwantare 
3283746d5c1STitus Rwantare     case PMBUS_PHASE:                     /* R/W byte */
3293746d5c1STitus Rwantare         pmbus_send8(pmdev, pmdev->pages[index].phase);
3303746d5c1STitus Rwantare         break;
3313746d5c1STitus Rwantare 
3323746d5c1STitus Rwantare     case PMBUS_WRITE_PROTECT:             /* R/W byte */
3333746d5c1STitus Rwantare         pmbus_send8(pmdev, pmdev->pages[index].write_protect);
3343746d5c1STitus Rwantare         break;
3353746d5c1STitus Rwantare 
3363746d5c1STitus Rwantare     case PMBUS_CAPABILITY:
3373746d5c1STitus Rwantare         pmbus_send8(pmdev, pmdev->capability);
3382192aaaeSTitus Rwantare         if (pmdev->capability & BIT(7)) {
3392192aaaeSTitus Rwantare             qemu_log_mask(LOG_UNIMP,
3402192aaaeSTitus Rwantare                           "%s: PEC is enabled but not yet supported.\n",
3412192aaaeSTitus Rwantare                           __func__);
3422192aaaeSTitus Rwantare         }
3433746d5c1STitus Rwantare         break;
3443746d5c1STitus Rwantare 
3453746d5c1STitus Rwantare     case PMBUS_VOUT_MODE:                 /* R/W byte */
3463746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MODE) {
3473746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].vout_mode);
3483746d5c1STitus Rwantare         } else {
3493746d5c1STitus Rwantare             goto passthough;
3503746d5c1STitus Rwantare         }
3513746d5c1STitus Rwantare         break;
3523746d5c1STitus Rwantare 
3533746d5c1STitus Rwantare     case PMBUS_VOUT_COMMAND:              /* R/W word */
3543746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
3553746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_command);
3563746d5c1STitus Rwantare         } else {
3573746d5c1STitus Rwantare             goto passthough;
3583746d5c1STitus Rwantare         }
3593746d5c1STitus Rwantare         break;
3603746d5c1STitus Rwantare 
3613746d5c1STitus Rwantare     case PMBUS_VOUT_TRIM:                 /* R/W word */
3623746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
3633746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_trim);
3643746d5c1STitus Rwantare         } else {
3653746d5c1STitus Rwantare             goto passthough;
3663746d5c1STitus Rwantare         }
3673746d5c1STitus Rwantare         break;
3683746d5c1STitus Rwantare 
3693746d5c1STitus Rwantare     case PMBUS_VOUT_CAL_OFFSET:           /* R/W word */
3703746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
3713746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_cal_offset);
3723746d5c1STitus Rwantare         } else {
3733746d5c1STitus Rwantare             goto passthough;
3743746d5c1STitus Rwantare         }
3753746d5c1STitus Rwantare         break;
3763746d5c1STitus Rwantare 
3773746d5c1STitus Rwantare     case PMBUS_VOUT_MAX:                  /* R/W word */
3783746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
3793746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_max);
3803746d5c1STitus Rwantare         } else {
3813746d5c1STitus Rwantare             goto passthough;
3823746d5c1STitus Rwantare         }
3833746d5c1STitus Rwantare         break;
3843746d5c1STitus Rwantare 
3853746d5c1STitus Rwantare     case PMBUS_VOUT_MARGIN_HIGH:          /* R/W word */
3863746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) {
3873746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_margin_high);
3883746d5c1STitus Rwantare         } else {
3893746d5c1STitus Rwantare             goto passthough;
3903746d5c1STitus Rwantare         }
3913746d5c1STitus Rwantare         break;
3923746d5c1STitus Rwantare 
3933746d5c1STitus Rwantare     case PMBUS_VOUT_MARGIN_LOW:           /* R/W word */
3943746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) {
3953746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_margin_low);
3963746d5c1STitus Rwantare         } else {
3973746d5c1STitus Rwantare             goto passthough;
3983746d5c1STitus Rwantare         }
3993746d5c1STitus Rwantare         break;
4003746d5c1STitus Rwantare 
4013746d5c1STitus Rwantare     case PMBUS_VOUT_TRANSITION_RATE:      /* R/W word */
4023746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
4033746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_transition_rate);
4043746d5c1STitus Rwantare         } else {
4053746d5c1STitus Rwantare             goto passthough;
4063746d5c1STitus Rwantare         }
4073746d5c1STitus Rwantare         break;
4083746d5c1STitus Rwantare 
4093746d5c1STitus Rwantare     case PMBUS_VOUT_DROOP:                /* R/W word */
4103746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
4113746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_droop);
4123746d5c1STitus Rwantare         } else {
4133746d5c1STitus Rwantare             goto passthough;
4143746d5c1STitus Rwantare         }
4153746d5c1STitus Rwantare         break;
4163746d5c1STitus Rwantare 
4173746d5c1STitus Rwantare     case PMBUS_VOUT_SCALE_LOOP:           /* R/W word */
4183746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
4193746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_scale_loop);
4203746d5c1STitus Rwantare         } else {
4213746d5c1STitus Rwantare             goto passthough;
4223746d5c1STitus Rwantare         }
4233746d5c1STitus Rwantare         break;
4243746d5c1STitus Rwantare 
4253746d5c1STitus Rwantare     case PMBUS_VOUT_SCALE_MONITOR:        /* R/W word */
4263746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
4273746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_scale_monitor);
4283746d5c1STitus Rwantare         } else {
4293746d5c1STitus Rwantare             goto passthough;
4303746d5c1STitus Rwantare         }
4313746d5c1STitus Rwantare         break;
4323746d5c1STitus Rwantare 
43332480293STitus Rwantare     case PMBUS_VOUT_MIN:        /* R/W word */
43432480293STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) {
43532480293STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_min);
43632480293STitus Rwantare         } else {
43732480293STitus Rwantare             goto passthough;
43832480293STitus Rwantare         }
43932480293STitus Rwantare         break;
44032480293STitus Rwantare 
4413746d5c1STitus Rwantare     /* TODO: implement coefficients support */
4423746d5c1STitus Rwantare 
4433746d5c1STitus Rwantare     case PMBUS_POUT_MAX:                  /* R/W word */
4443746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
4453746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].pout_max);
4463746d5c1STitus Rwantare         } else {
4473746d5c1STitus Rwantare             goto passthough;
4483746d5c1STitus Rwantare         }
4493746d5c1STitus Rwantare         break;
4503746d5c1STitus Rwantare 
4513746d5c1STitus Rwantare     case PMBUS_VIN_ON:                    /* R/W word */
4523746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
4533746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vin_on);
4543746d5c1STitus Rwantare         } else {
4553746d5c1STitus Rwantare             goto passthough;
4563746d5c1STitus Rwantare         }
4573746d5c1STitus Rwantare         break;
4583746d5c1STitus Rwantare 
4593746d5c1STitus Rwantare     case PMBUS_VIN_OFF:                   /* R/W word */
4603746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
4613746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vin_off);
4623746d5c1STitus Rwantare         } else {
4633746d5c1STitus Rwantare             goto passthough;
4643746d5c1STitus Rwantare         }
4653746d5c1STitus Rwantare         break;
4663746d5c1STitus Rwantare 
4673746d5c1STitus Rwantare     case PMBUS_IOUT_CAL_GAIN:             /* R/W word */
4683746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT_GAIN) {
4693746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].iout_cal_gain);
4703746d5c1STitus Rwantare         } else {
4713746d5c1STitus Rwantare             goto passthough;
4723746d5c1STitus Rwantare         }
4733746d5c1STitus Rwantare         break;
4743746d5c1STitus Rwantare 
4753746d5c1STitus Rwantare     case PMBUS_VOUT_OV_FAULT_LIMIT:       /* R/W word */
4763746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
4773746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_ov_fault_limit);
4783746d5c1STitus Rwantare         } else {
4793746d5c1STitus Rwantare             goto passthough;
4803746d5c1STitus Rwantare         }
4813746d5c1STitus Rwantare         break;
4823746d5c1STitus Rwantare 
4833746d5c1STitus Rwantare     case PMBUS_VOUT_OV_FAULT_RESPONSE:    /* R/W byte */
4843746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
4853746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].vout_ov_fault_response);
4863746d5c1STitus Rwantare         } else {
4873746d5c1STitus Rwantare             goto passthough;
4883746d5c1STitus Rwantare         }
4893746d5c1STitus Rwantare         break;
4903746d5c1STitus Rwantare 
4913746d5c1STitus Rwantare     case PMBUS_VOUT_OV_WARN_LIMIT:        /* R/W word */
4923746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
4933746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_ov_warn_limit);
4943746d5c1STitus Rwantare         } else {
4953746d5c1STitus Rwantare             goto passthough;
4963746d5c1STitus Rwantare         }
4973746d5c1STitus Rwantare         break;
4983746d5c1STitus Rwantare 
4993746d5c1STitus Rwantare     case PMBUS_VOUT_UV_WARN_LIMIT:        /* R/W word */
5003746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
5013746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_uv_warn_limit);
5023746d5c1STitus Rwantare         } else {
5033746d5c1STitus Rwantare             goto passthough;
5043746d5c1STitus Rwantare         }
5053746d5c1STitus Rwantare         break;
5063746d5c1STitus Rwantare 
5073746d5c1STitus Rwantare     case PMBUS_VOUT_UV_FAULT_LIMIT:       /* R/W word */
5083746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
5093746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vout_uv_fault_limit);
5103746d5c1STitus Rwantare         } else {
5113746d5c1STitus Rwantare             goto passthough;
5123746d5c1STitus Rwantare         }
5133746d5c1STitus Rwantare         break;
5143746d5c1STitus Rwantare 
5153746d5c1STitus Rwantare     case PMBUS_VOUT_UV_FAULT_RESPONSE:    /* R/W byte */
5163746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
5173746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].vout_uv_fault_response);
5183746d5c1STitus Rwantare         } else {
5193746d5c1STitus Rwantare             goto passthough;
5203746d5c1STitus Rwantare         }
5213746d5c1STitus Rwantare         break;
5223746d5c1STitus Rwantare 
5233746d5c1STitus Rwantare     case PMBUS_IOUT_OC_FAULT_LIMIT:       /* R/W word */
5243746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
5253746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].iout_oc_fault_limit);
5263746d5c1STitus Rwantare         } else {
5273746d5c1STitus Rwantare             goto passthough;
5283746d5c1STitus Rwantare         }
5293746d5c1STitus Rwantare         break;
5303746d5c1STitus Rwantare 
5313746d5c1STitus Rwantare     case PMBUS_IOUT_OC_FAULT_RESPONSE:    /* R/W byte */
5323746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
5333746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].iout_oc_fault_response);
5343746d5c1STitus Rwantare         } else {
5353746d5c1STitus Rwantare             goto passthough;
5363746d5c1STitus Rwantare         }
5373746d5c1STitus Rwantare         break;
5383746d5c1STitus Rwantare 
5393746d5c1STitus Rwantare     case PMBUS_IOUT_OC_LV_FAULT_LIMIT:    /* R/W word */
5403746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
5413746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].iout_oc_lv_fault_limit);
5423746d5c1STitus Rwantare         } else {
5433746d5c1STitus Rwantare             goto passthough;
5443746d5c1STitus Rwantare         }
5453746d5c1STitus Rwantare         break;
5463746d5c1STitus Rwantare 
5473746d5c1STitus Rwantare     case PMBUS_IOUT_OC_LV_FAULT_RESPONSE: /* R/W byte */
5483746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
5493746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].iout_oc_lv_fault_response);
5503746d5c1STitus Rwantare         } else {
5513746d5c1STitus Rwantare             goto passthough;
5523746d5c1STitus Rwantare         }
5533746d5c1STitus Rwantare         break;
5543746d5c1STitus Rwantare 
5553746d5c1STitus Rwantare     case PMBUS_IOUT_OC_WARN_LIMIT:        /* R/W word */
5563746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
5573746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].iout_oc_warn_limit);
5583746d5c1STitus Rwantare         } else {
5593746d5c1STitus Rwantare             goto passthough;
5603746d5c1STitus Rwantare         }
5613746d5c1STitus Rwantare         break;
5623746d5c1STitus Rwantare 
5633746d5c1STitus Rwantare     case PMBUS_IOUT_UC_FAULT_LIMIT:       /* R/W word */
5643746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
5653746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].iout_uc_fault_limit);
5663746d5c1STitus Rwantare         } else {
5673746d5c1STitus Rwantare             goto passthough;
5683746d5c1STitus Rwantare         }
5693746d5c1STitus Rwantare         break;
5703746d5c1STitus Rwantare 
5713746d5c1STitus Rwantare     case PMBUS_IOUT_UC_FAULT_RESPONSE:    /* R/W byte */
5723746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
5733746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].iout_uc_fault_response);
5743746d5c1STitus Rwantare         } else {
5753746d5c1STitus Rwantare             goto passthough;
5763746d5c1STitus Rwantare         }
5773746d5c1STitus Rwantare         break;
5783746d5c1STitus Rwantare 
5793746d5c1STitus Rwantare     case PMBUS_OT_FAULT_LIMIT:            /* R/W word */
5803746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
5813746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].ot_fault_limit);
5823746d5c1STitus Rwantare         } else {
5833746d5c1STitus Rwantare             goto passthough;
5843746d5c1STitus Rwantare         }
5853746d5c1STitus Rwantare         break;
5863746d5c1STitus Rwantare 
5873746d5c1STitus Rwantare     case PMBUS_OT_FAULT_RESPONSE:         /* R/W byte */
5883746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
5893746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].ot_fault_response);
5903746d5c1STitus Rwantare         } else {
5913746d5c1STitus Rwantare             goto passthough;
5923746d5c1STitus Rwantare         }
5933746d5c1STitus Rwantare         break;
5943746d5c1STitus Rwantare 
5953746d5c1STitus Rwantare     case PMBUS_OT_WARN_LIMIT:             /* R/W word */
5963746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
5973746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].ot_warn_limit);
5983746d5c1STitus Rwantare         } else {
5993746d5c1STitus Rwantare             goto passthough;
6003746d5c1STitus Rwantare         }
6013746d5c1STitus Rwantare         break;
6023746d5c1STitus Rwantare 
6033746d5c1STitus Rwantare     case PMBUS_UT_WARN_LIMIT:             /* R/W word */
6043746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
6053746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].ut_warn_limit);
6063746d5c1STitus Rwantare         } else {
6073746d5c1STitus Rwantare             goto passthough;
6083746d5c1STitus Rwantare         }
6093746d5c1STitus Rwantare         break;
6103746d5c1STitus Rwantare 
6113746d5c1STitus Rwantare     case PMBUS_UT_FAULT_LIMIT:            /* R/W word */
6123746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
6133746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].ut_fault_limit);
6143746d5c1STitus Rwantare         } else {
6153746d5c1STitus Rwantare             goto passthough;
6163746d5c1STitus Rwantare         }
6173746d5c1STitus Rwantare         break;
6183746d5c1STitus Rwantare 
6193746d5c1STitus Rwantare     case PMBUS_UT_FAULT_RESPONSE:         /* R/W byte */
6203746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
6213746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].ut_fault_response);
6223746d5c1STitus Rwantare         } else {
6233746d5c1STitus Rwantare             goto passthough;
6243746d5c1STitus Rwantare         }
6253746d5c1STitus Rwantare         break;
6263746d5c1STitus Rwantare 
6273746d5c1STitus Rwantare     case PMBUS_VIN_OV_FAULT_LIMIT:        /* R/W word */
6283746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
6293746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vin_ov_fault_limit);
6303746d5c1STitus Rwantare         } else {
6313746d5c1STitus Rwantare             goto passthough;
6323746d5c1STitus Rwantare         }
6333746d5c1STitus Rwantare         break;
6343746d5c1STitus Rwantare 
6353746d5c1STitus Rwantare     case PMBUS_VIN_OV_FAULT_RESPONSE:     /* R/W byte */
6363746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
6373746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].vin_ov_fault_response);
6383746d5c1STitus Rwantare         } else {
6393746d5c1STitus Rwantare             goto passthough;
6403746d5c1STitus Rwantare         }
6413746d5c1STitus Rwantare         break;
6423746d5c1STitus Rwantare 
6433746d5c1STitus Rwantare     case PMBUS_VIN_OV_WARN_LIMIT:         /* R/W word */
6443746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
6453746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vin_ov_warn_limit);
6463746d5c1STitus Rwantare         } else {
6473746d5c1STitus Rwantare             goto passthough;
6483746d5c1STitus Rwantare         }
6493746d5c1STitus Rwantare         break;
6503746d5c1STitus Rwantare 
6513746d5c1STitus Rwantare     case PMBUS_VIN_UV_WARN_LIMIT:         /* R/W word */
6523746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
6533746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vin_uv_warn_limit);
6543746d5c1STitus Rwantare         } else {
6553746d5c1STitus Rwantare             goto passthough;
6563746d5c1STitus Rwantare         }
6573746d5c1STitus Rwantare         break;
6583746d5c1STitus Rwantare 
6593746d5c1STitus Rwantare     case PMBUS_VIN_UV_FAULT_LIMIT:        /* R/W word */
6603746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
6613746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].vin_uv_fault_limit);
6623746d5c1STitus Rwantare         } else {
6633746d5c1STitus Rwantare             goto passthough;
6643746d5c1STitus Rwantare         }
6653746d5c1STitus Rwantare         break;
6663746d5c1STitus Rwantare 
6673746d5c1STitus Rwantare     case PMBUS_VIN_UV_FAULT_RESPONSE:     /* R/W byte */
6683746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
6693746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].vin_uv_fault_response);
6703746d5c1STitus Rwantare         } else {
6713746d5c1STitus Rwantare             goto passthough;
6723746d5c1STitus Rwantare         }
6733746d5c1STitus Rwantare         break;
6743746d5c1STitus Rwantare 
6753746d5c1STitus Rwantare     case PMBUS_IIN_OC_FAULT_LIMIT:        /* R/W word */
6763746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
6773746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].iin_oc_fault_limit);
6783746d5c1STitus Rwantare         } else {
6793746d5c1STitus Rwantare             goto passthough;
6803746d5c1STitus Rwantare         }
6813746d5c1STitus Rwantare         break;
6823746d5c1STitus Rwantare 
6833746d5c1STitus Rwantare     case PMBUS_IIN_OC_FAULT_RESPONSE:     /* R/W byte */
6843746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
6853746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].iin_oc_fault_response);
6863746d5c1STitus Rwantare         } else {
6873746d5c1STitus Rwantare             goto passthough;
6883746d5c1STitus Rwantare         }
6893746d5c1STitus Rwantare         break;
6903746d5c1STitus Rwantare 
6913746d5c1STitus Rwantare     case PMBUS_IIN_OC_WARN_LIMIT:         /* R/W word */
6923746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
6933746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].iin_oc_warn_limit);
6943746d5c1STitus Rwantare         } else {
6953746d5c1STitus Rwantare             goto passthough;
6963746d5c1STitus Rwantare         }
6973746d5c1STitus Rwantare         break;
6983746d5c1STitus Rwantare 
6993746d5c1STitus Rwantare     case PMBUS_POUT_OP_FAULT_LIMIT:       /* R/W word */
7003746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
7013746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].pout_op_fault_limit);
7023746d5c1STitus Rwantare         } else {
7033746d5c1STitus Rwantare             goto passthough;
7043746d5c1STitus Rwantare         }
7053746d5c1STitus Rwantare         break;
7063746d5c1STitus Rwantare 
7073746d5c1STitus Rwantare     case PMBUS_POUT_OP_FAULT_RESPONSE:    /* R/W byte */
7083746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
7093746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].pout_op_fault_response);
7103746d5c1STitus Rwantare         } else {
7113746d5c1STitus Rwantare             goto passthough;
7123746d5c1STitus Rwantare         }
7133746d5c1STitus Rwantare         break;
7143746d5c1STitus Rwantare 
7153746d5c1STitus Rwantare     case PMBUS_POUT_OP_WARN_LIMIT:        /* R/W word */
7163746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
7173746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].pout_op_warn_limit);
7183746d5c1STitus Rwantare         } else {
7193746d5c1STitus Rwantare             goto passthough;
7203746d5c1STitus Rwantare         }
7213746d5c1STitus Rwantare         break;
7223746d5c1STitus Rwantare 
7233746d5c1STitus Rwantare     case PMBUS_PIN_OP_WARN_LIMIT:         /* R/W word */
7243746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_PIN) {
7253746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].pin_op_warn_limit);
7263746d5c1STitus Rwantare         } else {
7273746d5c1STitus Rwantare             goto passthough;
7283746d5c1STitus Rwantare         }
7293746d5c1STitus Rwantare         break;
7303746d5c1STitus Rwantare 
7313746d5c1STitus Rwantare     case PMBUS_STATUS_BYTE:               /* R/W byte */
7323746d5c1STitus Rwantare         pmbus_send8(pmdev, pmdev->pages[index].status_word & 0xFF);
7333746d5c1STitus Rwantare         break;
7343746d5c1STitus Rwantare 
7353746d5c1STitus Rwantare     case PMBUS_STATUS_WORD:               /* R/W word */
7363746d5c1STitus Rwantare         pmbus_send16(pmdev, pmdev->pages[index].status_word);
7373746d5c1STitus Rwantare         break;
7383746d5c1STitus Rwantare 
7393746d5c1STitus Rwantare     case PMBUS_STATUS_VOUT:               /* R/W byte */
7403746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
7413746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].status_vout);
7423746d5c1STitus Rwantare         } else {
7433746d5c1STitus Rwantare             goto passthough;
7443746d5c1STitus Rwantare         }
7453746d5c1STitus Rwantare         break;
7463746d5c1STitus Rwantare 
7473746d5c1STitus Rwantare     case PMBUS_STATUS_IOUT:               /* R/W byte */
7483746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
7493746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].status_iout);
7503746d5c1STitus Rwantare         } else {
7513746d5c1STitus Rwantare             goto passthough;
7523746d5c1STitus Rwantare         }
7533746d5c1STitus Rwantare         break;
7543746d5c1STitus Rwantare 
7553746d5c1STitus Rwantare     case PMBUS_STATUS_INPUT:              /* R/W byte */
7563746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN ||
7573746d5c1STitus Rwantare             pmdev->pages[index].page_flags & PB_HAS_IIN ||
7583746d5c1STitus Rwantare             pmdev->pages[index].page_flags & PB_HAS_PIN) {
7593746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].status_input);
7603746d5c1STitus Rwantare         } else {
7613746d5c1STitus Rwantare             goto passthough;
7623746d5c1STitus Rwantare         }
7633746d5c1STitus Rwantare         break;
7643746d5c1STitus Rwantare 
7653746d5c1STitus Rwantare     case PMBUS_STATUS_TEMPERATURE:        /* R/W byte */
7663746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
7673746d5c1STitus Rwantare             pmbus_send8(pmdev, pmdev->pages[index].status_temperature);
7683746d5c1STitus Rwantare         } else {
7693746d5c1STitus Rwantare             goto passthough;
7703746d5c1STitus Rwantare         }
7713746d5c1STitus Rwantare         break;
7723746d5c1STitus Rwantare 
7733746d5c1STitus Rwantare     case PMBUS_STATUS_CML:                /* R/W byte */
7743746d5c1STitus Rwantare         pmbus_send8(pmdev, pmdev->pages[index].status_cml);
7753746d5c1STitus Rwantare         break;
7763746d5c1STitus Rwantare 
7773746d5c1STitus Rwantare     case PMBUS_STATUS_OTHER:              /* R/W byte */
7783746d5c1STitus Rwantare         pmbus_send8(pmdev, pmdev->pages[index].status_other);
7793746d5c1STitus Rwantare         break;
7803746d5c1STitus Rwantare 
78132480293STitus Rwantare     case PMBUS_STATUS_MFR_SPECIFIC:       /* R/W byte */
78232480293STitus Rwantare         pmbus_send8(pmdev, pmdev->pages[index].status_mfr_specific);
78332480293STitus Rwantare         break;
78432480293STitus Rwantare 
7853746d5c1STitus Rwantare     case PMBUS_READ_EIN:                  /* Read-Only block 5 bytes */
7863746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_EIN) {
7873746d5c1STitus Rwantare             pmbus_send(pmdev, pmdev->pages[index].read_ein, 5);
7883746d5c1STitus Rwantare         } else {
7893746d5c1STitus Rwantare             goto passthough;
7903746d5c1STitus Rwantare         }
7913746d5c1STitus Rwantare         break;
7923746d5c1STitus Rwantare 
7933746d5c1STitus Rwantare     case PMBUS_READ_EOUT:                 /* Read-Only block 5 bytes */
7943746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_EOUT) {
7953746d5c1STitus Rwantare             pmbus_send(pmdev, pmdev->pages[index].read_eout, 5);
7963746d5c1STitus Rwantare         } else {
7973746d5c1STitus Rwantare             goto passthough;
7983746d5c1STitus Rwantare         }
7993746d5c1STitus Rwantare         break;
8003746d5c1STitus Rwantare 
8013746d5c1STitus Rwantare     case PMBUS_READ_VIN:                  /* Read-Only word */
8023746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
8033746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].read_vin);
8043746d5c1STitus Rwantare         } else {
8053746d5c1STitus Rwantare             goto passthough;
8063746d5c1STitus Rwantare         }
8073746d5c1STitus Rwantare         break;
8083746d5c1STitus Rwantare 
8093746d5c1STitus Rwantare     case PMBUS_READ_IIN:                  /* Read-Only word */
8103746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
8113746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].read_iin);
8123746d5c1STitus Rwantare         } else {
8133746d5c1STitus Rwantare             goto passthough;
8143746d5c1STitus Rwantare         }
8153746d5c1STitus Rwantare         break;
8163746d5c1STitus Rwantare 
8173746d5c1STitus Rwantare     case PMBUS_READ_VOUT:                 /* Read-Only word */
8183746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
8193746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].read_vout);
8203746d5c1STitus Rwantare         } else {
8213746d5c1STitus Rwantare             goto passthough;
8223746d5c1STitus Rwantare         }
8233746d5c1STitus Rwantare         break;
8243746d5c1STitus Rwantare 
8253746d5c1STitus Rwantare     case PMBUS_READ_IOUT:                 /* Read-Only word */
8263746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
8273746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].read_iout);
8283746d5c1STitus Rwantare         } else {
8293746d5c1STitus Rwantare             goto passthough;
8303746d5c1STitus Rwantare         }
8313746d5c1STitus Rwantare         break;
8323746d5c1STitus Rwantare 
8333746d5c1STitus Rwantare     case PMBUS_READ_TEMPERATURE_1:        /* Read-Only word */
8343746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
8353746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].read_temperature_1);
8363746d5c1STitus Rwantare         } else {
8373746d5c1STitus Rwantare             goto passthough;
8383746d5c1STitus Rwantare         }
8393746d5c1STitus Rwantare         break;
8403746d5c1STitus Rwantare 
8413746d5c1STitus Rwantare     case PMBUS_READ_TEMPERATURE_2:        /* Read-Only word */
8423746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMP2) {
8433746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].read_temperature_2);
8443746d5c1STitus Rwantare         } else {
8453746d5c1STitus Rwantare             goto passthough;
8463746d5c1STitus Rwantare         }
8473746d5c1STitus Rwantare         break;
8483746d5c1STitus Rwantare 
8493746d5c1STitus Rwantare     case PMBUS_READ_TEMPERATURE_3:        /* Read-Only word */
8503746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMP3) {
8513746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].read_temperature_3);
8523746d5c1STitus Rwantare         } else {
8533746d5c1STitus Rwantare             goto passthough;
8543746d5c1STitus Rwantare         }
8553746d5c1STitus Rwantare         break;
8563746d5c1STitus Rwantare 
8573746d5c1STitus Rwantare     case PMBUS_READ_POUT:                 /* Read-Only word */
8583746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
8593746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].read_pout);
8603746d5c1STitus Rwantare         } else {
8613746d5c1STitus Rwantare             goto passthough;
8623746d5c1STitus Rwantare         }
8633746d5c1STitus Rwantare         break;
8643746d5c1STitus Rwantare 
8653746d5c1STitus Rwantare     case PMBUS_READ_PIN:                  /* Read-Only word */
8663746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_PIN) {
8673746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].read_pin);
8683746d5c1STitus Rwantare         } else {
8693746d5c1STitus Rwantare             goto passthough;
8703746d5c1STitus Rwantare         }
8713746d5c1STitus Rwantare         break;
8723746d5c1STitus Rwantare 
8733746d5c1STitus Rwantare     case PMBUS_REVISION:                  /* Read-Only byte */
8743746d5c1STitus Rwantare         pmbus_send8(pmdev, pmdev->pages[index].revision);
8753746d5c1STitus Rwantare         break;
8763746d5c1STitus Rwantare 
8773746d5c1STitus Rwantare     case PMBUS_MFR_ID:                    /* R/W block */
8783746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) {
8793746d5c1STitus Rwantare             pmbus_send_string(pmdev, pmdev->pages[index].mfr_id);
8803746d5c1STitus Rwantare         } else {
8813746d5c1STitus Rwantare             goto passthough;
8823746d5c1STitus Rwantare         }
8833746d5c1STitus Rwantare         break;
8843746d5c1STitus Rwantare 
8853746d5c1STitus Rwantare     case PMBUS_MFR_MODEL:                 /* R/W block */
8863746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) {
8873746d5c1STitus Rwantare             pmbus_send_string(pmdev, pmdev->pages[index].mfr_model);
8883746d5c1STitus Rwantare         } else {
8893746d5c1STitus Rwantare             goto passthough;
8903746d5c1STitus Rwantare         }
8913746d5c1STitus Rwantare         break;
8923746d5c1STitus Rwantare 
8933746d5c1STitus Rwantare     case PMBUS_MFR_REVISION:              /* R/W block */
8943746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) {
8953746d5c1STitus Rwantare             pmbus_send_string(pmdev, pmdev->pages[index].mfr_revision);
8963746d5c1STitus Rwantare         } else {
8973746d5c1STitus Rwantare             goto passthough;
8983746d5c1STitus Rwantare         }
8993746d5c1STitus Rwantare         break;
9003746d5c1STitus Rwantare 
9013746d5c1STitus Rwantare     case PMBUS_MFR_LOCATION:              /* R/W block */
9023746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) {
9033746d5c1STitus Rwantare             pmbus_send_string(pmdev, pmdev->pages[index].mfr_location);
9043746d5c1STitus Rwantare         } else {
9053746d5c1STitus Rwantare             goto passthough;
9063746d5c1STitus Rwantare         }
9073746d5c1STitus Rwantare         break;
9083746d5c1STitus Rwantare 
9093746d5c1STitus Rwantare     case PMBUS_MFR_VIN_MIN:               /* Read-Only word */
9103746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN_RATING) {
9113746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].mfr_vin_min);
9123746d5c1STitus Rwantare         } else {
9133746d5c1STitus Rwantare             goto passthough;
9143746d5c1STitus Rwantare         }
9153746d5c1STitus Rwantare         break;
9163746d5c1STitus Rwantare 
9173746d5c1STitus Rwantare     case PMBUS_MFR_VIN_MAX:               /* Read-Only word */
9183746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN_RATING) {
9193746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].mfr_vin_max);
9203746d5c1STitus Rwantare         } else {
9213746d5c1STitus Rwantare             goto passthough;
9223746d5c1STitus Rwantare         }
9233746d5c1STitus Rwantare         break;
9243746d5c1STitus Rwantare 
9253746d5c1STitus Rwantare     case PMBUS_MFR_IIN_MAX:               /* Read-Only word */
9263746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IIN_RATING) {
9273746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].mfr_iin_max);
9283746d5c1STitus Rwantare         } else {
9293746d5c1STitus Rwantare             goto passthough;
9303746d5c1STitus Rwantare         }
9313746d5c1STitus Rwantare         break;
9323746d5c1STitus Rwantare 
9333746d5c1STitus Rwantare     case PMBUS_MFR_PIN_MAX:               /* Read-Only word */
9343746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_PIN_RATING) {
9353746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].mfr_pin_max);
9363746d5c1STitus Rwantare         } else {
9373746d5c1STitus Rwantare             goto passthough;
9383746d5c1STitus Rwantare         }
9393746d5c1STitus Rwantare         break;
9403746d5c1STitus Rwantare 
9413746d5c1STitus Rwantare     case PMBUS_MFR_VOUT_MIN:              /* Read-Only word */
9423746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) {
9433746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].mfr_vout_min);
9443746d5c1STitus Rwantare         } else {
9453746d5c1STitus Rwantare             goto passthough;
9463746d5c1STitus Rwantare         }
9473746d5c1STitus Rwantare         break;
9483746d5c1STitus Rwantare 
9493746d5c1STitus Rwantare     case PMBUS_MFR_VOUT_MAX:              /* Read-Only word */
9503746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) {
9513746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].mfr_vout_max);
9523746d5c1STitus Rwantare         } else {
9533746d5c1STitus Rwantare             goto passthough;
9543746d5c1STitus Rwantare         }
9553746d5c1STitus Rwantare         break;
9563746d5c1STitus Rwantare 
9573746d5c1STitus Rwantare     case PMBUS_MFR_IOUT_MAX:              /* Read-Only word */
9583746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT_RATING) {
9593746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].mfr_iout_max);
9603746d5c1STitus Rwantare         } else {
9613746d5c1STitus Rwantare             goto passthough;
9623746d5c1STitus Rwantare         }
9633746d5c1STitus Rwantare         break;
9643746d5c1STitus Rwantare 
9653746d5c1STitus Rwantare     case PMBUS_MFR_POUT_MAX:              /* Read-Only word */
9663746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_POUT_RATING) {
9673746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].mfr_pout_max);
9683746d5c1STitus Rwantare         } else {
9693746d5c1STitus Rwantare             goto passthough;
9703746d5c1STitus Rwantare         }
9713746d5c1STitus Rwantare         break;
9723746d5c1STitus Rwantare 
9733746d5c1STitus Rwantare     case PMBUS_MFR_MAX_TEMP_1:            /* R/W word */
9743746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) {
9753746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_1);
9763746d5c1STitus Rwantare         } else {
9773746d5c1STitus Rwantare             goto passthough;
9783746d5c1STitus Rwantare         }
9793746d5c1STitus Rwantare         break;
9803746d5c1STitus Rwantare 
9813746d5c1STitus Rwantare     case PMBUS_MFR_MAX_TEMP_2:            /* R/W word */
9823746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) {
9833746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_2);
9843746d5c1STitus Rwantare         } else {
9853746d5c1STitus Rwantare             goto passthough;
9863746d5c1STitus Rwantare         }
9873746d5c1STitus Rwantare         break;
9883746d5c1STitus Rwantare 
9893746d5c1STitus Rwantare     case PMBUS_MFR_MAX_TEMP_3:            /* R/W word */
9903746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) {
9913746d5c1STitus Rwantare             pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_3);
9923746d5c1STitus Rwantare         } else {
9933746d5c1STitus Rwantare             goto passthough;
9943746d5c1STitus Rwantare         }
9953746d5c1STitus Rwantare         break;
9963746d5c1STitus Rwantare 
997d272d141SPeter Delevoryas     case PMBUS_IDLE_STATE:
998d272d141SPeter Delevoryas         pmbus_send8(pmdev, PMBUS_ERR_BYTE);
999d272d141SPeter Delevoryas         break;
1000d272d141SPeter Delevoryas 
10013746d5c1STitus Rwantare     case PMBUS_CLEAR_FAULTS:              /* Send Byte */
10023746d5c1STitus Rwantare     case PMBUS_PAGE_PLUS_WRITE:           /* Block Write-only */
10033746d5c1STitus Rwantare     case PMBUS_STORE_DEFAULT_ALL:         /* Send Byte */
10043746d5c1STitus Rwantare     case PMBUS_RESTORE_DEFAULT_ALL:       /* Send Byte */
10053746d5c1STitus Rwantare     case PMBUS_STORE_DEFAULT_CODE:        /* Write-only Byte */
10063746d5c1STitus Rwantare     case PMBUS_RESTORE_DEFAULT_CODE:      /* Write-only Byte */
10073746d5c1STitus Rwantare     case PMBUS_STORE_USER_ALL:            /* Send Byte */
10083746d5c1STitus Rwantare     case PMBUS_RESTORE_USER_ALL:          /* Send Byte */
10093746d5c1STitus Rwantare     case PMBUS_STORE_USER_CODE:           /* Write-only Byte */
10103746d5c1STitus Rwantare     case PMBUS_RESTORE_USER_CODE:         /* Write-only Byte */
10113746d5c1STitus Rwantare     case PMBUS_QUERY:                     /* Write-Only */
10123746d5c1STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
10133746d5c1STitus Rwantare                       "%s: reading from write only register 0x%02x\n",
10143746d5c1STitus Rwantare                       __func__, pmdev->code);
10153746d5c1STitus Rwantare         break;
10163746d5c1STitus Rwantare 
10173746d5c1STitus Rwantare passthough:
10183746d5c1STitus Rwantare     default:
10193746d5c1STitus Rwantare         /* Pass through read request if not handled */
10203746d5c1STitus Rwantare         if (pmdc->receive_byte) {
10213746d5c1STitus Rwantare             ret = pmdc->receive_byte(pmdev);
10223746d5c1STitus Rwantare         }
10233746d5c1STitus Rwantare         break;
10243746d5c1STitus Rwantare     }
10253746d5c1STitus Rwantare 
10263746d5c1STitus Rwantare     if (pmdev->out_buf_len != 0) {
10273746d5c1STitus Rwantare         ret = pmbus_out_buf_pop(pmdev);
10283746d5c1STitus Rwantare         return ret;
10293746d5c1STitus Rwantare     }
10303746d5c1STitus Rwantare 
10313746d5c1STitus Rwantare     return ret;
10323746d5c1STitus Rwantare }
10333746d5c1STitus Rwantare 
10343746d5c1STitus Rwantare /*
10353746d5c1STitus Rwantare  * PMBus clear faults command applies to all status registers, existing faults
10363746d5c1STitus Rwantare  * should separately get re-asserted.
10373746d5c1STitus Rwantare  */
10383746d5c1STitus Rwantare static void pmbus_clear_faults(PMBusDevice *pmdev)
10393746d5c1STitus Rwantare {
10403746d5c1STitus Rwantare     for (uint8_t i = 0; i < pmdev->num_pages; i++) {
10413746d5c1STitus Rwantare         pmdev->pages[i].status_word = 0;
10423746d5c1STitus Rwantare         pmdev->pages[i].status_vout = 0;
10433746d5c1STitus Rwantare         pmdev->pages[i].status_iout = 0;
10443746d5c1STitus Rwantare         pmdev->pages[i].status_input = 0;
10453746d5c1STitus Rwantare         pmdev->pages[i].status_temperature = 0;
10463746d5c1STitus Rwantare         pmdev->pages[i].status_cml = 0;
10473746d5c1STitus Rwantare         pmdev->pages[i].status_other = 0;
10483746d5c1STitus Rwantare         pmdev->pages[i].status_mfr_specific = 0;
10493746d5c1STitus Rwantare         pmdev->pages[i].status_fans_1_2 = 0;
10503746d5c1STitus Rwantare         pmdev->pages[i].status_fans_3_4 = 0;
10513746d5c1STitus Rwantare     }
10523746d5c1STitus Rwantare 
10533746d5c1STitus Rwantare }
10543746d5c1STitus Rwantare 
10553746d5c1STitus Rwantare /*
10563746d5c1STitus Rwantare  * PMBus operation is used to turn On and Off PSUs
10573746d5c1STitus Rwantare  * Therefore, default value for the Operation should be PB_OP_ON or 0x80
10583746d5c1STitus Rwantare  */
10593746d5c1STitus Rwantare static void pmbus_operation(PMBusDevice *pmdev)
10603746d5c1STitus Rwantare {
10613746d5c1STitus Rwantare     uint8_t index = pmdev->page;
10623746d5c1STitus Rwantare     if ((pmdev->pages[index].operation & PB_OP_ON) == 0) {
10633746d5c1STitus Rwantare         pmdev->pages[index].read_vout = 0;
10643746d5c1STitus Rwantare         pmdev->pages[index].read_iout = 0;
10653746d5c1STitus Rwantare         pmdev->pages[index].read_pout = 0;
10663746d5c1STitus Rwantare         return;
10673746d5c1STitus Rwantare     }
10683746d5c1STitus Rwantare 
10693746d5c1STitus Rwantare     if (pmdev->pages[index].operation & (PB_OP_ON | PB_OP_MARGIN_HIGH)) {
10703746d5c1STitus Rwantare         pmdev->pages[index].read_vout = pmdev->pages[index].vout_margin_high;
10713746d5c1STitus Rwantare     }
10723746d5c1STitus Rwantare 
10733746d5c1STitus Rwantare     if (pmdev->pages[index].operation & (PB_OP_ON | PB_OP_MARGIN_LOW)) {
10743746d5c1STitus Rwantare         pmdev->pages[index].read_vout = pmdev->pages[index].vout_margin_low;
10753746d5c1STitus Rwantare     }
10763746d5c1STitus Rwantare     pmbus_check_limits(pmdev);
10773746d5c1STitus Rwantare }
10783746d5c1STitus Rwantare 
10793746d5c1STitus Rwantare static int pmbus_write_data(SMBusDevice *smd, uint8_t *buf, uint8_t len)
10803746d5c1STitus Rwantare {
10813746d5c1STitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(smd);
10823746d5c1STitus Rwantare     PMBusDeviceClass *pmdc = PMBUS_DEVICE_GET_CLASS(pmdev);
10833746d5c1STitus Rwantare     int ret = 0;
10843746d5c1STitus Rwantare     uint8_t index;
10853746d5c1STitus Rwantare 
10863746d5c1STitus Rwantare     if (len == 0) {
10873746d5c1STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__);
108838870253STitus Rwantare         return PMBUS_ERR_BYTE;
10893746d5c1STitus Rwantare     }
10903746d5c1STitus Rwantare 
10913746d5c1STitus Rwantare     if (!pmdev->pages) { /* allocate memory for pages on first use */
10923746d5c1STitus Rwantare         pmbus_pages_alloc(pmdev);
10933746d5c1STitus Rwantare     }
10943746d5c1STitus Rwantare 
10953746d5c1STitus Rwantare     pmdev->in_buf_len = len;
10963746d5c1STitus Rwantare     pmdev->in_buf = buf;
10973746d5c1STitus Rwantare 
10983746d5c1STitus Rwantare     pmdev->code = buf[0]; /* PMBus command code */
10993746d5c1STitus Rwantare     if (len == 1) { /* Single length writes are command codes only */
11003746d5c1STitus Rwantare         return 0;
11013746d5c1STitus Rwantare     }
11023746d5c1STitus Rwantare 
11033746d5c1STitus Rwantare     if (pmdev->code == PMBUS_PAGE) {
11043746d5c1STitus Rwantare         pmdev->page = pmbus_receive8(pmdev);
11053746d5c1STitus Rwantare         return 0;
11063746d5c1STitus Rwantare     }
110738870253STitus Rwantare 
11083746d5c1STitus Rwantare     /* loop through all the pages when 0xFF is received */
11093746d5c1STitus Rwantare     if (pmdev->page == PB_ALL_PAGES) {
11103746d5c1STitus Rwantare         for (int i = 0; i < pmdev->num_pages; i++) {
11113746d5c1STitus Rwantare             pmdev->page = i;
11123746d5c1STitus Rwantare             pmbus_write_data(smd, buf, len);
11133746d5c1STitus Rwantare         }
11143746d5c1STitus Rwantare         pmdev->page = PB_ALL_PAGES;
11153746d5c1STitus Rwantare         return 0;
11163746d5c1STitus Rwantare     }
11173746d5c1STitus Rwantare 
111838870253STitus Rwantare     if (pmdev->page > pmdev->num_pages - 1) {
111938870253STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
112038870253STitus Rwantare                         "%s: page %u is out of range\n",
112138870253STitus Rwantare                         __func__, pmdev->page);
112238870253STitus Rwantare         pmdev->page = 0; /* undefined behaviour - reset to page 0 */
112338870253STitus Rwantare         pmbus_cml_error(pmdev);
112438870253STitus Rwantare         return PMBUS_ERR_BYTE;
112538870253STitus Rwantare     }
112638870253STitus Rwantare 
11273746d5c1STitus Rwantare     index = pmdev->page;
11283746d5c1STitus Rwantare 
11293746d5c1STitus Rwantare     switch (pmdev->code) {
11303746d5c1STitus Rwantare     case PMBUS_OPERATION:                 /* R/W byte */
11313746d5c1STitus Rwantare         pmdev->pages[index].operation = pmbus_receive8(pmdev);
11323746d5c1STitus Rwantare         pmbus_operation(pmdev);
11333746d5c1STitus Rwantare         break;
11343746d5c1STitus Rwantare 
11353746d5c1STitus Rwantare     case PMBUS_ON_OFF_CONFIG:             /* R/W byte */
11363746d5c1STitus Rwantare         pmdev->pages[index].on_off_config = pmbus_receive8(pmdev);
11373746d5c1STitus Rwantare         break;
11383746d5c1STitus Rwantare 
11393746d5c1STitus Rwantare     case PMBUS_CLEAR_FAULTS:              /* Send Byte */
11403746d5c1STitus Rwantare         pmbus_clear_faults(pmdev);
11413746d5c1STitus Rwantare         break;
11423746d5c1STitus Rwantare 
11433746d5c1STitus Rwantare     case PMBUS_PHASE:                     /* R/W byte */
11443746d5c1STitus Rwantare         pmdev->pages[index].phase = pmbus_receive8(pmdev);
11453746d5c1STitus Rwantare         break;
11463746d5c1STitus Rwantare 
11473746d5c1STitus Rwantare     case PMBUS_PAGE_PLUS_WRITE:           /* Block Write-only */
11483746d5c1STitus Rwantare     case PMBUS_WRITE_PROTECT:             /* R/W byte */
11493746d5c1STitus Rwantare         pmdev->pages[index].write_protect = pmbus_receive8(pmdev);
11503746d5c1STitus Rwantare         break;
11513746d5c1STitus Rwantare 
11523746d5c1STitus Rwantare     case PMBUS_VOUT_MODE:                 /* R/W byte */
11533746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MODE) {
11543746d5c1STitus Rwantare             pmdev->pages[index].vout_mode = pmbus_receive8(pmdev);
11553746d5c1STitus Rwantare         } else {
11563746d5c1STitus Rwantare             goto passthrough;
11573746d5c1STitus Rwantare         }
11583746d5c1STitus Rwantare         break;
11593746d5c1STitus Rwantare 
11603746d5c1STitus Rwantare     case PMBUS_VOUT_COMMAND:              /* R/W word */
11613746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
11623746d5c1STitus Rwantare             pmdev->pages[index].vout_command = pmbus_receive16(pmdev);
11633746d5c1STitus Rwantare         } else {
11643746d5c1STitus Rwantare             goto passthrough;
11653746d5c1STitus Rwantare         }
11663746d5c1STitus Rwantare         break;
11673746d5c1STitus Rwantare 
11683746d5c1STitus Rwantare     case PMBUS_VOUT_TRIM:                 /* R/W word */
11693746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
11703746d5c1STitus Rwantare             pmdev->pages[index].vout_trim = pmbus_receive16(pmdev);
11713746d5c1STitus Rwantare         } else {
11723746d5c1STitus Rwantare             goto passthrough;
11733746d5c1STitus Rwantare         }
11743746d5c1STitus Rwantare         break;
11753746d5c1STitus Rwantare 
11763746d5c1STitus Rwantare     case PMBUS_VOUT_CAL_OFFSET:           /* R/W word */
11773746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
11783746d5c1STitus Rwantare             pmdev->pages[index].vout_cal_offset = pmbus_receive16(pmdev);
11793746d5c1STitus Rwantare         } else {
11803746d5c1STitus Rwantare             goto passthrough;
11813746d5c1STitus Rwantare         }
11823746d5c1STitus Rwantare         break;
11833746d5c1STitus Rwantare 
11843746d5c1STitus Rwantare     case PMBUS_VOUT_MAX:                  /* R/W word */
11853746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
11863746d5c1STitus Rwantare             pmdev->pages[index].vout_max = pmbus_receive16(pmdev);
11873746d5c1STitus Rwantare         } else {
11883746d5c1STitus Rwantare             goto passthrough;
11893746d5c1STitus Rwantare         }
11903746d5c1STitus Rwantare         break;
11913746d5c1STitus Rwantare 
11923746d5c1STitus Rwantare     case PMBUS_VOUT_MARGIN_HIGH:          /* R/W word */
11933746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) {
11943746d5c1STitus Rwantare             pmdev->pages[index].vout_margin_high = pmbus_receive16(pmdev);
11953746d5c1STitus Rwantare         } else {
11963746d5c1STitus Rwantare             goto passthrough;
11973746d5c1STitus Rwantare         }
11983746d5c1STitus Rwantare         break;
11993746d5c1STitus Rwantare 
12003746d5c1STitus Rwantare     case PMBUS_VOUT_MARGIN_LOW:           /* R/W word */
12013746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) {
12023746d5c1STitus Rwantare             pmdev->pages[index].vout_margin_low = pmbus_receive16(pmdev);
12033746d5c1STitus Rwantare         } else {
12043746d5c1STitus Rwantare             goto passthrough;
12053746d5c1STitus Rwantare         }
12063746d5c1STitus Rwantare         break;
12073746d5c1STitus Rwantare 
12083746d5c1STitus Rwantare     case PMBUS_VOUT_TRANSITION_RATE:      /* R/W word */
12093746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
12103746d5c1STitus Rwantare             pmdev->pages[index].vout_transition_rate = pmbus_receive16(pmdev);
12113746d5c1STitus Rwantare         } else {
12123746d5c1STitus Rwantare             goto passthrough;
12133746d5c1STitus Rwantare         }
12143746d5c1STitus Rwantare         break;
12153746d5c1STitus Rwantare 
12163746d5c1STitus Rwantare     case PMBUS_VOUT_DROOP:                /* R/W word */
12173746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
12183746d5c1STitus Rwantare             pmdev->pages[index].vout_droop = pmbus_receive16(pmdev);
12193746d5c1STitus Rwantare         } else {
12203746d5c1STitus Rwantare             goto passthrough;
12213746d5c1STitus Rwantare         }
12223746d5c1STitus Rwantare         break;
12233746d5c1STitus Rwantare 
12243746d5c1STitus Rwantare     case PMBUS_VOUT_SCALE_LOOP:           /* R/W word */
12253746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
12263746d5c1STitus Rwantare             pmdev->pages[index].vout_scale_loop = pmbus_receive16(pmdev);
12273746d5c1STitus Rwantare         } else {
12283746d5c1STitus Rwantare             goto passthrough;
12293746d5c1STitus Rwantare         }
12303746d5c1STitus Rwantare         break;
12313746d5c1STitus Rwantare 
12323746d5c1STitus Rwantare     case PMBUS_VOUT_SCALE_MONITOR:        /* R/W word */
12333746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
12343746d5c1STitus Rwantare             pmdev->pages[index].vout_scale_monitor = pmbus_receive16(pmdev);
12353746d5c1STitus Rwantare         } else {
12363746d5c1STitus Rwantare             goto passthrough;
12373746d5c1STitus Rwantare         }
12383746d5c1STitus Rwantare         break;
12393746d5c1STitus Rwantare 
124032480293STitus Rwantare     case PMBUS_VOUT_MIN:                  /* R/W word */
124132480293STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) {
124232480293STitus Rwantare             pmdev->pages[index].vout_min = pmbus_receive16(pmdev);
124332480293STitus Rwantare         } else {
124432480293STitus Rwantare             goto passthrough;
124532480293STitus Rwantare         }
124632480293STitus Rwantare         break;
124732480293STitus Rwantare 
12483746d5c1STitus Rwantare     case PMBUS_POUT_MAX:                  /* R/W word */
12493746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
12503746d5c1STitus Rwantare             pmdev->pages[index].pout_max = pmbus_receive16(pmdev);
12513746d5c1STitus Rwantare         } else {
12523746d5c1STitus Rwantare             goto passthrough;
12533746d5c1STitus Rwantare         }
12543746d5c1STitus Rwantare         break;
12553746d5c1STitus Rwantare 
12563746d5c1STitus Rwantare     case PMBUS_VIN_ON:                    /* R/W word */
12573746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
12583746d5c1STitus Rwantare             pmdev->pages[index].vin_on = pmbus_receive16(pmdev);
12593746d5c1STitus Rwantare         } else {
12603746d5c1STitus Rwantare             goto passthrough;
12613746d5c1STitus Rwantare         }
12623746d5c1STitus Rwantare         break;
12633746d5c1STitus Rwantare 
12643746d5c1STitus Rwantare     case PMBUS_VIN_OFF:                   /* R/W word */
12653746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
12663746d5c1STitus Rwantare             pmdev->pages[index].vin_off = pmbus_receive16(pmdev);
12673746d5c1STitus Rwantare         } else {
12683746d5c1STitus Rwantare             goto passthrough;
12693746d5c1STitus Rwantare         }
12703746d5c1STitus Rwantare         break;
12713746d5c1STitus Rwantare 
12723746d5c1STitus Rwantare     case PMBUS_IOUT_CAL_GAIN:             /* R/W word */
12733746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT_GAIN) {
12743746d5c1STitus Rwantare             pmdev->pages[index].iout_cal_gain = pmbus_receive16(pmdev);
12753746d5c1STitus Rwantare         } else {
12763746d5c1STitus Rwantare             goto passthrough;
12773746d5c1STitus Rwantare         }
12783746d5c1STitus Rwantare         break;
12793746d5c1STitus Rwantare 
12803746d5c1STitus Rwantare     case PMBUS_VOUT_OV_FAULT_LIMIT:       /* R/W word */
12813746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
12823746d5c1STitus Rwantare             pmdev->pages[index].vout_ov_fault_limit = pmbus_receive16(pmdev);
12833746d5c1STitus Rwantare         } else {
12843746d5c1STitus Rwantare             goto passthrough;
12853746d5c1STitus Rwantare         }
12863746d5c1STitus Rwantare         break;
12873746d5c1STitus Rwantare 
12883746d5c1STitus Rwantare     case PMBUS_VOUT_OV_FAULT_RESPONSE:    /* R/W byte */
12893746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
12903746d5c1STitus Rwantare             pmdev->pages[index].vout_ov_fault_response = pmbus_receive8(pmdev);
12913746d5c1STitus Rwantare         } else {
12923746d5c1STitus Rwantare             goto passthrough;
12933746d5c1STitus Rwantare         }
12943746d5c1STitus Rwantare         break;
12953746d5c1STitus Rwantare 
12963746d5c1STitus Rwantare     case PMBUS_VOUT_OV_WARN_LIMIT:        /* R/W word */
12973746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
12983746d5c1STitus Rwantare             pmdev->pages[index].vout_ov_warn_limit = pmbus_receive16(pmdev);
12993746d5c1STitus Rwantare         } else {
13003746d5c1STitus Rwantare             goto passthrough;
13013746d5c1STitus Rwantare         }
13023746d5c1STitus Rwantare         break;
13033746d5c1STitus Rwantare 
13043746d5c1STitus Rwantare     case PMBUS_VOUT_UV_WARN_LIMIT:        /* R/W word */
13053746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
13063746d5c1STitus Rwantare             pmdev->pages[index].vout_uv_warn_limit = pmbus_receive16(pmdev);
13073746d5c1STitus Rwantare         } else {
13083746d5c1STitus Rwantare             goto passthrough;
13093746d5c1STitus Rwantare         }
13103746d5c1STitus Rwantare         break;
13113746d5c1STitus Rwantare 
13123746d5c1STitus Rwantare     case PMBUS_VOUT_UV_FAULT_LIMIT:       /* R/W word */
13133746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
13143746d5c1STitus Rwantare             pmdev->pages[index].vout_uv_fault_limit = pmbus_receive16(pmdev);
13153746d5c1STitus Rwantare         } else {
13163746d5c1STitus Rwantare             goto passthrough;
13173746d5c1STitus Rwantare         }
13183746d5c1STitus Rwantare         break;
13193746d5c1STitus Rwantare 
13203746d5c1STitus Rwantare     case PMBUS_VOUT_UV_FAULT_RESPONSE:    /* R/W byte */
13213746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
13223746d5c1STitus Rwantare             pmdev->pages[index].vout_uv_fault_response = pmbus_receive8(pmdev);
13233746d5c1STitus Rwantare         } else {
13243746d5c1STitus Rwantare             goto passthrough;
13253746d5c1STitus Rwantare         }
13263746d5c1STitus Rwantare         break;
13273746d5c1STitus Rwantare 
13283746d5c1STitus Rwantare     case PMBUS_IOUT_OC_FAULT_LIMIT:       /* R/W word */
13293746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
13303746d5c1STitus Rwantare             pmdev->pages[index].iout_oc_fault_limit = pmbus_receive16(pmdev);
13313746d5c1STitus Rwantare         } else {
13323746d5c1STitus Rwantare             goto passthrough;
13333746d5c1STitus Rwantare         }
13343746d5c1STitus Rwantare         break;
13353746d5c1STitus Rwantare 
13363746d5c1STitus Rwantare     case PMBUS_IOUT_OC_FAULT_RESPONSE:    /* R/W byte */
13373746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
13383746d5c1STitus Rwantare             pmdev->pages[index].iout_oc_fault_response = pmbus_receive8(pmdev);
13393746d5c1STitus Rwantare         } else {
13403746d5c1STitus Rwantare             goto passthrough;
13413746d5c1STitus Rwantare         }
13423746d5c1STitus Rwantare         break;
13433746d5c1STitus Rwantare 
13443746d5c1STitus Rwantare     case PMBUS_IOUT_OC_LV_FAULT_LIMIT:    /* R/W word */
13453746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
13463746d5c1STitus Rwantare             pmdev->pages[index].iout_oc_lv_fault_limit = pmbus_receive16(pmdev);
13473746d5c1STitus Rwantare         } else {
13483746d5c1STitus Rwantare             goto passthrough;
13493746d5c1STitus Rwantare         }
13503746d5c1STitus Rwantare         break;
13513746d5c1STitus Rwantare 
13523746d5c1STitus Rwantare     case PMBUS_IOUT_OC_LV_FAULT_RESPONSE: /* R/W byte */
13533746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
13543746d5c1STitus Rwantare             pmdev->pages[index].iout_oc_lv_fault_response
13553746d5c1STitus Rwantare                 = pmbus_receive8(pmdev);
13563746d5c1STitus Rwantare         } else {
13573746d5c1STitus Rwantare             goto passthrough;
13583746d5c1STitus Rwantare         }
13593746d5c1STitus Rwantare         break;
13603746d5c1STitus Rwantare 
13613746d5c1STitus Rwantare     case PMBUS_IOUT_OC_WARN_LIMIT:        /* R/W word */
13623746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
13633746d5c1STitus Rwantare             pmdev->pages[index].iout_oc_warn_limit = pmbus_receive16(pmdev);
13643746d5c1STitus Rwantare         } else {
13653746d5c1STitus Rwantare             goto passthrough;
13663746d5c1STitus Rwantare         }
13673746d5c1STitus Rwantare         break;
13683746d5c1STitus Rwantare 
13693746d5c1STitus Rwantare     case PMBUS_IOUT_UC_FAULT_LIMIT:       /* R/W word */
13703746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
13713746d5c1STitus Rwantare             pmdev->pages[index].iout_uc_fault_limit = pmbus_receive16(pmdev);
13723746d5c1STitus Rwantare         } else {
13733746d5c1STitus Rwantare             goto passthrough;
13743746d5c1STitus Rwantare         }
13753746d5c1STitus Rwantare         break;
13763746d5c1STitus Rwantare 
13773746d5c1STitus Rwantare     case PMBUS_IOUT_UC_FAULT_RESPONSE:    /* R/W byte */
13783746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
13793746d5c1STitus Rwantare             pmdev->pages[index].iout_uc_fault_response = pmbus_receive8(pmdev);
13803746d5c1STitus Rwantare         } else {
13813746d5c1STitus Rwantare             goto passthrough;
13823746d5c1STitus Rwantare         }
13833746d5c1STitus Rwantare         break;
13843746d5c1STitus Rwantare 
13853746d5c1STitus Rwantare     case PMBUS_OT_FAULT_LIMIT:            /* R/W word */
13863746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
13873746d5c1STitus Rwantare             pmdev->pages[index].ot_fault_limit = pmbus_receive16(pmdev);
13883746d5c1STitus Rwantare         } else {
13893746d5c1STitus Rwantare             goto passthrough;
13903746d5c1STitus Rwantare         }
13913746d5c1STitus Rwantare         break;
13923746d5c1STitus Rwantare 
13933746d5c1STitus Rwantare     case PMBUS_OT_FAULT_RESPONSE:         /* R/W byte */
13943746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
13953746d5c1STitus Rwantare             pmdev->pages[index].ot_fault_response = pmbus_receive8(pmdev);
13963746d5c1STitus Rwantare         } else {
13973746d5c1STitus Rwantare             goto passthrough;
13983746d5c1STitus Rwantare         }
13993746d5c1STitus Rwantare         break;
14003746d5c1STitus Rwantare 
14013746d5c1STitus Rwantare     case PMBUS_OT_WARN_LIMIT:             /* R/W word */
14023746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
14033746d5c1STitus Rwantare             pmdev->pages[index].ot_warn_limit = pmbus_receive16(pmdev);
14043746d5c1STitus Rwantare         } else {
14053746d5c1STitus Rwantare             goto passthrough;
14063746d5c1STitus Rwantare         }
14073746d5c1STitus Rwantare         break;
14083746d5c1STitus Rwantare 
14093746d5c1STitus Rwantare     case PMBUS_UT_WARN_LIMIT:             /* R/W word */
14103746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
14113746d5c1STitus Rwantare             pmdev->pages[index].ut_warn_limit = pmbus_receive16(pmdev);
14123746d5c1STitus Rwantare         } else {
14133746d5c1STitus Rwantare             goto passthrough;
14143746d5c1STitus Rwantare         }
14153746d5c1STitus Rwantare         break;
14163746d5c1STitus Rwantare 
14173746d5c1STitus Rwantare     case PMBUS_UT_FAULT_LIMIT:            /* R/W word */
14183746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
14193746d5c1STitus Rwantare             pmdev->pages[index].ut_fault_limit = pmbus_receive16(pmdev);
14203746d5c1STitus Rwantare         } else {
14213746d5c1STitus Rwantare             goto passthrough;
14223746d5c1STitus Rwantare         }
14233746d5c1STitus Rwantare         break;
14243746d5c1STitus Rwantare 
14253746d5c1STitus Rwantare     case PMBUS_UT_FAULT_RESPONSE:         /* R/W byte */
14263746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
14273746d5c1STitus Rwantare             pmdev->pages[index].ut_fault_response = pmbus_receive8(pmdev);
14283746d5c1STitus Rwantare         } else {
14293746d5c1STitus Rwantare             goto passthrough;
14303746d5c1STitus Rwantare         }
14313746d5c1STitus Rwantare         break;
14323746d5c1STitus Rwantare 
14333746d5c1STitus Rwantare     case PMBUS_VIN_OV_FAULT_LIMIT:        /* R/W word */
14343746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
14353746d5c1STitus Rwantare             pmdev->pages[index].vin_ov_fault_limit = pmbus_receive16(pmdev);
14363746d5c1STitus Rwantare         } else {
14373746d5c1STitus Rwantare             goto passthrough;
14383746d5c1STitus Rwantare         }
14393746d5c1STitus Rwantare         break;
14403746d5c1STitus Rwantare 
14413746d5c1STitus Rwantare     case PMBUS_VIN_OV_FAULT_RESPONSE:     /* R/W byte */
14423746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
14433746d5c1STitus Rwantare             pmdev->pages[index].vin_ov_fault_response = pmbus_receive8(pmdev);
14443746d5c1STitus Rwantare         } else {
14453746d5c1STitus Rwantare             goto passthrough;
14463746d5c1STitus Rwantare         }
14473746d5c1STitus Rwantare         break;
14483746d5c1STitus Rwantare 
14493746d5c1STitus Rwantare     case PMBUS_VIN_OV_WARN_LIMIT:         /* R/W word */
14503746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
14513746d5c1STitus Rwantare             pmdev->pages[index].vin_ov_warn_limit = pmbus_receive16(pmdev);
14523746d5c1STitus Rwantare         } else {
14533746d5c1STitus Rwantare             goto passthrough;
14543746d5c1STitus Rwantare         }
14553746d5c1STitus Rwantare         break;
14563746d5c1STitus Rwantare 
14573746d5c1STitus Rwantare     case PMBUS_VIN_UV_WARN_LIMIT:         /* R/W word */
14583746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
14593746d5c1STitus Rwantare             pmdev->pages[index].vin_uv_warn_limit = pmbus_receive16(pmdev);
14603746d5c1STitus Rwantare         } else {
14613746d5c1STitus Rwantare             goto passthrough;
14623746d5c1STitus Rwantare         }
14633746d5c1STitus Rwantare         break;
14643746d5c1STitus Rwantare 
14653746d5c1STitus Rwantare     case PMBUS_VIN_UV_FAULT_LIMIT:        /* R/W word */
14663746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
14673746d5c1STitus Rwantare             pmdev->pages[index].vin_uv_fault_limit = pmbus_receive16(pmdev);
14683746d5c1STitus Rwantare         } else {
14693746d5c1STitus Rwantare             goto passthrough;
14703746d5c1STitus Rwantare         }
14713746d5c1STitus Rwantare         break;
14723746d5c1STitus Rwantare 
14733746d5c1STitus Rwantare     case PMBUS_VIN_UV_FAULT_RESPONSE:     /* R/W byte */
14743746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
14753746d5c1STitus Rwantare             pmdev->pages[index].vin_uv_fault_response = pmbus_receive8(pmdev);
14763746d5c1STitus Rwantare         } else {
14773746d5c1STitus Rwantare             goto passthrough;
14783746d5c1STitus Rwantare         }
14793746d5c1STitus Rwantare         break;
14803746d5c1STitus Rwantare 
14813746d5c1STitus Rwantare     case PMBUS_IIN_OC_FAULT_LIMIT:        /* R/W word */
14823746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
14833746d5c1STitus Rwantare             pmdev->pages[index].iin_oc_fault_limit = pmbus_receive16(pmdev);
14843746d5c1STitus Rwantare         } else {
14853746d5c1STitus Rwantare             goto passthrough;
14863746d5c1STitus Rwantare         }
14873746d5c1STitus Rwantare         break;
14883746d5c1STitus Rwantare 
14893746d5c1STitus Rwantare     case PMBUS_IIN_OC_FAULT_RESPONSE:     /* R/W byte */
14903746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
14913746d5c1STitus Rwantare             pmdev->pages[index].iin_oc_fault_response = pmbus_receive8(pmdev);
14923746d5c1STitus Rwantare         } else {
14933746d5c1STitus Rwantare             goto passthrough;
14943746d5c1STitus Rwantare         }
14953746d5c1STitus Rwantare         break;
14963746d5c1STitus Rwantare 
14973746d5c1STitus Rwantare     case PMBUS_IIN_OC_WARN_LIMIT:         /* R/W word */
14983746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
14993746d5c1STitus Rwantare             pmdev->pages[index].iin_oc_warn_limit = pmbus_receive16(pmdev);
15003746d5c1STitus Rwantare         } else {
15013746d5c1STitus Rwantare             goto passthrough;
15023746d5c1STitus Rwantare         }
15033746d5c1STitus Rwantare         break;
15043746d5c1STitus Rwantare 
15053746d5c1STitus Rwantare     case PMBUS_POUT_OP_FAULT_LIMIT:       /* R/W word */
15063746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
15073746d5c1STitus Rwantare             pmdev->pages[index].pout_op_fault_limit = pmbus_receive16(pmdev);
15083746d5c1STitus Rwantare         } else {
15093746d5c1STitus Rwantare             goto passthrough;
15103746d5c1STitus Rwantare         }
15113746d5c1STitus Rwantare         break;
15123746d5c1STitus Rwantare 
15133746d5c1STitus Rwantare     case PMBUS_POUT_OP_FAULT_RESPONSE:    /* R/W byte */
15143746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
15153746d5c1STitus Rwantare             pmdev->pages[index].pout_op_fault_response = pmbus_receive8(pmdev);
15163746d5c1STitus Rwantare         } else {
15173746d5c1STitus Rwantare             goto passthrough;
15183746d5c1STitus Rwantare         }
15193746d5c1STitus Rwantare         break;
15203746d5c1STitus Rwantare 
15213746d5c1STitus Rwantare     case PMBUS_POUT_OP_WARN_LIMIT:        /* R/W word */
15223746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
15233746d5c1STitus Rwantare             pmdev->pages[index].pout_op_warn_limit = pmbus_receive16(pmdev);
15243746d5c1STitus Rwantare         } else {
15253746d5c1STitus Rwantare             goto passthrough;
15263746d5c1STitus Rwantare         }
15273746d5c1STitus Rwantare         break;
15283746d5c1STitus Rwantare 
15293746d5c1STitus Rwantare     case PMBUS_PIN_OP_WARN_LIMIT:         /* R/W word */
15303746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_PIN) {
15313746d5c1STitus Rwantare             pmdev->pages[index].pin_op_warn_limit = pmbus_receive16(pmdev);
15323746d5c1STitus Rwantare         } else {
15333746d5c1STitus Rwantare             goto passthrough;
15343746d5c1STitus Rwantare         }
15353746d5c1STitus Rwantare         break;
15363746d5c1STitus Rwantare 
15373746d5c1STitus Rwantare     case PMBUS_STATUS_BYTE:               /* R/W byte */
15383746d5c1STitus Rwantare         pmdev->pages[index].status_word = pmbus_receive8(pmdev);
15393746d5c1STitus Rwantare         break;
15403746d5c1STitus Rwantare 
15413746d5c1STitus Rwantare     case PMBUS_STATUS_WORD:               /* R/W word */
15423746d5c1STitus Rwantare         pmdev->pages[index].status_word = pmbus_receive16(pmdev);
15433746d5c1STitus Rwantare         break;
15443746d5c1STitus Rwantare 
15453746d5c1STitus Rwantare     case PMBUS_STATUS_VOUT:               /* R/W byte */
15463746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
15473746d5c1STitus Rwantare             pmdev->pages[index].status_vout = pmbus_receive8(pmdev);
15483746d5c1STitus Rwantare         } else {
15493746d5c1STitus Rwantare             goto passthrough;
15503746d5c1STitus Rwantare         }
15513746d5c1STitus Rwantare         break;
15523746d5c1STitus Rwantare 
15533746d5c1STitus Rwantare     case PMBUS_STATUS_IOUT:               /* R/W byte */
15543746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
15553746d5c1STitus Rwantare             pmdev->pages[index].status_iout = pmbus_receive8(pmdev);
15563746d5c1STitus Rwantare         } else {
15573746d5c1STitus Rwantare             goto passthrough;
15583746d5c1STitus Rwantare         }
15593746d5c1STitus Rwantare         break;
15603746d5c1STitus Rwantare 
15613746d5c1STitus Rwantare     case PMBUS_STATUS_INPUT:              /* R/W byte */
15623746d5c1STitus Rwantare         pmdev->pages[index].status_input = pmbus_receive8(pmdev);
15633746d5c1STitus Rwantare         break;
15643746d5c1STitus Rwantare 
15653746d5c1STitus Rwantare     case PMBUS_STATUS_TEMPERATURE:        /* R/W byte */
15663746d5c1STitus Rwantare         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
15673746d5c1STitus Rwantare             pmdev->pages[index].status_temperature = pmbus_receive8(pmdev);
15683746d5c1STitus Rwantare         } else {
15693746d5c1STitus Rwantare             goto passthrough;
15703746d5c1STitus Rwantare         }
15713746d5c1STitus Rwantare         break;
15723746d5c1STitus Rwantare 
15733746d5c1STitus Rwantare     case PMBUS_STATUS_CML:                /* R/W byte */
15743746d5c1STitus Rwantare         pmdev->pages[index].status_cml = pmbus_receive8(pmdev);
15753746d5c1STitus Rwantare         break;
15763746d5c1STitus Rwantare 
15773746d5c1STitus Rwantare     case PMBUS_STATUS_OTHER:              /* R/W byte */
15783746d5c1STitus Rwantare         pmdev->pages[index].status_other = pmbus_receive8(pmdev);
15793746d5c1STitus Rwantare         break;
15803746d5c1STitus Rwantare 
158132480293STitus Rwantare     case PMBUS_STATUS_MFR_SPECIFIC:        /* R/W byte */
158232480293STitus Rwantare         pmdev->pages[index].status_mfr_specific = pmbus_receive8(pmdev);
158332480293STitus Rwantare         break;
158432480293STitus Rwantare 
15853746d5c1STitus Rwantare     case PMBUS_PAGE_PLUS_READ:            /* Block Read-only */
15863746d5c1STitus Rwantare     case PMBUS_CAPABILITY:                /* Read-Only byte */
15873746d5c1STitus Rwantare     case PMBUS_COEFFICIENTS:              /* Read-only block 5 bytes */
15883746d5c1STitus Rwantare     case PMBUS_READ_EIN:                  /* Read-Only block 5 bytes */
15893746d5c1STitus Rwantare     case PMBUS_READ_EOUT:                 /* Read-Only block 5 bytes */
15903746d5c1STitus Rwantare     case PMBUS_READ_VIN:                  /* Read-Only word */
15913746d5c1STitus Rwantare     case PMBUS_READ_IIN:                  /* Read-Only word */
15923746d5c1STitus Rwantare     case PMBUS_READ_VCAP:                 /* Read-Only word */
15933746d5c1STitus Rwantare     case PMBUS_READ_VOUT:                 /* Read-Only word */
15943746d5c1STitus Rwantare     case PMBUS_READ_IOUT:                 /* Read-Only word */
15953746d5c1STitus Rwantare     case PMBUS_READ_TEMPERATURE_1:        /* Read-Only word */
15963746d5c1STitus Rwantare     case PMBUS_READ_TEMPERATURE_2:        /* Read-Only word */
15973746d5c1STitus Rwantare     case PMBUS_READ_TEMPERATURE_3:        /* Read-Only word */
15983746d5c1STitus Rwantare     case PMBUS_READ_FAN_SPEED_1:          /* Read-Only word */
15993746d5c1STitus Rwantare     case PMBUS_READ_FAN_SPEED_2:          /* Read-Only word */
16003746d5c1STitus Rwantare     case PMBUS_READ_FAN_SPEED_3:          /* Read-Only word */
16013746d5c1STitus Rwantare     case PMBUS_READ_FAN_SPEED_4:          /* Read-Only word */
16023746d5c1STitus Rwantare     case PMBUS_READ_DUTY_CYCLE:           /* Read-Only word */
16033746d5c1STitus Rwantare     case PMBUS_READ_FREQUENCY:            /* Read-Only word */
16043746d5c1STitus Rwantare     case PMBUS_READ_POUT:                 /* Read-Only word */
16053746d5c1STitus Rwantare     case PMBUS_READ_PIN:                  /* Read-Only word */
16063746d5c1STitus Rwantare     case PMBUS_REVISION:                  /* Read-Only byte */
16073746d5c1STitus Rwantare     case PMBUS_APP_PROFILE_SUPPORT:       /* Read-Only block-read */
16083746d5c1STitus Rwantare     case PMBUS_MFR_VIN_MIN:               /* Read-Only word */
16093746d5c1STitus Rwantare     case PMBUS_MFR_VIN_MAX:               /* Read-Only word */
16103746d5c1STitus Rwantare     case PMBUS_MFR_IIN_MAX:               /* Read-Only word */
16113746d5c1STitus Rwantare     case PMBUS_MFR_PIN_MAX:               /* Read-Only word */
16123746d5c1STitus Rwantare     case PMBUS_MFR_VOUT_MIN:              /* Read-Only word */
16133746d5c1STitus Rwantare     case PMBUS_MFR_VOUT_MAX:              /* Read-Only word */
16143746d5c1STitus Rwantare     case PMBUS_MFR_IOUT_MAX:              /* Read-Only word */
16153746d5c1STitus Rwantare     case PMBUS_MFR_POUT_MAX:              /* Read-Only word */
16163746d5c1STitus Rwantare     case PMBUS_MFR_TAMBIENT_MAX:          /* Read-Only word */
16173746d5c1STitus Rwantare     case PMBUS_MFR_TAMBIENT_MIN:          /* Read-Only word */
16183746d5c1STitus Rwantare     case PMBUS_MFR_EFFICIENCY_LL:         /* Read-Only block 14 bytes */
16193746d5c1STitus Rwantare     case PMBUS_MFR_EFFICIENCY_HL:         /* Read-Only block 14 bytes */
16203746d5c1STitus Rwantare     case PMBUS_MFR_PIN_ACCURACY:          /* Read-Only byte */
16213746d5c1STitus Rwantare     case PMBUS_IC_DEVICE_ID:              /* Read-Only block-read */
16223746d5c1STitus Rwantare     case PMBUS_IC_DEVICE_REV:             /* Read-Only block-read */
16233746d5c1STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
16243746d5c1STitus Rwantare                       "%s: writing to read-only register 0x%02x\n",
16253746d5c1STitus Rwantare                       __func__, pmdev->code);
16263746d5c1STitus Rwantare         break;
16273746d5c1STitus Rwantare 
16283746d5c1STitus Rwantare passthrough:
1629*8fa21b80SMichael Tokarev     /* Unimplemented registers get passed to the device */
16303746d5c1STitus Rwantare     default:
16313746d5c1STitus Rwantare         if (pmdc->write_data) {
16323746d5c1STitus Rwantare             ret = pmdc->write_data(pmdev, buf, len);
16333746d5c1STitus Rwantare         }
16343746d5c1STitus Rwantare         break;
16353746d5c1STitus Rwantare     }
16363746d5c1STitus Rwantare     pmbus_check_limits(pmdev);
16373746d5c1STitus Rwantare     pmdev->in_buf_len = 0;
16383746d5c1STitus Rwantare     return ret;
16393746d5c1STitus Rwantare }
16403746d5c1STitus Rwantare 
16413746d5c1STitus Rwantare int pmbus_page_config(PMBusDevice *pmdev, uint8_t index, uint64_t flags)
16423746d5c1STitus Rwantare {
16433746d5c1STitus Rwantare     if (!pmdev->pages) { /* allocate memory for pages on first use */
16443746d5c1STitus Rwantare         pmbus_pages_alloc(pmdev);
16453746d5c1STitus Rwantare     }
16463746d5c1STitus Rwantare 
16473746d5c1STitus Rwantare     /* The 0xFF page is special for commands applying to all pages */
16483746d5c1STitus Rwantare     if (index == PB_ALL_PAGES) {
16493746d5c1STitus Rwantare         for (int i = 0; i < pmdev->num_pages; i++) {
16503746d5c1STitus Rwantare             pmdev->pages[i].page_flags = flags;
16513746d5c1STitus Rwantare         }
16523746d5c1STitus Rwantare         return 0;
16533746d5c1STitus Rwantare     }
16543746d5c1STitus Rwantare 
16553746d5c1STitus Rwantare     if (index > pmdev->num_pages - 1) {
16563746d5c1STitus Rwantare         qemu_log_mask(LOG_GUEST_ERROR,
16573746d5c1STitus Rwantare                       "%s: index %u is out of range\n",
16583746d5c1STitus Rwantare                       __func__, index);
16593746d5c1STitus Rwantare         return -1;
16603746d5c1STitus Rwantare     }
16613746d5c1STitus Rwantare 
16623746d5c1STitus Rwantare     pmdev->pages[index].page_flags = flags;
16633746d5c1STitus Rwantare 
16643746d5c1STitus Rwantare     return 0;
16653746d5c1STitus Rwantare }
16663746d5c1STitus Rwantare 
16673746d5c1STitus Rwantare /* TODO: include pmbus page info in vmstate */
16683746d5c1STitus Rwantare const VMStateDescription vmstate_pmbus_device = {
16693746d5c1STitus Rwantare     .name = TYPE_PMBUS_DEVICE,
16703746d5c1STitus Rwantare     .version_id = 0,
16713746d5c1STitus Rwantare     .minimum_version_id = 0,
16723746d5c1STitus Rwantare     .fields = (VMStateField[]) {
16733746d5c1STitus Rwantare         VMSTATE_SMBUS_DEVICE(smb, PMBusDevice),
16743746d5c1STitus Rwantare         VMSTATE_UINT8(num_pages, PMBusDevice),
16753746d5c1STitus Rwantare         VMSTATE_UINT8(code, PMBusDevice),
16763746d5c1STitus Rwantare         VMSTATE_UINT8(page, PMBusDevice),
16773746d5c1STitus Rwantare         VMSTATE_UINT8(capability, PMBusDevice),
16783746d5c1STitus Rwantare         VMSTATE_END_OF_LIST()
16793746d5c1STitus Rwantare     }
16803746d5c1STitus Rwantare };
16813746d5c1STitus Rwantare 
16823746d5c1STitus Rwantare static void pmbus_device_finalize(Object *obj)
16833746d5c1STitus Rwantare {
16843746d5c1STitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
16853746d5c1STitus Rwantare     g_free(pmdev->pages);
16863746d5c1STitus Rwantare }
16873746d5c1STitus Rwantare 
16883746d5c1STitus Rwantare static void pmbus_device_class_init(ObjectClass *klass, void *data)
16893746d5c1STitus Rwantare {
16903746d5c1STitus Rwantare     SMBusDeviceClass *k = SMBUS_DEVICE_CLASS(klass);
16913746d5c1STitus Rwantare 
16923746d5c1STitus Rwantare     k->quick_cmd = pmbus_quick_cmd;
16933746d5c1STitus Rwantare     k->write_data = pmbus_write_data;
16943746d5c1STitus Rwantare     k->receive_byte = pmbus_receive_byte;
16953746d5c1STitus Rwantare }
16963746d5c1STitus Rwantare 
16973746d5c1STitus Rwantare static const TypeInfo pmbus_device_type_info = {
16983746d5c1STitus Rwantare     .name = TYPE_PMBUS_DEVICE,
16993746d5c1STitus Rwantare     .parent = TYPE_SMBUS_DEVICE,
17003746d5c1STitus Rwantare     .instance_size = sizeof(PMBusDevice),
17013746d5c1STitus Rwantare     .instance_finalize = pmbus_device_finalize,
17023746d5c1STitus Rwantare     .abstract = true,
17033746d5c1STitus Rwantare     .class_size = sizeof(PMBusDeviceClass),
17043746d5c1STitus Rwantare     .class_init = pmbus_device_class_init,
17053746d5c1STitus Rwantare };
17063746d5c1STitus Rwantare 
17073746d5c1STitus Rwantare static void pmbus_device_register_types(void)
17083746d5c1STitus Rwantare {
17093746d5c1STitus Rwantare     type_register_static(&pmbus_device_type_info);
17103746d5c1STitus Rwantare }
17113746d5c1STitus Rwantare 
17123746d5c1STitus Rwantare type_init(pmbus_device_register_types)
1713