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 == 0) 35 ret = i2c_read(chip, 0, 0, val, 1); 36 if (ret) 37 ERROR("PMIC: Cannot read AXP805 register %02x\n", reg); 38 39 return ret; 40 } 41 42 int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) 43 { 44 int ret; 45 46 ret = i2c_write(chip, reg, 1, &val, 1); 47 if (ret) 48 ERROR("PMIC: Cannot write AXP805 register %02x\n", reg); 49 50 return ret; 51 } 52 53 static int axp805_probe(void) 54 { 55 int ret; 56 uint8_t val; 57 58 /* Switch the AXP805 to master/single-PMIC mode. */ 59 ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); 60 if (ret) 61 return ret; 62 63 ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); 64 if (ret) 65 return ret; 66 67 val &= 0xcf; 68 if (val != 0x40) { 69 ERROR("PMIC: Found unknown PMIC %02x\n", val); 70 return -EINVAL; 71 } 72 73 return 0; 74 } 75 76 int sunxi_pmic_setup(uint16_t socid, const void *fdt) 77 { 78 int ret; 79 80 INFO("PMIC: Probing AXP805 on I2C\n"); 81 82 ret = sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 83 if (ret) 84 return ret; 85 86 /* initialise mi2cv driver */ 87 i2c_init((void *)SUNXI_R_I2C_BASE); 88 89 ret = axp805_probe(); 90 if (ret) 91 return ret; 92 93 pmic = AXP805; 94 95 return 0; 96 } 97 98 void sunxi_power_down(void) 99 { 100 uint8_t val; 101 102 switch (pmic) { 103 case AXP805: 104 /* Re-initialise after rich OS might have used it. */ 105 sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 106 /* initialise mi2cv driver */ 107 i2c_init((void *)SUNXI_R_I2C_BASE); 108 axp_i2c_read(AXP805_ADDR, 0x32, &val); 109 axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80); 110 break; 111 default: 112 break; 113 } 114 } 115