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 /* switch pins PL0 and PL1 to I2C */ 32 reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x00); 33 mmio_write_32(SUNXI_R_PIO_BASE + 0x00, (reg & ~0xff) | 0x33); 34 35 /* level 2 drive strength */ 36 reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x14); 37 mmio_write_32(SUNXI_R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa); 38 39 /* set both ports to pull-up */ 40 reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x1c); 41 mmio_write_32(SUNXI_R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5); 42 43 /* assert & de-assert reset of R_I2C */ 44 reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c); 45 mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg & ~BIT(16)); 46 mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | BIT(16)); 47 48 /* un-gate R_I2C clock */ 49 mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | BIT(16) | BIT(0)); 50 51 /* call mi2cv driver */ 52 i2c_init((void *)SUNXI_R_I2C_BASE); 53 54 return 0; 55 } 56 57 int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val) 58 { 59 int ret; 60 61 ret = i2c_write(chip, 0, 0, ®, 1); 62 if (ret) 63 return ret; 64 65 return i2c_read(chip, 0, 0, val, 1); 66 } 67 68 int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) 69 { 70 return i2c_write(chip, reg, 1, &val, 1); 71 } 72 73 static int axp805_probe(void) 74 { 75 int ret; 76 uint8_t val; 77 78 ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); 79 if (ret) { 80 ERROR("PMIC: Cannot put AXP805 to master mode.\n"); 81 return -EPERM; 82 } 83 84 ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); 85 86 if (!ret && ((val & 0xcf) == 0x40)) 87 NOTICE("PMIC: AXP805 detected\n"); 88 else if (ret) { 89 ERROR("PMIC: Cannot communicate with AXP805.\n"); 90 return -EPERM; 91 } else { 92 ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n"); 93 return -EINVAL; 94 } 95 96 return 0; 97 } 98 99 int sunxi_pmic_setup(void) 100 { 101 int ret; 102 103 sunxi_init_r_i2c(); 104 105 NOTICE("PMIC: Probing AXP805\n"); 106 pmic = AXP805; 107 108 ret = axp805_probe(); 109 if (ret) 110 pmic = NO_PMIC; 111 else 112 pmic = AXP805; 113 114 return 0; 115 } 116 117 void __dead2 sunxi_power_down(void) 118 { 119 uint8_t val; 120 121 switch (pmic) { 122 case AXP805: 123 sunxi_init_r_i2c(); 124 axp_i2c_read(AXP805_ADDR, 0x32, &val); 125 axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80); 126 break; 127 default: 128 break; 129 } 130 131 udelay(1000); 132 ERROR("PSCI: Cannot communicate with PMIC, halting\n"); 133 wfi(); 134 panic(); 135 } 136