blob: 3e07f23c20c621ba9cbfc101d788462aed93026d [file] [log] [blame]
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +02001/*
Hans de Goedebdcdf842014-11-29 23:54:25 +01002 * 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>
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +02008 * (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>
Hans de Goedebdcdf842014-11-29 23:54:25 +010016#include <asm/arch/rsb.h>
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +020017#include <axp221.h>
18
Hans de Goedebdcdf842014-11-29 23:54:25 +010019/*
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 */
23static 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
Hans de Goede37d46dd2015-01-26 16:59:12 +010032 ret = rsb_init();
Hans de Goedebdcdf842014-11-29 23:54:25 +010033 if (ret)
34 return ret;
35
36 return rsb_set_device_address(AXP223_DEVICE_ADDR, AXP223_RUNTIME_ADDR);
37#endif
38}
39
40static 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
49static 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
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +020058static 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
68static int axp221_setbits(u8 reg, u8 bits)
69{
70 int ret;
71 u8 val;
72
Hans de Goedebdcdf842014-11-29 23:54:25 +010073 ret = pmic_bus_read(reg, &val);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +020074 if (ret)
75 return ret;
76
77 val |= bits;
Hans de Goedebdcdf842014-11-29 23:54:25 +010078 return pmic_bus_write(reg, val);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +020079}
80
Hans de Goede50e0d5e2014-12-13 14:02:38 +010081static 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
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +020094int axp221_set_dcdc1(unsigned int mvolt)
95{
96 int ret;
97 u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100);
98
Hans de Goede50e0d5e2014-12-13 14:02:38 +010099 if (mvolt == 0)
100 return axp221_clrbits(AXP221_OUTPUT_CTRL1,
101 AXP221_OUTPUT_CTRL1_DCDC1_EN);
102
Hans de Goedebdcdf842014-11-29 23:54:25 +0100103 ret = pmic_bus_write(AXP221_DCDC1_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200104 if (ret)
105 return ret;
106
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100107 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);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200114}
115
116int axp221_set_dcdc2(unsigned int mvolt)
117{
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100118 int ret;
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200119 u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
120
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100121 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);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200131}
132
133int axp221_set_dcdc3(unsigned int mvolt)
134{
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100135 int ret;
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200136 u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20);
137
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100138 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);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200148}
149
150int axp221_set_dcdc4(unsigned int mvolt)
151{
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100152 int ret;
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200153 u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
154
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100155 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);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200165}
166
167int axp221_set_dcdc5(unsigned int mvolt)
168{
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100169 int ret;
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200170 u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50);
171
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100172 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);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200182}
183
184int axp221_set_dldo1(unsigned int mvolt)
185{
186 int ret;
187 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
188
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100189 if (mvolt == 0)
190 return axp221_clrbits(AXP221_OUTPUT_CTRL2,
191 AXP221_OUTPUT_CTRL2_DLDO1_EN);
192
Hans de Goedebdcdf842014-11-29 23:54:25 +0100193 ret = pmic_bus_write(AXP221_DLDO1_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200194 if (ret)
195 return ret;
196
197 return axp221_setbits(AXP221_OUTPUT_CTRL2,
198 AXP221_OUTPUT_CTRL2_DLDO1_EN);
199}
200
201int axp221_set_dldo2(unsigned int mvolt)
202{
203 int ret;
204 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
205
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100206 if (mvolt == 0)
207 return axp221_clrbits(AXP221_OUTPUT_CTRL2,
208 AXP221_OUTPUT_CTRL2_DLDO2_EN);
209
Hans de Goedebdcdf842014-11-29 23:54:25 +0100210 ret = pmic_bus_write(AXP221_DLDO2_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200211 if (ret)
212 return ret;
213
214 return axp221_setbits(AXP221_OUTPUT_CTRL2,
215 AXP221_OUTPUT_CTRL2_DLDO2_EN);
216}
217
218int axp221_set_dldo3(unsigned int mvolt)
219{
220 int ret;
221 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
222
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100223 if (mvolt == 0)
224 return axp221_clrbits(AXP221_OUTPUT_CTRL2,
225 AXP221_OUTPUT_CTRL2_DLDO3_EN);
226
Hans de Goedebdcdf842014-11-29 23:54:25 +0100227 ret = pmic_bus_write(AXP221_DLDO3_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200228 if (ret)
229 return ret;
230
231 return axp221_setbits(AXP221_OUTPUT_CTRL2,
232 AXP221_OUTPUT_CTRL2_DLDO3_EN);
233}
234
235int axp221_set_dldo4(unsigned int mvolt)
236{
237 int ret;
238 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
239
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100240 if (mvolt == 0)
241 return axp221_clrbits(AXP221_OUTPUT_CTRL2,
242 AXP221_OUTPUT_CTRL2_DLDO4_EN);
243
Hans de Goedebdcdf842014-11-29 23:54:25 +0100244 ret = pmic_bus_write(AXP221_DLDO4_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200245 if (ret)
246 return ret;
247
248 return axp221_setbits(AXP221_OUTPUT_CTRL2,
249 AXP221_OUTPUT_CTRL2_DLDO4_EN);
250}
251
252int axp221_set_aldo1(unsigned int mvolt)
253{
254 int ret;
255 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
256
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100257 if (mvolt == 0)
258 return axp221_clrbits(AXP221_OUTPUT_CTRL1,
259 AXP221_OUTPUT_CTRL1_ALDO1_EN);
260
Hans de Goedebdcdf842014-11-29 23:54:25 +0100261 ret = pmic_bus_write(AXP221_ALDO1_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200262 if (ret)
263 return ret;
264
265 return axp221_setbits(AXP221_OUTPUT_CTRL1,
266 AXP221_OUTPUT_CTRL1_ALDO1_EN);
267}
268
269int axp221_set_aldo2(unsigned int mvolt)
270{
271 int ret;
272 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
273
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100274 if (mvolt == 0)
275 return axp221_clrbits(AXP221_OUTPUT_CTRL1,
276 AXP221_OUTPUT_CTRL1_ALDO2_EN);
277
Hans de Goedebdcdf842014-11-29 23:54:25 +0100278 ret = pmic_bus_write(AXP221_ALDO2_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200279 if (ret)
280 return ret;
281
282 return axp221_setbits(AXP221_OUTPUT_CTRL1,
283 AXP221_OUTPUT_CTRL1_ALDO2_EN);
284}
285
286int axp221_set_aldo3(unsigned int mvolt)
287{
288 int ret;
289 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
290
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100291 if (mvolt == 0)
292 return axp221_clrbits(AXP221_OUTPUT_CTRL3,
293 AXP221_OUTPUT_CTRL3_ALDO3_EN);
294
Hans de Goedebdcdf842014-11-29 23:54:25 +0100295 ret = pmic_bus_write(AXP221_ALDO3_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200296 if (ret)
297 return ret;
298
299 return axp221_setbits(AXP221_OUTPUT_CTRL3,
300 AXP221_OUTPUT_CTRL3_ALDO3_EN);
301}
302
Siarhei Siamashka6906df12015-01-19 05:23:30 +0200303int 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
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200336int axp221_init(void)
337{
Hans de Goede3c781192015-01-11 19:43:56 +0100338 /* This cannot be 0 because it is used in SPL before BSS is ready */
339 static int needs_init = 1;
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200340 u8 axp_chip_id;
341 int ret;
342
Hans de Goede3c781192015-01-11 19:43:56 +0100343 if (!needs_init)
344 return 0;
345
Hans de Goedebdcdf842014-11-29 23:54:25 +0100346 ret = pmic_bus_init();
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200347 if (ret)
348 return ret;
349
Hans de Goedebdcdf842014-11-29 23:54:25 +0100350 ret = pmic_bus_read(AXP221_CHIP_ID, &axp_chip_id);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200351 if (ret)
352 return ret;
353
354 if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17))
355 return -ENODEV;
356
Hans de Goede3c781192015-01-11 19:43:56 +0100357 needs_init = 0;
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200358 return 0;
359}
Hans de Goedef3fba562014-11-25 16:37:52 +0100360
361int 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
Hans de Goedebdcdf842014-11-29 23:54:25 +0100370 ret = pmic_bus_write(AXP221_PAGE, 1);
Hans de Goedef3fba562014-11-25 16:37:52 +0100371 if (ret)
372 return ret;
373
374 for (i = 0; i < 16; i++) {
Hans de Goedebdcdf842014-11-29 23:54:25 +0100375 ret = pmic_bus_read(AXP221_SID + i, &dest[i]);
Hans de Goedef3fba562014-11-25 16:37:52 +0100376 if (ret)
377 return ret;
378 }
379
Hans de Goedebdcdf842014-11-29 23:54:25 +0100380 pmic_bus_write(AXP221_PAGE, 0);
Hans de Goedef3fba562014-11-25 16:37:52 +0100381
382 for (i = 0; i < 4; i++)
383 sid[i] = be32_to_cpu(sid[i]);
384
385 return 0;
386}
Hans de Goede2abac622015-01-11 19:58:03 +0100387
388static int axp_drivebus_setup(void)
389{
390 int ret;
391
392 ret = axp221_init();
393 if (ret)
394 return ret;
395
396 /* Set N_VBUSEN pin to output / DRIVEBUS function */
397 return axp221_clrbits(AXP221_MISC_CTRL, AXP221_MISC_CTRL_N_VBUSEN_FUNC);
398}
399
400int axp_drivebus_enable(void)
401{
402 int ret;
403
404 ret = axp_drivebus_setup();
405 if (ret)
406 return ret;
407
408 /* Set DRIVEBUS high */
409 return axp221_setbits(AXP221_VBUS_IPSOUT, AXP221_VBUS_IPSOUT_DRIVEBUS);
410}
411
412int axp_drivebus_disable(void)
413{
414 int ret;
415
416 ret = axp_drivebus_setup();
417 if (ret)
418 return ret;
419
420 /* Set DRIVEBUS low */
421 return axp221_clrbits(AXP221_VBUS_IPSOUT, AXP221_VBUS_IPSOUT_DRIVEBUS);
422}