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 8*5069c1cfSIcenowy Zheng #include <arch_helpers.h> 97c26b6ecSIcenowy Zheng #include <debug.h> 106d372828SIcenowy Zheng #include <delay_timer.h> 116d372828SIcenowy Zheng #include <errno.h> 126d372828SIcenowy Zheng #include <mmio.h> 136d372828SIcenowy Zheng #include <mentor/mi2cv.h> 146d372828SIcenowy Zheng #include <string.h> 156d372828SIcenowy Zheng #include <sunxi_mmap.h> 166d372828SIcenowy Zheng 176d372828SIcenowy Zheng #define AXP805_ADDR 0x36 186d372828SIcenowy Zheng #define AXP805_ID 0x03 196d372828SIcenowy Zheng 206d372828SIcenowy Zheng enum pmic_type { 216d372828SIcenowy Zheng NO_PMIC, 226d372828SIcenowy Zheng AXP805, 236d372828SIcenowy Zheng }; 246d372828SIcenowy Zheng 256d372828SIcenowy Zheng enum pmic_type pmic; 266d372828SIcenowy Zheng 276d372828SIcenowy Zheng static int sunxi_init_r_i2c(void) 286d372828SIcenowy Zheng { 296d372828SIcenowy Zheng uint32_t reg; 306d372828SIcenowy Zheng 316d372828SIcenowy Zheng /* get currently configured function for pins PL0 and PL1 */ 326d372828SIcenowy Zheng reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x00); 336d372828SIcenowy Zheng if ((reg & 0xff) == 0x33) { 346d372828SIcenowy Zheng NOTICE("PMIC: already configured for TWI\n"); 356d372828SIcenowy Zheng } 366d372828SIcenowy Zheng 376d372828SIcenowy Zheng /* switch pins PL0 and PL1 to I2C */ 386d372828SIcenowy Zheng mmio_write_32(SUNXI_R_PIO_BASE + 0x00, (reg & ~0xff) | 0x33); 396d372828SIcenowy Zheng 406d372828SIcenowy Zheng /* level 2 drive strength */ 416d372828SIcenowy Zheng reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x14); 426d372828SIcenowy Zheng mmio_write_32(SUNXI_R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa); 436d372828SIcenowy Zheng 446d372828SIcenowy Zheng /* set both ports to pull-up */ 456d372828SIcenowy Zheng reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x1c); 466d372828SIcenowy Zheng mmio_write_32(SUNXI_R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5); 476d372828SIcenowy Zheng 486d372828SIcenowy Zheng /* assert & de-assert reset of R_I2C */ 496d372828SIcenowy Zheng reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c); 506d372828SIcenowy Zheng mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, 0); 516d372828SIcenowy Zheng reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c); 526d372828SIcenowy Zheng mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00010000); 536d372828SIcenowy Zheng 546d372828SIcenowy Zheng /* un-gate R_I2C clock */ 556d372828SIcenowy Zheng reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c); 566d372828SIcenowy Zheng mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00000001); 576d372828SIcenowy Zheng 586d372828SIcenowy Zheng /* call mi2cv driver */ 596d372828SIcenowy Zheng i2c_init((void *)SUNXI_R_I2C_BASE); 606d372828SIcenowy Zheng 616d372828SIcenowy Zheng return 0; 626d372828SIcenowy Zheng } 636d372828SIcenowy Zheng 646d372828SIcenowy Zheng int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val) 656d372828SIcenowy Zheng { 666d372828SIcenowy Zheng int ret; 676d372828SIcenowy Zheng 686d372828SIcenowy Zheng ret = i2c_write(chip, 0, 0, ®, 1); 696d372828SIcenowy Zheng if (ret) 706d372828SIcenowy Zheng return ret; 716d372828SIcenowy Zheng 726d372828SIcenowy Zheng return i2c_read(chip, 0, 0, val, 1); 736d372828SIcenowy Zheng } 746d372828SIcenowy Zheng 756d372828SIcenowy Zheng int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) 766d372828SIcenowy Zheng { 776d372828SIcenowy Zheng return i2c_write(chip, reg, 1, &val, 1); 786d372828SIcenowy Zheng } 796d372828SIcenowy Zheng 806d372828SIcenowy Zheng static int axp805_probe(void) 816d372828SIcenowy Zheng { 826d372828SIcenowy Zheng int ret; 836d372828SIcenowy Zheng uint8_t val; 846d372828SIcenowy Zheng 856d372828SIcenowy Zheng ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); 866d372828SIcenowy Zheng if (ret) { 876d372828SIcenowy Zheng ERROR("PMIC: Cannot put AXP805 to master mode.\n"); 886d372828SIcenowy Zheng return -EPERM; 896d372828SIcenowy Zheng } 906d372828SIcenowy Zheng 916d372828SIcenowy Zheng ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); 926d372828SIcenowy Zheng 936d372828SIcenowy Zheng if (!ret && ((val & 0xcf) == 0x40)) 946d372828SIcenowy Zheng NOTICE("PMIC: AXP805 detected\n"); 956d372828SIcenowy Zheng else if (ret) { 966d372828SIcenowy Zheng ERROR("PMIC: Cannot communicate with AXP805.\n"); 976d372828SIcenowy Zheng return -EPERM; 986d372828SIcenowy Zheng } else { 996d372828SIcenowy Zheng ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n"); 1006d372828SIcenowy Zheng return -EINVAL; 1016d372828SIcenowy Zheng } 1026d372828SIcenowy Zheng 1036d372828SIcenowy Zheng return 0; 1046d372828SIcenowy Zheng } 1057c26b6ecSIcenowy Zheng 1067c26b6ecSIcenowy Zheng int sunxi_pmic_setup(void) 1077c26b6ecSIcenowy Zheng { 1086d372828SIcenowy Zheng int ret; 1096d372828SIcenowy Zheng 1106d372828SIcenowy Zheng sunxi_init_r_i2c(); 1116d372828SIcenowy Zheng 1126d372828SIcenowy Zheng NOTICE("PMIC: Probing AXP805\n"); 1136d372828SIcenowy Zheng pmic = AXP805; 1146d372828SIcenowy Zheng 1156d372828SIcenowy Zheng ret = axp805_probe(); 1166d372828SIcenowy Zheng if (ret) 1176d372828SIcenowy Zheng pmic = NO_PMIC; 1186d372828SIcenowy Zheng else 1196d372828SIcenowy Zheng pmic = AXP805; 1207c26b6ecSIcenowy Zheng 1217c26b6ecSIcenowy Zheng return 0; 1227c26b6ecSIcenowy Zheng } 123*5069c1cfSIcenowy Zheng 124*5069c1cfSIcenowy Zheng void __dead2 sunxi_power_down(void) 125*5069c1cfSIcenowy Zheng { 126*5069c1cfSIcenowy Zheng uint8_t val; 127*5069c1cfSIcenowy Zheng 128*5069c1cfSIcenowy Zheng switch (pmic) { 129*5069c1cfSIcenowy Zheng case AXP805: 130*5069c1cfSIcenowy Zheng val = 0x26; /* Default value for REG 32H */ 131*5069c1cfSIcenowy Zheng axp_i2c_read(AXP805_ADDR, 0x32, &val); 132*5069c1cfSIcenowy Zheng val |= 0x80; 133*5069c1cfSIcenowy Zheng axp_i2c_write(AXP805_ADDR, 0x32, val); 134*5069c1cfSIcenowy Zheng break; 135*5069c1cfSIcenowy Zheng default: 136*5069c1cfSIcenowy Zheng break; 137*5069c1cfSIcenowy Zheng } 138*5069c1cfSIcenowy Zheng 139*5069c1cfSIcenowy Zheng udelay(1000); 140*5069c1cfSIcenowy Zheng ERROR("PSCI: Cannot communicate with PMIC, halting\n"); 141*5069c1cfSIcenowy Zheng wfi(); 142*5069c1cfSIcenowy Zheng panic(); 143*5069c1cfSIcenowy Zheng } 144