blob: ec1037d7a5fb26e15c6a80e975371fb4873cf812 [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>
13#include <i2c.h>
14#include <power/pmic.h>
15#include <power/regulator.h>
16#include <power/lp873x.h>
17
Keerthy947d9282016-09-30 09:34:03 +053018static const char lp873x_buck_ctrl[LP873X_BUCK_NUM] = {0x2, 0x4};
19static const char lp873x_buck_volt[LP873X_BUCK_NUM] = {0x6, 0x7};
20static const char lp873x_ldo_ctrl[LP873X_LDO_NUM] = {0x8, 0x9};
21static const char lp873x_ldo_volt[LP873X_LDO_NUM] = {0xA, 0xB};
22
23static int lp873x_buck_enable(struct udevice *dev, int op, bool *enable)
24{
25 int ret;
26 unsigned int adr;
Simon Glass71fa5b42020-12-03 16:55:18 -070027 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy947d9282016-09-30 09:34:03 +053028
Simon Glass71fa5b42020-12-03 16:55:18 -070029 uc_pdata = dev_get_uclass_plat(dev);
Keerthy947d9282016-09-30 09:34:03 +053030 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
58static 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
72static 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
86static int lp873x_buck_val(struct udevice *dev, int op, int *uV)
87{
88 unsigned int hex, adr;
89 int ret;
Simon Glass71fa5b42020-12-03 16:55:18 -070090 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy947d9282016-09-30 09:34:03 +053091
Simon Glass71fa5b42020-12-03 16:55:18 -070092 uc_pdata = dev_get_uclass_plat(dev);
Keerthy947d9282016-09-30 09:34:03 +053093
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
125static int lp873x_ldo_enable(struct udevice *dev, int op, bool *enable)
126{
127 int ret;
128 unsigned int adr;
Simon Glass71fa5b42020-12-03 16:55:18 -0700129 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy947d9282016-09-30 09:34:03 +0530130
Simon Glass71fa5b42020-12-03 16:55:18 -0700131 uc_pdata = dev_get_uclass_plat(dev);
Keerthy947d9282016-09-30 09:34:03 +0530132 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
161static 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
169static 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
180static int lp873x_ldo_val(struct udevice *dev, int op, int *uV)
181{
182 unsigned int hex, adr;
183 int ret;
184
Simon Glass71fa5b42020-12-03 16:55:18 -0700185 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy947d9282016-09-30 09:34:03 +0530186
187 if (op == PMIC_OP_GET)
188 *uV = 0;
189
Simon Glass71fa5b42020-12-03 16:55:18 -0700190 uc_pdata = dev_get_uclass_plat(dev);
Keerthy947d9282016-09-30 09:34:03 +0530191
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
220static int lp873x_ldo_probe(struct udevice *dev)
221{
Simon Glass71fa5b42020-12-03 16:55:18 -0700222 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy947d9282016-09-30 09:34:03 +0530223
Simon Glass71fa5b42020-12-03 16:55:18 -0700224 uc_pdata = dev_get_uclass_plat(dev);
Keerthy947d9282016-09-30 09:34:03 +0530225 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
239static 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
251static int ldo_set_value(struct udevice *dev, int uV)
252{
253 return lp873x_ldo_val(dev, PMIC_OP_SET, &uV);
254}
255
Keerthy08f0a7c2017-06-13 09:53:55 +0530256static int ldo_get_enable(struct udevice *dev)
Keerthy947d9282016-09-30 09:34:03 +0530257{
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
268static int ldo_set_enable(struct udevice *dev, bool enable)
269{
270 return lp873x_ldo_enable(dev, PMIC_OP_SET, &enable);
271}
272
273static int lp873x_buck_probe(struct udevice *dev)
274{
Simon Glass71fa5b42020-12-03 16:55:18 -0700275 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy947d9282016-09-30 09:34:03 +0530276 int idx;
277
Simon Glass71fa5b42020-12-03 16:55:18 -0700278 uc_pdata = dev_get_uclass_plat(dev);
Keerthy947d9282016-09-30 09:34:03 +0530279 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
293static 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
305static int buck_set_value(struct udevice *dev, int uV)
306{
307 return lp873x_buck_val(dev, PMIC_OP_SET, &uV);
308}
309
Keerthy08f0a7c2017-06-13 09:53:55 +0530310static int buck_get_enable(struct udevice *dev)
Keerthy947d9282016-09-30 09:34:03 +0530311{
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
323static int buck_set_enable(struct udevice *dev, bool enable)
324{
325 return lp873x_buck_enable(dev, PMIC_OP_SET, &enable);
326}
327
328static 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
335U_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
342static 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
349U_BOOT_DRIVER(lp873x_buck) = {
350 .name = LP873X_BUCK_DRIVER,
351 .id = UCLASS_REGULATOR,
352 .ops = &lp873x_buck_ops,
353 .probe = lp873x_buck_probe,
354};