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