axp2xx.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * AXP-2XX PMU Emulation, supported lists:
  3. * AXP209
  4. * AXP221
  5. *
  6. * Copyright (C) 2022 Strahinja Jankovic <strahinja.p.jankovic@gmail.com>
  7. * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a
  10. * copy of this software and associated documentation files (the "Software"),
  11. * to deal in the Software without restriction, including without limitation
  12. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  13. * and/or sell copies of the Software, and to permit persons to whom the
  14. * Software is furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  24. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  25. * DEALINGS IN THE SOFTWARE.
  26. *
  27. * SPDX-License-Identifier: MIT
  28. */
  29. #include "qemu/osdep.h"
  30. #include "qemu/log.h"
  31. #include "qom/object.h"
  32. #include "trace.h"
  33. #include "hw/i2c/i2c.h"
  34. #include "migration/vmstate.h"
  35. #define TYPE_AXP2XX "axp2xx_pmu"
  36. #define TYPE_AXP209_PMU "axp209_pmu"
  37. #define TYPE_AXP221_PMU "axp221_pmu"
  38. OBJECT_DECLARE_TYPE(AXP2xxI2CState, AXP2xxClass, AXP2XX)
  39. #define NR_REGS (0xff)
  40. /* A simple I2C slave which returns values of ID or CNT register. */
  41. typedef struct AXP2xxI2CState {
  42. /*< private >*/
  43. I2CSlave i2c;
  44. /*< public >*/
  45. uint8_t regs[NR_REGS]; /* peripheral registers */
  46. uint8_t ptr; /* current register index */
  47. uint8_t count; /* counter used for tx/rx */
  48. } AXP2xxI2CState;
  49. typedef struct AXP2xxClass {
  50. /*< private >*/
  51. I2CSlaveClass parent_class;
  52. /*< public >*/
  53. void (*reset_enter)(AXP2xxI2CState *s, ResetType type);
  54. } AXP2xxClass;
  55. #define AXP209_CHIP_VERSION_ID (0x01)
  56. #define AXP209_DC_DC2_OUT_V_CTRL_RESET (0x16)
  57. /* Reset all counters and load ID register */
  58. static void axp209_reset_enter(AXP2xxI2CState *s, ResetType type)
  59. {
  60. memset(s->regs, 0, NR_REGS);
  61. s->ptr = 0;
  62. s->count = 0;
  63. s->regs[0x03] = AXP209_CHIP_VERSION_ID;
  64. s->regs[0x23] = AXP209_DC_DC2_OUT_V_CTRL_RESET;
  65. s->regs[0x30] = 0x60;
  66. s->regs[0x32] = 0x46;
  67. s->regs[0x34] = 0x41;
  68. s->regs[0x35] = 0x22;
  69. s->regs[0x36] = 0x5d;
  70. s->regs[0x37] = 0x08;
  71. s->regs[0x38] = 0xa5;
  72. s->regs[0x39] = 0x1f;
  73. s->regs[0x3a] = 0x68;
  74. s->regs[0x3b] = 0x5f;
  75. s->regs[0x3c] = 0xfc;
  76. s->regs[0x3d] = 0x16;
  77. s->regs[0x40] = 0xd8;
  78. s->regs[0x42] = 0xff;
  79. s->regs[0x43] = 0x3b;
  80. s->regs[0x80] = 0xe0;
  81. s->regs[0x82] = 0x83;
  82. s->regs[0x83] = 0x80;
  83. s->regs[0x84] = 0x32;
  84. s->regs[0x86] = 0xff;
  85. s->regs[0x90] = 0x07;
  86. s->regs[0x91] = 0xa0;
  87. s->regs[0x92] = 0x07;
  88. s->regs[0x93] = 0x07;
  89. }
  90. #define AXP221_PWR_STATUS_ACIN_PRESENT BIT(7)
  91. #define AXP221_PWR_STATUS_ACIN_AVAIL BIT(6)
  92. #define AXP221_PWR_STATUS_VBUS_PRESENT BIT(5)
  93. #define AXP221_PWR_STATUS_VBUS_USED BIT(4)
  94. #define AXP221_PWR_STATUS_BAT_CHARGING BIT(2)
  95. #define AXP221_PWR_STATUS_ACIN_VBUS_POWERED BIT(1)
  96. /* Reset all counters and load ID register */
  97. static void axp221_reset_enter(AXP2xxI2CState *s, ResetType type)
  98. {
  99. memset(s->regs, 0, NR_REGS);
  100. s->ptr = 0;
  101. s->count = 0;
  102. /* input power status register */
  103. s->regs[0x00] = AXP221_PWR_STATUS_ACIN_PRESENT
  104. | AXP221_PWR_STATUS_ACIN_AVAIL
  105. | AXP221_PWR_STATUS_ACIN_VBUS_POWERED;
  106. s->regs[0x01] = 0x00; /* no battery is connected */
  107. /*
  108. * CHIPID register, no documented on datasheet, but it is checked in
  109. * u-boot spl. I had read it from AXP221s and got 0x06 value.
  110. * So leave 06h here.
  111. */
  112. s->regs[0x03] = 0x06;
  113. s->regs[0x10] = 0xbf;
  114. s->regs[0x13] = 0x01;
  115. s->regs[0x30] = 0x60;
  116. s->regs[0x31] = 0x03;
  117. s->regs[0x32] = 0x43;
  118. s->regs[0x33] = 0xc6;
  119. s->regs[0x34] = 0x45;
  120. s->regs[0x35] = 0x0e;
  121. s->regs[0x36] = 0x5d;
  122. s->regs[0x37] = 0x08;
  123. s->regs[0x38] = 0xa5;
  124. s->regs[0x39] = 0x1f;
  125. s->regs[0x3c] = 0xfc;
  126. s->regs[0x3d] = 0x16;
  127. s->regs[0x80] = 0x80;
  128. s->regs[0x82] = 0xe0;
  129. s->regs[0x84] = 0x32;
  130. s->regs[0x8f] = 0x01;
  131. s->regs[0x90] = 0x07;
  132. s->regs[0x91] = 0x1f;
  133. s->regs[0x92] = 0x07;
  134. s->regs[0x93] = 0x1f;
  135. s->regs[0x40] = 0xd8;
  136. s->regs[0x41] = 0xff;
  137. s->regs[0x42] = 0x03;
  138. s->regs[0x43] = 0x03;
  139. s->regs[0xb8] = 0xc0;
  140. s->regs[0xb9] = 0x64;
  141. s->regs[0xe6] = 0xa0;
  142. }
  143. static void axp2xx_reset_enter(Object *obj, ResetType type)
  144. {
  145. AXP2xxI2CState *s = AXP2XX(obj);
  146. AXP2xxClass *sc = AXP2XX_GET_CLASS(s);
  147. sc->reset_enter(s, type);
  148. }
  149. /* Handle events from master. */
  150. static int axp2xx_event(I2CSlave *i2c, enum i2c_event event)
  151. {
  152. AXP2xxI2CState *s = AXP2XX(i2c);
  153. s->count = 0;
  154. return 0;
  155. }
  156. /* Called when master requests read */
  157. static uint8_t axp2xx_rx(I2CSlave *i2c)
  158. {
  159. AXP2xxI2CState *s = AXP2XX(i2c);
  160. uint8_t ret = 0xff;
  161. if (s->ptr < NR_REGS) {
  162. ret = s->regs[s->ptr++];
  163. }
  164. trace_axp2xx_rx(s->ptr - 1, ret);
  165. return ret;
  166. }
  167. /*
  168. * Called when master sends write.
  169. * Update ptr with byte 0, then perform write with second byte.
  170. */
  171. static int axp2xx_tx(I2CSlave *i2c, uint8_t data)
  172. {
  173. AXP2xxI2CState *s = AXP2XX(i2c);
  174. if (s->count == 0) {
  175. /* Store register address */
  176. s->ptr = data;
  177. s->count++;
  178. trace_axp2xx_select(data);
  179. } else {
  180. trace_axp2xx_tx(s->ptr, data);
  181. s->regs[s->ptr++] = data;
  182. }
  183. return 0;
  184. }
  185. static const VMStateDescription vmstate_axp2xx = {
  186. .name = TYPE_AXP2XX,
  187. .version_id = 1,
  188. .fields = (const VMStateField[]) {
  189. VMSTATE_UINT8_ARRAY(regs, AXP2xxI2CState, NR_REGS),
  190. VMSTATE_UINT8(ptr, AXP2xxI2CState),
  191. VMSTATE_UINT8(count, AXP2xxI2CState),
  192. VMSTATE_END_OF_LIST()
  193. }
  194. };
  195. static void axp2xx_class_init(ObjectClass *oc, void *data)
  196. {
  197. DeviceClass *dc = DEVICE_CLASS(oc);
  198. I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc);
  199. ResettableClass *rc = RESETTABLE_CLASS(oc);
  200. rc->phases.enter = axp2xx_reset_enter;
  201. dc->vmsd = &vmstate_axp2xx;
  202. isc->event = axp2xx_event;
  203. isc->recv = axp2xx_rx;
  204. isc->send = axp2xx_tx;
  205. }
  206. static const TypeInfo axp2xx_info = {
  207. .name = TYPE_AXP2XX,
  208. .parent = TYPE_I2C_SLAVE,
  209. .instance_size = sizeof(AXP2xxI2CState),
  210. .class_size = sizeof(AXP2xxClass),
  211. .class_init = axp2xx_class_init,
  212. .abstract = true,
  213. };
  214. static void axp209_class_init(ObjectClass *oc, void *data)
  215. {
  216. AXP2xxClass *sc = AXP2XX_CLASS(oc);
  217. sc->reset_enter = axp209_reset_enter;
  218. }
  219. static const TypeInfo axp209_info = {
  220. .name = TYPE_AXP209_PMU,
  221. .parent = TYPE_AXP2XX,
  222. .class_init = axp209_class_init
  223. };
  224. static void axp221_class_init(ObjectClass *oc, void *data)
  225. {
  226. AXP2xxClass *sc = AXP2XX_CLASS(oc);
  227. sc->reset_enter = axp221_reset_enter;
  228. }
  229. static const TypeInfo axp221_info = {
  230. .name = TYPE_AXP221_PMU,
  231. .parent = TYPE_AXP2XX,
  232. .class_init = axp221_class_init,
  233. };
  234. static void axp2xx_register_devices(void)
  235. {
  236. type_register_static(&axp2xx_info);
  237. type_register_static(&axp209_info);
  238. type_register_static(&axp221_info);
  239. }
  240. type_init(axp2xx_register_devices);