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 */ 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 */ 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 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. */ 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 */ 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 */ 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 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 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 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 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