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