blob: 36e3dbe74984b46f5032023538102e933a085c9d [file] [log] [blame]
Icenowy Zheng7508bef2018-07-21 20:41:12 +08001/*
Samuel Hollandf95b3682019-10-20 15:12:20 -05002 * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
Icenowy Zheng7508bef2018-07-21 20:41:12 +08003 * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
Icenowy Zheng8d769822018-07-22 21:30:14 +08008#include <errno.h>
Icenowy Zheng8d769822018-07-22 21:30:14 +08009#include <string.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010
11#include <arch_helpers.h>
12#include <common/debug.h>
13#include <drivers/delay_timer.h>
14#include <drivers/mentor/mi2cv.h>
15#include <lib/mmio.h>
16
Andre Przywara67537762018-10-14 22:13:53 +010017#include <sunxi_def.h>
Icenowy Zheng8d769822018-07-22 21:30:14 +080018#include <sunxi_mmap.h>
Andre Przywara456208a2018-10-14 12:02:02 +010019#include <sunxi_private.h>
Icenowy Zheng8d769822018-07-22 21:30:14 +080020
21#define AXP805_ADDR 0x36
22#define AXP805_ID 0x03
23
Samuel Hollandf95b3682019-10-20 15:12:20 -050024static enum pmic_type {
25 UNKNOWN,
Icenowy Zheng8d769822018-07-22 21:30:14 +080026 AXP805,
Samuel Hollandf95b3682019-10-20 15:12:20 -050027} pmic;
Icenowy Zheng8d769822018-07-22 21:30:14 +080028
Icenowy Zheng8d769822018-07-22 21:30:14 +080029int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val)
30{
31 int ret;
32
33 ret = i2c_write(chip, 0, 0, &reg, 1);
34 if (ret)
35 return ret;
36
37 return i2c_read(chip, 0, 0, val, 1);
38}
39
40int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
41{
42 return i2c_write(chip, reg, 1, &val, 1);
43}
44
45static int axp805_probe(void)
46{
47 int ret;
48 uint8_t val;
49
50 ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0);
51 if (ret) {
52 ERROR("PMIC: Cannot put AXP805 to master mode.\n");
53 return -EPERM;
54 }
55
56 ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val);
57
58 if (!ret && ((val & 0xcf) == 0x40))
59 NOTICE("PMIC: AXP805 detected\n");
60 else if (ret) {
61 ERROR("PMIC: Cannot communicate with AXP805.\n");
62 return -EPERM;
63 } else {
64 ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n");
65 return -EINVAL;
66 }
67
68 return 0;
69}
Icenowy Zheng7508bef2018-07-21 20:41:12 +080070
Andre Przywara4e4b1e62018-09-08 19:18:37 +010071int sunxi_pmic_setup(uint16_t socid, const void *fdt)
Icenowy Zheng7508bef2018-07-21 20:41:12 +080072{
Icenowy Zheng8d769822018-07-22 21:30:14 +080073 int ret;
74
Andre Przywara67537762018-10-14 22:13:53 +010075 sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
76 /* initialise mi2cv driver */
77 i2c_init((void *)SUNXI_R_I2C_BASE);
Icenowy Zheng8d769822018-07-22 21:30:14 +080078
79 NOTICE("PMIC: Probing AXP805\n");
Icenowy Zheng8d769822018-07-22 21:30:14 +080080
81 ret = axp805_probe();
82 if (ret)
Samuel Hollandf95b3682019-10-20 15:12:20 -050083 return ret;
84
85 pmic = AXP805;
Icenowy Zheng7508bef2018-07-21 20:41:12 +080086
87 return 0;
88}
Icenowy Zhengbd57eb52018-07-22 21:52:50 +080089
90void __dead2 sunxi_power_down(void)
91{
92 uint8_t val;
93
94 switch (pmic) {
95 case AXP805:
Andre Przywara67537762018-10-14 22:13:53 +010096 /* Re-initialise after rich OS might have used it. */
97 sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
98 /* initialise mi2cv driver */
99 i2c_init((void *)SUNXI_R_I2C_BASE);
Icenowy Zhengbd57eb52018-07-22 21:52:50 +0800100 axp_i2c_read(AXP805_ADDR, 0x32, &val);
Andre Przywaraaffb9322018-09-09 00:38:58 +0100101 axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80);
Icenowy Zhengbd57eb52018-07-22 21:52:50 +0800102 break;
103 default:
104 break;
105 }
106
107 udelay(1000);
108 ERROR("PSCI: Cannot communicate with PMIC, halting\n");
109 wfi();
110 panic();
111}