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 86d372828SIcenowy Zheng #include <errno.h> 96d372828SIcenowy Zheng #include <string.h> 10*09d40e0eSAntonio Nino Diaz 11*09d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 12*09d40e0eSAntonio Nino Diaz #include <common/debug.h> 13*09d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h> 14*09d40e0eSAntonio Nino Diaz #include <drivers/mentor/mi2cv.h> 15*09d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 16*09d40e0eSAntonio 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 246d372828SIcenowy Zheng enum pmic_type { 256d372828SIcenowy Zheng NO_PMIC, 266d372828SIcenowy Zheng AXP805, 276d372828SIcenowy Zheng }; 286d372828SIcenowy Zheng 296d372828SIcenowy Zheng enum pmic_type pmic; 306d372828SIcenowy Zheng 316d372828SIcenowy Zheng int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val) 326d372828SIcenowy Zheng { 336d372828SIcenowy Zheng int ret; 346d372828SIcenowy Zheng 356d372828SIcenowy Zheng ret = i2c_write(chip, 0, 0, ®, 1); 366d372828SIcenowy Zheng if (ret) 376d372828SIcenowy Zheng return ret; 386d372828SIcenowy Zheng 396d372828SIcenowy Zheng return i2c_read(chip, 0, 0, val, 1); 406d372828SIcenowy Zheng } 416d372828SIcenowy Zheng 426d372828SIcenowy Zheng int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) 436d372828SIcenowy Zheng { 446d372828SIcenowy Zheng return i2c_write(chip, reg, 1, &val, 1); 456d372828SIcenowy Zheng } 466d372828SIcenowy Zheng 476d372828SIcenowy Zheng static int axp805_probe(void) 486d372828SIcenowy Zheng { 496d372828SIcenowy Zheng int ret; 506d372828SIcenowy Zheng uint8_t val; 516d372828SIcenowy Zheng 526d372828SIcenowy Zheng ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); 536d372828SIcenowy Zheng if (ret) { 546d372828SIcenowy Zheng ERROR("PMIC: Cannot put AXP805 to master mode.\n"); 556d372828SIcenowy Zheng return -EPERM; 566d372828SIcenowy Zheng } 576d372828SIcenowy Zheng 586d372828SIcenowy Zheng ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); 596d372828SIcenowy Zheng 606d372828SIcenowy Zheng if (!ret && ((val & 0xcf) == 0x40)) 616d372828SIcenowy Zheng NOTICE("PMIC: AXP805 detected\n"); 626d372828SIcenowy Zheng else if (ret) { 636d372828SIcenowy Zheng ERROR("PMIC: Cannot communicate with AXP805.\n"); 646d372828SIcenowy Zheng return -EPERM; 656d372828SIcenowy Zheng } else { 666d372828SIcenowy Zheng ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n"); 676d372828SIcenowy Zheng return -EINVAL; 686d372828SIcenowy Zheng } 696d372828SIcenowy Zheng 706d372828SIcenowy Zheng return 0; 716d372828SIcenowy Zheng } 727c26b6ecSIcenowy Zheng 73df301601SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt) 747c26b6ecSIcenowy Zheng { 756d372828SIcenowy Zheng int ret; 766d372828SIcenowy Zheng 77d5ddf67aSAndre Przywara sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 78d5ddf67aSAndre Przywara /* initialise mi2cv driver */ 79d5ddf67aSAndre Przywara i2c_init((void *)SUNXI_R_I2C_BASE); 806d372828SIcenowy Zheng 816d372828SIcenowy Zheng NOTICE("PMIC: Probing AXP805\n"); 826d372828SIcenowy Zheng pmic = AXP805; 836d372828SIcenowy Zheng 846d372828SIcenowy Zheng ret = axp805_probe(); 856d372828SIcenowy Zheng if (ret) 866d372828SIcenowy Zheng pmic = NO_PMIC; 876d372828SIcenowy Zheng else 886d372828SIcenowy Zheng pmic = AXP805; 897c26b6ecSIcenowy Zheng 907c26b6ecSIcenowy Zheng return 0; 917c26b6ecSIcenowy Zheng } 925069c1cfSIcenowy Zheng 935069c1cfSIcenowy Zheng void __dead2 sunxi_power_down(void) 945069c1cfSIcenowy Zheng { 955069c1cfSIcenowy Zheng uint8_t val; 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); 1035069c1cfSIcenowy Zheng axp_i2c_read(AXP805_ADDR, 0x32, &val); 104159c5249SAndre Przywara axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80); 1055069c1cfSIcenowy Zheng break; 1065069c1cfSIcenowy Zheng default: 1075069c1cfSIcenowy Zheng break; 1085069c1cfSIcenowy Zheng } 1095069c1cfSIcenowy Zheng 1105069c1cfSIcenowy Zheng udelay(1000); 1115069c1cfSIcenowy Zheng ERROR("PSCI: Cannot communicate with PMIC, halting\n"); 1125069c1cfSIcenowy Zheng wfi(); 1135069c1cfSIcenowy Zheng panic(); 1145069c1cfSIcenowy Zheng } 115