power: axp209: Add support for voltage rate control on LDO3
[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         if (mvolt == -1) {
126                 cfg = AXP209_LDO3_VOLTAGE_FROM_LDO3IN;
127         } else {
128                 cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
129                 cfg = AXP209_LDO3_VOLTAGE_SET(cfg);
130         }
131
132         rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, cfg);
133         if (rc)
134                 return rc;
135
136         return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO3);
137 }
138
139 int axp_set_aldo4(unsigned int mvolt)
140 {
141         int rc;
142         static const unsigned int vindex[] = {
143                 1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2500,
144                 2700, 2800, 3000, 3100, 3200, 3300
145         };
146         u8 cfg, reg;
147
148         if (mvolt == 0)
149                 return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
150                                         AXP209_OUTPUT_CTRL_LDO4);
151
152         /* Translate mvolt to register cfg value, requested <= selected */
153         for (cfg = 15; vindex[cfg] > mvolt && cfg > 0; cfg--);
154
155         rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, &reg);
156         if (rc)
157                 return rc;
158
159         reg |= AXP209_LDO24_LDO4_SET(reg, cfg);
160         rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
161         if (rc)
162                 return rc;
163
164         return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO4);
165 }
166
167 int axp_init(void)
168 {
169         u8 ver;
170         int i, rc;
171
172         rc = pmic_bus_init();
173         if (rc)
174                 return rc;
175
176         rc = pmic_bus_read(AXP209_CHIP_VERSION, &ver);
177         if (rc)
178                 return rc;
179
180         if ((ver & AXP209_CHIP_VERSION_MASK) != 0x1)
181                 return -EINVAL;
182
183         /* Mask all interrupts */
184         for (i = AXP209_IRQ_ENABLE1; i <= AXP209_IRQ_ENABLE5; i++) {
185                 rc = pmic_bus_write(i, 0);
186                 if (rc)
187                         return rc;
188         }
189
190         /*
191          * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
192          * from android these are sometimes on.
193          */
194         rc = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
195         if (rc)
196                 return rc;
197
198         rc = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
199         if (rc)
200                 return rc;
201
202         rc = pmic_bus_write(AXP_GPIO2_CTRL, AXP_GPIO_CTRL_INPUT);
203         if (rc)
204                 return rc;
205
206         return 0;
207 }
208
209 int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
210 {
211         pmic_bus_write(AXP209_SHUTDOWN, AXP209_POWEROFF);
212
213         /* infinite loop during shutdown */
214         while (1) {}
215
216         /* not reached */
217         return 0;
218 }