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 85069c1cfSIcenowy 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 /* switch pins PL0 and PL1 to I2C */ 32*1a910bceSAndre Przywara reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x00); 336d372828SIcenowy Zheng mmio_write_32(SUNXI_R_PIO_BASE + 0x00, (reg & ~0xff) | 0x33); 346d372828SIcenowy Zheng 356d372828SIcenowy Zheng /* level 2 drive strength */ 366d372828SIcenowy Zheng reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x14); 376d372828SIcenowy Zheng mmio_write_32(SUNXI_R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa); 386d372828SIcenowy Zheng 396d372828SIcenowy Zheng /* set both ports to pull-up */ 406d372828SIcenowy Zheng reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x1c); 416d372828SIcenowy Zheng mmio_write_32(SUNXI_R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5); 426d372828SIcenowy Zheng 436d372828SIcenowy Zheng /* assert & de-assert reset of R_I2C */ 446d372828SIcenowy Zheng reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c); 45*1a910bceSAndre Przywara mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg & ~BIT(16)); 46*1a910bceSAndre Przywara mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | BIT(16)); 476d372828SIcenowy Zheng 486d372828SIcenowy Zheng /* un-gate R_I2C clock */ 49*1a910bceSAndre Przywara mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | BIT(16) | BIT(0)); 506d372828SIcenowy Zheng 516d372828SIcenowy Zheng /* call mi2cv driver */ 526d372828SIcenowy Zheng i2c_init((void *)SUNXI_R_I2C_BASE); 536d372828SIcenowy Zheng 546d372828SIcenowy Zheng return 0; 556d372828SIcenowy Zheng } 566d372828SIcenowy Zheng 576d372828SIcenowy Zheng int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val) 586d372828SIcenowy Zheng { 596d372828SIcenowy Zheng int ret; 606d372828SIcenowy Zheng 616d372828SIcenowy Zheng ret = i2c_write(chip, 0, 0, ®, 1); 626d372828SIcenowy Zheng if (ret) 636d372828SIcenowy Zheng return ret; 646d372828SIcenowy Zheng 656d372828SIcenowy Zheng return i2c_read(chip, 0, 0, val, 1); 666d372828SIcenowy Zheng } 676d372828SIcenowy Zheng 686d372828SIcenowy Zheng int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) 696d372828SIcenowy Zheng { 706d372828SIcenowy Zheng return i2c_write(chip, reg, 1, &val, 1); 716d372828SIcenowy Zheng } 726d372828SIcenowy Zheng 736d372828SIcenowy Zheng static int axp805_probe(void) 746d372828SIcenowy Zheng { 756d372828SIcenowy Zheng int ret; 766d372828SIcenowy Zheng uint8_t val; 776d372828SIcenowy Zheng 786d372828SIcenowy Zheng ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); 796d372828SIcenowy Zheng if (ret) { 806d372828SIcenowy Zheng ERROR("PMIC: Cannot put AXP805 to master mode.\n"); 816d372828SIcenowy Zheng return -EPERM; 826d372828SIcenowy Zheng } 836d372828SIcenowy Zheng 846d372828SIcenowy Zheng ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); 856d372828SIcenowy Zheng 866d372828SIcenowy Zheng if (!ret && ((val & 0xcf) == 0x40)) 876d372828SIcenowy Zheng NOTICE("PMIC: AXP805 detected\n"); 886d372828SIcenowy Zheng else if (ret) { 896d372828SIcenowy Zheng ERROR("PMIC: Cannot communicate with AXP805.\n"); 906d372828SIcenowy Zheng return -EPERM; 916d372828SIcenowy Zheng } else { 926d372828SIcenowy Zheng ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n"); 936d372828SIcenowy Zheng return -EINVAL; 946d372828SIcenowy Zheng } 956d372828SIcenowy Zheng 966d372828SIcenowy Zheng return 0; 976d372828SIcenowy Zheng } 987c26b6ecSIcenowy Zheng 997c26b6ecSIcenowy Zheng int sunxi_pmic_setup(void) 1007c26b6ecSIcenowy Zheng { 1016d372828SIcenowy Zheng int ret; 1026d372828SIcenowy Zheng 1036d372828SIcenowy Zheng sunxi_init_r_i2c(); 1046d372828SIcenowy Zheng 1056d372828SIcenowy Zheng NOTICE("PMIC: Probing AXP805\n"); 1066d372828SIcenowy Zheng pmic = AXP805; 1076d372828SIcenowy Zheng 1086d372828SIcenowy Zheng ret = axp805_probe(); 1096d372828SIcenowy Zheng if (ret) 1106d372828SIcenowy Zheng pmic = NO_PMIC; 1116d372828SIcenowy Zheng else 1126d372828SIcenowy Zheng pmic = AXP805; 1137c26b6ecSIcenowy Zheng 1147c26b6ecSIcenowy Zheng return 0; 1157c26b6ecSIcenowy Zheng } 1165069c1cfSIcenowy Zheng 1175069c1cfSIcenowy Zheng void __dead2 sunxi_power_down(void) 1185069c1cfSIcenowy Zheng { 1195069c1cfSIcenowy Zheng uint8_t val; 1205069c1cfSIcenowy Zheng 1215069c1cfSIcenowy Zheng switch (pmic) { 1225069c1cfSIcenowy Zheng case AXP805: 1235069c1cfSIcenowy Zheng val = 0x26; /* Default value for REG 32H */ 1245069c1cfSIcenowy Zheng axp_i2c_read(AXP805_ADDR, 0x32, &val); 1255069c1cfSIcenowy Zheng val |= 0x80; 1265069c1cfSIcenowy Zheng axp_i2c_write(AXP805_ADDR, 0x32, val); 1275069c1cfSIcenowy Zheng break; 1285069c1cfSIcenowy Zheng default: 1295069c1cfSIcenowy Zheng break; 1305069c1cfSIcenowy Zheng } 1315069c1cfSIcenowy Zheng 1325069c1cfSIcenowy Zheng udelay(1000); 1335069c1cfSIcenowy Zheng ERROR("PSCI: Cannot communicate with PMIC, halting\n"); 1345069c1cfSIcenowy Zheng wfi(); 1355069c1cfSIcenowy Zheng panic(); 1365069c1cfSIcenowy Zheng } 137