]> git.ipfire.org Git - people/ms/u-boot.git/blame - drivers/power/axp221.c
serial: UniPhier: move LCR register setting to probe function
[people/ms/u-boot.git] / drivers / power / axp221.c
CommitLineData
5c7f10fd 1/*
bdcdf846
HG
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>
5c7f10fd
OS
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>
bdcdf846 16#include <asm/arch/rsb.h>
5c7f10fd
OS
17#include <axp221.h>
18
bdcdf846
HG
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 */
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
37d46dd3 32 ret = rsb_init();
bdcdf846
HG
33 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
5c7f10fd
OS
58static 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
bdcdf846 73 ret = pmic_bus_read(reg, &val);
5c7f10fd
OS
74 if (ret)
75 return ret;
76
77 val |= bits;
bdcdf846 78 return pmic_bus_write(reg, val);
5c7f10fd
OS
79}
80
50e0d5e6
HG
81static 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
5c7f10fd
OS
94int axp221_set_dcdc1(unsigned int mvolt)
95{
96 int ret;
97 u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100);
98
50e0d5e6
HG
99 if (mvolt == 0)
100 return axp221_clrbits(AXP221_OUTPUT_CTRL1,
101 AXP221_OUTPUT_CTRL1_DCDC1_EN);
102
bdcdf846 103 ret = pmic_bus_write(AXP221_DCDC1_CTRL, cfg);
5c7f10fd
OS
104 if (ret)
105 return ret;
106
50e0d5e6
HG
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);
5c7f10fd
OS
114}
115
116int axp221_set_dcdc2(unsigned int mvolt)
117{
50e0d5e6 118 int ret;
5c7f10fd
OS
119 u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
120
50e0d5e6
HG
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);
5c7f10fd
OS
131}
132
133int axp221_set_dcdc3(unsigned int mvolt)
134{
50e0d5e6 135 int ret;
5c7f10fd
OS
136 u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20);
137
50e0d5e6
HG
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);
5c7f10fd
OS
148}
149
150int axp221_set_dcdc4(unsigned int mvolt)
151{
50e0d5e6 152 int ret;
5c7f10fd
OS
153 u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
154
50e0d5e6
HG
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);
5c7f10fd
OS
165}
166
167int axp221_set_dcdc5(unsigned int mvolt)
168{
50e0d5e6 169 int ret;
5c7f10fd
OS
170 u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50);
171
50e0d5e6
HG
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);
5c7f10fd
OS
182}
183
184int axp221_set_dldo1(unsigned int mvolt)
185{
186 int ret;
187 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
188
50e0d5e6
HG
189 if (mvolt == 0)
190 return axp221_clrbits(AXP221_OUTPUT_CTRL2,
191 AXP221_OUTPUT_CTRL2_DLDO1_EN);
192
bdcdf846 193 ret = pmic_bus_write(AXP221_DLDO1_CTRL, cfg);
5c7f10fd
OS
194 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
50e0d5e6
HG
206 if (mvolt == 0)
207 return axp221_clrbits(AXP221_OUTPUT_CTRL2,
208 AXP221_OUTPUT_CTRL2_DLDO2_EN);
209
bdcdf846 210 ret = pmic_bus_write(AXP221_DLDO2_CTRL, cfg);
5c7f10fd
OS
211 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
50e0d5e6
HG
223 if (mvolt == 0)
224 return axp221_clrbits(AXP221_OUTPUT_CTRL2,
225 AXP221_OUTPUT_CTRL2_DLDO3_EN);
226
bdcdf846 227 ret = pmic_bus_write(AXP221_DLDO3_CTRL, cfg);
5c7f10fd
OS
228 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
50e0d5e6
HG
240 if (mvolt == 0)
241 return axp221_clrbits(AXP221_OUTPUT_CTRL2,
242 AXP221_OUTPUT_CTRL2_DLDO4_EN);
243
bdcdf846 244 ret = pmic_bus_write(AXP221_DLDO4_CTRL, cfg);
5c7f10fd
OS
245 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
50e0d5e6
HG
257 if (mvolt == 0)
258 return axp221_clrbits(AXP221_OUTPUT_CTRL1,
259 AXP221_OUTPUT_CTRL1_ALDO1_EN);
260
bdcdf846 261 ret = pmic_bus_write(AXP221_ALDO1_CTRL, cfg);
5c7f10fd
OS
262 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
50e0d5e6
HG
274 if (mvolt == 0)
275 return axp221_clrbits(AXP221_OUTPUT_CTRL1,
276 AXP221_OUTPUT_CTRL1_ALDO2_EN);
277
bdcdf846 278 ret = pmic_bus_write(AXP221_ALDO2_CTRL, cfg);
5c7f10fd
OS
279 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
50e0d5e6
HG
291 if (mvolt == 0)
292 return axp221_clrbits(AXP221_OUTPUT_CTRL3,
293 AXP221_OUTPUT_CTRL3_ALDO3_EN);
294
bdcdf846 295 ret = pmic_bus_write(AXP221_ALDO3_CTRL, cfg);
5c7f10fd
OS
296 if (ret)
297 return ret;
298
299 return axp221_setbits(AXP221_OUTPUT_CTRL3,
300 AXP221_OUTPUT_CTRL3_ALDO3_EN);
301}
302
6906df1a
SS
303int 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
5c7f10fd
OS
336int axp221_init(void)
337{
3c781190
HG
338 /* This cannot be 0 because it is used in SPL before BSS is ready */
339 static int needs_init = 1;
5c7f10fd
OS
340 u8 axp_chip_id;
341 int ret;
342
3c781190
HG
343 if (!needs_init)
344 return 0;
345
bdcdf846 346 ret = pmic_bus_init();
5c7f10fd
OS
347 if (ret)
348 return ret;
349
bdcdf846 350 ret = pmic_bus_read(AXP221_CHIP_ID, &axp_chip_id);
5c7f10fd
OS
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
3c781190 357 needs_init = 0;
5c7f10fd
OS
358 return 0;
359}
f3fba566
HG
360
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
bdcdf846 370 ret = pmic_bus_write(AXP221_PAGE, 1);
f3fba566
HG
371 if (ret)
372 return ret;
373
374 for (i = 0; i < 16; i++) {
bdcdf846 375 ret = pmic_bus_read(AXP221_SID + i, &dest[i]);
f3fba566
HG
376 if (ret)
377 return ret;
378 }
379
bdcdf846 380 pmic_bus_write(AXP221_PAGE, 0);
f3fba566
HG
381
382 for (i = 0; i < 4; i++)
383 sid[i] = be32_to_cpu(sid[i]);
384
385 return 0;
386}
2abac621
HG
387
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}