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