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