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> 1309d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h> 1409d40e0eSAntonio Nino Diaz #include <drivers/mentor/mi2cv.h> 1509d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 1609d40e0eSAntonio Nino Diaz 17d5ddf67aSAndre Przywara #include <sunxi_def.h> 186d372828SIcenowy Zheng #include <sunxi_mmap.h> 194ec1a239SAndre Przywara #include <sunxi_private.h> 206d372828SIcenowy Zheng 216d372828SIcenowy Zheng #define AXP805_ADDR 0x36 226d372828SIcenowy Zheng #define AXP805_ID 0x03 236d372828SIcenowy Zheng 24c0e109f2SSamuel Holland static enum pmic_type { 25c0e109f2SSamuel Holland UNKNOWN, 266d372828SIcenowy Zheng AXP805, 27c0e109f2SSamuel Holland } pmic; 286d372828SIcenowy Zheng 296d372828SIcenowy Zheng int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val) 306d372828SIcenowy Zheng { 316d372828SIcenowy Zheng int ret; 326d372828SIcenowy Zheng 336d372828SIcenowy Zheng ret = i2c_write(chip, 0, 0, ®, 1); 344538c498SSamuel Holland if (ret == 0) 354538c498SSamuel Holland ret = i2c_read(chip, 0, 0, val, 1); 366d372828SIcenowy Zheng if (ret) 374538c498SSamuel Holland ERROR("PMIC: Cannot read AXP805 register %02x\n", reg); 386d372828SIcenowy Zheng 394538c498SSamuel Holland return ret; 406d372828SIcenowy Zheng } 416d372828SIcenowy Zheng 426d372828SIcenowy Zheng int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) 436d372828SIcenowy Zheng { 444538c498SSamuel Holland int ret; 454538c498SSamuel Holland 464538c498SSamuel Holland ret = i2c_write(chip, reg, 1, &val, 1); 474538c498SSamuel Holland if (ret) 484538c498SSamuel Holland ERROR("PMIC: Cannot write AXP805 register %02x\n", reg); 494538c498SSamuel Holland 504538c498SSamuel Holland return ret; 516d372828SIcenowy Zheng } 526d372828SIcenowy Zheng 536d372828SIcenowy Zheng static int axp805_probe(void) 546d372828SIcenowy Zheng { 556d372828SIcenowy Zheng int ret; 566d372828SIcenowy Zheng uint8_t val; 576d372828SIcenowy Zheng 584538c498SSamuel Holland /* Switch the AXP805 to master/single-PMIC mode. */ 596d372828SIcenowy Zheng ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); 604538c498SSamuel Holland if (ret) 614538c498SSamuel Holland return ret; 626d372828SIcenowy Zheng 636d372828SIcenowy Zheng ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); 644538c498SSamuel Holland if (ret) 654538c498SSamuel Holland return ret; 666d372828SIcenowy Zheng 674538c498SSamuel Holland val &= 0xcf; 684538c498SSamuel Holland if (val != 0x40) { 694538c498SSamuel Holland ERROR("PMIC: Found unknown PMIC %02x\n", val); 706d372828SIcenowy Zheng return -EINVAL; 716d372828SIcenowy Zheng } 726d372828SIcenowy Zheng 736d372828SIcenowy Zheng return 0; 746d372828SIcenowy Zheng } 757c26b6ecSIcenowy Zheng 76df301601SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt) 777c26b6ecSIcenowy Zheng { 786d372828SIcenowy Zheng int ret; 796d372828SIcenowy Zheng 804538c498SSamuel Holland INFO("PMIC: Probing AXP805 on I2C\n"); 814538c498SSamuel Holland 824538c498SSamuel Holland ret = sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 834538c498SSamuel Holland if (ret) 844538c498SSamuel Holland return ret; 854538c498SSamuel Holland 86d5ddf67aSAndre Przywara /* initialise mi2cv driver */ 87d5ddf67aSAndre Przywara i2c_init((void *)SUNXI_R_I2C_BASE); 886d372828SIcenowy Zheng 896d372828SIcenowy Zheng ret = axp805_probe(); 906d372828SIcenowy Zheng if (ret) 91c0e109f2SSamuel Holland return ret; 92c0e109f2SSamuel Holland 936d372828SIcenowy Zheng pmic = AXP805; 947c26b6ecSIcenowy Zheng 957c26b6ecSIcenowy Zheng return 0; 967c26b6ecSIcenowy Zheng } 975069c1cfSIcenowy Zheng 98*818e6732SSamuel Holland void sunxi_power_down(void) 995069c1cfSIcenowy Zheng { 1005069c1cfSIcenowy Zheng uint8_t val; 1015069c1cfSIcenowy Zheng 1025069c1cfSIcenowy Zheng switch (pmic) { 1035069c1cfSIcenowy Zheng case AXP805: 104d5ddf67aSAndre Przywara /* Re-initialise after rich OS might have used it. */ 105d5ddf67aSAndre Przywara sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 106d5ddf67aSAndre Przywara /* initialise mi2cv driver */ 107d5ddf67aSAndre Przywara i2c_init((void *)SUNXI_R_I2C_BASE); 1085069c1cfSIcenowy Zheng axp_i2c_read(AXP805_ADDR, 0x32, &val); 109159c5249SAndre Przywara axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80); 1105069c1cfSIcenowy Zheng break; 1115069c1cfSIcenowy Zheng default: 1125069c1cfSIcenowy Zheng break; 1135069c1cfSIcenowy Zheng } 1145069c1cfSIcenowy Zheng } 115