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