blob: 987a1f9d8638af32bb4c28973cd494c2f885eb92 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0
Jaehoon Chung76f20082018-01-16 15:33:50 +09002/*
3 * Copyright (C) 2018 Samsung Electronics
4 * Jaehoon Chung <jh80.chung@samsung.com>
Jaehoon Chung76f20082018-01-16 15:33:50 +09005 */
6
Tom Riniabb9a042024-05-18 20:20:43 -06007#include <common.h>
Jaehoon Chung76f20082018-01-16 15:33:50 +09008#include <fdtdec.h>
9#include <errno.h>
10#include <dm.h>
Simon Glassdbd79542020-05-10 11:40:11 -060011#include <linux/delay.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060012#include <linux/printk.h>
Jaehoon Chung76f20082018-01-16 15:33:50 +090013#include <power/pmic.h>
14#include <power/regulator.h>
15#include <power/s2mps11.h>
16
Jaehoon Chung76f20082018-01-16 15:33:50 +090017#define MODE(_id, _val, _name) { \
18 .id = _id, \
19 .register_value = _val, \
20 .name = _name, \
21}
22
23/* BUCK : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 */
24static struct dm_regulator_mode s2mps11_buck_modes[] = {
25 MODE(OP_OFF, S2MPS11_BUCK_MODE_OFF, "OFF"),
26 MODE(OP_STANDBY, S2MPS11_BUCK_MODE_STANDBY, "ON/OFF"),
27 MODE(OP_ON, S2MPS11_BUCK_MODE_STANDBY, "ON"),
28};
29
30static struct dm_regulator_mode s2mps11_ldo_modes[] = {
31 MODE(OP_OFF, S2MPS11_LDO_MODE_OFF, "OFF"),
32 MODE(OP_STANDBY, S2MPS11_LDO_MODE_STANDBY, "ON/OFF"),
33 MODE(OP_STANDBY_LPM, S2MPS11_LDO_MODE_STANDBY_LPM, "ON/LPM"),
34 MODE(OP_ON, S2MPS11_LDO_MODE_ON, "ON"),
35};
36
37static const char s2mps11_buck_ctrl[] = {
38 0xff, 0x25, 0x27, 0x29, 0x2b, 0x2d, 0x33, 0x35, 0x37, 0x39, 0x3b
39};
40
41static const char s2mps11_buck_out[] = {
42 0xff, 0x26, 0x28, 0x2a, 0x2c, 0x2f, 0x34, 0x36, 0x38, 0x3a, 0x3c
43};
44
45static int s2mps11_buck_hex2volt(int buck, int hex)
46{
47 unsigned int uV = 0;
48
49 if (hex < 0)
50 goto bad;
51
52 switch (buck) {
53 case 7:
54 case 8:
55 case 10:
56 if (hex > S2MPS11_BUCK7_8_10_VOLT_MAX_HEX)
57 goto bad;
58
59 uV = hex * S2MPS11_BUCK_HSTEP + S2MPS11_BUCK_UV_HMIN;
60 break;
61 case 9:
62 if (hex > S2MPS11_BUCK9_VOLT_MAX_HEX)
63 goto bad;
64 uV = hex * S2MPS11_BUCK9_STEP * 2 + S2MPS11_BUCK9_UV_MIN;
65 break;
66 default:
67 if (buck == 5 && hex > S2MPS11_BUCK5_VOLT_MAX_HEX)
68 goto bad;
69 else if (buck != 5 && hex > S2MPS11_BUCK_VOLT_MAX_HEX)
70 goto bad;
71
72 uV = hex * S2MPS11_BUCK_LSTEP + S2MPS11_BUCK_UV_MIN;
73 break;
74 }
75
76 return uV;
77bad:
78 pr_err("Value: %#x is wrong for BUCK%d", hex, buck);
79 return -EINVAL;
80}
81
82static int s2mps11_buck_volt2hex(int buck, int uV)
83{
84 int hex;
85
86 switch (buck) {
87 case 7:
88 case 8:
89 case 10:
90 hex = (uV - S2MPS11_BUCK_UV_HMIN) / S2MPS11_BUCK_HSTEP;
91 if (hex > S2MPS11_BUCK7_8_10_VOLT_MAX_HEX)
92 goto bad;
93
94 break;
95 case 9:
96 hex = (uV - S2MPS11_BUCK9_UV_MIN) / S2MPS11_BUCK9_STEP;
97 if (hex > S2MPS11_BUCK9_VOLT_MAX_HEX)
98 goto bad;
99 break;
100 default:
101 hex = (uV - S2MPS11_BUCK_UV_MIN) / S2MPS11_BUCK_LSTEP;
102 if (buck == 5 && hex > S2MPS11_BUCK5_VOLT_MAX_HEX)
103 goto bad;
104 else if (buck != 5 && hex > S2MPS11_BUCK_VOLT_MAX_HEX)
105 goto bad;
106 break;
107 };
108
109 if (hex >= 0)
110 return hex;
111
112bad:
113 pr_err("Value: %d uV is wrong for BUCK%d", uV, buck);
114 return -EINVAL;
115}
116
117static int s2mps11_buck_val(struct udevice *dev, int op, int *uV)
118{
119 int hex, buck, ret;
120 u32 mask, addr;
121 u8 val;
122
123 buck = dev->driver_data;
124 if (buck < 1 || buck > S2MPS11_BUCK_NUM) {
125 pr_err("Wrong buck number: %d\n", buck);
126 return -EINVAL;
127 }
128
129 if (op == PMIC_OP_GET)
130 *uV = 0;
131
132 addr = s2mps11_buck_out[buck];
133
134 switch (buck) {
135 case 9:
136 mask = S2MPS11_BUCK9_VOLT_MASK;
137 break;
138 default:
139 mask = S2MPS11_BUCK_VOLT_MASK;
140 break;
141 }
142
143 ret = pmic_read(dev->parent, addr, &val, 1);
144 if (ret)
145 return ret;
146
147 if (op == PMIC_OP_GET) {
148 val &= mask;
149 ret = s2mps11_buck_hex2volt(buck, val);
150 if (ret < 0)
151 return ret;
152 *uV = ret;
153 return 0;
154 }
155
156 hex = s2mps11_buck_volt2hex(buck, *uV);
157 if (hex < 0)
158 return hex;
159
160 val &= ~mask;
161 val |= hex;
162 ret = pmic_write(dev->parent, addr, &val, 1);
163
164 return ret;
165}
166
167static int s2mps11_buck_mode(struct udevice *dev, int op, int *opmode)
168{
169 unsigned int addr, mode;
170 unsigned char val;
171 int buck, ret;
172
173 buck = dev->driver_data;
174 if (buck < 1 || buck > S2MPS11_BUCK_NUM) {
175 pr_err("Wrong buck number: %d\n", buck);
176 return -EINVAL;
177 }
178
179 addr = s2mps11_buck_ctrl[buck];
180
181 ret = pmic_read(dev->parent, addr, &val, 1);
182 if (ret)
183 return ret;
184
185 if (op == PMIC_OP_GET) {
186 val &= (S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT);
187 switch (val) {
188 case S2MPS11_BUCK_MODE_OFF:
189 *opmode = OP_OFF;
190 break;
191 case S2MPS11_BUCK_MODE_STANDBY:
192 *opmode = OP_STANDBY;
193 break;
194 case S2MPS11_BUCK_MODE_ON:
195 *opmode = OP_ON;
196 break;
197 default:
198 return -EINVAL;
199 }
200 return 0;
201 }
202
203 switch (*opmode) {
204 case OP_OFF:
205 mode = S2MPS11_BUCK_MODE_OFF;
206 break;
207 case OP_STANDBY:
208 mode = S2MPS11_BUCK_MODE_STANDBY;
209 break;
210 case OP_ON:
211 mode = S2MPS11_BUCK_MODE_ON;
212 break;
213 default:
214 pr_err("Wrong mode: %d for buck: %d\n", *opmode, buck);
215 return -EINVAL;
216 }
217
218 val &= ~(S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT);
219 val |= mode;
220 ret = pmic_write(dev->parent, addr, &val, 1);
221
222 return ret;
223}
224
225static int s2mps11_buck_enable(struct udevice *dev, int op, bool *enable)
226{
227 int ret, on_off;
228
229 if (op == PMIC_OP_GET) {
230 ret = s2mps11_buck_mode(dev, op, &on_off);
231 if (ret)
232 return ret;
233 switch (on_off) {
234 case OP_OFF:
235 *enable = false;
236 break;
237 case OP_ON:
238 *enable = true;
239 break;
240 default:
241 return -EINVAL;
242 }
243 } else if (op == PMIC_OP_SET) {
244 if (*enable)
245 on_off = OP_ON;
246 else
247 on_off = OP_OFF;
248
249 ret = s2mps11_buck_mode(dev, op, &on_off);
250 if (ret)
251 return ret;
252 }
253
254 return 0;
255}
256
257static int buck_get_value(struct udevice *dev)
258{
259 int uV;
260 int ret;
261
262 ret = s2mps11_buck_val(dev, PMIC_OP_GET, &uV);
263 if (ret)
264 return ret;
265 return uV;
266}
267
268static int buck_set_value(struct udevice *dev, int uV)
269{
270 return s2mps11_buck_val(dev, PMIC_OP_SET, &uV);
271}
272
273static int buck_get_enable(struct udevice *dev)
274{
275 bool enable = false;
276 int ret;
277
278 ret = s2mps11_buck_enable(dev, PMIC_OP_GET, &enable);
279 if (ret)
280 return ret;
281 return enable;
282}
283
284static int buck_set_enable(struct udevice *dev, bool enable)
285{
286 return s2mps11_buck_enable(dev, PMIC_OP_SET, &enable);
287}
288
289static int buck_get_mode(struct udevice *dev)
290{
291 int mode;
292 int ret;
293
294 ret = s2mps11_buck_mode(dev, PMIC_OP_GET, &mode);
295 if (ret)
296 return ret;
297
298 return mode;
299}
300
301static int buck_set_mode(struct udevice *dev, int mode)
302{
303 return s2mps11_buck_mode(dev, PMIC_OP_SET, &mode);
304}
305
306static int s2mps11_buck_probe(struct udevice *dev)
307{
Simon Glass71fa5b42020-12-03 16:55:18 -0700308 struct dm_regulator_uclass_plat *uc_pdata;
Jaehoon Chung76f20082018-01-16 15:33:50 +0900309
Simon Glass71fa5b42020-12-03 16:55:18 -0700310 uc_pdata = dev_get_uclass_plat(dev);
Jaehoon Chung76f20082018-01-16 15:33:50 +0900311
312 uc_pdata->type = REGULATOR_TYPE_BUCK;
313 uc_pdata->mode = s2mps11_buck_modes;
314 uc_pdata->mode_count = ARRAY_SIZE(s2mps11_buck_modes);
315
316 return 0;
317}
318
319static const struct dm_regulator_ops s2mps11_buck_ops = {
320 .get_value = buck_get_value,
321 .set_value = buck_set_value,
322 .get_enable = buck_get_enable,
323 .set_enable = buck_set_enable,
324 .get_mode = buck_get_mode,
325 .set_mode = buck_set_mode,
326};
327
328U_BOOT_DRIVER(s2mps11_buck) = {
329 .name = S2MPS11_BUCK_DRIVER,
330 .id = UCLASS_REGULATOR,
331 .ops = &s2mps11_buck_ops,
332 .probe = s2mps11_buck_probe,
333};
334
335static int s2mps11_ldo_hex2volt(int ldo, int hex)
336{
337 unsigned int uV = 0;
338
339 if (hex > S2MPS11_LDO_VOLT_MAX_HEX) {
340 pr_err("Value: %#x is wrong for LDO%d", hex, ldo);
341 return -EINVAL;
342 }
343
344 switch (ldo) {
345 case 1:
346 case 6:
347 case 11:
348 case 22:
349 case 23:
Krzysztof Kozlowski80368352019-03-06 19:37:50 +0100350 case 27:
351 case 35:
Jaehoon Chung76f20082018-01-16 15:33:50 +0900352 uV = hex * S2MPS11_LDO_STEP + S2MPS11_LDO_UV_MIN;
353 break;
354 default:
355 uV = hex * S2MPS11_LDO_STEP * 2 + S2MPS11_LDO_UV_MIN;
356 break;
357 }
358
359 return uV;
360}
361
362static int s2mps11_ldo_volt2hex(int ldo, int uV)
363{
364 int hex = 0;
365
366 switch (ldo) {
367 case 1:
368 case 6:
369 case 11:
370 case 22:
371 case 23:
Krzysztof Kozlowski80368352019-03-06 19:37:50 +0100372 case 27:
373 case 35:
Jaehoon Chung76f20082018-01-16 15:33:50 +0900374 hex = (uV - S2MPS11_LDO_UV_MIN) / S2MPS11_LDO_STEP;
375 break;
376 default:
377 hex = (uV - S2MPS11_LDO_UV_MIN) / (S2MPS11_LDO_STEP * 2);
378 break;
379 }
380
381 if (hex >= 0 && hex <= S2MPS11_LDO_VOLT_MAX_HEX)
382 return hex;
383
384 pr_err("Value: %d uV is wrong for LDO%d", uV, ldo);
385 return -EINVAL;
386
387 return 0;
388}
389
390static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV)
391{
392 unsigned int addr;
393 unsigned char val;
394 int hex, ldo, ret;
395
396 ldo = dev->driver_data;
397 if (ldo < 1 || ldo > S2MPS11_LDO_NUM) {
398 pr_err("Wrong ldo number: %d\n", ldo);
399 return -EINVAL;
400 }
401
402 addr = S2MPS11_REG_L1CTRL + ldo - 1;
403
404 ret = pmic_read(dev->parent, addr, &val, 1);
405 if (ret)
406 return ret;
407
408 if (op == PMIC_OP_GET) {
409 *uV = 0;
410 val &= S2MPS11_LDO_VOLT_MASK;
411 ret = s2mps11_ldo_hex2volt(ldo, val);
412 if (ret < 0)
413 return ret;
414
415 *uV = ret;
416 return 0;
417 }
418
419 hex = s2mps11_ldo_volt2hex(ldo, *uV);
420 if (hex < 0)
421 return hex;
422
423 val &= ~S2MPS11_LDO_VOLT_MASK;
424 val |= hex;
425 ret = pmic_write(dev->parent, addr, &val, 1);
426
427 return ret;
428}
429
430static int s2mps11_ldo_mode(struct udevice *dev, int op, int *opmode)
431{
432 unsigned int addr, mode;
433 unsigned char val;
434 int ldo, ret;
435
436 ldo = dev->driver_data;
437 if (ldo < 1 || ldo > S2MPS11_LDO_NUM) {
438 pr_err("Wrong ldo number: %d\n", ldo);
439 return -EINVAL;
440 }
441 addr = S2MPS11_REG_L1CTRL + ldo - 1;
442
443 ret = pmic_read(dev->parent, addr, &val, 1);
444 if (ret)
445 return ret;
446
447 if (op == PMIC_OP_GET) {
448 val &= (S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT);
449 switch (val) {
450 case S2MPS11_LDO_MODE_OFF:
451 *opmode = OP_OFF;
452 break;
453 case S2MPS11_LDO_MODE_STANDBY:
454 *opmode = OP_STANDBY;
455 break;
456 case S2MPS11_LDO_MODE_STANDBY_LPM:
457 *opmode = OP_STANDBY_LPM;
458 break;
459 case S2MPS11_LDO_MODE_ON:
460 *opmode = OP_ON;
461 break;
462 default:
463 return -EINVAL;
464 }
465 return 0;
466 }
467
468 switch (*opmode) {
469 case OP_OFF:
470 mode = S2MPS11_LDO_MODE_OFF;
471 break;
472 case OP_STANDBY:
473 mode = S2MPS11_LDO_MODE_STANDBY;
474 break;
475 case OP_STANDBY_LPM:
476 mode = S2MPS11_LDO_MODE_STANDBY_LPM;
477 break;
478 case OP_ON:
479 mode = S2MPS11_LDO_MODE_ON;
480 break;
481 default:
482 pr_err("Wrong mode: %d for ldo: %d\n", *opmode, ldo);
483 return -EINVAL;
484 }
485
486 val &= ~(S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT);
487 val |= mode;
488 ret = pmic_write(dev->parent, addr, &val, 1);
489
490 return ret;
491}
492
493static int s2mps11_ldo_enable(struct udevice *dev, int op, bool *enable)
494{
495 int ret, on_off;
496
497 if (op == PMIC_OP_GET) {
498 ret = s2mps11_ldo_mode(dev, op, &on_off);
499 if (ret)
500 return ret;
501 switch (on_off) {
502 case OP_OFF:
503 *enable = false;
504 break;
505 case OP_ON:
506 *enable = true;
507 break;
508 default:
509 return -EINVAL;
510 }
511 } else if (op == PMIC_OP_SET) {
512 if (*enable)
513 on_off = OP_ON;
514 else
515 on_off = OP_OFF;
516
517 ret = s2mps11_ldo_mode(dev, op, &on_off);
518 if (ret)
519 return ret;
520 }
521
522 return 0;
523}
524
525static int ldo_get_value(struct udevice *dev)
526{
527 int uV;
528 int ret;
529
530 ret = s2mps11_ldo_val(dev, PMIC_OP_GET, &uV);
531 if (ret)
532 return ret;
533
534 return uV;
535}
536
537static int ldo_set_value(struct udevice *dev, int uV)
538{
539 return s2mps11_ldo_val(dev, PMIC_OP_SET, &uV);
540}
541
542static int ldo_get_enable(struct udevice *dev)
543{
544 bool enable = false;
545 int ret;
546
547 ret = s2mps11_ldo_enable(dev, PMIC_OP_GET, &enable);
548 if (ret)
549 return ret;
550 return enable;
551}
552
553static int ldo_set_enable(struct udevice *dev, bool enable)
554{
Krzysztof Kozlowski42757c32019-03-06 19:37:55 +0100555 int ret;
556
557 ret = s2mps11_ldo_enable(dev, PMIC_OP_SET, &enable);
558 if (ret)
559 return ret;
560
561 /* Wait the "enable delay" for voltage to start to rise */
562 udelay(15);
563
564 return 0;
Jaehoon Chung76f20082018-01-16 15:33:50 +0900565}
566
567static int ldo_get_mode(struct udevice *dev)
568{
569 int mode, ret;
570
571 ret = s2mps11_ldo_mode(dev, PMIC_OP_GET, &mode);
572 if (ret)
573 return ret;
574 return mode;
575}
576
577static int ldo_set_mode(struct udevice *dev, int mode)
578{
579 return s2mps11_ldo_mode(dev, PMIC_OP_SET, &mode);
580}
581
582static int s2mps11_ldo_probe(struct udevice *dev)
583{
Simon Glass71fa5b42020-12-03 16:55:18 -0700584 struct dm_regulator_uclass_plat *uc_pdata;
Jaehoon Chung76f20082018-01-16 15:33:50 +0900585
Simon Glass71fa5b42020-12-03 16:55:18 -0700586 uc_pdata = dev_get_uclass_plat(dev);
Jaehoon Chung76f20082018-01-16 15:33:50 +0900587 uc_pdata->type = REGULATOR_TYPE_LDO;
588 uc_pdata->mode = s2mps11_ldo_modes;
589 uc_pdata->mode_count = ARRAY_SIZE(s2mps11_ldo_modes);
590
591 return 0;
592}
593
594static const struct dm_regulator_ops s2mps11_ldo_ops = {
595 .get_value = ldo_get_value,
596 .set_value = ldo_set_value,
597 .get_enable = ldo_get_enable,
598 .set_enable = ldo_set_enable,
599 .get_mode = ldo_get_mode,
600 .set_mode = ldo_set_mode,
601};
602
603U_BOOT_DRIVER(s2mps11_ldo) = {
604 .name = S2MPS11_LDO_DRIVER,
605 .id = UCLASS_REGULATOR,
606 .ops = &s2mps11_ldo_ops,
607 .probe = s2mps11_ldo_probe,
608};