2
0

adm1266.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /*
  2. * Analog Devices ADM1266 Cascadable Super Sequencer with Margin Control and
  3. * Fault Recording with PMBus
  4. *
  5. * https://www.analog.com/media/en/technical-documentation/data-sheets/adm1266.pdf
  6. *
  7. * Copyright 2023 Google LLC
  8. *
  9. * SPDX-License-Identifier: GPL-2.0-or-later
  10. */
  11. #include "qemu/osdep.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. #define TYPE_ADM1266 "adm1266"
  20. OBJECT_DECLARE_SIMPLE_TYPE(ADM1266State, ADM1266)
  21. #define ADM1266_BLACKBOX_CONFIG 0xD3
  22. #define ADM1266_PDIO_CONFIG 0xD4
  23. #define ADM1266_READ_STATE 0xD9
  24. #define ADM1266_READ_BLACKBOX 0xDE
  25. #define ADM1266_SET_RTC 0xDF
  26. #define ADM1266_GPIO_SYNC_CONFIGURATION 0xE1
  27. #define ADM1266_BLACKBOX_INFORMATION 0xE6
  28. #define ADM1266_PDIO_STATUS 0xE9
  29. #define ADM1266_GPIO_STATUS 0xEA
  30. /* Defaults */
  31. #define ADM1266_OPERATION_DEFAULT 0x80
  32. #define ADM1266_CAPABILITY_DEFAULT 0xA0
  33. #define ADM1266_CAPABILITY_NO_PEC 0x20
  34. #define ADM1266_PMBUS_REVISION_DEFAULT 0x22
  35. #define ADM1266_MFR_ID_DEFAULT "ADI"
  36. #define ADM1266_MFR_ID_DEFAULT_LEN 32
  37. #define ADM1266_MFR_MODEL_DEFAULT "ADM1266-A1"
  38. #define ADM1266_MFR_MODEL_DEFAULT_LEN 32
  39. #define ADM1266_MFR_REVISION_DEFAULT "25"
  40. #define ADM1266_MFR_REVISION_DEFAULT_LEN 8
  41. #define ADM1266_NUM_PAGES 17
  42. /**
  43. * PAGE Index
  44. * Page 0 VH1.
  45. * Page 1 VH2.
  46. * Page 2 VH3.
  47. * Page 3 VH4.
  48. * Page 4 VP1.
  49. * Page 5 VP2.
  50. * Page 6 VP3.
  51. * Page 7 VP4.
  52. * Page 8 VP5.
  53. * Page 9 VP6.
  54. * Page 10 VP7.
  55. * Page 11 VP8.
  56. * Page 12 VP9.
  57. * Page 13 VP10.
  58. * Page 14 VP11.
  59. * Page 15 VP12.
  60. * Page 16 VP13.
  61. */
  62. typedef struct ADM1266State {
  63. PMBusDevice parent;
  64. char mfr_id[32];
  65. char mfr_model[32];
  66. char mfr_rev[8];
  67. } ADM1266State;
  68. static const uint8_t adm1266_ic_device_id[] = {0x03, 0x41, 0x12, 0x66};
  69. static const uint8_t adm1266_ic_device_rev[] = {0x08, 0x01, 0x08, 0x07, 0x0,
  70. 0x0, 0x07, 0x41, 0x30};
  71. static void adm1266_exit_reset(Object *obj, ResetType type)
  72. {
  73. ADM1266State *s = ADM1266(obj);
  74. PMBusDevice *pmdev = PMBUS_DEVICE(obj);
  75. pmdev->page = 0;
  76. pmdev->capability = ADM1266_CAPABILITY_NO_PEC;
  77. for (int i = 0; i < ADM1266_NUM_PAGES; i++) {
  78. pmdev->pages[i].operation = ADM1266_OPERATION_DEFAULT;
  79. pmdev->pages[i].revision = ADM1266_PMBUS_REVISION_DEFAULT;
  80. pmdev->pages[i].vout_mode = 0;
  81. pmdev->pages[i].read_vout = pmbus_data2linear_mode(12, 0);
  82. pmdev->pages[i].vout_margin_high = pmbus_data2linear_mode(15, 0);
  83. pmdev->pages[i].vout_margin_low = pmbus_data2linear_mode(3, 0);
  84. pmdev->pages[i].vout_ov_fault_limit = pmbus_data2linear_mode(16, 0);
  85. pmdev->pages[i].revision = ADM1266_PMBUS_REVISION_DEFAULT;
  86. }
  87. strncpy(s->mfr_id, ADM1266_MFR_ID_DEFAULT, 4);
  88. strncpy(s->mfr_model, ADM1266_MFR_MODEL_DEFAULT, 11);
  89. strncpy(s->mfr_rev, ADM1266_MFR_REVISION_DEFAULT, 3);
  90. }
  91. static uint8_t adm1266_read_byte(PMBusDevice *pmdev)
  92. {
  93. ADM1266State *s = ADM1266(pmdev);
  94. switch (pmdev->code) {
  95. case PMBUS_MFR_ID: /* R/W block */
  96. pmbus_send_string(pmdev, s->mfr_id);
  97. break;
  98. case PMBUS_MFR_MODEL: /* R/W block */
  99. pmbus_send_string(pmdev, s->mfr_model);
  100. break;
  101. case PMBUS_MFR_REVISION: /* R/W block */
  102. pmbus_send_string(pmdev, s->mfr_rev);
  103. break;
  104. case PMBUS_IC_DEVICE_ID:
  105. pmbus_send(pmdev, adm1266_ic_device_id, sizeof(adm1266_ic_device_id));
  106. break;
  107. case PMBUS_IC_DEVICE_REV:
  108. pmbus_send(pmdev, adm1266_ic_device_rev, sizeof(adm1266_ic_device_rev));
  109. break;
  110. default:
  111. qemu_log_mask(LOG_UNIMP,
  112. "%s: reading from unimplemented register: 0x%02x\n",
  113. __func__, pmdev->code);
  114. return 0xFF;
  115. }
  116. return 0;
  117. }
  118. static int adm1266_write_data(PMBusDevice *pmdev, const uint8_t *buf,
  119. uint8_t len)
  120. {
  121. ADM1266State *s = ADM1266(pmdev);
  122. switch (pmdev->code) {
  123. case PMBUS_MFR_ID: /* R/W block */
  124. pmbus_receive_block(pmdev, (uint8_t *)s->mfr_id, sizeof(s->mfr_id));
  125. break;
  126. case PMBUS_MFR_MODEL: /* R/W block */
  127. pmbus_receive_block(pmdev, (uint8_t *)s->mfr_model,
  128. sizeof(s->mfr_model));
  129. break;
  130. case PMBUS_MFR_REVISION: /* R/W block*/
  131. pmbus_receive_block(pmdev, (uint8_t *)s->mfr_rev, sizeof(s->mfr_rev));
  132. break;
  133. case ADM1266_SET_RTC: /* do nothing */
  134. break;
  135. default:
  136. qemu_log_mask(LOG_UNIMP,
  137. "%s: writing to unimplemented register: 0x%02x\n",
  138. __func__, pmdev->code);
  139. break;
  140. }
  141. return 0;
  142. }
  143. static void adm1266_get(Object *obj, Visitor *v, const char *name, void *opaque,
  144. Error **errp)
  145. {
  146. uint16_t value;
  147. PMBusDevice *pmdev = PMBUS_DEVICE(obj);
  148. PMBusVoutMode *mode = (PMBusVoutMode *)&pmdev->pages[0].vout_mode;
  149. if (strcmp(name, "vout") == 0) {
  150. value = pmbus_linear_mode2data(*(uint16_t *)opaque, mode->exp);
  151. } else {
  152. value = *(uint16_t *)opaque;
  153. }
  154. visit_type_uint16(v, name, &value, errp);
  155. }
  156. static void adm1266_set(Object *obj, Visitor *v, const char *name, void *opaque,
  157. Error **errp)
  158. {
  159. uint16_t *internal = opaque;
  160. uint16_t value;
  161. PMBusDevice *pmdev = PMBUS_DEVICE(obj);
  162. PMBusVoutMode *mode = (PMBusVoutMode *)&pmdev->pages[0].vout_mode;
  163. if (!visit_type_uint16(v, name, &value, errp)) {
  164. return;
  165. }
  166. *internal = pmbus_data2linear_mode(value, mode->exp);
  167. pmbus_check_limits(pmdev);
  168. }
  169. static const VMStateDescription vmstate_adm1266 = {
  170. .name = "ADM1266",
  171. .version_id = 0,
  172. .minimum_version_id = 0,
  173. .fields = (const VMStateField[]){
  174. VMSTATE_PMBUS_DEVICE(parent, ADM1266State),
  175. VMSTATE_END_OF_LIST()
  176. }
  177. };
  178. static void adm1266_init(Object *obj)
  179. {
  180. PMBusDevice *pmdev = PMBUS_DEVICE(obj);
  181. uint64_t flags = PB_HAS_VOUT_MODE | PB_HAS_VOUT | PB_HAS_VOUT_MARGIN |
  182. PB_HAS_VOUT_RATING | PB_HAS_STATUS_MFR_SPECIFIC;
  183. for (int i = 0; i < ADM1266_NUM_PAGES; i++) {
  184. pmbus_page_config(pmdev, i, flags);
  185. object_property_add(obj, "vout[*]", "uint16",
  186. adm1266_get,
  187. adm1266_set, NULL, &pmdev->pages[i].read_vout);
  188. }
  189. }
  190. static void adm1266_class_init(ObjectClass *klass, void *data)
  191. {
  192. ResettableClass *rc = RESETTABLE_CLASS(klass);
  193. DeviceClass *dc = DEVICE_CLASS(klass);
  194. PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass);
  195. dc->desc = "Analog Devices ADM1266 Hot Swap controller";
  196. dc->vmsd = &vmstate_adm1266;
  197. k->write_data = adm1266_write_data;
  198. k->receive_byte = adm1266_read_byte;
  199. k->device_num_pages = 17;
  200. rc->phases.exit = adm1266_exit_reset;
  201. }
  202. static const TypeInfo adm1266_info = {
  203. .name = TYPE_ADM1266,
  204. .parent = TYPE_PMBUS_DEVICE,
  205. .instance_size = sizeof(ADM1266State),
  206. .instance_init = adm1266_init,
  207. .class_init = adm1266_class_init,
  208. };
  209. static void adm1266_register_types(void)
  210. {
  211. type_register_static(&adm1266_info);
  212. }
  213. type_init(adm1266_register_types)