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 <arch_helpers.h> 9 #include <debug.h> 10 #include <delay_timer.h> 11 #include <errno.h> 12 #include <mmio.h> 13 #include <mentor/mi2cv.h> 14 #include <string.h> 15 #include <sunxi_mmap.h> 16 17 #define AXP805_ADDR 0x36 18 #define AXP805_ID 0x03 19 20 enum pmic_type { 21 NO_PMIC, 22 AXP805, 23 }; 24 25 enum pmic_type pmic; 26 27 static int sunxi_init_r_i2c(void) 28 { 29 uint32_t reg; 30 31 /* get currently configured function for pins PL0 and PL1 */ 32 reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x00); 33 if ((reg & 0xff) == 0x33) { 34 NOTICE("PMIC: already configured for TWI\n"); 35 } 36 37 /* switch pins PL0 and PL1 to I2C */ 38 mmio_write_32(SUNXI_R_PIO_BASE + 0x00, (reg & ~0xff) | 0x33); 39 40 /* level 2 drive strength */ 41 reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x14); 42 mmio_write_32(SUNXI_R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa); 43 44 /* set both ports to pull-up */ 45 reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x1c); 46 mmio_write_32(SUNXI_R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5); 47 48 /* assert & de-assert reset of R_I2C */ 49 reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c); 50 mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, 0); 51 reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c); 52 mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00010000); 53 54 /* un-gate R_I2C clock */ 55 reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c); 56 mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00000001); 57 58 /* call mi2cv driver */ 59 i2c_init((void *)SUNXI_R_I2C_BASE); 60 61 return 0; 62 } 63 64 int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val) 65 { 66 int ret; 67 68 ret = i2c_write(chip, 0, 0, ®, 1); 69 if (ret) 70 return ret; 71 72 return i2c_read(chip, 0, 0, val, 1); 73 } 74 75 int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) 76 { 77 return i2c_write(chip, reg, 1, &val, 1); 78 } 79 80 static int axp805_probe(void) 81 { 82 int ret; 83 uint8_t val; 84 85 ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); 86 if (ret) { 87 ERROR("PMIC: Cannot put AXP805 to master mode.\n"); 88 return -EPERM; 89 } 90 91 ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); 92 93 if (!ret && ((val & 0xcf) == 0x40)) 94 NOTICE("PMIC: AXP805 detected\n"); 95 else if (ret) { 96 ERROR("PMIC: Cannot communicate with AXP805.\n"); 97 return -EPERM; 98 } else { 99 ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n"); 100 return -EINVAL; 101 } 102 103 return 0; 104 } 105 106 int sunxi_pmic_setup(void) 107 { 108 int ret; 109 110 sunxi_init_r_i2c(); 111 112 NOTICE("PMIC: Probing AXP805\n"); 113 pmic = AXP805; 114 115 ret = axp805_probe(); 116 if (ret) 117 pmic = NO_PMIC; 118 else 119 pmic = AXP805; 120 121 return 0; 122 } 123 124 void __dead2 sunxi_power_down(void) 125 { 126 uint8_t val; 127 128 switch (pmic) { 129 case AXP805: 130 val = 0x26; /* Default value for REG 32H */ 131 axp_i2c_read(AXP805_ADDR, 0x32, &val); 132 val |= 0x80; 133 axp_i2c_write(AXP805_ADDR, 0x32, val); 134 break; 135 default: 136 break; 137 } 138 139 udelay(1000); 140 ERROR("PSCI: Cannot communicate with PMIC, halting\n"); 141 wfi(); 142 panic(); 143 } 144