blob: c326f8efa471cc04d85fe0c47efde2b6eed79d7f [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Keerthy947d9282016-09-30 09:34:03 +05302/*
3 * (C) Copyright 2016
4 * Texas Instruments Incorporated, <www.ti.com>
5 *
6 * Keerthy <j-keerthy@ti.com>
Keerthy947d9282016-09-30 09:34:03 +05307 */
8
9#include <common.h>
10#include <fdtdec.h>
11#include <errno.h>
12#include <dm.h>
Keerthy947d9282016-09-30 09:34:03 +053013#include <power/pmic.h>
14#include <power/regulator.h>
15#include <power/lp873x.h>
16
Keerthy947d9282016-09-30 09:34:03 +053017static const char lp873x_buck_ctrl[LP873X_BUCK_NUM] = {0x2, 0x4};
18static const char lp873x_buck_volt[LP873X_BUCK_NUM] = {0x6, 0x7};
19static const char lp873x_ldo_ctrl[LP873X_LDO_NUM] = {0x8, 0x9};
20static const char lp873x_ldo_volt[LP873X_LDO_NUM] = {0xA, 0xB};
21
22static int lp873x_buck_enable(struct udevice *dev, int op, bool *enable)
23{
24 int ret;
25 unsigned int adr;
Simon Glass71fa5b42020-12-03 16:55:18 -070026 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy947d9282016-09-30 09:34:03 +053027
Simon Glass71fa5b42020-12-03 16:55:18 -070028 uc_pdata = dev_get_uclass_plat(dev);
Keerthy947d9282016-09-30 09:34:03 +053029 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
57static 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
71static 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
85static int lp873x_buck_val(struct udevice *dev, int op, int *uV)
86{
87 unsigned int hex, adr;
88 int ret;
Simon Glass71fa5b42020-12-03 16:55:18 -070089 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy947d9282016-09-30 09:34:03 +053090
Simon Glass71fa5b42020-12-03 16:55:18 -070091 uc_pdata = dev_get_uclass_plat(dev);
Keerthy947d9282016-09-30 09:34:03 +053092
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
124static int lp873x_ldo_enable(struct udevice *dev, int op, bool *enable)
125{
126 int ret;
127 unsigned int adr;
Simon Glass71fa5b42020-12-03 16:55:18 -0700128 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy947d9282016-09-30 09:34:03 +0530129
Simon Glass71fa5b42020-12-03 16:55:18 -0700130 uc_pdata = dev_get_uclass_plat(dev);
Keerthy947d9282016-09-30 09:34:03 +0530131 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
160static 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
168static 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
179static int lp873x_ldo_val(struct udevice *dev, int op, int *uV)
180{
181 unsigned int hex, adr;
182 int ret;
183
Simon Glass71fa5b42020-12-03 16:55:18 -0700184 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy947d9282016-09-30 09:34:03 +0530185
186 if (op == PMIC_OP_GET)
187 *uV = 0;
188
Simon Glass71fa5b42020-12-03 16:55:18 -0700189 uc_pdata = dev_get_uclass_plat(dev);
Keerthy947d9282016-09-30 09:34:03 +0530190
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
219static int lp873x_ldo_probe(struct udevice *dev)
220{
Simon Glass71fa5b42020-12-03 16:55:18 -0700221 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy947d9282016-09-30 09:34:03 +0530222
Simon Glass71fa5b42020-12-03 16:55:18 -0700223 uc_pdata = dev_get_uclass_plat(dev);
Keerthy947d9282016-09-30 09:34:03 +0530224 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
238static 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
250static int ldo_set_value(struct udevice *dev, int uV)
251{
252 return lp873x_ldo_val(dev, PMIC_OP_SET, &uV);
253}
254
Keerthy08f0a7c2017-06-13 09:53:55 +0530255static int ldo_get_enable(struct udevice *dev)
Keerthy947d9282016-09-30 09:34:03 +0530256{
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
267static int ldo_set_enable(struct udevice *dev, bool enable)
268{
269 return lp873x_ldo_enable(dev, PMIC_OP_SET, &enable);
270}
271
272static int lp873x_buck_probe(struct udevice *dev)
273{
Simon Glass71fa5b42020-12-03 16:55:18 -0700274 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy947d9282016-09-30 09:34:03 +0530275 int idx;
276
Simon Glass71fa5b42020-12-03 16:55:18 -0700277 uc_pdata = dev_get_uclass_plat(dev);
Keerthy947d9282016-09-30 09:34:03 +0530278 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
292static 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
304static int buck_set_value(struct udevice *dev, int uV)
305{
306 return lp873x_buck_val(dev, PMIC_OP_SET, &uV);
307}
308
Keerthy08f0a7c2017-06-13 09:53:55 +0530309static int buck_get_enable(struct udevice *dev)
Keerthy947d9282016-09-30 09:34:03 +0530310{
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
322static int buck_set_enable(struct udevice *dev, bool enable)
323{
324 return lp873x_buck_enable(dev, PMIC_OP_SET, &enable);
325}
326
327static 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
334U_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
341static 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
348U_BOOT_DRIVER(lp873x_buck) = {
349 .name = LP873X_BUCK_DRIVER,
350 .id = UCLASS_REGULATOR,
351 .ops = &lp873x_buck_ops,
352 .probe = lp873x_buck_probe,
353};