xref: /openbmc/qemu/hw/sensor/adm1266.c (revision ad80e367)
16f351a7aSTitus Rwantare /*
26f351a7aSTitus Rwantare  * Analog Devices ADM1266 Cascadable Super Sequencer with Margin Control and
36f351a7aSTitus Rwantare  * Fault Recording with PMBus
46f351a7aSTitus Rwantare  *
56f351a7aSTitus Rwantare  * https://www.analog.com/media/en/technical-documentation/data-sheets/adm1266.pdf
66f351a7aSTitus Rwantare  *
76f351a7aSTitus Rwantare  * Copyright 2023 Google LLC
86f351a7aSTitus Rwantare  *
96f351a7aSTitus Rwantare  * SPDX-License-Identifier: GPL-2.0-or-later
106f351a7aSTitus Rwantare  */
116f351a7aSTitus Rwantare 
126f351a7aSTitus Rwantare #include "qemu/osdep.h"
136f351a7aSTitus Rwantare #include "hw/i2c/pmbus_device.h"
146f351a7aSTitus Rwantare #include "hw/irq.h"
156f351a7aSTitus Rwantare #include "migration/vmstate.h"
166f351a7aSTitus Rwantare #include "qapi/error.h"
176f351a7aSTitus Rwantare #include "qapi/visitor.h"
186f351a7aSTitus Rwantare #include "qemu/log.h"
196f351a7aSTitus Rwantare #include "qemu/module.h"
206f351a7aSTitus Rwantare 
216f351a7aSTitus Rwantare #define TYPE_ADM1266 "adm1266"
226f351a7aSTitus Rwantare OBJECT_DECLARE_SIMPLE_TYPE(ADM1266State, ADM1266)
236f351a7aSTitus Rwantare 
246f351a7aSTitus Rwantare #define ADM1266_BLACKBOX_CONFIG                 0xD3
256f351a7aSTitus Rwantare #define ADM1266_PDIO_CONFIG                     0xD4
266f351a7aSTitus Rwantare #define ADM1266_READ_STATE                      0xD9
276f351a7aSTitus Rwantare #define ADM1266_READ_BLACKBOX                   0xDE
286f351a7aSTitus Rwantare #define ADM1266_SET_RTC                         0xDF
296f351a7aSTitus Rwantare #define ADM1266_GPIO_SYNC_CONFIGURATION         0xE1
306f351a7aSTitus Rwantare #define ADM1266_BLACKBOX_INFORMATION            0xE6
316f351a7aSTitus Rwantare #define ADM1266_PDIO_STATUS                     0xE9
326f351a7aSTitus Rwantare #define ADM1266_GPIO_STATUS                     0xEA
336f351a7aSTitus Rwantare 
346f351a7aSTitus Rwantare /* Defaults */
356f351a7aSTitus Rwantare #define ADM1266_OPERATION_DEFAULT               0x80
366f351a7aSTitus Rwantare #define ADM1266_CAPABILITY_DEFAULT              0xA0
376f351a7aSTitus Rwantare #define ADM1266_CAPABILITY_NO_PEC               0x20
386f351a7aSTitus Rwantare #define ADM1266_PMBUS_REVISION_DEFAULT          0x22
396f351a7aSTitus Rwantare #define ADM1266_MFR_ID_DEFAULT                  "ADI"
406f351a7aSTitus Rwantare #define ADM1266_MFR_ID_DEFAULT_LEN              32
416f351a7aSTitus Rwantare #define ADM1266_MFR_MODEL_DEFAULT               "ADM1266-A1"
426f351a7aSTitus Rwantare #define ADM1266_MFR_MODEL_DEFAULT_LEN           32
436f351a7aSTitus Rwantare #define ADM1266_MFR_REVISION_DEFAULT            "25"
446f351a7aSTitus Rwantare #define ADM1266_MFR_REVISION_DEFAULT_LEN        8
456f351a7aSTitus Rwantare 
466f351a7aSTitus Rwantare #define ADM1266_NUM_PAGES               17
476f351a7aSTitus Rwantare /**
486f351a7aSTitus Rwantare  * PAGE Index
496f351a7aSTitus Rwantare  * Page 0 VH1.
506f351a7aSTitus Rwantare  * Page 1 VH2.
516f351a7aSTitus Rwantare  * Page 2 VH3.
526f351a7aSTitus Rwantare  * Page 3 VH4.
536f351a7aSTitus Rwantare  * Page 4 VP1.
546f351a7aSTitus Rwantare  * Page 5 VP2.
556f351a7aSTitus Rwantare  * Page 6 VP3.
566f351a7aSTitus Rwantare  * Page 7 VP4.
576f351a7aSTitus Rwantare  * Page 8 VP5.
586f351a7aSTitus Rwantare  * Page 9 VP6.
596f351a7aSTitus Rwantare  * Page 10 VP7.
606f351a7aSTitus Rwantare  * Page 11 VP8.
616f351a7aSTitus Rwantare  * Page 12 VP9.
626f351a7aSTitus Rwantare  * Page 13 VP10.
636f351a7aSTitus Rwantare  * Page 14 VP11.
646f351a7aSTitus Rwantare  * Page 15 VP12.
656f351a7aSTitus Rwantare  * Page 16 VP13.
666f351a7aSTitus Rwantare  */
676f351a7aSTitus Rwantare typedef struct ADM1266State {
686f351a7aSTitus Rwantare     PMBusDevice parent;
696f351a7aSTitus Rwantare 
706f351a7aSTitus Rwantare     char mfr_id[32];
716f351a7aSTitus Rwantare     char mfr_model[32];
726f351a7aSTitus Rwantare     char mfr_rev[8];
736f351a7aSTitus Rwantare } ADM1266State;
746f351a7aSTitus Rwantare 
756f351a7aSTitus Rwantare static const uint8_t adm1266_ic_device_id[] = {0x03, 0x41, 0x12, 0x66};
766f351a7aSTitus Rwantare static const uint8_t adm1266_ic_device_rev[] = {0x08, 0x01, 0x08, 0x07, 0x0,
776f351a7aSTitus Rwantare                                                 0x0, 0x07, 0x41, 0x30};
786f351a7aSTitus Rwantare 
adm1266_exit_reset(Object * obj,ResetType type)79*ad80e367SPeter Maydell static void adm1266_exit_reset(Object *obj, ResetType type)
806f351a7aSTitus Rwantare {
816f351a7aSTitus Rwantare     ADM1266State *s = ADM1266(obj);
826f351a7aSTitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
836f351a7aSTitus Rwantare 
846f351a7aSTitus Rwantare     pmdev->page = 0;
856f351a7aSTitus Rwantare     pmdev->capability = ADM1266_CAPABILITY_NO_PEC;
866f351a7aSTitus Rwantare 
876f351a7aSTitus Rwantare     for (int i = 0; i < ADM1266_NUM_PAGES; i++) {
886f351a7aSTitus Rwantare         pmdev->pages[i].operation = ADM1266_OPERATION_DEFAULT;
896f351a7aSTitus Rwantare         pmdev->pages[i].revision = ADM1266_PMBUS_REVISION_DEFAULT;
906f351a7aSTitus Rwantare         pmdev->pages[i].vout_mode = 0;
916f351a7aSTitus Rwantare         pmdev->pages[i].read_vout = pmbus_data2linear_mode(12, 0);
926f351a7aSTitus Rwantare         pmdev->pages[i].vout_margin_high = pmbus_data2linear_mode(15, 0);
936f351a7aSTitus Rwantare         pmdev->pages[i].vout_margin_low = pmbus_data2linear_mode(3, 0);
946f351a7aSTitus Rwantare         pmdev->pages[i].vout_ov_fault_limit = pmbus_data2linear_mode(16, 0);
956f351a7aSTitus Rwantare         pmdev->pages[i].revision = ADM1266_PMBUS_REVISION_DEFAULT;
966f351a7aSTitus Rwantare     }
976f351a7aSTitus Rwantare 
986f351a7aSTitus Rwantare     strncpy(s->mfr_id, ADM1266_MFR_ID_DEFAULT, 4);
996f351a7aSTitus Rwantare     strncpy(s->mfr_model, ADM1266_MFR_MODEL_DEFAULT, 11);
1006f351a7aSTitus Rwantare     strncpy(s->mfr_rev, ADM1266_MFR_REVISION_DEFAULT, 3);
1016f351a7aSTitus Rwantare }
1026f351a7aSTitus Rwantare 
adm1266_read_byte(PMBusDevice * pmdev)1036f351a7aSTitus Rwantare static uint8_t adm1266_read_byte(PMBusDevice *pmdev)
1046f351a7aSTitus Rwantare {
1056f351a7aSTitus Rwantare     ADM1266State *s = ADM1266(pmdev);
1066f351a7aSTitus Rwantare 
1076f351a7aSTitus Rwantare     switch (pmdev->code) {
1086f351a7aSTitus Rwantare     case PMBUS_MFR_ID:                    /* R/W block */
1096f351a7aSTitus Rwantare         pmbus_send_string(pmdev, s->mfr_id);
1106f351a7aSTitus Rwantare         break;
1116f351a7aSTitus Rwantare 
1126f351a7aSTitus Rwantare     case PMBUS_MFR_MODEL:                 /* R/W block */
1136f351a7aSTitus Rwantare         pmbus_send_string(pmdev, s->mfr_model);
1146f351a7aSTitus Rwantare         break;
1156f351a7aSTitus Rwantare 
1166f351a7aSTitus Rwantare     case PMBUS_MFR_REVISION:              /* R/W block */
1176f351a7aSTitus Rwantare         pmbus_send_string(pmdev, s->mfr_rev);
1186f351a7aSTitus Rwantare         break;
1196f351a7aSTitus Rwantare 
1206f351a7aSTitus Rwantare     case PMBUS_IC_DEVICE_ID:
1216f351a7aSTitus Rwantare         pmbus_send(pmdev, adm1266_ic_device_id, sizeof(adm1266_ic_device_id));
1226f351a7aSTitus Rwantare         break;
1236f351a7aSTitus Rwantare 
1246f351a7aSTitus Rwantare     case PMBUS_IC_DEVICE_REV:
1256f351a7aSTitus Rwantare         pmbus_send(pmdev, adm1266_ic_device_rev, sizeof(adm1266_ic_device_rev));
1266f351a7aSTitus Rwantare         break;
1276f351a7aSTitus Rwantare 
1286f351a7aSTitus Rwantare     default:
1296f351a7aSTitus Rwantare         qemu_log_mask(LOG_UNIMP,
1306f351a7aSTitus Rwantare                       "%s: reading from unimplemented register: 0x%02x\n",
1316f351a7aSTitus Rwantare                       __func__, pmdev->code);
1326f351a7aSTitus Rwantare         return 0xFF;
1336f351a7aSTitus Rwantare     }
1346f351a7aSTitus Rwantare 
1356f351a7aSTitus Rwantare     return 0;
1366f351a7aSTitus Rwantare }
1376f351a7aSTitus Rwantare 
adm1266_write_data(PMBusDevice * pmdev,const uint8_t * buf,uint8_t len)1386f351a7aSTitus Rwantare static int adm1266_write_data(PMBusDevice *pmdev, const uint8_t *buf,
1396f351a7aSTitus Rwantare                               uint8_t len)
1406f351a7aSTitus Rwantare {
1416f351a7aSTitus Rwantare     ADM1266State *s = ADM1266(pmdev);
1426f351a7aSTitus Rwantare 
1436f351a7aSTitus Rwantare     switch (pmdev->code) {
1446f351a7aSTitus Rwantare     case PMBUS_MFR_ID:                    /* R/W block */
1456f351a7aSTitus Rwantare         pmbus_receive_block(pmdev, (uint8_t *)s->mfr_id, sizeof(s->mfr_id));
1466f351a7aSTitus Rwantare         break;
1476f351a7aSTitus Rwantare 
1486f351a7aSTitus Rwantare     case PMBUS_MFR_MODEL:                 /* R/W block */
1496f351a7aSTitus Rwantare         pmbus_receive_block(pmdev, (uint8_t *)s->mfr_model,
1506f351a7aSTitus Rwantare                             sizeof(s->mfr_model));
1516f351a7aSTitus Rwantare         break;
1526f351a7aSTitus Rwantare 
1536f351a7aSTitus Rwantare     case PMBUS_MFR_REVISION:               /* R/W block*/
1546f351a7aSTitus Rwantare         pmbus_receive_block(pmdev, (uint8_t *)s->mfr_rev, sizeof(s->mfr_rev));
1556f351a7aSTitus Rwantare         break;
1566f351a7aSTitus Rwantare 
1576f351a7aSTitus Rwantare     case ADM1266_SET_RTC:   /* do nothing */
1586f351a7aSTitus Rwantare         break;
1596f351a7aSTitus Rwantare 
1606f351a7aSTitus Rwantare     default:
1616f351a7aSTitus Rwantare         qemu_log_mask(LOG_UNIMP,
1626f351a7aSTitus Rwantare                       "%s: writing to unimplemented register: 0x%02x\n",
1636f351a7aSTitus Rwantare                       __func__, pmdev->code);
1646f351a7aSTitus Rwantare         break;
1656f351a7aSTitus Rwantare     }
1666f351a7aSTitus Rwantare     return 0;
1676f351a7aSTitus Rwantare }
1686f351a7aSTitus Rwantare 
adm1266_get(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)1696f351a7aSTitus Rwantare static void adm1266_get(Object *obj, Visitor *v, const char *name, void *opaque,
1706f351a7aSTitus Rwantare                         Error **errp)
1716f351a7aSTitus Rwantare {
1726f351a7aSTitus Rwantare     uint16_t value;
1736f351a7aSTitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
1746f351a7aSTitus Rwantare     PMBusVoutMode *mode = (PMBusVoutMode *)&pmdev->pages[0].vout_mode;
1756f351a7aSTitus Rwantare 
1766f351a7aSTitus Rwantare     if (strcmp(name, "vout") == 0) {
1776f351a7aSTitus Rwantare         value = pmbus_linear_mode2data(*(uint16_t *)opaque, mode->exp);
1786f351a7aSTitus Rwantare     } else {
1796f351a7aSTitus Rwantare         value = *(uint16_t *)opaque;
1806f351a7aSTitus Rwantare     }
1816f351a7aSTitus Rwantare 
1826f351a7aSTitus Rwantare     visit_type_uint16(v, name, &value, errp);
1836f351a7aSTitus Rwantare }
1846f351a7aSTitus Rwantare 
adm1266_set(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)1856f351a7aSTitus Rwantare static void adm1266_set(Object *obj, Visitor *v, const char *name, void *opaque,
1866f351a7aSTitus Rwantare                         Error **errp)
1876f351a7aSTitus Rwantare {
1886f351a7aSTitus Rwantare     uint16_t *internal = opaque;
1896f351a7aSTitus Rwantare     uint16_t value;
1906f351a7aSTitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
1916f351a7aSTitus Rwantare     PMBusVoutMode *mode = (PMBusVoutMode *)&pmdev->pages[0].vout_mode;
1926f351a7aSTitus Rwantare 
1936f351a7aSTitus Rwantare     if (!visit_type_uint16(v, name, &value, errp)) {
1946f351a7aSTitus Rwantare         return;
1956f351a7aSTitus Rwantare     }
1966f351a7aSTitus Rwantare 
1976f351a7aSTitus Rwantare     *internal = pmbus_data2linear_mode(value, mode->exp);
1986f351a7aSTitus Rwantare     pmbus_check_limits(pmdev);
1996f351a7aSTitus Rwantare }
2006f351a7aSTitus Rwantare 
2016f351a7aSTitus Rwantare static const VMStateDescription vmstate_adm1266 = {
2026f351a7aSTitus Rwantare     .name = "ADM1266",
2036f351a7aSTitus Rwantare     .version_id = 0,
2046f351a7aSTitus Rwantare     .minimum_version_id = 0,
205af10fff2SRichard Henderson     .fields = (const VMStateField[]){
2066f351a7aSTitus Rwantare         VMSTATE_PMBUS_DEVICE(parent, ADM1266State),
2076f351a7aSTitus Rwantare         VMSTATE_END_OF_LIST()
2086f351a7aSTitus Rwantare     }
2096f351a7aSTitus Rwantare };
2106f351a7aSTitus Rwantare 
adm1266_init(Object * obj)2116f351a7aSTitus Rwantare static void adm1266_init(Object *obj)
2126f351a7aSTitus Rwantare {
2136f351a7aSTitus Rwantare     PMBusDevice *pmdev = PMBUS_DEVICE(obj);
2146f351a7aSTitus Rwantare     uint64_t flags = PB_HAS_VOUT_MODE | PB_HAS_VOUT | PB_HAS_VOUT_MARGIN |
2156f351a7aSTitus Rwantare                      PB_HAS_VOUT_RATING | PB_HAS_STATUS_MFR_SPECIFIC;
2166f351a7aSTitus Rwantare 
2176f351a7aSTitus Rwantare     for (int i = 0; i < ADM1266_NUM_PAGES; i++) {
2186f351a7aSTitus Rwantare         pmbus_page_config(pmdev, i, flags);
2196f351a7aSTitus Rwantare 
2206f351a7aSTitus Rwantare         object_property_add(obj, "vout[*]", "uint16",
2216f351a7aSTitus Rwantare                             adm1266_get,
2226f351a7aSTitus Rwantare                             adm1266_set, NULL, &pmdev->pages[i].read_vout);
2236f351a7aSTitus Rwantare     }
2246f351a7aSTitus Rwantare }
2256f351a7aSTitus Rwantare 
adm1266_class_init(ObjectClass * klass,void * data)2266f351a7aSTitus Rwantare static void adm1266_class_init(ObjectClass *klass, void *data)
2276f351a7aSTitus Rwantare {
2286f351a7aSTitus Rwantare     ResettableClass *rc = RESETTABLE_CLASS(klass);
2296f351a7aSTitus Rwantare     DeviceClass *dc = DEVICE_CLASS(klass);
2306f351a7aSTitus Rwantare     PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass);
2316f351a7aSTitus Rwantare 
2326f351a7aSTitus Rwantare     dc->desc = "Analog Devices ADM1266 Hot Swap controller";
2336f351a7aSTitus Rwantare     dc->vmsd = &vmstate_adm1266;
2346f351a7aSTitus Rwantare     k->write_data = adm1266_write_data;
2356f351a7aSTitus Rwantare     k->receive_byte = adm1266_read_byte;
2366f351a7aSTitus Rwantare     k->device_num_pages = 17;
2376f351a7aSTitus Rwantare 
2386f351a7aSTitus Rwantare     rc->phases.exit = adm1266_exit_reset;
2396f351a7aSTitus Rwantare }
2406f351a7aSTitus Rwantare 
2416f351a7aSTitus Rwantare static const TypeInfo adm1266_info = {
2426f351a7aSTitus Rwantare     .name = TYPE_ADM1266,
2436f351a7aSTitus Rwantare     .parent = TYPE_PMBUS_DEVICE,
2446f351a7aSTitus Rwantare     .instance_size = sizeof(ADM1266State),
2456f351a7aSTitus Rwantare     .instance_init = adm1266_init,
2466f351a7aSTitus Rwantare     .class_init = adm1266_class_init,
2476f351a7aSTitus Rwantare };
2486f351a7aSTitus Rwantare 
adm1266_register_types(void)2496f351a7aSTitus Rwantare static void adm1266_register_types(void)
2506f351a7aSTitus Rwantare {
2516f351a7aSTitus Rwantare     type_register_static(&adm1266_info);
2526f351a7aSTitus Rwantare }
2536f351a7aSTitus Rwantare 
2546f351a7aSTitus Rwantare type_init(adm1266_register_types)
255