1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2012
4  * Henrik Nordstrom <henrik@henriknordstrom.net>
5  */
6 
7 #include <common.h>
8 #include <command.h>
9 #include <asm/arch/pmic_bus.h>
10 #include <axp_pmic.h>
11 #include <linux/delay.h>
12 
13 #ifdef CONFIG_AXP_ALDO3_VOLT_SLOPE_08
14 #  define AXP209_VRC_SLOPE AXP209_VRC_LDO3_800uV_uS
15 #endif
16 #ifdef CONFIG_AXP_ALDO3_VOLT_SLOPE_16
17 #  define AXP209_VRC_SLOPE AXP209_VRC_LDO3_1600uV_uS
18 #endif
19 #if defined CONFIG_AXP_ALDO3_VOLT_SLOPE_NONE || !defined AXP209_VRC_SLOPE
20 #  define AXP209_VRC_SLOPE 0x00
21 #endif
22 
axp209_mvolt_to_cfg(int mvolt,int min,int max,int div)23 static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div)
24 {
25 	if (mvolt < min)
26 		mvolt = min;
27 	else if (mvolt > max)
28 		mvolt = max;
29 
30 	return (mvolt - min) / div;
31 }
32 
axp_set_dcdc2(unsigned int mvolt)33 int axp_set_dcdc2(unsigned int mvolt)
34 {
35 	int rc;
36 	u8 cfg, current;
37 
38 	if (mvolt == 0)
39 		return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
40 					AXP209_OUTPUT_CTRL_DCDC2);
41 
42 	rc = pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC2);
43 	if (rc)
44 		return rc;
45 
46 	cfg = axp209_mvolt_to_cfg(mvolt, 700, 2275, 25);
47 
48 	/* Do we really need to be this gentle? It has built-in voltage slope */
49 	while ((rc = pmic_bus_read(AXP209_DCDC2_VOLTAGE, &current)) == 0 &&
50 	       current != cfg) {
51 		if (current < cfg)
52 			current++;
53 		else
54 			current--;
55 
56 		rc = pmic_bus_write(AXP209_DCDC2_VOLTAGE, current);
57 		if (rc)
58 			break;
59 	}
60 
61 	return rc;
62 }
63 
axp_set_dcdc3(unsigned int mvolt)64 int axp_set_dcdc3(unsigned int mvolt)
65 {
66 	u8 cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
67 	int rc;
68 
69 	if (mvolt == 0)
70 		return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
71 					AXP209_OUTPUT_CTRL_DCDC3);
72 
73 	rc = pmic_bus_write(AXP209_DCDC3_VOLTAGE, cfg);
74 	if (rc)
75 		return rc;
76 
77 	return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC3);
78 }
79 
axp_set_aldo2(unsigned int mvolt)80 int axp_set_aldo2(unsigned int mvolt)
81 {
82 	int rc;
83 	u8 cfg, reg;
84 
85 	if (mvolt == 0)
86 		return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
87 					AXP209_OUTPUT_CTRL_LDO2);
88 
89 	cfg = axp209_mvolt_to_cfg(mvolt, 1800, 3300, 100);
90 
91 	rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, &reg);
92 	if (rc)
93 		return rc;
94 
95 	reg |= AXP209_LDO24_LDO2_SET(reg, cfg);
96 	rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
97 	if (rc)
98 		return rc;
99 
100 	return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO2);
101 }
102 
axp_set_aldo3(unsigned int mvolt)103 int axp_set_aldo3(unsigned int mvolt)
104 {
105 	u8 cfg;
106 	int rc;
107 
108 	if (mvolt == 0)
109 		return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
110 					AXP209_OUTPUT_CTRL_LDO3);
111 
112 	/*
113 	 * Some boards have trouble reaching the target voltage without causing
114 	 * great inrush currents. To prevent this, boards can enable a certain
115 	 * slope to ramp up voltage. Note, this only works when changing an
116 	 * already active power rail. When toggling power on, the AXP ramps up
117 	 * steeply at 0.0167 V/uS.
118 	 */
119 	rc = pmic_bus_read(AXP209_VRC_DCDC2_LDO3, &cfg);
120 	cfg = AXP209_VRC_LDO3_SLOPE_SET(cfg, AXP209_VRC_SLOPE);
121 	rc |= pmic_bus_write(AXP209_VRC_DCDC2_LDO3, cfg);
122 
123 	if (rc)
124 		return rc;
125 
126 #ifdef CONFIG_AXP_ALDO3_INRUSH_QUIRK
127 	/*
128 	 * On some boards, LDO3 has a too big capacitor installed. When
129 	 * turning on LDO3, this causes the AXP209 to shutdown on
130 	 * voltages over 1.9 volt. As a workaround, we enable LDO3
131 	 * first with the lowest possible voltage. If this still causes
132 	 * high inrush currents, the voltage slope should be increased.
133 	 */
134 	rc = pmic_bus_read(AXP209_OUTPUT_CTRL, &cfg);
135 	if (rc)
136 		return rc;
137 
138 	if (!(cfg & AXP209_OUTPUT_CTRL_LDO3)) {
139 		rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, 0x0); /* 0.7 Volt */
140 		mdelay(1);
141 		rc |= pmic_bus_setbits(AXP209_OUTPUT_CTRL,
142 				       AXP209_OUTPUT_CTRL_LDO3);
143 
144 		if (rc)
145 			return rc;
146 	}
147 #endif
148 
149 	if (mvolt == -1) {
150 		cfg = AXP209_LDO3_VOLTAGE_FROM_LDO3IN;
151 	} else {
152 		cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
153 		cfg = AXP209_LDO3_VOLTAGE_SET(cfg);
154 	}
155 
156 	rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, cfg);
157 	if (rc)
158 		return rc;
159 
160 	return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO3);
161 }
162 
axp_set_aldo4(unsigned int mvolt)163 int axp_set_aldo4(unsigned int mvolt)
164 {
165 	int rc;
166 	static const unsigned int vindex[] = {
167 		1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2500,
168 		2700, 2800, 3000, 3100, 3200, 3300
169 	};
170 	u8 cfg, reg;
171 
172 	if (mvolt == 0)
173 		return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
174 					AXP209_OUTPUT_CTRL_LDO4);
175 
176 	/* Translate mvolt to register cfg value, requested <= selected */
177 	for (cfg = 15; vindex[cfg] > mvolt && cfg > 0; cfg--);
178 
179 	rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, &reg);
180 	if (rc)
181 		return rc;
182 
183 	reg |= AXP209_LDO24_LDO4_SET(reg, cfg);
184 	rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
185 	if (rc)
186 		return rc;
187 
188 	return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO4);
189 }
190 
axp_init(void)191 int axp_init(void)
192 {
193 	u8 ver;
194 	int i, rc;
195 
196 	rc = pmic_bus_init();
197 	if (rc)
198 		return rc;
199 
200 	rc = pmic_bus_read(AXP209_CHIP_VERSION, &ver);
201 	if (rc)
202 		return rc;
203 
204 	if ((ver & AXP209_CHIP_VERSION_MASK) != 0x1)
205 		return -EINVAL;
206 
207 	/* Mask all interrupts */
208 	for (i = AXP209_IRQ_ENABLE1; i <= AXP209_IRQ_ENABLE5; i++) {
209 		rc = pmic_bus_write(i, 0);
210 		if (rc)
211 			return rc;
212 	}
213 
214 	/*
215 	 * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
216 	 * from android these are sometimes on.
217 	 */
218 	rc = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
219 	if (rc)
220 		return rc;
221 
222 	rc = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
223 	if (rc)
224 		return rc;
225 
226 	rc = pmic_bus_write(AXP_GPIO2_CTRL, AXP_GPIO_CTRL_INPUT);
227 	if (rc)
228 		return rc;
229 
230 	return 0;
231 }
232 
do_poweroff(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])233 int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
234 {
235 	pmic_bus_write(AXP209_SHUTDOWN, AXP209_POWEROFF);
236 
237 	/* infinite loop during shutdown */
238 	while (1) {}
239 
240 	/* not reached */
241 	return 0;
242 }
243