1 /* 2 * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. 3 * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io> 4 * 5 * SPDX-License-Identifier: BSD-3-Clause 6 */ 7 8 #include <errno.h> 9 #include <string.h> 10 11 #include <arch_helpers.h> 12 #include <common/debug.h> 13 #include <drivers/delay_timer.h> 14 #include <drivers/mentor/mi2cv.h> 15 #include <lib/mmio.h> 16 17 #include <sunxi_def.h> 18 #include <sunxi_mmap.h> 19 #include <sunxi_private.h> 20 21 #define AXP805_ADDR 0x36 22 #define AXP805_ID 0x03 23 24 static enum pmic_type { 25 UNKNOWN, 26 AXP805, 27 } pmic; 28 29 int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val) 30 { 31 int ret; 32 33 ret = i2c_write(chip, 0, 0, ®, 1); 34 if (ret) 35 return ret; 36 37 return i2c_read(chip, 0, 0, val, 1); 38 } 39 40 int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) 41 { 42 return i2c_write(chip, reg, 1, &val, 1); 43 } 44 45 static int axp805_probe(void) 46 { 47 int ret; 48 uint8_t val; 49 50 ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); 51 if (ret) { 52 ERROR("PMIC: Cannot put AXP805 to master mode.\n"); 53 return -EPERM; 54 } 55 56 ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); 57 58 if (!ret && ((val & 0xcf) == 0x40)) 59 NOTICE("PMIC: AXP805 detected\n"); 60 else if (ret) { 61 ERROR("PMIC: Cannot communicate with AXP805.\n"); 62 return -EPERM; 63 } else { 64 ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n"); 65 return -EINVAL; 66 } 67 68 return 0; 69 } 70 71 int sunxi_pmic_setup(uint16_t socid, const void *fdt) 72 { 73 int ret; 74 75 sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 76 /* initialise mi2cv driver */ 77 i2c_init((void *)SUNXI_R_I2C_BASE); 78 79 NOTICE("PMIC: Probing AXP805\n"); 80 81 ret = axp805_probe(); 82 if (ret) 83 return ret; 84 85 pmic = AXP805; 86 87 return 0; 88 } 89 90 void __dead2 sunxi_power_down(void) 91 { 92 uint8_t val; 93 94 switch (pmic) { 95 case AXP805: 96 /* Re-initialise after rich OS might have used it. */ 97 sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 98 /* initialise mi2cv driver */ 99 i2c_init((void *)SUNXI_R_I2C_BASE); 100 axp_i2c_read(AXP805_ADDR, 0x32, &val); 101 axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80); 102 break; 103 default: 104 break; 105 } 106 107 udelay(1000); 108 ERROR("PSCI: Cannot communicate with PMIC, halting\n"); 109 wfi(); 110 panic(); 111 } 112