xref: /openbmc/u-boot/drivers/power/axp221.c (revision 4d93617d)
1 /*
2  * AXP221 and AXP223 driver
3  *
4  * IMPORTANT when making changes to this file check that the registers
5  * used are the same for the axp221 and axp223.
6  *
7  * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
8  * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
9  *
10  * SPDX-License-Identifier:	GPL-2.0+
11  */
12 
13 #include <common.h>
14 #include <errno.h>
15 #include <asm/arch/p2wi.h>
16 #include <asm/arch/rsb.h>
17 #include <axp221.h>
18 
19 /*
20  * The axp221 uses the p2wi bus, the axp223 is identical (for all registers
21  * used sofar) but uses the rsb bus. These functions abstract this.
22  */
23 static int pmic_bus_init(void)
24 {
25 #ifdef CONFIG_MACH_SUN6I
26 	p2wi_init();
27 	return p2wi_change_to_p2wi_mode(AXP221_CHIP_ADDR, AXP221_CTRL_ADDR,
28 					AXP221_INIT_DATA);
29 #else
30 	int ret;
31 
32 	ret = rsb_init();
33 	if (ret)
34 		return ret;
35 
36 	return rsb_set_device_address(AXP223_DEVICE_ADDR, AXP223_RUNTIME_ADDR);
37 #endif
38 }
39 
40 static int pmic_bus_read(const u8 addr, u8 *data)
41 {
42 #ifdef CONFIG_MACH_SUN6I
43 	return p2wi_read(addr, data);
44 #else
45 	return rsb_read(AXP223_RUNTIME_ADDR, addr, data);
46 #endif
47 }
48 
49 static int pmic_bus_write(const u8 addr, u8 data)
50 {
51 #ifdef CONFIG_MACH_SUN6I
52 	return p2wi_write(addr, data);
53 #else
54 	return rsb_write(AXP223_RUNTIME_ADDR, addr, data);
55 #endif
56 }
57 
58 static u8 axp221_mvolt_to_cfg(int mvolt, int min, int max, int div)
59 {
60 	if (mvolt < min)
61 		mvolt = min;
62 	else if (mvolt > max)
63 		mvolt = max;
64 
65 	return (mvolt - min) / div;
66 }
67 
68 static int axp221_setbits(u8 reg, u8 bits)
69 {
70 	int ret;
71 	u8 val;
72 
73 	ret = pmic_bus_read(reg, &val);
74 	if (ret)
75 		return ret;
76 
77 	val |= bits;
78 	return pmic_bus_write(reg, val);
79 }
80 
81 static int axp221_clrbits(u8 reg, u8 bits)
82 {
83 	int ret;
84 	u8 val;
85 
86 	ret = pmic_bus_read(reg, &val);
87 	if (ret)
88 		return ret;
89 
90 	val &= ~bits;
91 	return pmic_bus_write(reg, val);
92 }
93 
94 int axp221_set_dcdc1(unsigned int mvolt)
95 {
96 	int ret;
97 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100);
98 
99 	if (mvolt == 0)
100 		return axp221_clrbits(AXP221_OUTPUT_CTRL1,
101 				      AXP221_OUTPUT_CTRL1_DCDC1_EN);
102 
103 	ret = pmic_bus_write(AXP221_DCDC1_CTRL, cfg);
104 	if (ret)
105 		return ret;
106 
107 	ret = axp221_setbits(AXP221_OUTPUT_CTRL2,
108 			     AXP221_OUTPUT_CTRL2_DCDC1SW_EN);
109 	if (ret)
110 		return ret;
111 
112 	return axp221_setbits(AXP221_OUTPUT_CTRL1,
113 			      AXP221_OUTPUT_CTRL1_DCDC1_EN);
114 }
115 
116 int axp221_set_dcdc2(unsigned int mvolt)
117 {
118 	int ret;
119 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
120 
121 	if (mvolt == 0)
122 		return axp221_clrbits(AXP221_OUTPUT_CTRL1,
123 				      AXP221_OUTPUT_CTRL1_DCDC2_EN);
124 
125 	ret = pmic_bus_write(AXP221_DCDC2_CTRL, cfg);
126 	if (ret)
127 		return ret;
128 
129 	return axp221_setbits(AXP221_OUTPUT_CTRL1,
130 			      AXP221_OUTPUT_CTRL1_DCDC2_EN);
131 }
132 
133 int axp221_set_dcdc3(unsigned int mvolt)
134 {
135 	int ret;
136 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20);
137 
138 	if (mvolt == 0)
139 		return axp221_clrbits(AXP221_OUTPUT_CTRL1,
140 				      AXP221_OUTPUT_CTRL1_DCDC3_EN);
141 
142 	ret = pmic_bus_write(AXP221_DCDC3_CTRL, cfg);
143 	if (ret)
144 		return ret;
145 
146 	return axp221_setbits(AXP221_OUTPUT_CTRL1,
147 			      AXP221_OUTPUT_CTRL1_DCDC3_EN);
148 }
149 
150 int axp221_set_dcdc4(unsigned int mvolt)
151 {
152 	int ret;
153 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
154 
155 	if (mvolt == 0)
156 		return axp221_clrbits(AXP221_OUTPUT_CTRL1,
157 				      AXP221_OUTPUT_CTRL1_DCDC4_EN);
158 
159 	ret = pmic_bus_write(AXP221_DCDC4_CTRL, cfg);
160 	if (ret)
161 		return ret;
162 
163 	return axp221_setbits(AXP221_OUTPUT_CTRL1,
164 			      AXP221_OUTPUT_CTRL1_DCDC4_EN);
165 }
166 
167 int axp221_set_dcdc5(unsigned int mvolt)
168 {
169 	int ret;
170 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50);
171 
172 	if (mvolt == 0)
173 		return axp221_clrbits(AXP221_OUTPUT_CTRL1,
174 				      AXP221_OUTPUT_CTRL1_DCDC5_EN);
175 
176 	ret = pmic_bus_write(AXP221_DCDC5_CTRL, cfg);
177 	if (ret)
178 		return ret;
179 
180 	return axp221_setbits(AXP221_OUTPUT_CTRL1,
181 			      AXP221_OUTPUT_CTRL1_DCDC5_EN);
182 }
183 
184 int axp221_set_dldo1(unsigned int mvolt)
185 {
186 	int ret;
187 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
188 
189 	if (mvolt == 0)
190 		return axp221_clrbits(AXP221_OUTPUT_CTRL2,
191 				      AXP221_OUTPUT_CTRL2_DLDO1_EN);
192 
193 	ret = pmic_bus_write(AXP221_DLDO1_CTRL, cfg);
194 	if (ret)
195 		return ret;
196 
197 	return axp221_setbits(AXP221_OUTPUT_CTRL2,
198 			      AXP221_OUTPUT_CTRL2_DLDO1_EN);
199 }
200 
201 int axp221_set_dldo2(unsigned int mvolt)
202 {
203 	int ret;
204 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
205 
206 	if (mvolt == 0)
207 		return axp221_clrbits(AXP221_OUTPUT_CTRL2,
208 				      AXP221_OUTPUT_CTRL2_DLDO2_EN);
209 
210 	ret = pmic_bus_write(AXP221_DLDO2_CTRL, cfg);
211 	if (ret)
212 		return ret;
213 
214 	return axp221_setbits(AXP221_OUTPUT_CTRL2,
215 			      AXP221_OUTPUT_CTRL2_DLDO2_EN);
216 }
217 
218 int axp221_set_dldo3(unsigned int mvolt)
219 {
220 	int ret;
221 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
222 
223 	if (mvolt == 0)
224 		return axp221_clrbits(AXP221_OUTPUT_CTRL2,
225 				      AXP221_OUTPUT_CTRL2_DLDO3_EN);
226 
227 	ret = pmic_bus_write(AXP221_DLDO3_CTRL, cfg);
228 	if (ret)
229 		return ret;
230 
231 	return axp221_setbits(AXP221_OUTPUT_CTRL2,
232 			      AXP221_OUTPUT_CTRL2_DLDO3_EN);
233 }
234 
235 int axp221_set_dldo4(unsigned int mvolt)
236 {
237 	int ret;
238 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
239 
240 	if (mvolt == 0)
241 		return axp221_clrbits(AXP221_OUTPUT_CTRL2,
242 				      AXP221_OUTPUT_CTRL2_DLDO4_EN);
243 
244 	ret = pmic_bus_write(AXP221_DLDO4_CTRL, cfg);
245 	if (ret)
246 		return ret;
247 
248 	return axp221_setbits(AXP221_OUTPUT_CTRL2,
249 			      AXP221_OUTPUT_CTRL2_DLDO4_EN);
250 }
251 
252 int axp221_set_aldo1(unsigned int mvolt)
253 {
254 	int ret;
255 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
256 
257 	if (mvolt == 0)
258 		return axp221_clrbits(AXP221_OUTPUT_CTRL1,
259 				      AXP221_OUTPUT_CTRL1_ALDO1_EN);
260 
261 	ret = pmic_bus_write(AXP221_ALDO1_CTRL, cfg);
262 	if (ret)
263 		return ret;
264 
265 	return axp221_setbits(AXP221_OUTPUT_CTRL1,
266 			      AXP221_OUTPUT_CTRL1_ALDO1_EN);
267 }
268 
269 int axp221_set_aldo2(unsigned int mvolt)
270 {
271 	int ret;
272 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
273 
274 	if (mvolt == 0)
275 		return axp221_clrbits(AXP221_OUTPUT_CTRL1,
276 				      AXP221_OUTPUT_CTRL1_ALDO2_EN);
277 
278 	ret = pmic_bus_write(AXP221_ALDO2_CTRL, cfg);
279 	if (ret)
280 		return ret;
281 
282 	return axp221_setbits(AXP221_OUTPUT_CTRL1,
283 			      AXP221_OUTPUT_CTRL1_ALDO2_EN);
284 }
285 
286 int axp221_set_aldo3(unsigned int mvolt)
287 {
288 	int ret;
289 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
290 
291 	if (mvolt == 0)
292 		return axp221_clrbits(AXP221_OUTPUT_CTRL3,
293 				      AXP221_OUTPUT_CTRL3_ALDO3_EN);
294 
295 	ret = pmic_bus_write(AXP221_ALDO3_CTRL, cfg);
296 	if (ret)
297 		return ret;
298 
299 	return axp221_setbits(AXP221_OUTPUT_CTRL3,
300 			      AXP221_OUTPUT_CTRL3_ALDO3_EN);
301 }
302 
303 int axp221_set_eldo(int eldo_num, unsigned int mvolt)
304 {
305 	int ret;
306 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
307 	u8 addr, bits;
308 
309 	switch (eldo_num) {
310 	case 3:
311 		addr = AXP221_ELDO3_CTRL;
312 		bits = AXP221_OUTPUT_CTRL2_ELDO3_EN;
313 		break;
314 	case 2:
315 		addr = AXP221_ELDO2_CTRL;
316 		bits = AXP221_OUTPUT_CTRL2_ELDO2_EN;
317 		break;
318 	case 1:
319 		addr = AXP221_ELDO1_CTRL;
320 		bits = AXP221_OUTPUT_CTRL2_ELDO1_EN;
321 		break;
322 	default:
323 		return -EINVAL;
324 	}
325 
326 	if (mvolt == 0)
327 		return axp221_clrbits(AXP221_OUTPUT_CTRL2, bits);
328 
329 	ret = pmic_bus_write(addr, cfg);
330 	if (ret)
331 		return ret;
332 
333 	return axp221_setbits(AXP221_OUTPUT_CTRL2, bits);
334 }
335 
336 int axp221_init(void)
337 {
338 	/* This cannot be 0 because it is used in SPL before BSS is ready */
339 	static int needs_init = 1;
340 	u8 axp_chip_id;
341 	int ret;
342 
343 	if (!needs_init)
344 		return 0;
345 
346 	ret = pmic_bus_init();
347 	if (ret)
348 		return ret;
349 
350 	ret = pmic_bus_read(AXP221_CHIP_ID, &axp_chip_id);
351 	if (ret)
352 		return ret;
353 
354 	if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17))
355 		return -ENODEV;
356 
357 	needs_init = 0;
358 	return 0;
359 }
360 
361 int axp221_get_sid(unsigned int *sid)
362 {
363 	u8 *dest = (u8 *)sid;
364 	int i, ret;
365 
366 	ret = axp221_init();
367 	if (ret)
368 		return ret;
369 
370 	ret = pmic_bus_write(AXP221_PAGE, 1);
371 	if (ret)
372 		return ret;
373 
374 	for (i = 0; i < 16; i++) {
375 		ret = pmic_bus_read(AXP221_SID + i, &dest[i]);
376 		if (ret)
377 			return ret;
378 	}
379 
380 	pmic_bus_write(AXP221_PAGE, 0);
381 
382 	for (i = 0; i < 4; i++)
383 		sid[i] = be32_to_cpu(sid[i]);
384 
385 	return 0;
386 }
387 
388 int axp_get_vbus(void)
389 {
390 	int ret;
391 	u8 val;
392 
393 	ret = axp221_init();
394 	if (ret)
395 		return ret;
396 
397 	ret = pmic_bus_read(AXP221_POWER_STATUS, &val);
398 	if (ret)
399 		return ret;
400 
401 	return (val & AXP221_POWER_STATUS_VBUS_USABLE) ? 1 : 0;
402 }
403 
404 static int axp_drivebus_setup(void)
405 {
406 	int ret;
407 
408 	ret = axp221_init();
409 	if (ret)
410 		return ret;
411 
412 	/* Set N_VBUSEN pin to output / DRIVEBUS function */
413 	return axp221_clrbits(AXP221_MISC_CTRL, AXP221_MISC_CTRL_N_VBUSEN_FUNC);
414 }
415 
416 int axp_drivebus_enable(void)
417 {
418 	int ret;
419 
420 	ret = axp_drivebus_setup();
421 	if (ret)
422 		return ret;
423 
424 	/* Set DRIVEBUS high */
425 	return axp221_setbits(AXP221_VBUS_IPSOUT, AXP221_VBUS_IPSOUT_DRIVEBUS);
426 }
427 
428 int axp_drivebus_disable(void)
429 {
430 	int ret;
431 
432 	ret = axp_drivebus_setup();
433 	if (ret)
434 		return ret;
435 
436 	/* Set DRIVEBUS low */
437 	return axp221_clrbits(AXP221_VBUS_IPSOUT, AXP221_VBUS_IPSOUT_DRIVEBUS);
438 }
439