xref: /rk3399_ARM-atf/plat/allwinner/sun50i_h6/sunxi_power.c (revision c3cf06f1a3a9b9ee8ac7a0ae505f95c45f7dca84)
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 <arch_helpers.h>
9 #include <debug.h>
10 #include <delay_timer.h>
11 #include <errno.h>
12 #include <mmio.h>
13 #include <mentor/mi2cv.h>
14 #include <string.h>
15 #include <sunxi_def.h>
16 #include <sunxi_mmap.h>
17 #include <sunxi_private.h>
18 
19 #define AXP805_ADDR	0x36
20 #define AXP805_ID	0x03
21 
22 enum pmic_type {
23 	NO_PMIC,
24 	AXP805,
25 };
26 
27 enum pmic_type pmic;
28 
29 int 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 
40 int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
41 {
42 	return i2c_write(chip, reg, 1, &val, 1);
43 }
44 
45 static 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 }
70 
71 int sunxi_pmic_setup(uint16_t socid, const void *fdt)
72 {
73 	int ret;
74 
75 	sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
76 	/* initialise mi2cv driver */
77 	i2c_init((void *)SUNXI_R_I2C_BASE);
78 
79 	NOTICE("PMIC: Probing AXP805\n");
80 	pmic = AXP805;
81 
82 	ret = axp805_probe();
83 	if (ret)
84 		pmic = NO_PMIC;
85 	else
86 		pmic = AXP805;
87 
88 	return 0;
89 }
90 
91 void __dead2 sunxi_power_down(void)
92 {
93 	uint8_t val;
94 
95 	switch (pmic) {
96 	case AXP805:
97 		/* Re-initialise after rich OS might have used it. */
98 		sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
99 		/* initialise mi2cv driver */
100 		i2c_init((void *)SUNXI_R_I2C_BASE);
101 		axp_i2c_read(AXP805_ADDR, 0x32, &val);
102 		axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80);
103 		break;
104 	default:
105 		break;
106 	}
107 
108 	udelay(1000);
109 	ERROR("PSCI: Cannot communicate with PMIC, halting\n");
110 	wfi();
111 	panic();
112 }
113