17c26b6ecSIcenowy Zheng /* 2*c0e109f2SSamuel 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 24*c0e109f2SSamuel Holland static enum pmic_type { 25*c0e109f2SSamuel Holland UNKNOWN, 266d372828SIcenowy Zheng AXP805, 27*c0e109f2SSamuel 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); 346d372828SIcenowy Zheng if (ret) 356d372828SIcenowy Zheng return ret; 366d372828SIcenowy Zheng 376d372828SIcenowy Zheng return i2c_read(chip, 0, 0, val, 1); 386d372828SIcenowy Zheng } 396d372828SIcenowy Zheng 406d372828SIcenowy Zheng int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) 416d372828SIcenowy Zheng { 426d372828SIcenowy Zheng return i2c_write(chip, reg, 1, &val, 1); 436d372828SIcenowy Zheng } 446d372828SIcenowy Zheng 456d372828SIcenowy Zheng static int axp805_probe(void) 466d372828SIcenowy Zheng { 476d372828SIcenowy Zheng int ret; 486d372828SIcenowy Zheng uint8_t val; 496d372828SIcenowy Zheng 506d372828SIcenowy Zheng ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); 516d372828SIcenowy Zheng if (ret) { 526d372828SIcenowy Zheng ERROR("PMIC: Cannot put AXP805 to master mode.\n"); 536d372828SIcenowy Zheng return -EPERM; 546d372828SIcenowy Zheng } 556d372828SIcenowy Zheng 566d372828SIcenowy Zheng ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); 576d372828SIcenowy Zheng 586d372828SIcenowy Zheng if (!ret && ((val & 0xcf) == 0x40)) 596d372828SIcenowy Zheng NOTICE("PMIC: AXP805 detected\n"); 606d372828SIcenowy Zheng else if (ret) { 616d372828SIcenowy Zheng ERROR("PMIC: Cannot communicate with AXP805.\n"); 626d372828SIcenowy Zheng return -EPERM; 636d372828SIcenowy Zheng } else { 646d372828SIcenowy Zheng ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n"); 656d372828SIcenowy Zheng return -EINVAL; 666d372828SIcenowy Zheng } 676d372828SIcenowy Zheng 686d372828SIcenowy Zheng return 0; 696d372828SIcenowy Zheng } 707c26b6ecSIcenowy Zheng 71df301601SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt) 727c26b6ecSIcenowy Zheng { 736d372828SIcenowy Zheng int ret; 746d372828SIcenowy Zheng 75d5ddf67aSAndre Przywara sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 76d5ddf67aSAndre Przywara /* initialise mi2cv driver */ 77d5ddf67aSAndre Przywara i2c_init((void *)SUNXI_R_I2C_BASE); 786d372828SIcenowy Zheng 796d372828SIcenowy Zheng NOTICE("PMIC: Probing AXP805\n"); 806d372828SIcenowy Zheng 816d372828SIcenowy Zheng ret = axp805_probe(); 826d372828SIcenowy Zheng if (ret) 83*c0e109f2SSamuel Holland return ret; 84*c0e109f2SSamuel Holland 856d372828SIcenowy Zheng pmic = AXP805; 867c26b6ecSIcenowy Zheng 877c26b6ecSIcenowy Zheng return 0; 887c26b6ecSIcenowy Zheng } 895069c1cfSIcenowy Zheng 905069c1cfSIcenowy Zheng void __dead2 sunxi_power_down(void) 915069c1cfSIcenowy Zheng { 925069c1cfSIcenowy Zheng uint8_t val; 935069c1cfSIcenowy Zheng 945069c1cfSIcenowy Zheng switch (pmic) { 955069c1cfSIcenowy Zheng case AXP805: 96d5ddf67aSAndre Przywara /* Re-initialise after rich OS might have used it. */ 97d5ddf67aSAndre Przywara sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); 98d5ddf67aSAndre Przywara /* initialise mi2cv driver */ 99d5ddf67aSAndre Przywara i2c_init((void *)SUNXI_R_I2C_BASE); 1005069c1cfSIcenowy Zheng axp_i2c_read(AXP805_ADDR, 0x32, &val); 101159c5249SAndre Przywara axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80); 1025069c1cfSIcenowy Zheng break; 1035069c1cfSIcenowy Zheng default: 1045069c1cfSIcenowy Zheng break; 1055069c1cfSIcenowy Zheng } 1065069c1cfSIcenowy Zheng 1075069c1cfSIcenowy Zheng udelay(1000); 1085069c1cfSIcenowy Zheng ERROR("PSCI: Cannot communicate with PMIC, halting\n"); 1095069c1cfSIcenowy Zheng wfi(); 1105069c1cfSIcenowy Zheng panic(); 1115069c1cfSIcenowy Zheng } 112