blob: f758a75e9a6ac4604593e4ce0d34e0738cc1882f [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>
Paul Kocialkowskif7c7ab62015-03-22 18:07:09 +010017#include <asm/arch/gpio.h>
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +020018#include <axp221.h>
19
Hans de Goedebdcdf842014-11-29 23:54:25 +010020/*
21 * The axp221 uses the p2wi bus, the axp223 is identical (for all registers
22 * used sofar) but uses the rsb bus. These functions abstract this.
23 */
24static int pmic_bus_init(void)
25{
26#ifdef CONFIG_MACH_SUN6I
27 p2wi_init();
28 return p2wi_change_to_p2wi_mode(AXP221_CHIP_ADDR, AXP221_CTRL_ADDR,
29 AXP221_INIT_DATA);
30#else
31 int ret;
32
Hans de Goede37d46dd2015-01-26 16:59:12 +010033 ret = rsb_init();
Hans de Goedebdcdf842014-11-29 23:54:25 +010034 if (ret)
35 return ret;
36
37 return rsb_set_device_address(AXP223_DEVICE_ADDR, AXP223_RUNTIME_ADDR);
38#endif
39}
40
41static int pmic_bus_read(const u8 addr, u8 *data)
42{
43#ifdef CONFIG_MACH_SUN6I
44 return p2wi_read(addr, data);
45#else
46 return rsb_read(AXP223_RUNTIME_ADDR, addr, data);
47#endif
48}
49
50static int pmic_bus_write(const u8 addr, u8 data)
51{
52#ifdef CONFIG_MACH_SUN6I
53 return p2wi_write(addr, data);
54#else
55 return rsb_write(AXP223_RUNTIME_ADDR, addr, data);
56#endif
57}
58
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +020059static u8 axp221_mvolt_to_cfg(int mvolt, int min, int max, int div)
60{
61 if (mvolt < min)
62 mvolt = min;
63 else if (mvolt > max)
64 mvolt = max;
65
66 return (mvolt - min) / div;
67}
68
69static int axp221_setbits(u8 reg, u8 bits)
70{
71 int ret;
72 u8 val;
73
Hans de Goedebdcdf842014-11-29 23:54:25 +010074 ret = pmic_bus_read(reg, &val);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +020075 if (ret)
76 return ret;
77
78 val |= bits;
Hans de Goedebdcdf842014-11-29 23:54:25 +010079 return pmic_bus_write(reg, val);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +020080}
81
Hans de Goede50e0d5e2014-12-13 14:02:38 +010082static int axp221_clrbits(u8 reg, u8 bits)
83{
84 int ret;
85 u8 val;
86
87 ret = pmic_bus_read(reg, &val);
88 if (ret)
89 return ret;
90
91 val &= ~bits;
92 return pmic_bus_write(reg, val);
93}
94
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +020095int axp221_set_dcdc1(unsigned int mvolt)
96{
97 int ret;
98 u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100);
99
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100100 if (mvolt == 0)
101 return axp221_clrbits(AXP221_OUTPUT_CTRL1,
102 AXP221_OUTPUT_CTRL1_DCDC1_EN);
103
Hans de Goedebdcdf842014-11-29 23:54:25 +0100104 ret = pmic_bus_write(AXP221_DCDC1_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200105 if (ret)
106 return ret;
107
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100108 ret = axp221_setbits(AXP221_OUTPUT_CTRL2,
109 AXP221_OUTPUT_CTRL2_DCDC1SW_EN);
110 if (ret)
111 return ret;
112
113 return axp221_setbits(AXP221_OUTPUT_CTRL1,
114 AXP221_OUTPUT_CTRL1_DCDC1_EN);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200115}
116
117int axp221_set_dcdc2(unsigned int mvolt)
118{
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100119 int ret;
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200120 u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
121
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100122 if (mvolt == 0)
123 return axp221_clrbits(AXP221_OUTPUT_CTRL1,
124 AXP221_OUTPUT_CTRL1_DCDC2_EN);
125
126 ret = pmic_bus_write(AXP221_DCDC2_CTRL, cfg);
127 if (ret)
128 return ret;
129
130 return axp221_setbits(AXP221_OUTPUT_CTRL1,
131 AXP221_OUTPUT_CTRL1_DCDC2_EN);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200132}
133
134int axp221_set_dcdc3(unsigned int mvolt)
135{
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100136 int ret;
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200137 u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20);
138
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100139 if (mvolt == 0)
140 return axp221_clrbits(AXP221_OUTPUT_CTRL1,
141 AXP221_OUTPUT_CTRL1_DCDC3_EN);
142
143 ret = pmic_bus_write(AXP221_DCDC3_CTRL, cfg);
144 if (ret)
145 return ret;
146
147 return axp221_setbits(AXP221_OUTPUT_CTRL1,
148 AXP221_OUTPUT_CTRL1_DCDC3_EN);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200149}
150
151int axp221_set_dcdc4(unsigned int mvolt)
152{
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100153 int ret;
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200154 u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
155
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100156 if (mvolt == 0)
157 return axp221_clrbits(AXP221_OUTPUT_CTRL1,
158 AXP221_OUTPUT_CTRL1_DCDC4_EN);
159
160 ret = pmic_bus_write(AXP221_DCDC4_CTRL, cfg);
161 if (ret)
162 return ret;
163
164 return axp221_setbits(AXP221_OUTPUT_CTRL1,
165 AXP221_OUTPUT_CTRL1_DCDC4_EN);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200166}
167
168int axp221_set_dcdc5(unsigned int mvolt)
169{
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100170 int ret;
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200171 u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50);
172
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100173 if (mvolt == 0)
174 return axp221_clrbits(AXP221_OUTPUT_CTRL1,
175 AXP221_OUTPUT_CTRL1_DCDC5_EN);
176
177 ret = pmic_bus_write(AXP221_DCDC5_CTRL, cfg);
178 if (ret)
179 return ret;
180
181 return axp221_setbits(AXP221_OUTPUT_CTRL1,
182 AXP221_OUTPUT_CTRL1_DCDC5_EN);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200183}
184
185int axp221_set_dldo1(unsigned int mvolt)
186{
187 int ret;
188 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
189
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100190 if (mvolt == 0)
191 return axp221_clrbits(AXP221_OUTPUT_CTRL2,
192 AXP221_OUTPUT_CTRL2_DLDO1_EN);
193
Hans de Goedebdcdf842014-11-29 23:54:25 +0100194 ret = pmic_bus_write(AXP221_DLDO1_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200195 if (ret)
196 return ret;
197
198 return axp221_setbits(AXP221_OUTPUT_CTRL2,
199 AXP221_OUTPUT_CTRL2_DLDO1_EN);
200}
201
202int axp221_set_dldo2(unsigned int mvolt)
203{
204 int ret;
205 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
206
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100207 if (mvolt == 0)
208 return axp221_clrbits(AXP221_OUTPUT_CTRL2,
209 AXP221_OUTPUT_CTRL2_DLDO2_EN);
210
Hans de Goedebdcdf842014-11-29 23:54:25 +0100211 ret = pmic_bus_write(AXP221_DLDO2_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200212 if (ret)
213 return ret;
214
215 return axp221_setbits(AXP221_OUTPUT_CTRL2,
216 AXP221_OUTPUT_CTRL2_DLDO2_EN);
217}
218
219int axp221_set_dldo3(unsigned int mvolt)
220{
221 int ret;
222 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
223
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100224 if (mvolt == 0)
225 return axp221_clrbits(AXP221_OUTPUT_CTRL2,
226 AXP221_OUTPUT_CTRL2_DLDO3_EN);
227
Hans de Goedebdcdf842014-11-29 23:54:25 +0100228 ret = pmic_bus_write(AXP221_DLDO3_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200229 if (ret)
230 return ret;
231
232 return axp221_setbits(AXP221_OUTPUT_CTRL2,
233 AXP221_OUTPUT_CTRL2_DLDO3_EN);
234}
235
236int axp221_set_dldo4(unsigned int mvolt)
237{
238 int ret;
239 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
240
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100241 if (mvolt == 0)
242 return axp221_clrbits(AXP221_OUTPUT_CTRL2,
243 AXP221_OUTPUT_CTRL2_DLDO4_EN);
244
Hans de Goedebdcdf842014-11-29 23:54:25 +0100245 ret = pmic_bus_write(AXP221_DLDO4_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200246 if (ret)
247 return ret;
248
249 return axp221_setbits(AXP221_OUTPUT_CTRL2,
250 AXP221_OUTPUT_CTRL2_DLDO4_EN);
251}
252
253int axp221_set_aldo1(unsigned int mvolt)
254{
255 int ret;
256 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
257
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100258 if (mvolt == 0)
259 return axp221_clrbits(AXP221_OUTPUT_CTRL1,
260 AXP221_OUTPUT_CTRL1_ALDO1_EN);
261
Hans de Goedebdcdf842014-11-29 23:54:25 +0100262 ret = pmic_bus_write(AXP221_ALDO1_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200263 if (ret)
264 return ret;
265
266 return axp221_setbits(AXP221_OUTPUT_CTRL1,
267 AXP221_OUTPUT_CTRL1_ALDO1_EN);
268}
269
270int axp221_set_aldo2(unsigned int mvolt)
271{
272 int ret;
273 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
274
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100275 if (mvolt == 0)
276 return axp221_clrbits(AXP221_OUTPUT_CTRL1,
277 AXP221_OUTPUT_CTRL1_ALDO2_EN);
278
Hans de Goedebdcdf842014-11-29 23:54:25 +0100279 ret = pmic_bus_write(AXP221_ALDO2_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200280 if (ret)
281 return ret;
282
283 return axp221_setbits(AXP221_OUTPUT_CTRL1,
284 AXP221_OUTPUT_CTRL1_ALDO2_EN);
285}
286
287int axp221_set_aldo3(unsigned int mvolt)
288{
289 int ret;
290 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
291
Hans de Goede50e0d5e2014-12-13 14:02:38 +0100292 if (mvolt == 0)
293 return axp221_clrbits(AXP221_OUTPUT_CTRL3,
294 AXP221_OUTPUT_CTRL3_ALDO3_EN);
295
Hans de Goedebdcdf842014-11-29 23:54:25 +0100296 ret = pmic_bus_write(AXP221_ALDO3_CTRL, cfg);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200297 if (ret)
298 return ret;
299
300 return axp221_setbits(AXP221_OUTPUT_CTRL3,
301 AXP221_OUTPUT_CTRL3_ALDO3_EN);
302}
303
Siarhei Siamashka6906df12015-01-19 05:23:30 +0200304int axp221_set_eldo(int eldo_num, unsigned int mvolt)
305{
306 int ret;
307 u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
308 u8 addr, bits;
309
310 switch (eldo_num) {
311 case 3:
312 addr = AXP221_ELDO3_CTRL;
313 bits = AXP221_OUTPUT_CTRL2_ELDO3_EN;
314 break;
315 case 2:
316 addr = AXP221_ELDO2_CTRL;
317 bits = AXP221_OUTPUT_CTRL2_ELDO2_EN;
318 break;
319 case 1:
320 addr = AXP221_ELDO1_CTRL;
321 bits = AXP221_OUTPUT_CTRL2_ELDO1_EN;
322 break;
323 default:
324 return -EINVAL;
325 }
326
327 if (mvolt == 0)
328 return axp221_clrbits(AXP221_OUTPUT_CTRL2, bits);
329
330 ret = pmic_bus_write(addr, cfg);
331 if (ret)
332 return ret;
333
334 return axp221_setbits(AXP221_OUTPUT_CTRL2, bits);
335}
336
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200337int axp221_init(void)
338{
Hans de Goede3c781192015-01-11 19:43:56 +0100339 /* This cannot be 0 because it is used in SPL before BSS is ready */
340 static int needs_init = 1;
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200341 u8 axp_chip_id;
342 int ret;
343
Hans de Goede3c781192015-01-11 19:43:56 +0100344 if (!needs_init)
345 return 0;
346
Hans de Goedebdcdf842014-11-29 23:54:25 +0100347 ret = pmic_bus_init();
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200348 if (ret)
349 return ret;
350
Hans de Goedebdcdf842014-11-29 23:54:25 +0100351 ret = pmic_bus_read(AXP221_CHIP_ID, &axp_chip_id);
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200352 if (ret)
353 return ret;
354
355 if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17))
356 return -ENODEV;
357
Hans de Goede3c781192015-01-11 19:43:56 +0100358 needs_init = 0;
Oliver Schinagl5c7f10f2013-07-26 12:56:58 +0200359 return 0;
360}
Hans de Goedef3fba562014-11-25 16:37:52 +0100361
362int axp221_get_sid(unsigned int *sid)
363{
364 u8 *dest = (u8 *)sid;
365 int i, ret;
366
367 ret = axp221_init();
368 if (ret)
369 return ret;
370
Hans de Goedebdcdf842014-11-29 23:54:25 +0100371 ret = pmic_bus_write(AXP221_PAGE, 1);
Hans de Goedef3fba562014-11-25 16:37:52 +0100372 if (ret)
373 return ret;
374
375 for (i = 0; i < 16; i++) {
Hans de Goedebdcdf842014-11-29 23:54:25 +0100376 ret = pmic_bus_read(AXP221_SID + i, &dest[i]);
Hans de Goedef3fba562014-11-25 16:37:52 +0100377 if (ret)
378 return ret;
379 }
380
Hans de Goedebdcdf842014-11-29 23:54:25 +0100381 pmic_bus_write(AXP221_PAGE, 0);
Hans de Goedef3fba562014-11-25 16:37:52 +0100382
383 for (i = 0; i < 4; i++)
384 sid[i] = be32_to_cpu(sid[i]);
385
386 return 0;
387}
Hans de Goede2abac622015-01-11 19:58:03 +0100388
Paul Kocialkowskif7c7ab62015-03-22 18:07:09 +0100389int axp_gpio_direction_input(unsigned int pin)
390{
391 switch (pin) {
392 case SUNXI_GPIO_AXP0_VBUS_DETECT:
393 return 0;
394 default:
395 return -EINVAL;
396 }
397}
398
399int axp_gpio_direction_output(unsigned int pin, unsigned int val)
400{
401 int ret;
402
403 switch (pin) {
404 case SUNXI_GPIO_AXP0_VBUS_ENABLE:
405 ret = axp221_clrbits(AXP221_MISC_CTRL,
406 AXP221_MISC_CTRL_N_VBUSEN_FUNC);
407 if (ret)
408 return ret;
409
410 return axp_gpio_set_value(pin, val);
411 default:
412 return -EINVAL;
413 }
414}
415
416int axp_gpio_get_value(unsigned int pin)
Chen-Yu Tsai1986c4c2015-03-09 15:44:15 +0800417{
418 int ret;
419 u8 val;
420
Paul Kocialkowskif7c7ab62015-03-22 18:07:09 +0100421 switch (pin) {
422 case SUNXI_GPIO_AXP0_VBUS_DETECT:
423 ret = pmic_bus_read(AXP221_POWER_STATUS, &val);
424 if (ret)
425 return ret;
Chen-Yu Tsai1986c4c2015-03-09 15:44:15 +0800426
Paul Kocialkowskif7c7ab62015-03-22 18:07:09 +0100427 return !!(val & AXP221_POWER_STATUS_VBUS_USABLE);
428 default:
429 return -EINVAL;
430 }
Chen-Yu Tsai1986c4c2015-03-09 15:44:15 +0800431}
432
Paul Kocialkowskif7c7ab62015-03-22 18:07:09 +0100433int axp_gpio_set_value(unsigned int pin, unsigned int val)
Hans de Goede2abac622015-01-11 19:58:03 +0100434{
435 int ret;
436
Paul Kocialkowskif7c7ab62015-03-22 18:07:09 +0100437 switch (pin) {
438 case SUNXI_GPIO_AXP0_VBUS_ENABLE:
439 if (val)
440 ret = axp221_setbits(AXP221_VBUS_IPSOUT,
441 AXP221_VBUS_IPSOUT_DRIVEBUS);
442 else
443 ret = axp221_clrbits(AXP221_VBUS_IPSOUT,
444 AXP221_VBUS_IPSOUT_DRIVEBUS);
Hans de Goede2abac622015-01-11 19:58:03 +0100445
Paul Kocialkowskif7c7ab62015-03-22 18:07:09 +0100446 if (ret)
447 return ret;
448 }
Hans de Goede2abac622015-01-11 19:58:03 +0100449
Paul Kocialkowskif7c7ab62015-03-22 18:07:09 +0100450 return 0;
Hans de Goede2abac622015-01-11 19:58:03 +0100451}