17c26b6ecSIcenowy Zheng /* 2c0e109f2SSamuel Holland * Copyright (c) 2017-2019, 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 86d372828SIcenowy Zheng #include <errno.h> 96d372828SIcenowy Zheng #include <string.h> 1009d40e0eSAntonio Nino Diaz 1109d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 1209d40e0eSAntonio Nino Diaz #include <common/debug.h> 13*fb23b104SSamuel Holland #include <drivers/allwinner/axp.h> 1409d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h> 1509d40e0eSAntonio Nino Diaz #include <drivers/mentor/mi2cv.h> 1609d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 1709d40e0eSAntonio Nino Diaz 18d5ddf67aSAndre Przywara #include <sunxi_def.h> 196d372828SIcenowy Zheng #include <sunxi_mmap.h> 204ec1a239SAndre Przywara #include <sunxi_private.h> 216d372828SIcenowy Zheng 226d372828SIcenowy Zheng #define AXP805_ADDR 0x36 236d372828SIcenowy Zheng 24c0e109f2SSamuel Holland static enum pmic_type { 25c0e109f2SSamuel Holland UNKNOWN, 266d372828SIcenowy Zheng AXP805, 27c0e109f2SSamuel Holland } pmic; 286d372828SIcenowy Zheng 29*fb23b104SSamuel Holland int axp_read(uint8_t reg) 306d372828SIcenowy Zheng { 31*fb23b104SSamuel Holland uint8_t val; 326d372828SIcenowy Zheng int ret; 336d372828SIcenowy Zheng 34*fb23b104SSamuel Holland ret = i2c_write(AXP805_ADDR, 0, 0, ®, 1); 354538c498SSamuel Holland if (ret == 0) 36*fb23b104SSamuel Holland ret = i2c_read(AXP805_ADDR, 0, 0, &val, 1); 37*fb23b104SSamuel Holland if (ret) { 384538c498SSamuel Holland ERROR("PMIC: Cannot read AXP805 register %02x\n", reg); 394538c498SSamuel Holland return ret; 406d372828SIcenowy Zheng } 416d372828SIcenowy Zheng 42*fb23b104SSamuel Holland return val; 43*fb23b104SSamuel Holland } 44*fb23b104SSamuel Holland 45*fb23b104SSamuel Holland int axp_write(uint8_t reg, uint8_t val) 466d372828SIcenowy Zheng { 474538c498SSamuel Holland int ret; 484538c498SSamuel Holland 49*fb23b104SSamuel Holland ret = i2c_write(AXP805_ADDR, reg, 1, &val, 1); 504538c498SSamuel Holland if (ret) 514538c498SSamuel Holland ERROR("PMIC: Cannot write AXP805 register %02x\n", reg); 524538c498SSamuel Holland 534538c498SSamuel Holland return ret; 546d372828SIcenowy Zheng } 556d372828SIcenowy Zheng 566d372828SIcenowy Zheng static int axp805_probe(void) 576d372828SIcenowy Zheng { 586d372828SIcenowy Zheng int ret; 596d372828SIcenowy Zheng 604538c498SSamuel Holland /* Switch the AXP805 to master/single-PMIC mode. */ 61*fb23b104SSamuel Holland ret = axp_write(0xff, 0x0); 624538c498SSamuel Holland if (ret) 634538c498SSamuel Holland return ret; 646d372828SIcenowy Zheng 65*fb23b104SSamuel Holland ret = axp_check_id(); 664538c498SSamuel Holland if (ret) 674538c498SSamuel Holland return ret; 686d372828SIcenowy Zheng 696d372828SIcenowy Zheng return 0; 706d372828SIcenowy Zheng } 717c26b6ecSIcenowy Zheng 72df301601SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt) 737c26b6ecSIcenowy Zheng { 746d372828SIcenowy Zheng int ret; 756d372828SIcenowy Zheng 764538c498SSamuel Holland INFO("PMIC: Probing AXP805 on I2C\n"); 774538c498SSamuel Holland 784538c498SSamuel Holland ret = sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 794538c498SSamuel Holland if (ret) 804538c498SSamuel Holland return ret; 814538c498SSamuel Holland 82d5ddf67aSAndre Przywara /* initialise mi2cv driver */ 83d5ddf67aSAndre Przywara i2c_init((void *)SUNXI_R_I2C_BASE); 846d372828SIcenowy Zheng 856d372828SIcenowy Zheng ret = axp805_probe(); 866d372828SIcenowy Zheng if (ret) 87c0e109f2SSamuel Holland return ret; 88c0e109f2SSamuel Holland 896d372828SIcenowy Zheng pmic = AXP805; 90*fb23b104SSamuel Holland axp_setup_regulators(fdt); 917c26b6ecSIcenowy Zheng 927c26b6ecSIcenowy Zheng return 0; 937c26b6ecSIcenowy Zheng } 945069c1cfSIcenowy Zheng 95818e6732SSamuel Holland void sunxi_power_down(void) 965069c1cfSIcenowy Zheng { 975069c1cfSIcenowy Zheng switch (pmic) { 985069c1cfSIcenowy Zheng case AXP805: 99d5ddf67aSAndre Przywara /* Re-initialise after rich OS might have used it. */ 100d5ddf67aSAndre Przywara sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 101d5ddf67aSAndre Przywara /* initialise mi2cv driver */ 102d5ddf67aSAndre Przywara i2c_init((void *)SUNXI_R_I2C_BASE); 103*fb23b104SSamuel Holland axp_power_off(); 1045069c1cfSIcenowy Zheng break; 1055069c1cfSIcenowy Zheng default: 1065069c1cfSIcenowy Zheng break; 1075069c1cfSIcenowy Zheng } 1085069c1cfSIcenowy Zheng } 109