1 /* 2 * Copyright (c) 2017-2018, 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 enum pmic_type { 25 NO_PMIC, 26 AXP805, 27 }; 28 29 enum pmic_type pmic; 30 31 int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val) 32 { 33 int ret; 34 35 ret = i2c_write(chip, 0, 0, ®, 1); 36 if (ret) 37 return ret; 38 39 return i2c_read(chip, 0, 0, val, 1); 40 } 41 42 int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) 43 { 44 return i2c_write(chip, reg, 1, &val, 1); 45 } 46 47 static int axp805_probe(void) 48 { 49 int ret; 50 uint8_t val; 51 52 ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); 53 if (ret) { 54 ERROR("PMIC: Cannot put AXP805 to master mode.\n"); 55 return -EPERM; 56 } 57 58 ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); 59 60 if (!ret && ((val & 0xcf) == 0x40)) 61 NOTICE("PMIC: AXP805 detected\n"); 62 else if (ret) { 63 ERROR("PMIC: Cannot communicate with AXP805.\n"); 64 return -EPERM; 65 } else { 66 ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n"); 67 return -EINVAL; 68 } 69 70 return 0; 71 } 72 73 int sunxi_pmic_setup(uint16_t socid, const void *fdt) 74 { 75 int ret; 76 77 sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 78 /* initialise mi2cv driver */ 79 i2c_init((void *)SUNXI_R_I2C_BASE); 80 81 NOTICE("PMIC: Probing AXP805\n"); 82 pmic = AXP805; 83 84 ret = axp805_probe(); 85 if (ret) 86 pmic = NO_PMIC; 87 else 88 pmic = AXP805; 89 90 return 0; 91 } 92 93 void __dead2 sunxi_power_down(void) 94 { 95 uint8_t val; 96 97 switch (pmic) { 98 case AXP805: 99 /* Re-initialise after rich OS might have used it. */ 100 sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 101 /* initialise mi2cv driver */ 102 i2c_init((void *)SUNXI_R_I2C_BASE); 103 axp_i2c_read(AXP805_ADDR, 0x32, &val); 104 axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80); 105 break; 106 default: 107 break; 108 } 109 110 udelay(1000); 111 ERROR("PSCI: Cannot communicate with PMIC, halting\n"); 112 wfi(); 113 panic(); 114 } 115