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