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