qemu

Форк
0
/
adm1272.c 
542 строки · 16.0 Кб
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 "hw/i2c/pmbus_device.h"
12
#include "hw/irq.h"
13
#include "migration/vmstate.h"
14
#include "qapi/error.h"
15
#include "qapi/visitor.h"
16
#include "qemu/log.h"
17
#include "qemu/module.h"
18

19
#define TYPE_ADM1272 "adm1272"
20
#define ADM1272(obj) OBJECT_CHECK(ADM1272State, (obj), TYPE_ADM1272)
21

22
#define ADM1272_RESTART_TIME            0xCC
23
#define ADM1272_MFR_PEAK_IOUT           0xD0
24
#define ADM1272_MFR_PEAK_VIN            0xD1
25
#define ADM1272_MFR_PEAK_VOUT           0xD2
26
#define ADM1272_MFR_PMON_CONTROL        0xD3
27
#define ADM1272_MFR_PMON_CONFIG         0xD4
28
#define ADM1272_MFR_ALERT1_CONFIG       0xD5
29
#define ADM1272_MFR_ALERT2_CONFIG       0xD6
30
#define ADM1272_MFR_PEAK_TEMPERATURE    0xD7
31
#define ADM1272_MFR_DEVICE_CONFIG       0xD8
32
#define ADM1272_MFR_POWER_CYCLE         0xD9
33
#define ADM1272_MFR_PEAK_PIN            0xDA
34
#define ADM1272_MFR_READ_PIN_EXT        0xDB
35
#define ADM1272_MFR_READ_EIN_EXT        0xDC
36

37
#define ADM1272_HYSTERESIS_LOW          0xF2
38
#define ADM1272_HYSTERESIS_HIGH         0xF3
39
#define ADM1272_STATUS_HYSTERESIS       0xF4
40
#define ADM1272_STATUS_GPIO             0xF5
41
#define ADM1272_STRT_UP_IOUT_LIM        0xF6
42

43
/* Defaults */
44
#define ADM1272_OPERATION_DEFAULT       0x80
45
#define ADM1272_CAPABILITY_DEFAULT      0xB0
46
#define ADM1272_CAPABILITY_NO_PEC       0x30
47
#define ADM1272_DIRECT_MODE             0x40
48
#define ADM1272_HIGH_LIMIT_DEFAULT      0x0FFF
49
#define ADM1272_PIN_OP_DEFAULT          0x7FFF
50
#define ADM1272_PMBUS_REVISION_DEFAULT  0x22
51
#define ADM1272_MFR_ID_DEFAULT          "ADI"
52
#define ADM1272_MODEL_DEFAULT           "ADM1272-A1"
53
#define ADM1272_MFR_DEFAULT_REVISION    "25"
54
#define ADM1272_DEFAULT_DATE            "160301"
55
#define ADM1272_RESTART_TIME_DEFAULT    0x64
56
#define ADM1272_PMON_CONTROL_DEFAULT    0x1
57
#define ADM1272_PMON_CONFIG_DEFAULT     0x3F35
58
#define ADM1272_DEVICE_CONFIG_DEFAULT   0x8
59
#define ADM1272_HYSTERESIS_HIGH_DEFAULT     0xFFFF
60
#define ADM1272_STRT_UP_IOUT_LIM_DEFAULT    0x000F
61
#define ADM1272_VOLT_DEFAULT            12000
62
#define ADM1272_IOUT_DEFAULT            25000
63
#define ADM1272_PWR_DEFAULT             300  /* 12V 25A */
64
#define ADM1272_SHUNT                   300 /* micro-ohms */
65
#define ADM1272_VOLTAGE_COEFF_DEFAULT   1
66
#define ADM1272_CURRENT_COEFF_DEFAULT   3
67
#define ADM1272_PWR_COEFF_DEFAULT       7
68
#define ADM1272_IOUT_OFFSET             0x5000
69
#define ADM1272_IOUT_OFFSET             0x5000
70

71

72
typedef struct ADM1272State {
73
    PMBusDevice parent;
74

75
    uint64_t ein_ext;
76
    uint32_t pin_ext;
77
    uint8_t restart_time;
78

79
    uint16_t peak_vin;
80
    uint16_t peak_vout;
81
    uint16_t peak_iout;
82
    uint16_t peak_temperature;
83
    uint16_t peak_pin;
84

85
    uint8_t pmon_control;
86
    uint16_t pmon_config;
87
    uint16_t alert1_config;
88
    uint16_t alert2_config;
89
    uint16_t device_config;
90

91
    uint16_t hysteresis_low;
92
    uint16_t hysteresis_high;
93
    uint8_t status_hysteresis;
94
    uint8_t status_gpio;
95

96
    uint16_t strt_up_iout_lim;
97

98
} ADM1272State;
99

100
static const PMBusCoefficients adm1272_coefficients[] = {
101
    [0] = { 6770, 0, -2 },        /* voltage, vrange 60V */
102
    [1] = { 4062, 0, -2 },        /* voltage, vrange 100V */
103
    [2] = { 1326, 20480, -1 },    /* current, vsense range 15mV */
104
    [3] = { 663, 20480, -1 },     /* current, vsense range 30mV */
105
    [4] = { 3512, 0, -2 },        /* power, vrange 60V, irange 15mV */
106
    [5] = { 21071, 0, -3 },       /* power, vrange 100V, irange 15mV */
107
    [6] = { 17561, 0, -3 },       /* power, vrange 60V, irange 30mV */
108
    [7] = { 10535, 0, -3 },       /* power, vrange 100V, irange 30mV */
109
    [8] = { 42, 31871, -1 },      /* temperature */
110
};
111

112
static void adm1272_check_limits(ADM1272State *s)
113
{
114
    PMBusDevice *pmdev = PMBUS_DEVICE(s);
115

116
    pmbus_check_limits(pmdev);
117

118
    if (pmdev->pages[0].read_vout > s->peak_vout) {
119
        s->peak_vout = pmdev->pages[0].read_vout;
120
    }
121

122
    if (pmdev->pages[0].read_vin > s->peak_vin) {
123
        s->peak_vin = pmdev->pages[0].read_vin;
124
    }
125

126
    if (pmdev->pages[0].read_iout > s->peak_iout) {
127
        s->peak_iout = pmdev->pages[0].read_iout;
128
    }
129

130
    if (pmdev->pages[0].read_temperature_1 > s->peak_temperature) {
131
        s->peak_temperature = pmdev->pages[0].read_temperature_1;
132
    }
133

134
    if (pmdev->pages[0].read_pin > s->peak_pin) {
135
        s->peak_pin = pmdev->pages[0].read_pin;
136
    }
137
}
138

139
static uint16_t adm1272_millivolts_to_direct(uint32_t value)
140
{
141
    PMBusCoefficients c = adm1272_coefficients[ADM1272_VOLTAGE_COEFF_DEFAULT];
142
    c.b = c.b * 1000;
143
    c.R = c.R - 3;
144
    return pmbus_data2direct_mode(c, value);
145
}
146

147
static uint32_t adm1272_direct_to_millivolts(uint16_t value)
148
{
149
    PMBusCoefficients c = adm1272_coefficients[ADM1272_VOLTAGE_COEFF_DEFAULT];
150
    c.b = c.b * 1000;
151
    c.R = c.R - 3;
152
    return pmbus_direct_mode2data(c, value);
153
}
154

155
static uint16_t adm1272_milliamps_to_direct(uint32_t value)
156
{
157
    PMBusCoefficients c = adm1272_coefficients[ADM1272_CURRENT_COEFF_DEFAULT];
158
    /* Y = (m * r_sense * x - b) * 10^R */
159
    c.m = c.m * ADM1272_SHUNT / 1000; /* micro-ohms */
160
    c.b = c.b * 1000;
161
    c.R = c.R - 3;
162
    return pmbus_data2direct_mode(c, value);
163
}
164

165
static uint32_t adm1272_direct_to_milliamps(uint16_t value)
166
{
167
    PMBusCoefficients c = adm1272_coefficients[ADM1272_CURRENT_COEFF_DEFAULT];
168
    c.m = c.m * ADM1272_SHUNT / 1000;
169
    c.b = c.b * 1000;
170
    c.R = c.R - 3;
171
    return pmbus_direct_mode2data(c, value);
172
}
173

174
static uint16_t adm1272_watts_to_direct(uint32_t value)
175
{
176
    PMBusCoefficients c = adm1272_coefficients[ADM1272_PWR_COEFF_DEFAULT];
177
    c.m = c.m * ADM1272_SHUNT / 1000;
178
    return pmbus_data2direct_mode(c, value);
179
}
180

181
static uint32_t adm1272_direct_to_watts(uint16_t value)
182
{
183
    PMBusCoefficients c = adm1272_coefficients[ADM1272_PWR_COEFF_DEFAULT];
184
    c.m = c.m * ADM1272_SHUNT / 1000;
185
    return pmbus_direct_mode2data(c, value);
186
}
187

188
static void adm1272_exit_reset(Object *obj, ResetType type)
189
{
190
    ADM1272State *s = ADM1272(obj);
191
    PMBusDevice *pmdev = PMBUS_DEVICE(obj);
192

193
    pmdev->page = 0;
194
    pmdev->pages[0].operation = ADM1272_OPERATION_DEFAULT;
195

196

197
    pmdev->capability = ADM1272_CAPABILITY_NO_PEC;
198
    pmdev->pages[0].revision = ADM1272_PMBUS_REVISION_DEFAULT;
199
    pmdev->pages[0].vout_mode = ADM1272_DIRECT_MODE;
200
    pmdev->pages[0].vout_ov_warn_limit = ADM1272_HIGH_LIMIT_DEFAULT;
201
    pmdev->pages[0].vout_uv_warn_limit = 0;
202
    pmdev->pages[0].iout_oc_warn_limit = ADM1272_HIGH_LIMIT_DEFAULT;
203
    pmdev->pages[0].ot_fault_limit = ADM1272_HIGH_LIMIT_DEFAULT;
204
    pmdev->pages[0].ot_warn_limit = ADM1272_HIGH_LIMIT_DEFAULT;
205
    pmdev->pages[0].vin_ov_warn_limit = ADM1272_HIGH_LIMIT_DEFAULT;
206
    pmdev->pages[0].vin_uv_warn_limit = 0;
207
    pmdev->pages[0].pin_op_warn_limit = ADM1272_PIN_OP_DEFAULT;
208

209
    pmdev->pages[0].status_word = 0;
210
    pmdev->pages[0].status_vout = 0;
211
    pmdev->pages[0].status_iout = 0;
212
    pmdev->pages[0].status_input = 0;
213
    pmdev->pages[0].status_temperature = 0;
214
    pmdev->pages[0].status_mfr_specific = 0;
215

216
    pmdev->pages[0].read_vin
217
        = adm1272_millivolts_to_direct(ADM1272_VOLT_DEFAULT);
218
    pmdev->pages[0].read_vout
219
        = adm1272_millivolts_to_direct(ADM1272_VOLT_DEFAULT);
220
    pmdev->pages[0].read_iout
221
        = adm1272_milliamps_to_direct(ADM1272_IOUT_DEFAULT);
222
    pmdev->pages[0].read_temperature_1 = 0;
223
    pmdev->pages[0].read_pin = adm1272_watts_to_direct(ADM1272_PWR_DEFAULT);
224
    pmdev->pages[0].revision = ADM1272_PMBUS_REVISION_DEFAULT;
225
    pmdev->pages[0].mfr_id = ADM1272_MFR_ID_DEFAULT;
226
    pmdev->pages[0].mfr_model = ADM1272_MODEL_DEFAULT;
227
    pmdev->pages[0].mfr_revision = ADM1272_MFR_DEFAULT_REVISION;
228
    pmdev->pages[0].mfr_date = ADM1272_DEFAULT_DATE;
229

230
    s->pin_ext = 0;
231
    s->ein_ext = 0;
232
    s->restart_time = ADM1272_RESTART_TIME_DEFAULT;
233

234
    s->peak_vin = 0;
235
    s->peak_vout = 0;
236
    s->peak_iout = 0;
237
    s->peak_temperature = 0;
238
    s->peak_pin = 0;
239

240
    s->pmon_control = ADM1272_PMON_CONTROL_DEFAULT;
241
    s->pmon_config = ADM1272_PMON_CONFIG_DEFAULT;
242
    s->alert1_config = 0;
243
    s->alert2_config = 0;
244
    s->device_config = ADM1272_DEVICE_CONFIG_DEFAULT;
245

246
    s->hysteresis_low = 0;
247
    s->hysteresis_high = ADM1272_HYSTERESIS_HIGH_DEFAULT;
248
    s->status_hysteresis = 0;
249
    s->status_gpio = 0;
250

251
    s->strt_up_iout_lim = ADM1272_STRT_UP_IOUT_LIM_DEFAULT;
252
}
253

254
static uint8_t adm1272_read_byte(PMBusDevice *pmdev)
255
{
256
    ADM1272State *s = ADM1272(pmdev);
257

258
    switch (pmdev->code) {
259
    case ADM1272_RESTART_TIME:
260
        pmbus_send8(pmdev, s->restart_time);
261
        break;
262

263
    case ADM1272_MFR_PEAK_IOUT:
264
        pmbus_send16(pmdev, s->peak_iout);
265
        break;
266

267
    case ADM1272_MFR_PEAK_VIN:
268
        pmbus_send16(pmdev, s->peak_vin);
269
        break;
270

271
    case ADM1272_MFR_PEAK_VOUT:
272
        pmbus_send16(pmdev, s->peak_vout);
273
        break;
274

275
    case ADM1272_MFR_PMON_CONTROL:
276
        pmbus_send8(pmdev, s->pmon_control);
277
        break;
278

279
    case ADM1272_MFR_PMON_CONFIG:
280
        pmbus_send16(pmdev, s->pmon_config);
281
        break;
282

283
    case ADM1272_MFR_ALERT1_CONFIG:
284
        pmbus_send16(pmdev, s->alert1_config);
285
        break;
286

287
    case ADM1272_MFR_ALERT2_CONFIG:
288
        pmbus_send16(pmdev, s->alert2_config);
289
        break;
290

291
    case ADM1272_MFR_PEAK_TEMPERATURE:
292
        pmbus_send16(pmdev, s->peak_temperature);
293
        break;
294

295
    case ADM1272_MFR_DEVICE_CONFIG:
296
        pmbus_send16(pmdev, s->device_config);
297
        break;
298

299
    case ADM1272_MFR_PEAK_PIN:
300
        pmbus_send16(pmdev, s->peak_pin);
301
        break;
302

303
    case ADM1272_MFR_READ_PIN_EXT:
304
        pmbus_send32(pmdev, s->pin_ext);
305
        break;
306

307
    case ADM1272_MFR_READ_EIN_EXT:
308
        pmbus_send64(pmdev, s->ein_ext);
309
        break;
310

311
    case ADM1272_HYSTERESIS_LOW:
312
        pmbus_send16(pmdev, s->hysteresis_low);
313
        break;
314

315
    case ADM1272_HYSTERESIS_HIGH:
316
        pmbus_send16(pmdev, s->hysteresis_high);
317
        break;
318

319
    case ADM1272_STATUS_HYSTERESIS:
320
        pmbus_send16(pmdev, s->status_hysteresis);
321
        break;
322

323
    case ADM1272_STATUS_GPIO:
324
        pmbus_send16(pmdev, s->status_gpio);
325
        break;
326

327
    case ADM1272_STRT_UP_IOUT_LIM:
328
        pmbus_send16(pmdev, s->strt_up_iout_lim);
329
        break;
330

331
    default:
332
        qemu_log_mask(LOG_GUEST_ERROR,
333
                      "%s: reading from unsupported register: 0x%02x\n",
334
                      __func__, pmdev->code);
335
        return 0xFF;
336
        break;
337
    }
338

339
    return 0;
340
}
341

342
static int adm1272_write_data(PMBusDevice *pmdev, const uint8_t *buf,
343
                              uint8_t len)
344
{
345
    ADM1272State *s = ADM1272(pmdev);
346

347
    if (len == 0) {
348
        qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__);
349
        return -1;
350
    }
351

352
    pmdev->code = buf[0]; /* PMBus command code */
353

354
    if (len == 1) {
355
        return 0;
356
    }
357

358
    /* Exclude command code from buffer */
359
    buf++;
360
    len--;
361

362
    switch (pmdev->code) {
363

364
    case ADM1272_RESTART_TIME:
365
        s->restart_time = pmbus_receive8(pmdev);
366
        break;
367

368
    case ADM1272_MFR_PMON_CONTROL:
369
        s->pmon_control = pmbus_receive8(pmdev);
370
        break;
371

372
    case ADM1272_MFR_PMON_CONFIG:
373
        s->pmon_config = pmbus_receive16(pmdev);
374
        break;
375

376
    case ADM1272_MFR_ALERT1_CONFIG:
377
        s->alert1_config = pmbus_receive16(pmdev);
378
        break;
379

380
    case ADM1272_MFR_ALERT2_CONFIG:
381
        s->alert2_config = pmbus_receive16(pmdev);
382
        break;
383

384
    case ADM1272_MFR_DEVICE_CONFIG:
385
        s->device_config = pmbus_receive16(pmdev);
386
        break;
387

388
    case ADM1272_MFR_POWER_CYCLE:
389
        device_cold_reset(DEVICE(s));
390
        break;
391

392
    case ADM1272_HYSTERESIS_LOW:
393
        s->hysteresis_low = pmbus_receive16(pmdev);
394
        break;
395

396
    case ADM1272_HYSTERESIS_HIGH:
397
        s->hysteresis_high = pmbus_receive16(pmdev);
398
        break;
399

400
    case ADM1272_STRT_UP_IOUT_LIM:
401
        s->strt_up_iout_lim = pmbus_receive16(pmdev);
402
        adm1272_check_limits(s);
403
        break;
404

405
    default:
406
        qemu_log_mask(LOG_GUEST_ERROR,
407
                      "%s: writing to unsupported register: 0x%02x\n",
408
                      __func__, pmdev->code);
409
        break;
410
    }
411
    return 0;
412
}
413

414
static void adm1272_get(Object *obj, Visitor *v, const char *name, void *opaque,
415
                        Error **errp)
416
{
417
    uint16_t value;
418

419
    if (strcmp(name, "vin") == 0 || strcmp(name, "vout") == 0) {
420
        value = adm1272_direct_to_millivolts(*(uint16_t *)opaque);
421
    } else if (strcmp(name, "iout") == 0) {
422
        value = adm1272_direct_to_milliamps(*(uint16_t *)opaque);
423
    } else if (strcmp(name, "pin") == 0) {
424
        value = adm1272_direct_to_watts(*(uint16_t *)opaque);
425
    } else {
426
        value = *(uint16_t *)opaque;
427
    }
428

429
    visit_type_uint16(v, name, &value, errp);
430
}
431

432
static void adm1272_set(Object *obj, Visitor *v, const char *name, void *opaque,
433
                        Error **errp)
434
{
435
    ADM1272State *s = ADM1272(obj);
436
    uint16_t *internal = opaque;
437
    uint16_t value;
438

439
    if (!visit_type_uint16(v, name, &value, errp)) {
440
        return;
441
    }
442

443
    if (strcmp(name, "vin") == 0 || strcmp(name, "vout") == 0) {
444
        *internal = adm1272_millivolts_to_direct(value);
445
    } else if (strcmp(name, "iout") == 0) {
446
        *internal = adm1272_milliamps_to_direct(value);
447
    } else if (strcmp(name, "pin") == 0) {
448
        *internal = adm1272_watts_to_direct(value);
449
    } else {
450
        *internal = value;
451
    }
452

453
    adm1272_check_limits(s);
454
}
455

456
static const VMStateDescription vmstate_adm1272 = {
457
    .name = "ADM1272",
458
    .version_id = 0,
459
    .minimum_version_id = 0,
460
    .fields = (const VMStateField[]){
461
        VMSTATE_PMBUS_DEVICE(parent, ADM1272State),
462
        VMSTATE_UINT64(ein_ext, ADM1272State),
463
        VMSTATE_UINT32(pin_ext, ADM1272State),
464
        VMSTATE_UINT8(restart_time, ADM1272State),
465

466
        VMSTATE_UINT16(peak_vin, ADM1272State),
467
        VMSTATE_UINT16(peak_vout, ADM1272State),
468
        VMSTATE_UINT16(peak_iout, ADM1272State),
469
        VMSTATE_UINT16(peak_temperature, ADM1272State),
470
        VMSTATE_UINT16(peak_pin, ADM1272State),
471

472
        VMSTATE_UINT8(pmon_control, ADM1272State),
473
        VMSTATE_UINT16(pmon_config, ADM1272State),
474
        VMSTATE_UINT16(alert1_config, ADM1272State),
475
        VMSTATE_UINT16(alert2_config, ADM1272State),
476
        VMSTATE_UINT16(device_config, ADM1272State),
477

478
        VMSTATE_UINT16(hysteresis_low, ADM1272State),
479
        VMSTATE_UINT16(hysteresis_high, ADM1272State),
480
        VMSTATE_UINT8(status_hysteresis, ADM1272State),
481
        VMSTATE_UINT8(status_gpio, ADM1272State),
482

483
        VMSTATE_UINT16(strt_up_iout_lim, ADM1272State),
484
        VMSTATE_END_OF_LIST()
485
    }
486
};
487

488
static void adm1272_init(Object *obj)
489
{
490
    PMBusDevice *pmdev = PMBUS_DEVICE(obj);
491
    uint64_t flags = PB_HAS_VOUT_MODE | PB_HAS_VOUT | PB_HAS_VIN | PB_HAS_IOUT |
492
                     PB_HAS_PIN | PB_HAS_TEMPERATURE | PB_HAS_MFR_INFO;
493

494
    pmbus_page_config(pmdev, 0, flags);
495

496
    object_property_add(obj, "vin", "uint16",
497
                        adm1272_get,
498
                        adm1272_set, NULL, &pmdev->pages[0].read_vin);
499

500
    object_property_add(obj, "vout", "uint16",
501
                        adm1272_get,
502
                        adm1272_set, NULL, &pmdev->pages[0].read_vout);
503

504
    object_property_add(obj, "iout", "uint16",
505
                        adm1272_get,
506
                        adm1272_set, NULL, &pmdev->pages[0].read_iout);
507

508
    object_property_add(obj, "pin", "uint16",
509
                        adm1272_get,
510
                        adm1272_set, NULL, &pmdev->pages[0].read_pin);
511

512
}
513

514
static void adm1272_class_init(ObjectClass *klass, void *data)
515
{
516
    ResettableClass *rc = RESETTABLE_CLASS(klass);
517
    DeviceClass *dc = DEVICE_CLASS(klass);
518
    PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass);
519

520
    dc->desc = "Analog Devices ADM1272 Hot Swap controller";
521
    dc->vmsd = &vmstate_adm1272;
522
    k->write_data = adm1272_write_data;
523
    k->receive_byte = adm1272_read_byte;
524
    k->device_num_pages = 1;
525

526
    rc->phases.exit = adm1272_exit_reset;
527
}
528

529
static const TypeInfo adm1272_info = {
530
    .name = TYPE_ADM1272,
531
    .parent = TYPE_PMBUS_DEVICE,
532
    .instance_size = sizeof(ADM1272State),
533
    .instance_init = adm1272_init,
534
    .class_init = adm1272_class_init,
535
};
536

537
static void adm1272_register_types(void)
538
{
539
    type_register_static(&adm1272_info);
540
}
541

542
type_init(adm1272_register_types)
543

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.