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
axp209_mvolt_to_cfg(int mvolt,int min,int max,int div)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
axp_set_dcdc2(unsigned int mvolt)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, ¤t)) == 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
axp_set_dcdc3(unsigned int mvolt)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
axp_set_aldo2(unsigned int mvolt)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, ®);
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
axp_set_aldo3(unsigned int mvolt)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
axp_set_aldo4(unsigned int mvolt)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, ®);
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
axp_init(void)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
do_poweroff(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])232 int do_poweroff(cmd_tbl_t *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 }
242