xref: /rk3399_ARM-atf/plat/allwinner/sun50i_h6/sunxi_power.c (revision c948f77136c42a92d0bb660543a3600c36dcf7f1)
1 /*
2  * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3  * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <errno.h>
9 #include <string.h>
10 
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 
17 #include <sunxi_def.h>
18 #include <sunxi_mmap.h>
19 #include <sunxi_private.h>
20 
21 #define AXP805_ADDR	0x36
22 #define AXP805_ID	0x03
23 
24 enum pmic_type {
25 	NO_PMIC,
26 	AXP805,
27 };
28 
29 enum pmic_type pmic;
30 
31 int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val)
32 {
33 	int ret;
34 
35 	ret = i2c_write(chip, 0, 0, &reg, 1);
36 	if (ret)
37 		return ret;
38 
39 	return i2c_read(chip, 0, 0, val, 1);
40 }
41 
42 int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
43 {
44 	return i2c_write(chip, reg, 1, &val, 1);
45 }
46 
47 static int axp805_probe(void)
48 {
49 	int ret;
50 	uint8_t val;
51 
52 	ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0);
53 	if (ret) {
54 		ERROR("PMIC: Cannot put AXP805 to master mode.\n");
55 		return -EPERM;
56 	}
57 
58 	ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val);
59 
60 	if (!ret && ((val & 0xcf) == 0x40))
61 		NOTICE("PMIC: AXP805 detected\n");
62 	else if (ret) {
63 		ERROR("PMIC: Cannot communicate with AXP805.\n");
64 		return -EPERM;
65 	} else {
66 		ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n");
67 		return -EINVAL;
68 	}
69 
70 	return 0;
71 }
72 
73 int sunxi_pmic_setup(uint16_t socid, const void *fdt)
74 {
75 	int ret;
76 
77 	sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
78 	/* initialise mi2cv driver */
79 	i2c_init((void *)SUNXI_R_I2C_BASE);
80 
81 	NOTICE("PMIC: Probing AXP805\n");
82 	pmic = AXP805;
83 
84 	ret = axp805_probe();
85 	if (ret)
86 		pmic = NO_PMIC;
87 	else
88 		pmic = AXP805;
89 
90 	return 0;
91 }
92 
93 void __dead2 sunxi_power_down(void)
94 {
95 	uint8_t val;
96 
97 	switch (pmic) {
98 	case AXP805:
99 		/* Re-initialise after rich OS might have used it. */
100 		sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
101 		/* initialise mi2cv driver */
102 		i2c_init((void *)SUNXI_R_I2C_BASE);
103 		axp_i2c_read(AXP805_ADDR, 0x32, &val);
104 		axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80);
105 		break;
106 	default:
107 		break;
108 	}
109 
110 	udelay(1000);
111 	ERROR("PSCI: Cannot communicate with PMIC, halting\n");
112 	wfi();
113 	panic();
114 }
115