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