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); 34*4538c498SSamuel Holland if (ret == 0) 35*4538c498SSamuel Holland ret = i2c_read(chip, 0, 0, val, 1); 366d372828SIcenowy Zheng if (ret) 37*4538c498SSamuel Holland ERROR("PMIC: Cannot read AXP805 register %02x\n", reg); 386d372828SIcenowy Zheng 39*4538c498SSamuel Holland return ret; 406d372828SIcenowy Zheng } 416d372828SIcenowy Zheng 426d372828SIcenowy Zheng int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) 436d372828SIcenowy Zheng { 44*4538c498SSamuel Holland int ret; 45*4538c498SSamuel Holland 46*4538c498SSamuel Holland ret = i2c_write(chip, reg, 1, &val, 1); 47*4538c498SSamuel Holland if (ret) 48*4538c498SSamuel Holland ERROR("PMIC: Cannot write AXP805 register %02x\n", reg); 49*4538c498SSamuel Holland 50*4538c498SSamuel 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 58*4538c498SSamuel Holland /* Switch the AXP805 to master/single-PMIC mode. */ 596d372828SIcenowy Zheng ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); 60*4538c498SSamuel Holland if (ret) 61*4538c498SSamuel Holland return ret; 626d372828SIcenowy Zheng 636d372828SIcenowy Zheng ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); 64*4538c498SSamuel Holland if (ret) 65*4538c498SSamuel Holland return ret; 666d372828SIcenowy Zheng 67*4538c498SSamuel Holland val &= 0xcf; 68*4538c498SSamuel Holland if (val != 0x40) { 69*4538c498SSamuel 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 80*4538c498SSamuel Holland INFO("PMIC: Probing AXP805 on I2C\n"); 81*4538c498SSamuel Holland 82*4538c498SSamuel Holland ret = sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 83*4538c498SSamuel Holland if (ret) 84*4538c498SSamuel Holland return ret; 85*4538c498SSamuel 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 985069c1cfSIcenowy Zheng void __dead2 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 1155069c1cfSIcenowy Zheng udelay(1000); 1165069c1cfSIcenowy Zheng ERROR("PSCI: Cannot communicate with PMIC, halting\n"); 1175069c1cfSIcenowy Zheng wfi(); 1185069c1cfSIcenowy Zheng panic(); 1195069c1cfSIcenowy Zheng } 120