qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

pmbus_device.c (55497B)


      1 /*
      2  * PMBus wrapper over SMBus
      3  *
      4  * Copyright 2021 Google LLC
      5  *
      6  * SPDX-License-Identifier: GPL-2.0-or-later
      7  */
      8 
      9 #include "qemu/osdep.h"
     10 #include <math.h>
     11 #include <string.h>
     12 #include "hw/i2c/pmbus_device.h"
     13 #include "migration/vmstate.h"
     14 #include "qemu/module.h"
     15 #include "qemu/log.h"
     16 
     17 uint16_t pmbus_data2direct_mode(PMBusCoefficients c, uint32_t value)
     18 {
     19     /* R is usually negative to fit large readings into 16 bits */
     20     uint16_t y = (c.m * value + c.b) * pow(10, c.R);
     21     return y;
     22 }
     23 
     24 uint32_t pmbus_direct_mode2data(PMBusCoefficients c, uint16_t value)
     25 {
     26     /* X = (Y * 10^-R - b) / m */
     27     uint32_t x = (value / pow(10, c.R) - c.b) / c.m;
     28     return x;
     29 }
     30 
     31 uint16_t pmbus_data2linear_mode(uint16_t value, int exp)
     32 {
     33     /* L = D * 2^(-e) */
     34     if (exp < 0) {
     35         return value << (-exp);
     36     }
     37     return value >> exp;
     38 }
     39 
     40 uint16_t pmbus_linear_mode2data(uint16_t value, int exp)
     41 {
     42     /* D = L * 2^e */
     43     if (exp < 0) {
     44         return value >> (-exp);
     45     }
     46     return value << exp;
     47 }
     48 
     49 void pmbus_send(PMBusDevice *pmdev, const uint8_t *data, uint16_t len)
     50 {
     51     if (pmdev->out_buf_len + len > SMBUS_DATA_MAX_LEN) {
     52         qemu_log_mask(LOG_GUEST_ERROR,
     53                       "PMBus device tried to send too much data");
     54         len = 0;
     55     }
     56 
     57     for (int i = len - 1; i >= 0; i--) {
     58         pmdev->out_buf[i + pmdev->out_buf_len] = data[len - i - 1];
     59     }
     60     pmdev->out_buf_len += len;
     61 }
     62 
     63 /* Internal only, convert unsigned ints to the little endian bus */
     64 static void pmbus_send_uint(PMBusDevice *pmdev, uint64_t data, uint8_t size)
     65 {
     66     uint8_t bytes[8];
     67     g_assert(size <= 8);
     68 
     69     for (int i = 0; i < size; i++) {
     70         bytes[i] = data & 0xFF;
     71         data = data >> 8;
     72     }
     73     pmbus_send(pmdev, bytes, size);
     74 }
     75 
     76 void pmbus_send8(PMBusDevice *pmdev, uint8_t data)
     77 {
     78     pmbus_send_uint(pmdev, data, 1);
     79 }
     80 
     81 void pmbus_send16(PMBusDevice *pmdev, uint16_t data)
     82 {
     83     pmbus_send_uint(pmdev, data, 2);
     84 }
     85 
     86 void pmbus_send32(PMBusDevice *pmdev, uint32_t data)
     87 {
     88     pmbus_send_uint(pmdev, data, 4);
     89 }
     90 
     91 void pmbus_send64(PMBusDevice *pmdev, uint64_t data)
     92 {
     93     pmbus_send_uint(pmdev, data, 8);
     94 }
     95 
     96 void pmbus_send_string(PMBusDevice *pmdev, const char *data)
     97 {
     98     size_t len = strlen(data);
     99     g_assert(len > 0);
    100     g_assert(len + pmdev->out_buf_len < SMBUS_DATA_MAX_LEN);
    101     pmdev->out_buf[len + pmdev->out_buf_len] = len;
    102 
    103     for (int i = len - 1; i >= 0; i--) {
    104         pmdev->out_buf[i + pmdev->out_buf_len] = data[len - 1 - i];
    105     }
    106     pmdev->out_buf_len += len + 1;
    107 }
    108 
    109 
    110 static uint64_t pmbus_receive_uint(PMBusDevice *pmdev)
    111 {
    112     uint64_t ret = 0;
    113 
    114     /* Exclude command code from return value */
    115     pmdev->in_buf++;
    116     pmdev->in_buf_len--;
    117 
    118     for (int i = pmdev->in_buf_len - 1; i >= 0; i--) {
    119         ret = ret << 8 | pmdev->in_buf[i];
    120     }
    121     return ret;
    122 }
    123 
    124 uint8_t pmbus_receive8(PMBusDevice *pmdev)
    125 {
    126     if (pmdev->in_buf_len - 1 != 1) {
    127         qemu_log_mask(LOG_GUEST_ERROR,
    128                       "%s: length mismatch. Expected 1 byte, got %d bytes\n",
    129                       __func__, pmdev->in_buf_len - 1);
    130     }
    131     return pmbus_receive_uint(pmdev);
    132 }
    133 
    134 uint16_t pmbus_receive16(PMBusDevice *pmdev)
    135 {
    136     if (pmdev->in_buf_len - 1 != 2) {
    137         qemu_log_mask(LOG_GUEST_ERROR,
    138                       "%s: length mismatch. Expected 2 bytes, got %d bytes\n",
    139                       __func__, pmdev->in_buf_len - 1);
    140     }
    141     return pmbus_receive_uint(pmdev);
    142 }
    143 
    144 uint32_t pmbus_receive32(PMBusDevice *pmdev)
    145 {
    146     if (pmdev->in_buf_len - 1 != 4) {
    147         qemu_log_mask(LOG_GUEST_ERROR,
    148                       "%s: length mismatch. Expected 4 bytes, got %d bytes\n",
    149                       __func__, pmdev->in_buf_len - 1);
    150     }
    151     return pmbus_receive_uint(pmdev);
    152 }
    153 
    154 uint64_t pmbus_receive64(PMBusDevice *pmdev)
    155 {
    156     if (pmdev->in_buf_len - 1 != 8) {
    157         qemu_log_mask(LOG_GUEST_ERROR,
    158                       "%s: length mismatch. Expected 8 bytes, got %d bytes\n",
    159                       __func__, pmdev->in_buf_len - 1);
    160     }
    161     return pmbus_receive_uint(pmdev);
    162 }
    163 
    164 static uint8_t pmbus_out_buf_pop(PMBusDevice *pmdev)
    165 {
    166     if (pmdev->out_buf_len == 0) {
    167         qemu_log_mask(LOG_GUEST_ERROR,
    168                       "%s: tried to read from empty buffer",
    169                       __func__);
    170         return PMBUS_ERR_BYTE;
    171     }
    172     uint8_t data = pmdev->out_buf[pmdev->out_buf_len - 1];
    173     pmdev->out_buf_len--;
    174     return data;
    175 }
    176 
    177 static void pmbus_quick_cmd(SMBusDevice *smd, uint8_t read)
    178 {
    179     PMBusDevice *pmdev = PMBUS_DEVICE(smd);
    180     PMBusDeviceClass *pmdc = PMBUS_DEVICE_GET_CLASS(pmdev);
    181 
    182     if (pmdc->quick_cmd) {
    183         pmdc->quick_cmd(pmdev, read);
    184     }
    185 }
    186 
    187 static void pmbus_pages_alloc(PMBusDevice *pmdev)
    188 {
    189     /* some PMBus devices don't use the PAGE command, so they get 1 page */
    190     PMBusDeviceClass *k = PMBUS_DEVICE_GET_CLASS(pmdev);
    191     if (k->device_num_pages == 0) {
    192         k->device_num_pages = 1;
    193     }
    194     pmdev->num_pages = k->device_num_pages;
    195     pmdev->pages = g_new0(PMBusPage, k->device_num_pages);
    196 }
    197 
    198 void pmbus_check_limits(PMBusDevice *pmdev)
    199 {
    200     for (int i = 0; i < pmdev->num_pages; i++) {
    201         if ((pmdev->pages[i].operation & PB_OP_ON) == 0) {
    202             continue;   /* don't check powered off devices */
    203         }
    204 
    205         if (pmdev->pages[i].read_vout > pmdev->pages[i].vout_ov_fault_limit) {
    206             pmdev->pages[i].status_word |= PB_STATUS_VOUT;
    207             pmdev->pages[i].status_vout |= PB_STATUS_VOUT_OV_FAULT;
    208         }
    209 
    210         if (pmdev->pages[i].read_vout > pmdev->pages[i].vout_ov_warn_limit) {
    211             pmdev->pages[i].status_word |= PB_STATUS_VOUT;
    212             pmdev->pages[i].status_vout |= PB_STATUS_VOUT_OV_WARN;
    213         }
    214 
    215         if (pmdev->pages[i].read_vout < pmdev->pages[i].vout_uv_warn_limit) {
    216             pmdev->pages[i].status_word |= PB_STATUS_VOUT;
    217             pmdev->pages[i].status_vout |= PB_STATUS_VOUT_UV_WARN;
    218         }
    219 
    220         if (pmdev->pages[i].read_vout < pmdev->pages[i].vout_uv_fault_limit) {
    221             pmdev->pages[i].status_word |= PB_STATUS_VOUT;
    222             pmdev->pages[i].status_vout |= PB_STATUS_VOUT_UV_FAULT;
    223         }
    224 
    225         if (pmdev->pages[i].read_vin > pmdev->pages[i].vin_ov_warn_limit) {
    226             pmdev->pages[i].status_word |= PB_STATUS_INPUT;
    227             pmdev->pages[i].status_input |= PB_STATUS_INPUT_VIN_OV_WARN;
    228         }
    229 
    230         if (pmdev->pages[i].read_vin < pmdev->pages[i].vin_uv_warn_limit) {
    231             pmdev->pages[i].status_word |= PB_STATUS_INPUT;
    232             pmdev->pages[i].status_input |= PB_STATUS_INPUT_VIN_UV_WARN;
    233         }
    234 
    235         if (pmdev->pages[i].read_iout > pmdev->pages[i].iout_oc_warn_limit) {
    236             pmdev->pages[i].status_word |= PB_STATUS_IOUT_POUT;
    237             pmdev->pages[i].status_iout |= PB_STATUS_IOUT_OC_WARN;
    238         }
    239 
    240         if (pmdev->pages[i].read_iout > pmdev->pages[i].iout_oc_fault_limit) {
    241             pmdev->pages[i].status_word |= PB_STATUS_IOUT_POUT;
    242             pmdev->pages[i].status_iout |= PB_STATUS_IOUT_OC_FAULT;
    243         }
    244 
    245         if (pmdev->pages[i].read_pin > pmdev->pages[i].pin_op_warn_limit) {
    246             pmdev->pages[i].status_word |= PB_STATUS_INPUT;
    247             pmdev->pages[i].status_input |= PB_STATUS_INPUT_PIN_OP_WARN;
    248         }
    249 
    250         if (pmdev->pages[i].read_temperature_1
    251                 > pmdev->pages[i].ot_fault_limit) {
    252             pmdev->pages[i].status_word |= PB_STATUS_TEMPERATURE;
    253             pmdev->pages[i].status_temperature |= PB_STATUS_OT_FAULT;
    254         }
    255 
    256         if (pmdev->pages[i].read_temperature_1
    257                 > pmdev->pages[i].ot_warn_limit) {
    258             pmdev->pages[i].status_word |= PB_STATUS_TEMPERATURE;
    259             pmdev->pages[i].status_temperature |= PB_STATUS_OT_WARN;
    260         }
    261     }
    262 }
    263 
    264 void pmbus_idle(PMBusDevice *pmdev)
    265 {
    266     pmdev->code = PMBUS_IDLE_STATE;
    267 }
    268 
    269 /* assert the status_cml error upon receipt of malformed command */
    270 static void pmbus_cml_error(PMBusDevice *pmdev)
    271 {
    272     for (int i = 0; i < pmdev->num_pages; i++) {
    273         pmdev->pages[i].status_word |= PMBUS_STATUS_CML;
    274         pmdev->pages[i].status_cml |= PB_CML_FAULT_INVALID_CMD;
    275     }
    276 }
    277 
    278 static uint8_t pmbus_receive_byte(SMBusDevice *smd)
    279 {
    280     PMBusDevice *pmdev = PMBUS_DEVICE(smd);
    281     PMBusDeviceClass *pmdc = PMBUS_DEVICE_GET_CLASS(pmdev);
    282     uint8_t ret = PMBUS_ERR_BYTE;
    283     uint8_t index;
    284 
    285     if (pmdev->out_buf_len != 0) {
    286         ret = pmbus_out_buf_pop(pmdev);
    287         return ret;
    288     }
    289 
    290     /*
    291      * Reading from all pages will return the value from page 0,
    292      * means that all subsequent commands are to be applied to all output.
    293      */
    294     if (pmdev->page == PB_ALL_PAGES) {
    295         index = 0;
    296     } else if (pmdev->page > pmdev->num_pages - 1) {
    297         qemu_log_mask(LOG_GUEST_ERROR,
    298                       "%s: page %d is out of range\n",
    299                       __func__, pmdev->page);
    300         pmbus_cml_error(pmdev);
    301         return PMBUS_ERR_BYTE;
    302     } else {
    303         index = pmdev->page;
    304     }
    305 
    306     switch (pmdev->code) {
    307     case PMBUS_PAGE:
    308         pmbus_send8(pmdev, pmdev->page);
    309         break;
    310 
    311     case PMBUS_OPERATION:                 /* R/W byte */
    312         pmbus_send8(pmdev, pmdev->pages[index].operation);
    313         break;
    314 
    315     case PMBUS_ON_OFF_CONFIG:             /* R/W byte */
    316         pmbus_send8(pmdev, pmdev->pages[index].on_off_config);
    317         break;
    318 
    319     case PMBUS_PHASE:                     /* R/W byte */
    320         pmbus_send8(pmdev, pmdev->pages[index].phase);
    321         break;
    322 
    323     case PMBUS_WRITE_PROTECT:             /* R/W byte */
    324         pmbus_send8(pmdev, pmdev->pages[index].write_protect);
    325         break;
    326 
    327     case PMBUS_CAPABILITY:
    328         pmbus_send8(pmdev, pmdev->capability);
    329         if (pmdev->capability & BIT(7)) {
    330             qemu_log_mask(LOG_UNIMP,
    331                           "%s: PEC is enabled but not yet supported.\n",
    332                           __func__);
    333         }
    334         break;
    335 
    336     case PMBUS_VOUT_MODE:                 /* R/W byte */
    337         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MODE) {
    338             pmbus_send8(pmdev, pmdev->pages[index].vout_mode);
    339         } else {
    340             goto passthough;
    341         }
    342         break;
    343 
    344     case PMBUS_VOUT_COMMAND:              /* R/W word */
    345         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    346             pmbus_send16(pmdev, pmdev->pages[index].vout_command);
    347         } else {
    348             goto passthough;
    349         }
    350         break;
    351 
    352     case PMBUS_VOUT_TRIM:                 /* R/W word */
    353         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    354             pmbus_send16(pmdev, pmdev->pages[index].vout_trim);
    355         } else {
    356             goto passthough;
    357         }
    358         break;
    359 
    360     case PMBUS_VOUT_CAL_OFFSET:           /* R/W word */
    361         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    362             pmbus_send16(pmdev, pmdev->pages[index].vout_cal_offset);
    363         } else {
    364             goto passthough;
    365         }
    366         break;
    367 
    368     case PMBUS_VOUT_MAX:                  /* R/W word */
    369         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    370             pmbus_send16(pmdev, pmdev->pages[index].vout_max);
    371         } else {
    372             goto passthough;
    373         }
    374         break;
    375 
    376     case PMBUS_VOUT_MARGIN_HIGH:          /* R/W word */
    377         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) {
    378             pmbus_send16(pmdev, pmdev->pages[index].vout_margin_high);
    379         } else {
    380             goto passthough;
    381         }
    382         break;
    383 
    384     case PMBUS_VOUT_MARGIN_LOW:           /* R/W word */
    385         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) {
    386             pmbus_send16(pmdev, pmdev->pages[index].vout_margin_low);
    387         } else {
    388             goto passthough;
    389         }
    390         break;
    391 
    392     case PMBUS_VOUT_TRANSITION_RATE:      /* R/W word */
    393         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    394             pmbus_send16(pmdev, pmdev->pages[index].vout_transition_rate);
    395         } else {
    396             goto passthough;
    397         }
    398         break;
    399 
    400     case PMBUS_VOUT_DROOP:                /* R/W word */
    401         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    402             pmbus_send16(pmdev, pmdev->pages[index].vout_droop);
    403         } else {
    404             goto passthough;
    405         }
    406         break;
    407 
    408     case PMBUS_VOUT_SCALE_LOOP:           /* R/W word */
    409         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    410             pmbus_send16(pmdev, pmdev->pages[index].vout_scale_loop);
    411         } else {
    412             goto passthough;
    413         }
    414         break;
    415 
    416     case PMBUS_VOUT_SCALE_MONITOR:        /* R/W word */
    417         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    418             pmbus_send16(pmdev, pmdev->pages[index].vout_scale_monitor);
    419         } else {
    420             goto passthough;
    421         }
    422         break;
    423 
    424     case PMBUS_VOUT_MIN:        /* R/W word */
    425         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) {
    426             pmbus_send16(pmdev, pmdev->pages[index].vout_min);
    427         } else {
    428             goto passthough;
    429         }
    430         break;
    431 
    432     /* TODO: implement coefficients support */
    433 
    434     case PMBUS_POUT_MAX:                  /* R/W word */
    435         if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
    436             pmbus_send16(pmdev, pmdev->pages[index].pout_max);
    437         } else {
    438             goto passthough;
    439         }
    440         break;
    441 
    442     case PMBUS_VIN_ON:                    /* R/W word */
    443         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
    444             pmbus_send16(pmdev, pmdev->pages[index].vin_on);
    445         } else {
    446             goto passthough;
    447         }
    448         break;
    449 
    450     case PMBUS_VIN_OFF:                   /* R/W word */
    451         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
    452             pmbus_send16(pmdev, pmdev->pages[index].vin_off);
    453         } else {
    454             goto passthough;
    455         }
    456         break;
    457 
    458     case PMBUS_IOUT_CAL_GAIN:             /* R/W word */
    459         if (pmdev->pages[index].page_flags & PB_HAS_IOUT_GAIN) {
    460             pmbus_send16(pmdev, pmdev->pages[index].iout_cal_gain);
    461         } else {
    462             goto passthough;
    463         }
    464         break;
    465 
    466     case PMBUS_VOUT_OV_FAULT_LIMIT:       /* R/W word */
    467         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    468             pmbus_send16(pmdev, pmdev->pages[index].vout_ov_fault_limit);
    469         } else {
    470             goto passthough;
    471         }
    472         break;
    473 
    474     case PMBUS_VOUT_OV_FAULT_RESPONSE:    /* R/W byte */
    475         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    476             pmbus_send8(pmdev, pmdev->pages[index].vout_ov_fault_response);
    477         } else {
    478             goto passthough;
    479         }
    480         break;
    481 
    482     case PMBUS_VOUT_OV_WARN_LIMIT:        /* R/W word */
    483         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    484             pmbus_send16(pmdev, pmdev->pages[index].vout_ov_warn_limit);
    485         } else {
    486             goto passthough;
    487         }
    488         break;
    489 
    490     case PMBUS_VOUT_UV_WARN_LIMIT:        /* R/W word */
    491         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    492             pmbus_send16(pmdev, pmdev->pages[index].vout_uv_warn_limit);
    493         } else {
    494             goto passthough;
    495         }
    496         break;
    497 
    498     case PMBUS_VOUT_UV_FAULT_LIMIT:       /* R/W word */
    499         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    500             pmbus_send16(pmdev, pmdev->pages[index].vout_uv_fault_limit);
    501         } else {
    502             goto passthough;
    503         }
    504         break;
    505 
    506     case PMBUS_VOUT_UV_FAULT_RESPONSE:    /* R/W byte */
    507         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    508             pmbus_send8(pmdev, pmdev->pages[index].vout_uv_fault_response);
    509         } else {
    510             goto passthough;
    511         }
    512         break;
    513 
    514     case PMBUS_IOUT_OC_FAULT_LIMIT:       /* R/W word */
    515         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
    516             pmbus_send16(pmdev, pmdev->pages[index].iout_oc_fault_limit);
    517         } else {
    518             goto passthough;
    519         }
    520         break;
    521 
    522     case PMBUS_IOUT_OC_FAULT_RESPONSE:    /* R/W byte */
    523         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
    524             pmbus_send8(pmdev, pmdev->pages[index].iout_oc_fault_response);
    525         } else {
    526             goto passthough;
    527         }
    528         break;
    529 
    530     case PMBUS_IOUT_OC_LV_FAULT_LIMIT:    /* R/W word */
    531         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
    532             pmbus_send16(pmdev, pmdev->pages[index].iout_oc_lv_fault_limit);
    533         } else {
    534             goto passthough;
    535         }
    536         break;
    537 
    538     case PMBUS_IOUT_OC_LV_FAULT_RESPONSE: /* R/W byte */
    539         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
    540             pmbus_send8(pmdev, pmdev->pages[index].iout_oc_lv_fault_response);
    541         } else {
    542             goto passthough;
    543         }
    544         break;
    545 
    546     case PMBUS_IOUT_OC_WARN_LIMIT:        /* R/W word */
    547         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
    548             pmbus_send16(pmdev, pmdev->pages[index].iout_oc_warn_limit);
    549         } else {
    550             goto passthough;
    551         }
    552         break;
    553 
    554     case PMBUS_IOUT_UC_FAULT_LIMIT:       /* R/W word */
    555         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
    556             pmbus_send16(pmdev, pmdev->pages[index].iout_uc_fault_limit);
    557         } else {
    558             goto passthough;
    559         }
    560         break;
    561 
    562     case PMBUS_IOUT_UC_FAULT_RESPONSE:    /* R/W byte */
    563         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
    564             pmbus_send8(pmdev, pmdev->pages[index].iout_uc_fault_response);
    565         } else {
    566             goto passthough;
    567         }
    568         break;
    569 
    570     case PMBUS_OT_FAULT_LIMIT:            /* R/W word */
    571         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
    572             pmbus_send16(pmdev, pmdev->pages[index].ot_fault_limit);
    573         } else {
    574             goto passthough;
    575         }
    576         break;
    577 
    578     case PMBUS_OT_FAULT_RESPONSE:         /* R/W byte */
    579         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
    580             pmbus_send8(pmdev, pmdev->pages[index].ot_fault_response);
    581         } else {
    582             goto passthough;
    583         }
    584         break;
    585 
    586     case PMBUS_OT_WARN_LIMIT:             /* R/W word */
    587         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
    588             pmbus_send16(pmdev, pmdev->pages[index].ot_warn_limit);
    589         } else {
    590             goto passthough;
    591         }
    592         break;
    593 
    594     case PMBUS_UT_WARN_LIMIT:             /* R/W word */
    595         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
    596             pmbus_send16(pmdev, pmdev->pages[index].ut_warn_limit);
    597         } else {
    598             goto passthough;
    599         }
    600         break;
    601 
    602     case PMBUS_UT_FAULT_LIMIT:            /* R/W word */
    603         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
    604             pmbus_send16(pmdev, pmdev->pages[index].ut_fault_limit);
    605         } else {
    606             goto passthough;
    607         }
    608         break;
    609 
    610     case PMBUS_UT_FAULT_RESPONSE:         /* R/W byte */
    611         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
    612             pmbus_send8(pmdev, pmdev->pages[index].ut_fault_response);
    613         } else {
    614             goto passthough;
    615         }
    616         break;
    617 
    618     case PMBUS_VIN_OV_FAULT_LIMIT:        /* R/W word */
    619         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
    620             pmbus_send16(pmdev, pmdev->pages[index].vin_ov_fault_limit);
    621         } else {
    622             goto passthough;
    623         }
    624         break;
    625 
    626     case PMBUS_VIN_OV_FAULT_RESPONSE:     /* R/W byte */
    627         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
    628             pmbus_send8(pmdev, pmdev->pages[index].vin_ov_fault_response);
    629         } else {
    630             goto passthough;
    631         }
    632         break;
    633 
    634     case PMBUS_VIN_OV_WARN_LIMIT:         /* R/W word */
    635         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
    636             pmbus_send16(pmdev, pmdev->pages[index].vin_ov_warn_limit);
    637         } else {
    638             goto passthough;
    639         }
    640         break;
    641 
    642     case PMBUS_VIN_UV_WARN_LIMIT:         /* R/W word */
    643         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
    644             pmbus_send16(pmdev, pmdev->pages[index].vin_uv_warn_limit);
    645         } else {
    646             goto passthough;
    647         }
    648         break;
    649 
    650     case PMBUS_VIN_UV_FAULT_LIMIT:        /* R/W word */
    651         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
    652             pmbus_send16(pmdev, pmdev->pages[index].vin_uv_fault_limit);
    653         } else {
    654             goto passthough;
    655         }
    656         break;
    657 
    658     case PMBUS_VIN_UV_FAULT_RESPONSE:     /* R/W byte */
    659         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
    660             pmbus_send8(pmdev, pmdev->pages[index].vin_uv_fault_response);
    661         } else {
    662             goto passthough;
    663         }
    664         break;
    665 
    666     case PMBUS_IIN_OC_FAULT_LIMIT:        /* R/W word */
    667         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
    668             pmbus_send16(pmdev, pmdev->pages[index].iin_oc_fault_limit);
    669         } else {
    670             goto passthough;
    671         }
    672         break;
    673 
    674     case PMBUS_IIN_OC_FAULT_RESPONSE:     /* R/W byte */
    675         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
    676             pmbus_send8(pmdev, pmdev->pages[index].iin_oc_fault_response);
    677         } else {
    678             goto passthough;
    679         }
    680         break;
    681 
    682     case PMBUS_IIN_OC_WARN_LIMIT:         /* R/W word */
    683         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
    684             pmbus_send16(pmdev, pmdev->pages[index].iin_oc_warn_limit);
    685         } else {
    686             goto passthough;
    687         }
    688         break;
    689 
    690     case PMBUS_POUT_OP_FAULT_LIMIT:       /* R/W word */
    691         if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
    692             pmbus_send16(pmdev, pmdev->pages[index].pout_op_fault_limit);
    693         } else {
    694             goto passthough;
    695         }
    696         break;
    697 
    698     case PMBUS_POUT_OP_FAULT_RESPONSE:    /* R/W byte */
    699         if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
    700             pmbus_send8(pmdev, pmdev->pages[index].pout_op_fault_response);
    701         } else {
    702             goto passthough;
    703         }
    704         break;
    705 
    706     case PMBUS_POUT_OP_WARN_LIMIT:        /* R/W word */
    707         if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
    708             pmbus_send16(pmdev, pmdev->pages[index].pout_op_warn_limit);
    709         } else {
    710             goto passthough;
    711         }
    712         break;
    713 
    714     case PMBUS_PIN_OP_WARN_LIMIT:         /* R/W word */
    715         if (pmdev->pages[index].page_flags & PB_HAS_PIN) {
    716             pmbus_send16(pmdev, pmdev->pages[index].pin_op_warn_limit);
    717         } else {
    718             goto passthough;
    719         }
    720         break;
    721 
    722     case PMBUS_STATUS_BYTE:               /* R/W byte */
    723         pmbus_send8(pmdev, pmdev->pages[index].status_word & 0xFF);
    724         break;
    725 
    726     case PMBUS_STATUS_WORD:               /* R/W word */
    727         pmbus_send16(pmdev, pmdev->pages[index].status_word);
    728         break;
    729 
    730     case PMBUS_STATUS_VOUT:               /* R/W byte */
    731         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    732             pmbus_send8(pmdev, pmdev->pages[index].status_vout);
    733         } else {
    734             goto passthough;
    735         }
    736         break;
    737 
    738     case PMBUS_STATUS_IOUT:               /* R/W byte */
    739         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
    740             pmbus_send8(pmdev, pmdev->pages[index].status_iout);
    741         } else {
    742             goto passthough;
    743         }
    744         break;
    745 
    746     case PMBUS_STATUS_INPUT:              /* R/W byte */
    747         if (pmdev->pages[index].page_flags & PB_HAS_VIN ||
    748             pmdev->pages[index].page_flags & PB_HAS_IIN ||
    749             pmdev->pages[index].page_flags & PB_HAS_PIN) {
    750             pmbus_send8(pmdev, pmdev->pages[index].status_input);
    751         } else {
    752             goto passthough;
    753         }
    754         break;
    755 
    756     case PMBUS_STATUS_TEMPERATURE:        /* R/W byte */
    757         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
    758             pmbus_send8(pmdev, pmdev->pages[index].status_temperature);
    759         } else {
    760             goto passthough;
    761         }
    762         break;
    763 
    764     case PMBUS_STATUS_CML:                /* R/W byte */
    765         pmbus_send8(pmdev, pmdev->pages[index].status_cml);
    766         break;
    767 
    768     case PMBUS_STATUS_OTHER:              /* R/W byte */
    769         pmbus_send8(pmdev, pmdev->pages[index].status_other);
    770         break;
    771 
    772     case PMBUS_STATUS_MFR_SPECIFIC:       /* R/W byte */
    773         pmbus_send8(pmdev, pmdev->pages[index].status_mfr_specific);
    774         break;
    775 
    776     case PMBUS_READ_EIN:                  /* Read-Only block 5 bytes */
    777         if (pmdev->pages[index].page_flags & PB_HAS_EIN) {
    778             pmbus_send(pmdev, pmdev->pages[index].read_ein, 5);
    779         } else {
    780             goto passthough;
    781         }
    782         break;
    783 
    784     case PMBUS_READ_EOUT:                 /* Read-Only block 5 bytes */
    785         if (pmdev->pages[index].page_flags & PB_HAS_EOUT) {
    786             pmbus_send(pmdev, pmdev->pages[index].read_eout, 5);
    787         } else {
    788             goto passthough;
    789         }
    790         break;
    791 
    792     case PMBUS_READ_VIN:                  /* Read-Only word */
    793         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
    794             pmbus_send16(pmdev, pmdev->pages[index].read_vin);
    795         } else {
    796             goto passthough;
    797         }
    798         break;
    799 
    800     case PMBUS_READ_IIN:                  /* Read-Only word */
    801         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
    802             pmbus_send16(pmdev, pmdev->pages[index].read_iin);
    803         } else {
    804             goto passthough;
    805         }
    806         break;
    807 
    808     case PMBUS_READ_VOUT:                 /* Read-Only word */
    809         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
    810             pmbus_send16(pmdev, pmdev->pages[index].read_vout);
    811         } else {
    812             goto passthough;
    813         }
    814         break;
    815 
    816     case PMBUS_READ_IOUT:                 /* Read-Only word */
    817         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
    818             pmbus_send16(pmdev, pmdev->pages[index].read_iout);
    819         } else {
    820             goto passthough;
    821         }
    822         break;
    823 
    824     case PMBUS_READ_TEMPERATURE_1:        /* Read-Only word */
    825         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
    826             pmbus_send16(pmdev, pmdev->pages[index].read_temperature_1);
    827         } else {
    828             goto passthough;
    829         }
    830         break;
    831 
    832     case PMBUS_READ_TEMPERATURE_2:        /* Read-Only word */
    833         if (pmdev->pages[index].page_flags & PB_HAS_TEMP2) {
    834             pmbus_send16(pmdev, pmdev->pages[index].read_temperature_2);
    835         } else {
    836             goto passthough;
    837         }
    838         break;
    839 
    840     case PMBUS_READ_TEMPERATURE_3:        /* Read-Only word */
    841         if (pmdev->pages[index].page_flags & PB_HAS_TEMP3) {
    842             pmbus_send16(pmdev, pmdev->pages[index].read_temperature_3);
    843         } else {
    844             goto passthough;
    845         }
    846         break;
    847 
    848     case PMBUS_READ_POUT:                 /* Read-Only word */
    849         if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
    850             pmbus_send16(pmdev, pmdev->pages[index].read_pout);
    851         } else {
    852             goto passthough;
    853         }
    854         break;
    855 
    856     case PMBUS_READ_PIN:                  /* Read-Only word */
    857         if (pmdev->pages[index].page_flags & PB_HAS_PIN) {
    858             pmbus_send16(pmdev, pmdev->pages[index].read_pin);
    859         } else {
    860             goto passthough;
    861         }
    862         break;
    863 
    864     case PMBUS_REVISION:                  /* Read-Only byte */
    865         pmbus_send8(pmdev, pmdev->pages[index].revision);
    866         break;
    867 
    868     case PMBUS_MFR_ID:                    /* R/W block */
    869         if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) {
    870             pmbus_send_string(pmdev, pmdev->pages[index].mfr_id);
    871         } else {
    872             goto passthough;
    873         }
    874         break;
    875 
    876     case PMBUS_MFR_MODEL:                 /* R/W block */
    877         if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) {
    878             pmbus_send_string(pmdev, pmdev->pages[index].mfr_model);
    879         } else {
    880             goto passthough;
    881         }
    882         break;
    883 
    884     case PMBUS_MFR_REVISION:              /* R/W block */
    885         if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) {
    886             pmbus_send_string(pmdev, pmdev->pages[index].mfr_revision);
    887         } else {
    888             goto passthough;
    889         }
    890         break;
    891 
    892     case PMBUS_MFR_LOCATION:              /* R/W block */
    893         if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) {
    894             pmbus_send_string(pmdev, pmdev->pages[index].mfr_location);
    895         } else {
    896             goto passthough;
    897         }
    898         break;
    899 
    900     case PMBUS_MFR_VIN_MIN:               /* Read-Only word */
    901         if (pmdev->pages[index].page_flags & PB_HAS_VIN_RATING) {
    902             pmbus_send16(pmdev, pmdev->pages[index].mfr_vin_min);
    903         } else {
    904             goto passthough;
    905         }
    906         break;
    907 
    908     case PMBUS_MFR_VIN_MAX:               /* Read-Only word */
    909         if (pmdev->pages[index].page_flags & PB_HAS_VIN_RATING) {
    910             pmbus_send16(pmdev, pmdev->pages[index].mfr_vin_max);
    911         } else {
    912             goto passthough;
    913         }
    914         break;
    915 
    916     case PMBUS_MFR_IIN_MAX:               /* Read-Only word */
    917         if (pmdev->pages[index].page_flags & PB_HAS_IIN_RATING) {
    918             pmbus_send16(pmdev, pmdev->pages[index].mfr_iin_max);
    919         } else {
    920             goto passthough;
    921         }
    922         break;
    923 
    924     case PMBUS_MFR_PIN_MAX:               /* Read-Only word */
    925         if (pmdev->pages[index].page_flags & PB_HAS_PIN_RATING) {
    926             pmbus_send16(pmdev, pmdev->pages[index].mfr_pin_max);
    927         } else {
    928             goto passthough;
    929         }
    930         break;
    931 
    932     case PMBUS_MFR_VOUT_MIN:              /* Read-Only word */
    933         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) {
    934             pmbus_send16(pmdev, pmdev->pages[index].mfr_vout_min);
    935         } else {
    936             goto passthough;
    937         }
    938         break;
    939 
    940     case PMBUS_MFR_VOUT_MAX:              /* Read-Only word */
    941         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) {
    942             pmbus_send16(pmdev, pmdev->pages[index].mfr_vout_max);
    943         } else {
    944             goto passthough;
    945         }
    946         break;
    947 
    948     case PMBUS_MFR_IOUT_MAX:              /* Read-Only word */
    949         if (pmdev->pages[index].page_flags & PB_HAS_IOUT_RATING) {
    950             pmbus_send16(pmdev, pmdev->pages[index].mfr_iout_max);
    951         } else {
    952             goto passthough;
    953         }
    954         break;
    955 
    956     case PMBUS_MFR_POUT_MAX:              /* Read-Only word */
    957         if (pmdev->pages[index].page_flags & PB_HAS_POUT_RATING) {
    958             pmbus_send16(pmdev, pmdev->pages[index].mfr_pout_max);
    959         } else {
    960             goto passthough;
    961         }
    962         break;
    963 
    964     case PMBUS_MFR_MAX_TEMP_1:            /* R/W word */
    965         if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) {
    966             pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_1);
    967         } else {
    968             goto passthough;
    969         }
    970         break;
    971 
    972     case PMBUS_MFR_MAX_TEMP_2:            /* R/W word */
    973         if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) {
    974             pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_2);
    975         } else {
    976             goto passthough;
    977         }
    978         break;
    979 
    980     case PMBUS_MFR_MAX_TEMP_3:            /* R/W word */
    981         if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) {
    982             pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_3);
    983         } else {
    984             goto passthough;
    985         }
    986         break;
    987 
    988     case PMBUS_IDLE_STATE:
    989         pmbus_send8(pmdev, PMBUS_ERR_BYTE);
    990         break;
    991 
    992     case PMBUS_CLEAR_FAULTS:              /* Send Byte */
    993     case PMBUS_PAGE_PLUS_WRITE:           /* Block Write-only */
    994     case PMBUS_STORE_DEFAULT_ALL:         /* Send Byte */
    995     case PMBUS_RESTORE_DEFAULT_ALL:       /* Send Byte */
    996     case PMBUS_STORE_DEFAULT_CODE:        /* Write-only Byte */
    997     case PMBUS_RESTORE_DEFAULT_CODE:      /* Write-only Byte */
    998     case PMBUS_STORE_USER_ALL:            /* Send Byte */
    999     case PMBUS_RESTORE_USER_ALL:          /* Send Byte */
   1000     case PMBUS_STORE_USER_CODE:           /* Write-only Byte */
   1001     case PMBUS_RESTORE_USER_CODE:         /* Write-only Byte */
   1002     case PMBUS_QUERY:                     /* Write-Only */
   1003         qemu_log_mask(LOG_GUEST_ERROR,
   1004                       "%s: reading from write only register 0x%02x\n",
   1005                       __func__, pmdev->code);
   1006         break;
   1007 
   1008 passthough:
   1009     default:
   1010         /* Pass through read request if not handled */
   1011         if (pmdc->receive_byte) {
   1012             ret = pmdc->receive_byte(pmdev);
   1013         }
   1014         break;
   1015     }
   1016 
   1017     if (pmdev->out_buf_len != 0) {
   1018         ret = pmbus_out_buf_pop(pmdev);
   1019         return ret;
   1020     }
   1021 
   1022     return ret;
   1023 }
   1024 
   1025 /*
   1026  * PMBus clear faults command applies to all status registers, existing faults
   1027  * should separately get re-asserted.
   1028  */
   1029 static void pmbus_clear_faults(PMBusDevice *pmdev)
   1030 {
   1031     for (uint8_t i = 0; i < pmdev->num_pages; i++) {
   1032         pmdev->pages[i].status_word = 0;
   1033         pmdev->pages[i].status_vout = 0;
   1034         pmdev->pages[i].status_iout = 0;
   1035         pmdev->pages[i].status_input = 0;
   1036         pmdev->pages[i].status_temperature = 0;
   1037         pmdev->pages[i].status_cml = 0;
   1038         pmdev->pages[i].status_other = 0;
   1039         pmdev->pages[i].status_mfr_specific = 0;
   1040         pmdev->pages[i].status_fans_1_2 = 0;
   1041         pmdev->pages[i].status_fans_3_4 = 0;
   1042     }
   1043 
   1044 }
   1045 
   1046 /*
   1047  * PMBus operation is used to turn On and Off PSUs
   1048  * Therefore, default value for the Operation should be PB_OP_ON or 0x80
   1049  */
   1050 static void pmbus_operation(PMBusDevice *pmdev)
   1051 {
   1052     uint8_t index = pmdev->page;
   1053     if ((pmdev->pages[index].operation & PB_OP_ON) == 0) {
   1054         pmdev->pages[index].read_vout = 0;
   1055         pmdev->pages[index].read_iout = 0;
   1056         pmdev->pages[index].read_pout = 0;
   1057         return;
   1058     }
   1059 
   1060     if (pmdev->pages[index].operation & (PB_OP_ON | PB_OP_MARGIN_HIGH)) {
   1061         pmdev->pages[index].read_vout = pmdev->pages[index].vout_margin_high;
   1062     }
   1063 
   1064     if (pmdev->pages[index].operation & (PB_OP_ON | PB_OP_MARGIN_LOW)) {
   1065         pmdev->pages[index].read_vout = pmdev->pages[index].vout_margin_low;
   1066     }
   1067     pmbus_check_limits(pmdev);
   1068 }
   1069 
   1070 static int pmbus_write_data(SMBusDevice *smd, uint8_t *buf, uint8_t len)
   1071 {
   1072     PMBusDevice *pmdev = PMBUS_DEVICE(smd);
   1073     PMBusDeviceClass *pmdc = PMBUS_DEVICE_GET_CLASS(pmdev);
   1074     int ret = 0;
   1075     uint8_t index;
   1076 
   1077     if (len == 0) {
   1078         qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__);
   1079         return PMBUS_ERR_BYTE;
   1080     }
   1081 
   1082     if (!pmdev->pages) { /* allocate memory for pages on first use */
   1083         pmbus_pages_alloc(pmdev);
   1084     }
   1085 
   1086     pmdev->in_buf_len = len;
   1087     pmdev->in_buf = buf;
   1088 
   1089     pmdev->code = buf[0]; /* PMBus command code */
   1090     if (len == 1) { /* Single length writes are command codes only */
   1091         return 0;
   1092     }
   1093 
   1094     if (pmdev->code == PMBUS_PAGE) {
   1095         pmdev->page = pmbus_receive8(pmdev);
   1096         return 0;
   1097     }
   1098 
   1099     /* loop through all the pages when 0xFF is received */
   1100     if (pmdev->page == PB_ALL_PAGES) {
   1101         for (int i = 0; i < pmdev->num_pages; i++) {
   1102             pmdev->page = i;
   1103             pmbus_write_data(smd, buf, len);
   1104         }
   1105         pmdev->page = PB_ALL_PAGES;
   1106         return 0;
   1107     }
   1108 
   1109     if (pmdev->page > pmdev->num_pages - 1) {
   1110         qemu_log_mask(LOG_GUEST_ERROR,
   1111                         "%s: page %u is out of range\n",
   1112                         __func__, pmdev->page);
   1113         pmdev->page = 0; /* undefined behaviour - reset to page 0 */
   1114         pmbus_cml_error(pmdev);
   1115         return PMBUS_ERR_BYTE;
   1116     }
   1117 
   1118     index = pmdev->page;
   1119 
   1120     switch (pmdev->code) {
   1121     case PMBUS_OPERATION:                 /* R/W byte */
   1122         pmdev->pages[index].operation = pmbus_receive8(pmdev);
   1123         pmbus_operation(pmdev);
   1124         break;
   1125 
   1126     case PMBUS_ON_OFF_CONFIG:             /* R/W byte */
   1127         pmdev->pages[index].on_off_config = pmbus_receive8(pmdev);
   1128         break;
   1129 
   1130     case PMBUS_CLEAR_FAULTS:              /* Send Byte */
   1131         pmbus_clear_faults(pmdev);
   1132         break;
   1133 
   1134     case PMBUS_PHASE:                     /* R/W byte */
   1135         pmdev->pages[index].phase = pmbus_receive8(pmdev);
   1136         break;
   1137 
   1138     case PMBUS_PAGE_PLUS_WRITE:           /* Block Write-only */
   1139     case PMBUS_WRITE_PROTECT:             /* R/W byte */
   1140         pmdev->pages[index].write_protect = pmbus_receive8(pmdev);
   1141         break;
   1142 
   1143     case PMBUS_VOUT_MODE:                 /* R/W byte */
   1144         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MODE) {
   1145             pmdev->pages[index].vout_mode = pmbus_receive8(pmdev);
   1146         } else {
   1147             goto passthrough;
   1148         }
   1149         break;
   1150 
   1151     case PMBUS_VOUT_COMMAND:              /* R/W word */
   1152         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1153             pmdev->pages[index].vout_command = pmbus_receive16(pmdev);
   1154         } else {
   1155             goto passthrough;
   1156         }
   1157         break;
   1158 
   1159     case PMBUS_VOUT_TRIM:                 /* R/W word */
   1160         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1161             pmdev->pages[index].vout_trim = pmbus_receive16(pmdev);
   1162         } else {
   1163             goto passthrough;
   1164         }
   1165         break;
   1166 
   1167     case PMBUS_VOUT_CAL_OFFSET:           /* R/W word */
   1168         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1169             pmdev->pages[index].vout_cal_offset = pmbus_receive16(pmdev);
   1170         } else {
   1171             goto passthrough;
   1172         }
   1173         break;
   1174 
   1175     case PMBUS_VOUT_MAX:                  /* R/W word */
   1176         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1177             pmdev->pages[index].vout_max = pmbus_receive16(pmdev);
   1178         } else {
   1179             goto passthrough;
   1180         }
   1181         break;
   1182 
   1183     case PMBUS_VOUT_MARGIN_HIGH:          /* R/W word */
   1184         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) {
   1185             pmdev->pages[index].vout_margin_high = pmbus_receive16(pmdev);
   1186         } else {
   1187             goto passthrough;
   1188         }
   1189         break;
   1190 
   1191     case PMBUS_VOUT_MARGIN_LOW:           /* R/W word */
   1192         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) {
   1193             pmdev->pages[index].vout_margin_low = pmbus_receive16(pmdev);
   1194         } else {
   1195             goto passthrough;
   1196         }
   1197         break;
   1198 
   1199     case PMBUS_VOUT_TRANSITION_RATE:      /* R/W word */
   1200         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1201             pmdev->pages[index].vout_transition_rate = pmbus_receive16(pmdev);
   1202         } else {
   1203             goto passthrough;
   1204         }
   1205         break;
   1206 
   1207     case PMBUS_VOUT_DROOP:                /* R/W word */
   1208         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1209             pmdev->pages[index].vout_droop = pmbus_receive16(pmdev);
   1210         } else {
   1211             goto passthrough;
   1212         }
   1213         break;
   1214 
   1215     case PMBUS_VOUT_SCALE_LOOP:           /* R/W word */
   1216         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1217             pmdev->pages[index].vout_scale_loop = pmbus_receive16(pmdev);
   1218         } else {
   1219             goto passthrough;
   1220         }
   1221         break;
   1222 
   1223     case PMBUS_VOUT_SCALE_MONITOR:        /* R/W word */
   1224         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1225             pmdev->pages[index].vout_scale_monitor = pmbus_receive16(pmdev);
   1226         } else {
   1227             goto passthrough;
   1228         }
   1229         break;
   1230 
   1231     case PMBUS_VOUT_MIN:                  /* R/W word */
   1232         if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) {
   1233             pmdev->pages[index].vout_min = pmbus_receive16(pmdev);
   1234         } else {
   1235             goto passthrough;
   1236         }
   1237         break;
   1238 
   1239     case PMBUS_POUT_MAX:                  /* R/W word */
   1240         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1241             pmdev->pages[index].pout_max = pmbus_receive16(pmdev);
   1242         } else {
   1243             goto passthrough;
   1244         }
   1245         break;
   1246 
   1247     case PMBUS_VIN_ON:                    /* R/W word */
   1248         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
   1249             pmdev->pages[index].vin_on = pmbus_receive16(pmdev);
   1250         } else {
   1251             goto passthrough;
   1252         }
   1253         break;
   1254 
   1255     case PMBUS_VIN_OFF:                   /* R/W word */
   1256         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
   1257             pmdev->pages[index].vin_off = pmbus_receive16(pmdev);
   1258         } else {
   1259             goto passthrough;
   1260         }
   1261         break;
   1262 
   1263     case PMBUS_IOUT_CAL_GAIN:             /* R/W word */
   1264         if (pmdev->pages[index].page_flags & PB_HAS_IOUT_GAIN) {
   1265             pmdev->pages[index].iout_cal_gain = pmbus_receive16(pmdev);
   1266         } else {
   1267             goto passthrough;
   1268         }
   1269         break;
   1270 
   1271     case PMBUS_VOUT_OV_FAULT_LIMIT:       /* R/W word */
   1272         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1273             pmdev->pages[index].vout_ov_fault_limit = pmbus_receive16(pmdev);
   1274         } else {
   1275             goto passthrough;
   1276         }
   1277         break;
   1278 
   1279     case PMBUS_VOUT_OV_FAULT_RESPONSE:    /* R/W byte */
   1280         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1281             pmdev->pages[index].vout_ov_fault_response = pmbus_receive8(pmdev);
   1282         } else {
   1283             goto passthrough;
   1284         }
   1285         break;
   1286 
   1287     case PMBUS_VOUT_OV_WARN_LIMIT:        /* R/W word */
   1288         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1289             pmdev->pages[index].vout_ov_warn_limit = pmbus_receive16(pmdev);
   1290         } else {
   1291             goto passthrough;
   1292         }
   1293         break;
   1294 
   1295     case PMBUS_VOUT_UV_WARN_LIMIT:        /* R/W word */
   1296         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1297             pmdev->pages[index].vout_uv_warn_limit = pmbus_receive16(pmdev);
   1298         } else {
   1299             goto passthrough;
   1300         }
   1301         break;
   1302 
   1303     case PMBUS_VOUT_UV_FAULT_LIMIT:       /* R/W word */
   1304         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1305             pmdev->pages[index].vout_uv_fault_limit = pmbus_receive16(pmdev);
   1306         } else {
   1307             goto passthrough;
   1308         }
   1309         break;
   1310 
   1311     case PMBUS_VOUT_UV_FAULT_RESPONSE:    /* R/W byte */
   1312         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1313             pmdev->pages[index].vout_uv_fault_response = pmbus_receive8(pmdev);
   1314         } else {
   1315             goto passthrough;
   1316         }
   1317         break;
   1318 
   1319     case PMBUS_IOUT_OC_FAULT_LIMIT:       /* R/W word */
   1320         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
   1321             pmdev->pages[index].iout_oc_fault_limit = pmbus_receive16(pmdev);
   1322         } else {
   1323             goto passthrough;
   1324         }
   1325         break;
   1326 
   1327     case PMBUS_IOUT_OC_FAULT_RESPONSE:    /* R/W byte */
   1328         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
   1329             pmdev->pages[index].iout_oc_fault_response = pmbus_receive8(pmdev);
   1330         } else {
   1331             goto passthrough;
   1332         }
   1333         break;
   1334 
   1335     case PMBUS_IOUT_OC_LV_FAULT_LIMIT:    /* R/W word */
   1336         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
   1337             pmdev->pages[index].iout_oc_lv_fault_limit = pmbus_receive16(pmdev);
   1338         } else {
   1339             goto passthrough;
   1340         }
   1341         break;
   1342 
   1343     case PMBUS_IOUT_OC_LV_FAULT_RESPONSE: /* R/W byte */
   1344         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
   1345             pmdev->pages[index].iout_oc_lv_fault_response
   1346                 = pmbus_receive8(pmdev);
   1347         } else {
   1348             goto passthrough;
   1349         }
   1350         break;
   1351 
   1352     case PMBUS_IOUT_OC_WARN_LIMIT:        /* R/W word */
   1353         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
   1354             pmdev->pages[index].iout_oc_warn_limit = pmbus_receive16(pmdev);
   1355         } else {
   1356             goto passthrough;
   1357         }
   1358         break;
   1359 
   1360     case PMBUS_IOUT_UC_FAULT_LIMIT:       /* R/W word */
   1361         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
   1362             pmdev->pages[index].iout_uc_fault_limit = pmbus_receive16(pmdev);
   1363         } else {
   1364             goto passthrough;
   1365         }
   1366         break;
   1367 
   1368     case PMBUS_IOUT_UC_FAULT_RESPONSE:    /* R/W byte */
   1369         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
   1370             pmdev->pages[index].iout_uc_fault_response = pmbus_receive8(pmdev);
   1371         } else {
   1372             goto passthrough;
   1373         }
   1374         break;
   1375 
   1376     case PMBUS_OT_FAULT_LIMIT:            /* R/W word */
   1377         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
   1378             pmdev->pages[index].ot_fault_limit = pmbus_receive16(pmdev);
   1379         } else {
   1380             goto passthrough;
   1381         }
   1382         break;
   1383 
   1384     case PMBUS_OT_FAULT_RESPONSE:         /* R/W byte */
   1385         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
   1386             pmdev->pages[index].ot_fault_response = pmbus_receive8(pmdev);
   1387         } else {
   1388             goto passthrough;
   1389         }
   1390         break;
   1391 
   1392     case PMBUS_OT_WARN_LIMIT:             /* R/W word */
   1393         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
   1394             pmdev->pages[index].ot_warn_limit = pmbus_receive16(pmdev);
   1395         } else {
   1396             goto passthrough;
   1397         }
   1398         break;
   1399 
   1400     case PMBUS_UT_WARN_LIMIT:             /* R/W word */
   1401         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
   1402             pmdev->pages[index].ut_warn_limit = pmbus_receive16(pmdev);
   1403         } else {
   1404             goto passthrough;
   1405         }
   1406         break;
   1407 
   1408     case PMBUS_UT_FAULT_LIMIT:            /* R/W word */
   1409         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
   1410             pmdev->pages[index].ut_fault_limit = pmbus_receive16(pmdev);
   1411         } else {
   1412             goto passthrough;
   1413         }
   1414         break;
   1415 
   1416     case PMBUS_UT_FAULT_RESPONSE:         /* R/W byte */
   1417         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
   1418             pmdev->pages[index].ut_fault_response = pmbus_receive8(pmdev);
   1419         } else {
   1420             goto passthrough;
   1421         }
   1422         break;
   1423 
   1424     case PMBUS_VIN_OV_FAULT_LIMIT:        /* R/W word */
   1425         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
   1426             pmdev->pages[index].vin_ov_fault_limit = pmbus_receive16(pmdev);
   1427         } else {
   1428             goto passthrough;
   1429         }
   1430         break;
   1431 
   1432     case PMBUS_VIN_OV_FAULT_RESPONSE:     /* R/W byte */
   1433         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
   1434             pmdev->pages[index].vin_ov_fault_response = pmbus_receive8(pmdev);
   1435         } else {
   1436             goto passthrough;
   1437         }
   1438         break;
   1439 
   1440     case PMBUS_VIN_OV_WARN_LIMIT:         /* R/W word */
   1441         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
   1442             pmdev->pages[index].vin_ov_warn_limit = pmbus_receive16(pmdev);
   1443         } else {
   1444             goto passthrough;
   1445         }
   1446         break;
   1447 
   1448     case PMBUS_VIN_UV_WARN_LIMIT:         /* R/W word */
   1449         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
   1450             pmdev->pages[index].vin_uv_warn_limit = pmbus_receive16(pmdev);
   1451         } else {
   1452             goto passthrough;
   1453         }
   1454         break;
   1455 
   1456     case PMBUS_VIN_UV_FAULT_LIMIT:        /* R/W word */
   1457         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
   1458             pmdev->pages[index].vin_uv_fault_limit = pmbus_receive16(pmdev);
   1459         } else {
   1460             goto passthrough;
   1461         }
   1462         break;
   1463 
   1464     case PMBUS_VIN_UV_FAULT_RESPONSE:     /* R/W byte */
   1465         if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
   1466             pmdev->pages[index].vin_uv_fault_response = pmbus_receive8(pmdev);
   1467         } else {
   1468             goto passthrough;
   1469         }
   1470         break;
   1471 
   1472     case PMBUS_IIN_OC_FAULT_LIMIT:        /* R/W word */
   1473         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
   1474             pmdev->pages[index].iin_oc_fault_limit = pmbus_receive16(pmdev);
   1475         } else {
   1476             goto passthrough;
   1477         }
   1478         break;
   1479 
   1480     case PMBUS_IIN_OC_FAULT_RESPONSE:     /* R/W byte */
   1481         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
   1482             pmdev->pages[index].iin_oc_fault_response = pmbus_receive8(pmdev);
   1483         } else {
   1484             goto passthrough;
   1485         }
   1486         break;
   1487 
   1488     case PMBUS_IIN_OC_WARN_LIMIT:         /* R/W word */
   1489         if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
   1490             pmdev->pages[index].iin_oc_warn_limit = pmbus_receive16(pmdev);
   1491         } else {
   1492             goto passthrough;
   1493         }
   1494         break;
   1495 
   1496     case PMBUS_POUT_OP_FAULT_LIMIT:       /* R/W word */
   1497         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1498             pmdev->pages[index].pout_op_fault_limit = pmbus_receive16(pmdev);
   1499         } else {
   1500             goto passthrough;
   1501         }
   1502         break;
   1503 
   1504     case PMBUS_POUT_OP_FAULT_RESPONSE:    /* R/W byte */
   1505         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1506             pmdev->pages[index].pout_op_fault_response = pmbus_receive8(pmdev);
   1507         } else {
   1508             goto passthrough;
   1509         }
   1510         break;
   1511 
   1512     case PMBUS_POUT_OP_WARN_LIMIT:        /* R/W word */
   1513         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1514             pmdev->pages[index].pout_op_warn_limit = pmbus_receive16(pmdev);
   1515         } else {
   1516             goto passthrough;
   1517         }
   1518         break;
   1519 
   1520     case PMBUS_PIN_OP_WARN_LIMIT:         /* R/W word */
   1521         if (pmdev->pages[index].page_flags & PB_HAS_PIN) {
   1522             pmdev->pages[index].pin_op_warn_limit = pmbus_receive16(pmdev);
   1523         } else {
   1524             goto passthrough;
   1525         }
   1526         break;
   1527 
   1528     case PMBUS_STATUS_BYTE:               /* R/W byte */
   1529         pmdev->pages[index].status_word = pmbus_receive8(pmdev);
   1530         break;
   1531 
   1532     case PMBUS_STATUS_WORD:               /* R/W word */
   1533         pmdev->pages[index].status_word = pmbus_receive16(pmdev);
   1534         break;
   1535 
   1536     case PMBUS_STATUS_VOUT:               /* R/W byte */
   1537         if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
   1538             pmdev->pages[index].status_vout = pmbus_receive8(pmdev);
   1539         } else {
   1540             goto passthrough;
   1541         }
   1542         break;
   1543 
   1544     case PMBUS_STATUS_IOUT:               /* R/W byte */
   1545         if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
   1546             pmdev->pages[index].status_iout = pmbus_receive8(pmdev);
   1547         } else {
   1548             goto passthrough;
   1549         }
   1550         break;
   1551 
   1552     case PMBUS_STATUS_INPUT:              /* R/W byte */
   1553         pmdev->pages[index].status_input = pmbus_receive8(pmdev);
   1554         break;
   1555 
   1556     case PMBUS_STATUS_TEMPERATURE:        /* R/W byte */
   1557         if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
   1558             pmdev->pages[index].status_temperature = pmbus_receive8(pmdev);
   1559         } else {
   1560             goto passthrough;
   1561         }
   1562         break;
   1563 
   1564     case PMBUS_STATUS_CML:                /* R/W byte */
   1565         pmdev->pages[index].status_cml = pmbus_receive8(pmdev);
   1566         break;
   1567 
   1568     case PMBUS_STATUS_OTHER:              /* R/W byte */
   1569         pmdev->pages[index].status_other = pmbus_receive8(pmdev);
   1570         break;
   1571 
   1572     case PMBUS_STATUS_MFR_SPECIFIC:        /* R/W byte */
   1573         pmdev->pages[index].status_mfr_specific = pmbus_receive8(pmdev);
   1574         break;
   1575 
   1576     case PMBUS_PAGE_PLUS_READ:            /* Block Read-only */
   1577     case PMBUS_CAPABILITY:                /* Read-Only byte */
   1578     case PMBUS_COEFFICIENTS:              /* Read-only block 5 bytes */
   1579     case PMBUS_READ_EIN:                  /* Read-Only block 5 bytes */
   1580     case PMBUS_READ_EOUT:                 /* Read-Only block 5 bytes */
   1581     case PMBUS_READ_VIN:                  /* Read-Only word */
   1582     case PMBUS_READ_IIN:                  /* Read-Only word */
   1583     case PMBUS_READ_VCAP:                 /* Read-Only word */
   1584     case PMBUS_READ_VOUT:                 /* Read-Only word */
   1585     case PMBUS_READ_IOUT:                 /* Read-Only word */
   1586     case PMBUS_READ_TEMPERATURE_1:        /* Read-Only word */
   1587     case PMBUS_READ_TEMPERATURE_2:        /* Read-Only word */
   1588     case PMBUS_READ_TEMPERATURE_3:        /* Read-Only word */
   1589     case PMBUS_READ_FAN_SPEED_1:          /* Read-Only word */
   1590     case PMBUS_READ_FAN_SPEED_2:          /* Read-Only word */
   1591     case PMBUS_READ_FAN_SPEED_3:          /* Read-Only word */
   1592     case PMBUS_READ_FAN_SPEED_4:          /* Read-Only word */
   1593     case PMBUS_READ_DUTY_CYCLE:           /* Read-Only word */
   1594     case PMBUS_READ_FREQUENCY:            /* Read-Only word */
   1595     case PMBUS_READ_POUT:                 /* Read-Only word */
   1596     case PMBUS_READ_PIN:                  /* Read-Only word */
   1597     case PMBUS_REVISION:                  /* Read-Only byte */
   1598     case PMBUS_APP_PROFILE_SUPPORT:       /* Read-Only block-read */
   1599     case PMBUS_MFR_VIN_MIN:               /* Read-Only word */
   1600     case PMBUS_MFR_VIN_MAX:               /* Read-Only word */
   1601     case PMBUS_MFR_IIN_MAX:               /* Read-Only word */
   1602     case PMBUS_MFR_PIN_MAX:               /* Read-Only word */
   1603     case PMBUS_MFR_VOUT_MIN:              /* Read-Only word */
   1604     case PMBUS_MFR_VOUT_MAX:              /* Read-Only word */
   1605     case PMBUS_MFR_IOUT_MAX:              /* Read-Only word */
   1606     case PMBUS_MFR_POUT_MAX:              /* Read-Only word */
   1607     case PMBUS_MFR_TAMBIENT_MAX:          /* Read-Only word */
   1608     case PMBUS_MFR_TAMBIENT_MIN:          /* Read-Only word */
   1609     case PMBUS_MFR_EFFICIENCY_LL:         /* Read-Only block 14 bytes */
   1610     case PMBUS_MFR_EFFICIENCY_HL:         /* Read-Only block 14 bytes */
   1611     case PMBUS_MFR_PIN_ACCURACY:          /* Read-Only byte */
   1612     case PMBUS_IC_DEVICE_ID:              /* Read-Only block-read */
   1613     case PMBUS_IC_DEVICE_REV:             /* Read-Only block-read */
   1614         qemu_log_mask(LOG_GUEST_ERROR,
   1615                       "%s: writing to read-only register 0x%02x\n",
   1616                       __func__, pmdev->code);
   1617         break;
   1618 
   1619 passthrough:
   1620     /* Unimplimented registers get passed to the device */
   1621     default:
   1622         if (pmdc->write_data) {
   1623             ret = pmdc->write_data(pmdev, buf, len);
   1624         }
   1625         break;
   1626     }
   1627     pmbus_check_limits(pmdev);
   1628     pmdev->in_buf_len = 0;
   1629     return ret;
   1630 }
   1631 
   1632 int pmbus_page_config(PMBusDevice *pmdev, uint8_t index, uint64_t flags)
   1633 {
   1634     if (!pmdev->pages) { /* allocate memory for pages on first use */
   1635         pmbus_pages_alloc(pmdev);
   1636     }
   1637 
   1638     /* The 0xFF page is special for commands applying to all pages */
   1639     if (index == PB_ALL_PAGES) {
   1640         for (int i = 0; i < pmdev->num_pages; i++) {
   1641             pmdev->pages[i].page_flags = flags;
   1642         }
   1643         return 0;
   1644     }
   1645 
   1646     if (index > pmdev->num_pages - 1) {
   1647         qemu_log_mask(LOG_GUEST_ERROR,
   1648                       "%s: index %u is out of range\n",
   1649                       __func__, index);
   1650         return -1;
   1651     }
   1652 
   1653     pmdev->pages[index].page_flags = flags;
   1654 
   1655     return 0;
   1656 }
   1657 
   1658 /* TODO: include pmbus page info in vmstate */
   1659 const VMStateDescription vmstate_pmbus_device = {
   1660     .name = TYPE_PMBUS_DEVICE,
   1661     .version_id = 0,
   1662     .minimum_version_id = 0,
   1663     .fields = (VMStateField[]) {
   1664         VMSTATE_SMBUS_DEVICE(smb, PMBusDevice),
   1665         VMSTATE_UINT8(num_pages, PMBusDevice),
   1666         VMSTATE_UINT8(code, PMBusDevice),
   1667         VMSTATE_UINT8(page, PMBusDevice),
   1668         VMSTATE_UINT8(capability, PMBusDevice),
   1669         VMSTATE_END_OF_LIST()
   1670     }
   1671 };
   1672 
   1673 static void pmbus_device_finalize(Object *obj)
   1674 {
   1675     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
   1676     g_free(pmdev->pages);
   1677 }
   1678 
   1679 static void pmbus_device_class_init(ObjectClass *klass, void *data)
   1680 {
   1681     SMBusDeviceClass *k = SMBUS_DEVICE_CLASS(klass);
   1682 
   1683     k->quick_cmd = pmbus_quick_cmd;
   1684     k->write_data = pmbus_write_data;
   1685     k->receive_byte = pmbus_receive_byte;
   1686 }
   1687 
   1688 static const TypeInfo pmbus_device_type_info = {
   1689     .name = TYPE_PMBUS_DEVICE,
   1690     .parent = TYPE_SMBUS_DEVICE,
   1691     .instance_size = sizeof(PMBusDevice),
   1692     .instance_finalize = pmbus_device_finalize,
   1693     .abstract = true,
   1694     .class_size = sizeof(PMBusDeviceClass),
   1695     .class_init = pmbus_device_class_init,
   1696 };
   1697 
   1698 static void pmbus_device_register_types(void)
   1699 {
   1700     type_register_static(&pmbus_device_type_info);
   1701 }
   1702 
   1703 type_init(pmbus_device_register_types)