qemu

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

adm1272.c (16385B)


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