60f69ec27ac965912bae1adff6ab4a90f0b661b1
[oweals/u-boot.git] / drivers / power / axp209.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2012
4  * Henrik Nordstrom <henrik@henriknordstrom.net>
5  */
6
7 #include <common.h>
8 #include <command.h>
9 #include <asm/arch/pmic_bus.h>
10 #include <axp_pmic.h>
11
12 #ifdef CONFIG_AXP_ALDO3_VOLT_SLOPE_08
13 #  define AXP209_VRC_SLOPE AXP209_VRC_LDO3_800uV_uS
14 #endif
15 #ifdef CONFIG_AXP_ALDO3_VOLT_SLOPE_16
16 #  define AXP209_VRC_SLOPE AXP209_VRC_LDO3_1600uV_uS
17 #endif
18 #if defined CONFIG_AXP_ALDO3_VOLT_SLOPE_NONE || !defined AXP209_VRC_SLOPE
19 #  define AXP209_VRC_SLOPE 0x00
20 #endif
21
22 static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div)
23 {
24         if (mvolt < min)
25                 mvolt = min;
26         else if (mvolt > max)
27                 mvolt = max;
28
29         return (mvolt - min) / div;
30 }
31
32 int axp_set_dcdc2(unsigned int mvolt)
33 {
34         int rc;
35         u8 cfg, current;
36
37         if (mvolt == 0)
38                 return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
39                                         AXP209_OUTPUT_CTRL_DCDC2);
40
41         rc = pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC2);
42         if (rc)
43                 return rc;
44
45         cfg = axp209_mvolt_to_cfg(mvolt, 700, 2275, 25);
46
47         /* Do we really need to be this gentle? It has built-in voltage slope */
48         while ((rc = pmic_bus_read(AXP209_DCDC2_VOLTAGE, &current)) == 0 &&
49                current != cfg) {
50                 if (current < cfg)
51                         current++;
52                 else
53                         current--;
54
55                 rc = pmic_bus_write(AXP209_DCDC2_VOLTAGE, current);
56                 if (rc)
57                         break;
58         }
59
60         return rc;
61 }
62
63 int axp_set_dcdc3(unsigned int mvolt)
64 {
65         u8 cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
66         int rc;
67
68         if (mvolt == 0)
69                 return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
70                                         AXP209_OUTPUT_CTRL_DCDC3);
71
72         rc = pmic_bus_write(AXP209_DCDC3_VOLTAGE, cfg);
73         if (rc)
74                 return rc;
75
76         return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC3);
77 }
78
79 int axp_set_aldo2(unsigned int mvolt)
80 {
81         int rc;
82         u8 cfg, reg;
83
84         if (mvolt == 0)
85                 return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
86                                         AXP209_OUTPUT_CTRL_LDO2);
87
88         cfg = axp209_mvolt_to_cfg(mvolt, 1800, 3300, 100);
89
90         rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, &reg);
91         if (rc)
92                 return rc;
93
94         reg |= AXP209_LDO24_LDO2_SET(reg, cfg);
95         rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
96         if (rc)
97                 return rc;
98
99         return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO2);
100 }
101
102 int axp_set_aldo3(unsigned int mvolt)
103 {
104         u8 cfg;
105         int rc;
106
107         if (mvolt == 0)
108                 return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
109                                         AXP209_OUTPUT_CTRL_LDO3);
110
111         /*
112          * Some boards have trouble reaching the target voltage without causing
113          * great inrush currents. To prevent this, boards can enable a certain
114          * slope to ramp up voltage. Note, this only works when changing an
115          * already active power rail. When toggling power on, the AXP ramps up
116          * steeply at 0.0167 V/uS.
117          */
118         rc = pmic_bus_read(AXP209_VRC_DCDC2_LDO3, &cfg);
119         cfg = AXP209_VRC_LDO3_SLOPE_SET(cfg, AXP209_VRC_SLOPE);
120         rc |= pmic_bus_write(AXP209_VRC_DCDC2_LDO3, cfg);
121
122         if (rc)
123                 return rc;
124
125 #ifdef CONFIG_AXP_ALDO3_INRUSH_QUIRK
126         /*
127          * On some boards, LDO3 has a too big capacitor installed. When
128          * turning on LDO3, this causes the AXP209 to shutdown on
129          * voltages over 1.9 volt. As a workaround, we enable LDO3
130          * first with the lowest possible voltage. If this still causes
131          * high inrush currents, the voltage slope should be increased.
132          */
133         rc = pmic_bus_read(AXP209_OUTPUT_CTRL, &cfg);
134         if (rc)
135                 return rc;
136
137         if (!(cfg & AXP209_OUTPUT_CTRL_LDO3)) {
138                 rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, 0x0); /* 0.7 Volt */
139                 mdelay(1);
140                 rc |= pmic_bus_setbits(AXP209_OUTPUT_CTRL,
141                                        AXP209_OUTPUT_CTRL_LDO3);
142
143                 if (rc)
144                         return rc;
145         }
146 #endif
147
148         if (mvolt == -1) {
149                 cfg = AXP209_LDO3_VOLTAGE_FROM_LDO3IN;
150         } else {
151                 cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
152                 cfg = AXP209_LDO3_VOLTAGE_SET(cfg);
153         }
154
155         rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, cfg);
156         if (rc)
157                 return rc;
158
159         return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO3);
160 }
161
162 int axp_set_aldo4(unsigned int mvolt)
163 {
164         int rc;
165         static const unsigned int vindex[] = {
166                 1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2500,
167                 2700, 2800, 3000, 3100, 3200, 3300
168         };
169         u8 cfg, reg;
170
171         if (mvolt == 0)
172                 return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
173                                         AXP209_OUTPUT_CTRL_LDO4);
174
175         /* Translate mvolt to register cfg value, requested <= selected */
176         for (cfg = 15; vindex[cfg] > mvolt && cfg > 0; cfg--);
177
178         rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, &reg);
179         if (rc)
180                 return rc;
181
182         reg |= AXP209_LDO24_LDO4_SET(reg, cfg);
183         rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
184         if (rc)
185                 return rc;
186
187         return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO4);
188 }
189
190 int axp_init(void)
191 {
192         u8 ver;
193         int i, rc;
194
195         rc = pmic_bus_init();
196         if (rc)
197                 return rc;
198
199         rc = pmic_bus_read(AXP209_CHIP_VERSION, &ver);
200         if (rc)
201                 return rc;
202
203         if ((ver & AXP209_CHIP_VERSION_MASK) != 0x1)
204                 return -EINVAL;
205
206         /* Mask all interrupts */
207         for (i = AXP209_IRQ_ENABLE1; i <= AXP209_IRQ_ENABLE5; i++) {
208                 rc = pmic_bus_write(i, 0);
209                 if (rc)
210                         return rc;
211         }
212
213         /*
214          * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
215          * from android these are sometimes on.
216          */
217         rc = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
218         if (rc)
219                 return rc;
220
221         rc = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
222         if (rc)
223                 return rc;
224
225         rc = pmic_bus_write(AXP_GPIO2_CTRL, AXP_GPIO_CTRL_INPUT);
226         if (rc)
227                 return rc;
228
229         return 0;
230 }
231
232 int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
233 {
234         pmic_bus_write(AXP209_SHUTDOWN, AXP209_POWEROFF);
235
236         /* infinite loop during shutdown */
237         while (1) {}
238
239         /* not reached */
240         return 0;
241 }