]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/power/axp221.c
sunxi: rsb: Move rsb_set_device_mode() call to rsb_init()
[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         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 static 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
400 int 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
412 int 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 }