]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
99785de8 K |
2 | /* |
3 | * (C) Copyright 2016 | |
4 | * Texas Instruments Incorporated, <www.ti.com> | |
5 | * | |
6 | * Keerthy <j-keerthy@ti.com> | |
99785de8 K |
7 | */ |
8 | ||
d678a59d | 9 | #include <common.h> |
99785de8 K |
10 | #include <fdtdec.h> |
11 | #include <errno.h> | |
12 | #include <dm.h> | |
99785de8 K |
13 | #include <power/pmic.h> |
14 | #include <power/regulator.h> | |
15 | #include <power/lp873x.h> | |
16 | ||
99785de8 K |
17 | static const char lp873x_buck_ctrl[LP873X_BUCK_NUM] = {0x2, 0x4}; |
18 | static const char lp873x_buck_volt[LP873X_BUCK_NUM] = {0x6, 0x7}; | |
19 | static const char lp873x_ldo_ctrl[LP873X_LDO_NUM] = {0x8, 0x9}; | |
20 | static const char lp873x_ldo_volt[LP873X_LDO_NUM] = {0xA, 0xB}; | |
21 | ||
22 | static int lp873x_buck_enable(struct udevice *dev, int op, bool *enable) | |
23 | { | |
24 | int ret; | |
25 | unsigned int adr; | |
caa4daa2 | 26 | struct dm_regulator_uclass_plat *uc_pdata; |
99785de8 | 27 | |
caa4daa2 | 28 | uc_pdata = dev_get_uclass_plat(dev); |
99785de8 K |
29 | adr = uc_pdata->ctrl_reg; |
30 | ||
31 | ret = pmic_reg_read(dev->parent, adr); | |
32 | if (ret < 0) | |
33 | return ret; | |
34 | ||
35 | if (op == PMIC_OP_GET) { | |
36 | ret &= LP873X_BUCK_MODE_MASK; | |
37 | ||
38 | if (ret) | |
39 | *enable = true; | |
40 | else | |
41 | *enable = false; | |
42 | ||
43 | return 0; | |
44 | } else if (op == PMIC_OP_SET) { | |
45 | if (*enable) | |
46 | ret |= LP873X_BUCK_MODE_MASK; | |
47 | else | |
48 | ret &= ~(LP873X_BUCK_MODE_MASK); | |
49 | ret = pmic_reg_write(dev->parent, adr, ret); | |
50 | if (ret) | |
51 | return ret; | |
52 | } | |
53 | ||
54 | return 0; | |
55 | } | |
56 | ||
57 | static int lp873x_buck_volt2hex(int uV) | |
58 | { | |
59 | if (uV > LP873X_BUCK_VOLT_MAX) | |
60 | return -EINVAL; | |
61 | else if (uV > 1400000) | |
62 | return (uV - 1420000) / 20000 + 0x9E; | |
63 | else if (uV > 730000) | |
64 | return (uV - 735000) / 5000 + 0x18; | |
65 | else if (uV >= 700000) | |
66 | return (uV - 700000) / 10000 + 0x1; | |
67 | else | |
68 | return -EINVAL; | |
69 | } | |
70 | ||
71 | static int lp873x_buck_hex2volt(int hex) | |
72 | { | |
73 | if (hex > LP873X_BUCK_VOLT_MAX_HEX) | |
74 | return -EINVAL; | |
75 | else if (hex > 0x9D) | |
76 | return 1400000 + (hex - 0x9D) * 20000; | |
77 | else if (hex > 0x17) | |
78 | return 730000 + (hex - 0x17) * 5000; | |
79 | else if (hex >= 0x14) | |
80 | return 700000 + (hex - 0x14) * 10000; | |
81 | else | |
82 | return -EINVAL; | |
83 | } | |
84 | ||
85 | static int lp873x_buck_val(struct udevice *dev, int op, int *uV) | |
86 | { | |
87 | unsigned int hex, adr; | |
88 | int ret; | |
caa4daa2 | 89 | struct dm_regulator_uclass_plat *uc_pdata; |
99785de8 | 90 | |
caa4daa2 | 91 | uc_pdata = dev_get_uclass_plat(dev); |
99785de8 K |
92 | |
93 | if (op == PMIC_OP_GET) | |
94 | *uV = 0; | |
95 | ||
96 | adr = uc_pdata->volt_reg; | |
97 | ||
98 | ret = pmic_reg_read(dev->parent, adr); | |
99 | if (ret < 0) | |
100 | return ret; | |
101 | ||
102 | if (op == PMIC_OP_GET) { | |
103 | ret &= LP873X_BUCK_VOLT_MASK; | |
104 | ret = lp873x_buck_hex2volt(ret); | |
105 | if (ret < 0) | |
106 | return ret; | |
107 | *uV = ret; | |
108 | ||
109 | return 0; | |
110 | } | |
111 | ||
112 | hex = lp873x_buck_volt2hex(*uV); | |
113 | if (hex < 0) | |
114 | return hex; | |
115 | ||
116 | ret &= 0x0; | |
117 | ret |= hex; | |
118 | ||
119 | ret = pmic_reg_write(dev->parent, adr, ret); | |
120 | ||
121 | return ret; | |
122 | } | |
123 | ||
124 | static int lp873x_ldo_enable(struct udevice *dev, int op, bool *enable) | |
125 | { | |
126 | int ret; | |
127 | unsigned int adr; | |
caa4daa2 | 128 | struct dm_regulator_uclass_plat *uc_pdata; |
99785de8 | 129 | |
caa4daa2 | 130 | uc_pdata = dev_get_uclass_plat(dev); |
99785de8 K |
131 | adr = uc_pdata->ctrl_reg; |
132 | ||
133 | ret = pmic_reg_read(dev->parent, adr); | |
134 | if (ret < 0) | |
135 | return ret; | |
136 | ||
137 | if (op == PMIC_OP_GET) { | |
138 | ret &= LP873X_LDO_MODE_MASK; | |
139 | ||
140 | if (ret) | |
141 | *enable = true; | |
142 | else | |
143 | *enable = false; | |
144 | ||
145 | return 0; | |
146 | } else if (op == PMIC_OP_SET) { | |
147 | if (*enable) | |
148 | ret |= LP873X_LDO_MODE_MASK; | |
149 | else | |
150 | ret &= ~(LP873X_LDO_MODE_MASK); | |
151 | ||
152 | ret = pmic_reg_write(dev->parent, adr, ret); | |
153 | if (ret) | |
154 | return ret; | |
155 | } | |
156 | ||
157 | return 0; | |
158 | } | |
159 | ||
160 | static int lp873x_ldo_volt2hex(int uV) | |
161 | { | |
162 | if (uV > LP873X_LDO_VOLT_MAX) | |
163 | return -EINVAL; | |
164 | ||
165 | return (uV - 800000) / 100000; | |
166 | } | |
167 | ||
168 | static int lp873x_ldo_hex2volt(int hex) | |
169 | { | |
170 | if (hex > LP873X_LDO_VOLT_MAX_HEX) | |
171 | return -EINVAL; | |
172 | ||
173 | if (!hex) | |
174 | return 0; | |
175 | ||
176 | return (hex * 100000) + 800000; | |
177 | } | |
178 | ||
179 | static int lp873x_ldo_val(struct udevice *dev, int op, int *uV) | |
180 | { | |
181 | unsigned int hex, adr; | |
182 | int ret; | |
183 | ||
caa4daa2 | 184 | struct dm_regulator_uclass_plat *uc_pdata; |
99785de8 K |
185 | |
186 | if (op == PMIC_OP_GET) | |
187 | *uV = 0; | |
188 | ||
caa4daa2 | 189 | uc_pdata = dev_get_uclass_plat(dev); |
99785de8 K |
190 | |
191 | adr = uc_pdata->volt_reg; | |
192 | ||
193 | ret = pmic_reg_read(dev->parent, adr); | |
194 | if (ret < 0) | |
195 | return ret; | |
196 | ||
197 | if (op == PMIC_OP_GET) { | |
198 | ret &= LP873X_LDO_VOLT_MASK; | |
199 | ret = lp873x_ldo_hex2volt(ret); | |
200 | if (ret < 0) | |
201 | return ret; | |
202 | *uV = ret; | |
203 | return 0; | |
204 | } | |
205 | ||
206 | hex = lp873x_ldo_volt2hex(*uV); | |
207 | if (hex < 0) | |
208 | return hex; | |
209 | ||
210 | ret &= ~LP873X_LDO_VOLT_MASK; | |
211 | ret |= hex; | |
212 | if (*uV > 1650000) | |
213 | ret |= 0x80; | |
214 | ret = pmic_reg_write(dev->parent, adr, ret); | |
215 | ||
216 | return ret; | |
217 | } | |
218 | ||
219 | static int lp873x_ldo_probe(struct udevice *dev) | |
220 | { | |
caa4daa2 | 221 | struct dm_regulator_uclass_plat *uc_pdata; |
99785de8 | 222 | |
caa4daa2 | 223 | uc_pdata = dev_get_uclass_plat(dev); |
99785de8 K |
224 | uc_pdata->type = REGULATOR_TYPE_LDO; |
225 | ||
226 | int idx = dev->driver_data; | |
227 | if (idx >= LP873X_LDO_NUM) { | |
228 | printf("Wrong ID for regulator\n"); | |
229 | return -1; | |
230 | } | |
231 | ||
232 | uc_pdata->ctrl_reg = lp873x_ldo_ctrl[idx]; | |
233 | uc_pdata->volt_reg = lp873x_ldo_volt[idx]; | |
234 | ||
235 | return 0; | |
236 | } | |
237 | ||
238 | static int ldo_get_value(struct udevice *dev) | |
239 | { | |
240 | int uV; | |
241 | int ret; | |
242 | ||
243 | ret = lp873x_ldo_val(dev, PMIC_OP_GET, &uV); | |
244 | if (ret) | |
245 | return ret; | |
246 | ||
247 | return uV; | |
248 | } | |
249 | ||
250 | static int ldo_set_value(struct udevice *dev, int uV) | |
251 | { | |
252 | return lp873x_ldo_val(dev, PMIC_OP_SET, &uV); | |
253 | } | |
254 | ||
43d0247e | 255 | static int ldo_get_enable(struct udevice *dev) |
99785de8 K |
256 | { |
257 | bool enable = false; | |
258 | int ret; | |
259 | ||
260 | ret = lp873x_ldo_enable(dev, PMIC_OP_GET, &enable); | |
261 | if (ret) | |
262 | return ret; | |
263 | ||
264 | return enable; | |
265 | } | |
266 | ||
267 | static int ldo_set_enable(struct udevice *dev, bool enable) | |
268 | { | |
269 | return lp873x_ldo_enable(dev, PMIC_OP_SET, &enable); | |
270 | } | |
271 | ||
272 | static int lp873x_buck_probe(struct udevice *dev) | |
273 | { | |
caa4daa2 | 274 | struct dm_regulator_uclass_plat *uc_pdata; |
99785de8 K |
275 | int idx; |
276 | ||
caa4daa2 | 277 | uc_pdata = dev_get_uclass_plat(dev); |
99785de8 K |
278 | uc_pdata->type = REGULATOR_TYPE_BUCK; |
279 | ||
280 | idx = dev->driver_data; | |
281 | if (idx >= LP873X_BUCK_NUM) { | |
282 | printf("Wrong ID for regulator\n"); | |
283 | return -1; | |
284 | } | |
285 | ||
286 | uc_pdata->ctrl_reg = lp873x_buck_ctrl[idx]; | |
287 | uc_pdata->volt_reg = lp873x_buck_volt[idx]; | |
288 | ||
289 | return 0; | |
290 | } | |
291 | ||
292 | static int buck_get_value(struct udevice *dev) | |
293 | { | |
294 | int uV; | |
295 | int ret; | |
296 | ||
297 | ret = lp873x_buck_val(dev, PMIC_OP_GET, &uV); | |
298 | if (ret) | |
299 | return ret; | |
300 | ||
301 | return uV; | |
302 | } | |
303 | ||
304 | static int buck_set_value(struct udevice *dev, int uV) | |
305 | { | |
306 | return lp873x_buck_val(dev, PMIC_OP_SET, &uV); | |
307 | } | |
308 | ||
43d0247e | 309 | static int buck_get_enable(struct udevice *dev) |
99785de8 K |
310 | { |
311 | bool enable = false; | |
312 | int ret; | |
313 | ||
314 | ||
315 | ret = lp873x_buck_enable(dev, PMIC_OP_GET, &enable); | |
316 | if (ret) | |
317 | return ret; | |
318 | ||
319 | return enable; | |
320 | } | |
321 | ||
322 | static int buck_set_enable(struct udevice *dev, bool enable) | |
323 | { | |
324 | return lp873x_buck_enable(dev, PMIC_OP_SET, &enable); | |
325 | } | |
326 | ||
327 | static const struct dm_regulator_ops lp873x_ldo_ops = { | |
328 | .get_value = ldo_get_value, | |
329 | .set_value = ldo_set_value, | |
330 | .get_enable = ldo_get_enable, | |
331 | .set_enable = ldo_set_enable, | |
332 | }; | |
333 | ||
334 | U_BOOT_DRIVER(lp873x_ldo) = { | |
335 | .name = LP873X_LDO_DRIVER, | |
336 | .id = UCLASS_REGULATOR, | |
337 | .ops = &lp873x_ldo_ops, | |
338 | .probe = lp873x_ldo_probe, | |
339 | }; | |
340 | ||
341 | static const struct dm_regulator_ops lp873x_buck_ops = { | |
342 | .get_value = buck_get_value, | |
343 | .set_value = buck_set_value, | |
344 | .get_enable = buck_get_enable, | |
345 | .set_enable = buck_set_enable, | |
346 | }; | |
347 | ||
348 | U_BOOT_DRIVER(lp873x_buck) = { | |
349 | .name = LP873X_BUCK_DRIVER, | |
350 | .id = UCLASS_REGULATOR, | |
351 | .ops = &lp873x_buck_ops, | |
352 | .probe = lp873x_buck_probe, | |
353 | }; |