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> 16*4ec1a239SAndre Przywara #include <sunxi_private.h> 176d372828SIcenowy Zheng 186d372828SIcenowy Zheng #define AXP805_ADDR 0x36 196d372828SIcenowy Zheng #define AXP805_ID 0x03 206d372828SIcenowy Zheng 216d372828SIcenowy Zheng enum pmic_type { 226d372828SIcenowy Zheng NO_PMIC, 236d372828SIcenowy Zheng AXP805, 246d372828SIcenowy Zheng }; 256d372828SIcenowy Zheng 266d372828SIcenowy Zheng enum pmic_type pmic; 276d372828SIcenowy Zheng 286d372828SIcenowy Zheng static int sunxi_init_r_i2c(void) 296d372828SIcenowy Zheng { 306d372828SIcenowy Zheng uint32_t reg; 316d372828SIcenowy Zheng 326d372828SIcenowy Zheng /* switch pins PL0 and PL1 to I2C */ 331a910bceSAndre Przywara reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x00); 346d372828SIcenowy Zheng mmio_write_32(SUNXI_R_PIO_BASE + 0x00, (reg & ~0xff) | 0x33); 356d372828SIcenowy Zheng 366d372828SIcenowy Zheng /* level 2 drive strength */ 376d372828SIcenowy Zheng reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x14); 386d372828SIcenowy Zheng mmio_write_32(SUNXI_R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa); 396d372828SIcenowy Zheng 406d372828SIcenowy Zheng /* set both ports to pull-up */ 416d372828SIcenowy Zheng reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x1c); 426d372828SIcenowy Zheng mmio_write_32(SUNXI_R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5); 436d372828SIcenowy Zheng 446d372828SIcenowy Zheng /* assert & de-assert reset of R_I2C */ 456d372828SIcenowy Zheng reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c); 461a910bceSAndre Przywara mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg & ~BIT(16)); 471a910bceSAndre Przywara mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | BIT(16)); 486d372828SIcenowy Zheng 496d372828SIcenowy Zheng /* un-gate R_I2C clock */ 501a910bceSAndre Przywara mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | BIT(16) | BIT(0)); 516d372828SIcenowy Zheng 526d372828SIcenowy Zheng /* call mi2cv driver */ 536d372828SIcenowy Zheng i2c_init((void *)SUNXI_R_I2C_BASE); 546d372828SIcenowy Zheng 556d372828SIcenowy Zheng return 0; 566d372828SIcenowy Zheng } 576d372828SIcenowy Zheng 586d372828SIcenowy Zheng int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val) 596d372828SIcenowy Zheng { 606d372828SIcenowy Zheng int ret; 616d372828SIcenowy Zheng 626d372828SIcenowy Zheng ret = i2c_write(chip, 0, 0, ®, 1); 636d372828SIcenowy Zheng if (ret) 646d372828SIcenowy Zheng return ret; 656d372828SIcenowy Zheng 666d372828SIcenowy Zheng return i2c_read(chip, 0, 0, val, 1); 676d372828SIcenowy Zheng } 686d372828SIcenowy Zheng 696d372828SIcenowy Zheng int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) 706d372828SIcenowy Zheng { 716d372828SIcenowy Zheng return i2c_write(chip, reg, 1, &val, 1); 726d372828SIcenowy Zheng } 736d372828SIcenowy Zheng 746d372828SIcenowy Zheng static int axp805_probe(void) 756d372828SIcenowy Zheng { 766d372828SIcenowy Zheng int ret; 776d372828SIcenowy Zheng uint8_t val; 786d372828SIcenowy Zheng 796d372828SIcenowy Zheng ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); 806d372828SIcenowy Zheng if (ret) { 816d372828SIcenowy Zheng ERROR("PMIC: Cannot put AXP805 to master mode.\n"); 826d372828SIcenowy Zheng return -EPERM; 836d372828SIcenowy Zheng } 846d372828SIcenowy Zheng 856d372828SIcenowy Zheng ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); 866d372828SIcenowy Zheng 876d372828SIcenowy Zheng if (!ret && ((val & 0xcf) == 0x40)) 886d372828SIcenowy Zheng NOTICE("PMIC: AXP805 detected\n"); 896d372828SIcenowy Zheng else if (ret) { 906d372828SIcenowy Zheng ERROR("PMIC: Cannot communicate with AXP805.\n"); 916d372828SIcenowy Zheng return -EPERM; 926d372828SIcenowy Zheng } else { 936d372828SIcenowy Zheng ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n"); 946d372828SIcenowy Zheng return -EINVAL; 956d372828SIcenowy Zheng } 966d372828SIcenowy Zheng 976d372828SIcenowy Zheng return 0; 986d372828SIcenowy Zheng } 997c26b6ecSIcenowy Zheng 100fe57c7d4SAndre Przywara int sunxi_pmic_setup(uint16_t socid) 1017c26b6ecSIcenowy Zheng { 1026d372828SIcenowy Zheng int ret; 1036d372828SIcenowy Zheng 1046d372828SIcenowy Zheng sunxi_init_r_i2c(); 1056d372828SIcenowy Zheng 1066d372828SIcenowy Zheng NOTICE("PMIC: Probing AXP805\n"); 1076d372828SIcenowy Zheng pmic = AXP805; 1086d372828SIcenowy Zheng 1096d372828SIcenowy Zheng ret = axp805_probe(); 1106d372828SIcenowy Zheng if (ret) 1116d372828SIcenowy Zheng pmic = NO_PMIC; 1126d372828SIcenowy Zheng else 1136d372828SIcenowy Zheng pmic = AXP805; 1147c26b6ecSIcenowy Zheng 1157c26b6ecSIcenowy Zheng return 0; 1167c26b6ecSIcenowy Zheng } 1175069c1cfSIcenowy Zheng 1185069c1cfSIcenowy Zheng void __dead2 sunxi_power_down(void) 1195069c1cfSIcenowy Zheng { 1205069c1cfSIcenowy Zheng uint8_t val; 1215069c1cfSIcenowy Zheng 1225069c1cfSIcenowy Zheng switch (pmic) { 1235069c1cfSIcenowy Zheng case AXP805: 124159c5249SAndre Przywara sunxi_init_r_i2c(); 1255069c1cfSIcenowy Zheng axp_i2c_read(AXP805_ADDR, 0x32, &val); 126159c5249SAndre Przywara axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80); 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