blob: d879c2301b441ede29a45c1e7bd0eb91a5ce26d9 [file] [log] [blame]
Keerthy4a030002019-10-24 15:00:51 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2019
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>
Simon Glass0f2af882020-05-10 11:40:05 -060013#include <log.h>
Simon Glassdbd79542020-05-10 11:40:11 -060014#include <linux/delay.h>
Keerthy4a030002019-10-24 15:00:51 +053015#include <power/pmic.h>
16#include <power/regulator.h>
17#include <power/tps65941.h>
18
Bhargav Raviprakash83491492024-04-22 09:48:53 +000019/* Single Phase Buck IDs */
20#define TPS65941_BUCK_ID_1 1
21#define TPS65941_BUCK_ID_2 2
22#define TPS65941_BUCK_ID_3 3
23#define TPS65941_BUCK_ID_4 4
24#define TPS65941_BUCK_ID_5 5
25
26/* Multi Phase Buck IDs */
27#define TPS65941_BUCK_ID_12 12
28#define TPS65941_BUCK_ID_34 34
29#define TPS65941_BUCK_ID_123 123
30#define TPS65941_BUCK_ID_1234 1234
31
32/* LDO IDs */
33#define TPS65941_LDO_ID_1 1
34#define TPS65941_LDO_ID_2 2
35#define TPS65941_LDO_ID_3 3
36#define TPS65941_LDO_ID_4 4
37
Bhargav Raviprakash096829d2024-04-22 09:49:01 +000038#define TPS65941_BUCK_CONV_OPS_IDX 0
39#define TPS65941_LDO_CONV_OPS_IDX 0
40
41struct tps65941_reg_conv_ops {
42 int volt_mask;
43 int (*volt2val)(int idx, int uV);
44 int (*val2volt)(int idx, int volt);
45 int slew_mask;
46 int (*lookup_slew)(int id);
47};
48
Keerthy4a030002019-10-24 15:00:51 +053049static const char tps65941_buck_ctrl[TPS65941_BUCK_NUM] = {0x4, 0x6, 0x8, 0xA,
50 0xC};
51static const char tps65941_buck_vout[TPS65941_BUCK_NUM] = {0xE, 0x10, 0x12,
52 0x14, 0x16};
53static const char tps65941_ldo_ctrl[TPS65941_BUCK_NUM] = {0x1D, 0x1E, 0x1F,
54 0x20};
55static const char tps65941_ldo_vout[TPS65941_BUCK_NUM] = {0x23, 0x24, 0x25,
56 0x26};
57
58static int tps65941_buck_enable(struct udevice *dev, int op, bool *enable)
59{
60 int ret;
61 unsigned int adr;
Simon Glass71fa5b42020-12-03 16:55:18 -070062 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy4a030002019-10-24 15:00:51 +053063
Simon Glass71fa5b42020-12-03 16:55:18 -070064 uc_pdata = dev_get_uclass_plat(dev);
Keerthy4a030002019-10-24 15:00:51 +053065 adr = uc_pdata->ctrl_reg;
66
67 ret = pmic_reg_read(dev->parent, adr);
68 if (ret < 0)
69 return ret;
70
71 if (op == PMIC_OP_GET) {
72 ret &= TPS65941_BUCK_MODE_MASK;
73
74 if (ret)
75 *enable = true;
76 else
77 *enable = false;
78
79 return 0;
80 } else if (op == PMIC_OP_SET) {
81 if (*enable)
82 ret |= TPS65941_BUCK_MODE_MASK;
83 else
84 ret &= ~TPS65941_BUCK_MODE_MASK;
85 ret = pmic_reg_write(dev->parent, adr, ret);
86 if (ret)
87 return ret;
88 }
89
90 return 0;
91}
92
Bhargav Raviprakash096829d2024-04-22 09:49:01 +000093static int tps65941_buck_volt2val(__maybe_unused int idx, int uV)
Keerthy4a030002019-10-24 15:00:51 +053094{
95 if (uV > TPS65941_BUCK_VOLT_MAX)
96 return -EINVAL;
97 else if (uV > 1650000)
98 return (uV - 1660000) / 20000 + 0xAB;
99 else if (uV > 1110000)
100 return (uV - 1110000) / 10000 + 0x73;
101 else if (uV > 600000)
102 return (uV - 600000) / 5000 + 0x0F;
103 else if (uV >= 300000)
104 return (uV - 300000) / 20000 + 0x00;
105 else
106 return -EINVAL;
107}
108
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000109static int tps65941_buck_val2volt(__maybe_unused int idx, int val)
Keerthy4a030002019-10-24 15:00:51 +0530110{
111 if (val > TPS65941_BUCK_VOLT_MAX_HEX)
112 return -EINVAL;
113 else if (val > 0xAB)
114 return 1660000 + (val - 0xAB) * 20000;
115 else if (val > 0x73)
116 return 1100000 + (val - 0x73) * 10000;
117 else if (val > 0xF)
118 return 600000 + (val - 0xF) * 5000;
119 else if (val >= 0x0)
120 return 300000 + val * 5000;
121 else
122 return -EINVAL;
123}
124
125int tps65941_lookup_slew(int id)
126{
127 switch (id) {
128 case 0:
129 return 33000;
130 case 1:
131 return 20000;
132 case 2:
133 return 10000;
134 case 3:
135 return 5000;
136 case 4:
137 return 2500;
138 case 5:
139 return 1300;
140 case 6:
141 return 630;
142 case 7:
143 return 310;
144 default:
145 return -1;
146 }
147}
148
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000149static const struct tps65941_reg_conv_ops buck_conv_ops[] = {
150 [TPS65941_BUCK_CONV_OPS_IDX] = {
151 .volt_mask = TPS65941_BUCK_VOLT_MASK,
152 .volt2val = tps65941_buck_volt2val,
153 .val2volt = tps65941_buck_val2volt,
154 .slew_mask = TP65941_BUCK_CONF_SLEW_MASK,
155 .lookup_slew = tps65941_lookup_slew,
156 },
157};
158
Keerthy4a030002019-10-24 15:00:51 +0530159static int tps65941_buck_val(struct udevice *dev, int op, int *uV)
160{
161 unsigned int hex, adr;
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000162 int ret, delta, uwait, slew, idx;
Simon Glass71fa5b42020-12-03 16:55:18 -0700163 struct dm_regulator_uclass_plat *uc_pdata;
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000164 const struct tps65941_reg_conv_ops *conv_ops;
Keerthy4a030002019-10-24 15:00:51 +0530165
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000166 idx = dev->driver_data;
167 conv_ops = &buck_conv_ops[TPS65941_BUCK_CONV_OPS_IDX];
Simon Glass71fa5b42020-12-03 16:55:18 -0700168 uc_pdata = dev_get_uclass_plat(dev);
Keerthy4a030002019-10-24 15:00:51 +0530169
170 if (op == PMIC_OP_GET)
171 *uV = 0;
172
173 adr = uc_pdata->volt_reg;
174
175 ret = pmic_reg_read(dev->parent, adr);
176 if (ret < 0)
177 return ret;
178
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000179 ret &= conv_ops->volt_mask;
180 ret = conv_ops->val2volt(idx, ret);
Keerthy4a030002019-10-24 15:00:51 +0530181 if (ret < 0)
182 return ret;
183
184 if (op == PMIC_OP_GET) {
185 *uV = ret;
186 return 0;
187 }
188
189 /*
190 * Compute the delta voltage, find the slew rate and wait
191 * for the appropriate amount of time after voltage switch
192 */
193 if (*uV > ret)
194 delta = *uV - ret;
195 else
196 delta = ret - *uV;
197
198 slew = pmic_reg_read(dev->parent, uc_pdata->ctrl_reg + 1);
199 if (slew < 0)
200 return ret;
201
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000202 slew &= conv_ops->slew_mask;
203 slew = conv_ops->lookup_slew(slew);
Keerthy4a030002019-10-24 15:00:51 +0530204 if (slew <= 0)
205 return ret;
206
207 uwait = delta / slew;
208
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000209 hex = conv_ops->volt2val(idx, *uV);
Keerthy4a030002019-10-24 15:00:51 +0530210 if (hex < 0)
211 return hex;
212
213 ret &= 0x0;
214 ret = hex;
215
216 ret = pmic_reg_write(dev->parent, adr, ret);
217
218 udelay(uwait);
219
220 return ret;
221}
222
223static int tps65941_ldo_enable(struct udevice *dev, int op, bool *enable)
224{
225 int ret;
226 unsigned int adr;
Simon Glass71fa5b42020-12-03 16:55:18 -0700227 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy4a030002019-10-24 15:00:51 +0530228
Simon Glass71fa5b42020-12-03 16:55:18 -0700229 uc_pdata = dev_get_uclass_plat(dev);
Keerthy4a030002019-10-24 15:00:51 +0530230 adr = uc_pdata->ctrl_reg;
231
232 ret = pmic_reg_read(dev->parent, adr);
233 if (ret < 0)
234 return ret;
235
236 if (op == PMIC_OP_GET) {
237 ret &= TPS65941_LDO_MODE_MASK;
238
239 if (ret)
240 *enable = true;
241 else
242 *enable = false;
243
244 return 0;
245 } else if (op == PMIC_OP_SET) {
246 if (*enable)
247 ret |= TPS65941_LDO_MODE_MASK;
248 else
249 ret &= ~TPS65941_LDO_MODE_MASK;
250 ret = pmic_reg_write(dev->parent, adr, ret);
251 if (ret)
252 return ret;
253 }
254
255 return 0;
256}
257
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000258static int tps65941_ldo_val2volt(__maybe_unused int idx, int val)
Keerthy4a030002019-10-24 15:00:51 +0530259{
260 if (val > TPS65941_LDO_VOLT_MAX_HEX || val < TPS65941_LDO_VOLT_MIN_HEX)
261 return -EINVAL;
262 else if (val >= TPS65941_LDO_VOLT_MIN_HEX)
263 return 600000 + (val - TPS65941_LDO_VOLT_MIN_HEX) * 50000;
264 else
265 return -EINVAL;
266}
267
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000268static const struct tps65941_reg_conv_ops ldo_conv_ops[] = {
269 [TPS65941_LDO_CONV_OPS_IDX] = {
270 .volt_mask = TPS65941_LDO_VOLT_MASK,
271 .volt2val = tps65941_buck_volt2val,
272 .val2volt = tps65941_ldo_val2volt,
273 },
274};
275
Keerthy4a030002019-10-24 15:00:51 +0530276static int tps65941_ldo_val(struct udevice *dev, int op, int *uV)
277{
278 unsigned int hex, adr;
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000279 int ret, idx;
Simon Glass71fa5b42020-12-03 16:55:18 -0700280 struct dm_regulator_uclass_plat *uc_pdata;
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000281 const struct tps65941_reg_conv_ops *conv_ops;
Keerthy4a030002019-10-24 15:00:51 +0530282
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000283 idx = dev->driver_data;
284 conv_ops = &ldo_conv_ops[TPS65941_LDO_CONV_OPS_IDX];
Simon Glass71fa5b42020-12-03 16:55:18 -0700285 uc_pdata = dev_get_uclass_plat(dev);
Keerthy4a030002019-10-24 15:00:51 +0530286
287 if (op == PMIC_OP_GET)
288 *uV = 0;
289
290 adr = uc_pdata->volt_reg;
291
292 ret = pmic_reg_read(dev->parent, adr);
293 if (ret < 0)
294 return ret;
295
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000296 ret &= conv_ops->volt_mask;
297 ret = conv_ops->val2volt(idx, ret);
Keerthy4a030002019-10-24 15:00:51 +0530298 if (ret < 0)
299 return ret;
300
301 if (op == PMIC_OP_GET) {
302 *uV = ret;
303 return 0;
304 }
305
Bhargav Raviprakash096829d2024-04-22 09:49:01 +0000306 hex = conv_ops->volt2val(idx, *uV);
Keerthy4a030002019-10-24 15:00:51 +0530307 if (hex < 0)
308 return hex;
309
310 ret &= 0x0;
311 ret = hex;
312
313 ret = pmic_reg_write(dev->parent, adr, ret);
314
315 return ret;
316}
317
318static int tps65941_ldo_probe(struct udevice *dev)
319{
Simon Glass71fa5b42020-12-03 16:55:18 -0700320 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy4a030002019-10-24 15:00:51 +0530321 int idx;
322
Simon Glass71fa5b42020-12-03 16:55:18 -0700323 uc_pdata = dev_get_uclass_plat(dev);
Keerthy4a030002019-10-24 15:00:51 +0530324 uc_pdata->type = REGULATOR_TYPE_LDO;
325
326 idx = dev->driver_data;
Bhargav Raviprakash83491492024-04-22 09:48:53 +0000327 switch (idx) {
328 case TPS65941_LDO_ID_1:
329 case TPS65941_LDO_ID_2:
330 case TPS65941_LDO_ID_3:
331 case TPS65941_LDO_ID_4:
Keerthy4a030002019-10-24 15:00:51 +0530332 debug("Single phase regulator\n");
Bhargav Raviprakash83491492024-04-22 09:48:53 +0000333 break;
334 default:
335 pr_err("Wrong ID for regulator\n");
Keerthy4a030002019-10-24 15:00:51 +0530336 return -EINVAL;
337 }
338
339 uc_pdata->ctrl_reg = tps65941_ldo_ctrl[idx - 1];
340 uc_pdata->volt_reg = tps65941_ldo_vout[idx - 1];
341
342 return 0;
343}
344
345static int tps65941_buck_probe(struct udevice *dev)
346{
Simon Glass71fa5b42020-12-03 16:55:18 -0700347 struct dm_regulator_uclass_plat *uc_pdata;
Keerthy4a030002019-10-24 15:00:51 +0530348 int idx;
349
Simon Glass71fa5b42020-12-03 16:55:18 -0700350 uc_pdata = dev_get_uclass_plat(dev);
Keerthy4a030002019-10-24 15:00:51 +0530351 uc_pdata->type = REGULATOR_TYPE_BUCK;
352
353 idx = dev->driver_data;
Bhargav Raviprakash83491492024-04-22 09:48:53 +0000354 switch (idx) {
355 case TPS65941_BUCK_ID_1:
356 case TPS65941_BUCK_ID_2:
357 case TPS65941_BUCK_ID_3:
358 case TPS65941_BUCK_ID_4:
359 case TPS65941_BUCK_ID_5:
Keerthy4a030002019-10-24 15:00:51 +0530360 debug("Single phase regulator\n");
Bhargav Raviprakash83491492024-04-22 09:48:53 +0000361 break;
362 case TPS65941_BUCK_ID_12:
363 case TPS65941_BUCK_ID_123:
364 case TPS65941_BUCK_ID_1234:
Keerthy4a030002019-10-24 15:00:51 +0530365 idx = 1;
Bhargav Raviprakash83491492024-04-22 09:48:53 +0000366 break;
367 case TPS65941_BUCK_ID_34:
Keerthy4a030002019-10-24 15:00:51 +0530368 idx = 3;
Bhargav Raviprakash83491492024-04-22 09:48:53 +0000369 break;
370 default:
371 pr_err("Wrong ID for regulator\n");
Keerthy4a030002019-10-24 15:00:51 +0530372 return -EINVAL;
373 }
374
375 uc_pdata->ctrl_reg = tps65941_buck_ctrl[idx - 1];
376 uc_pdata->volt_reg = tps65941_buck_vout[idx - 1];
377
378 return 0;
379}
380
381static int ldo_get_value(struct udevice *dev)
382{
383 int uV;
384 int ret;
385
386 ret = tps65941_ldo_val(dev, PMIC_OP_GET, &uV);
387 if (ret)
388 return ret;
389
390 return uV;
391}
392
393static int ldo_set_value(struct udevice *dev, int uV)
394{
395 return tps65941_ldo_val(dev, PMIC_OP_SET, &uV);
396}
397
398static int ldo_get_enable(struct udevice *dev)
399{
400 bool enable = false;
401 int ret;
402
403 ret = tps65941_ldo_enable(dev, PMIC_OP_GET, &enable);
404 if (ret)
405 return ret;
406
407 return enable;
408}
409
410static int ldo_set_enable(struct udevice *dev, bool enable)
411{
412 return tps65941_ldo_enable(dev, PMIC_OP_SET, &enable);
413}
414
415static int buck_get_value(struct udevice *dev)
416{
417 int uV;
418 int ret;
419
420 ret = tps65941_buck_val(dev, PMIC_OP_GET, &uV);
421 if (ret)
422 return ret;
423
424 return uV;
425}
426
427static int buck_set_value(struct udevice *dev, int uV)
428{
429 return tps65941_buck_val(dev, PMIC_OP_SET, &uV);
430}
431
432static int buck_get_enable(struct udevice *dev)
433{
434 bool enable = false;
435 int ret;
436
437 ret = tps65941_buck_enable(dev, PMIC_OP_GET, &enable);
438 if (ret)
439 return ret;
440
441 return enable;
442}
443
444static int buck_set_enable(struct udevice *dev, bool enable)
445{
446 return tps65941_buck_enable(dev, PMIC_OP_SET, &enable);
447}
448
449static const struct dm_regulator_ops tps65941_ldo_ops = {
450 .get_value = ldo_get_value,
451 .set_value = ldo_set_value,
452 .get_enable = ldo_get_enable,
453 .set_enable = ldo_set_enable,
454};
455
456U_BOOT_DRIVER(tps65941_ldo) = {
457 .name = TPS65941_LDO_DRIVER,
458 .id = UCLASS_REGULATOR,
459 .ops = &tps65941_ldo_ops,
460 .probe = tps65941_ldo_probe,
461};
462
463static const struct dm_regulator_ops tps65941_buck_ops = {
464 .get_value = buck_get_value,
465 .set_value = buck_set_value,
466 .get_enable = buck_get_enable,
467 .set_enable = buck_set_enable,
468};
469
470U_BOOT_DRIVER(tps65941_buck) = {
471 .name = TPS65941_BUCK_DRIVER,
472 .id = UCLASS_REGULATOR,
473 .ops = &tps65941_buck_ops,
474 .probe = tps65941_buck_probe,
475};