qemu/hw/sensor/adm1272.c
<<
>>
Prefs
   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
  73typedef 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
 101static 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
 113static 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
 140static 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
 148static 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
 156static 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
 166static 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
 175static 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
 182static 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
 189static 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
 255static 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
 343static 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
 415static 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
 433static 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
 457static 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
 489static 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
 515static 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
 530static 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
 538static void adm1272_register_types(void)
 539{
 540    type_register_static(&adm1272_info);
 541}
 542
 543type_init(adm1272_register_types)
 544