xref: /rk3399_ARM-atf/plat/allwinner/sun50i_h6/sunxi_power.c (revision a08a2014300a495381cdb8f6d59523bcd5d3b883)
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_mmap.h>
16 
17 #define AXP805_ADDR	0x36
18 #define AXP805_ID	0x03
19 
20 enum pmic_type {
21 	NO_PMIC,
22 	AXP805,
23 };
24 
25 enum pmic_type pmic;
26 
27 static int sunxi_init_r_i2c(void)
28 {
29 	uint32_t reg;
30 
31 	/* get currently configured function for pins PL0 and PL1 */
32 	reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x00);
33 	if ((reg & 0xff) == 0x33) {
34 		NOTICE("PMIC: already configured for TWI\n");
35 	}
36 
37 	/* switch pins PL0 and PL1 to I2C */
38 	mmio_write_32(SUNXI_R_PIO_BASE + 0x00, (reg & ~0xff) | 0x33);
39 
40 	/* level 2 drive strength */
41 	reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x14);
42 	mmio_write_32(SUNXI_R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa);
43 
44 	/* set both ports to pull-up */
45 	reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x1c);
46 	mmio_write_32(SUNXI_R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5);
47 
48 	/* assert & de-assert reset of R_I2C */
49 	reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
50 	mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, 0);
51 	reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
52 	mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00010000);
53 
54 	/* un-gate R_I2C clock */
55 	reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
56 	mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00000001);
57 
58 	/* call mi2cv driver */
59 	i2c_init((void *)SUNXI_R_I2C_BASE);
60 
61 	return 0;
62 }
63 
64 int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val)
65 {
66 	int ret;
67 
68 	ret = i2c_write(chip, 0, 0, &reg, 1);
69 	if (ret)
70 		return ret;
71 
72 	return i2c_read(chip, 0, 0, val, 1);
73 }
74 
75 int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
76 {
77 	return i2c_write(chip, reg, 1, &val, 1);
78 }
79 
80 static int axp805_probe(void)
81 {
82 	int ret;
83 	uint8_t val;
84 
85 	ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0);
86 	if (ret) {
87 		ERROR("PMIC: Cannot put AXP805 to master mode.\n");
88 		return -EPERM;
89 	}
90 
91 	ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val);
92 
93 	if (!ret && ((val & 0xcf) == 0x40))
94 		NOTICE("PMIC: AXP805 detected\n");
95 	else if (ret) {
96 		ERROR("PMIC: Cannot communicate with AXP805.\n");
97 		return -EPERM;
98 	} else {
99 		ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n");
100 		return -EINVAL;
101 	}
102 
103 	return 0;
104 }
105 
106 int sunxi_pmic_setup(void)
107 {
108 	int ret;
109 
110 	sunxi_init_r_i2c();
111 
112 	NOTICE("PMIC: Probing AXP805\n");
113 	pmic = AXP805;
114 
115 	ret = axp805_probe();
116 	if (ret)
117 		pmic = NO_PMIC;
118 	else
119 		pmic = AXP805;
120 
121 	return 0;
122 }
123 
124 void __dead2 sunxi_power_down(void)
125 {
126 	uint8_t val;
127 
128 	switch (pmic) {
129 	case AXP805:
130 		val = 0x26; /* Default value for REG 32H */
131 		axp_i2c_read(AXP805_ADDR, 0x32, &val);
132 		val |= 0x80;
133 		axp_i2c_write(AXP805_ADDR, 0x32, val);
134 		break;
135 	default:
136 		break;
137 	}
138 
139 	udelay(1000);
140 	ERROR("PSCI: Cannot communicate with PMIC, halting\n");
141 	wfi();
142 	panic();
143 }
144