blob: 37eb50bbcedfd4f949c9e82a5eaf8fab9b909f6c [file] [log] [blame]
Yann Gautierbb836ee2018-07-16 17:55:07 +02001/*
Yann Gautier328bba62020-03-23 17:44:30 +01002 * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved
Yann Gautierbb836ee2018-07-16 17:55:07 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Yann Gautier328bba62020-03-23 17:44:30 +01007#include <errno.h>
Yann Gautierbb836ee2018-07-16 17:55:07 +02008#include <string.h>
9
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010#include <common/debug.h>
Yann Gautiera45433b2019-01-16 18:31:00 +010011#include <drivers/st/stpmic1.h>
Yann Gautierf3928f62019-02-14 11:15:03 +010012
13#define I2C_TIMEOUT_MS 25
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000014
Yann Gautierbb836ee2018-07-16 17:55:07 +020015struct regul_struct {
16 const char *dt_node_name;
17 const uint16_t *voltage_table;
18 uint8_t voltage_table_size;
19 uint8_t control_reg;
Pascal Paillet84bca882021-03-10 14:37:03 +010020 uint8_t enable_mask;
Yann Gautierbb836ee2018-07-16 17:55:07 +020021 uint8_t low_power_reg;
Yann Gautieref85e532019-01-17 14:27:50 +010022 uint8_t pull_down_reg;
23 uint8_t pull_down;
24 uint8_t mask_reset_reg;
25 uint8_t mask_reset;
Pascal Pailletc18c4542020-12-15 18:28:34 +010026 uint8_t icc_reg;
27 uint8_t icc_mask;
Yann Gautierbb836ee2018-07-16 17:55:07 +020028};
29
Yann Gautiera45433b2019-01-16 18:31:00 +010030static struct i2c_handle_s *pmic_i2c_handle;
31static uint16_t pmic_i2c_addr;
Pascal Pailletc18c4542020-12-15 18:28:34 +010032/*
33 * Special mode corresponds to LDO3 in sink source mode or in bypass mode.
34 * LDO3 doesn't switch back from special to normal mode.
35 */
36static bool ldo3_special_mode;
Yann Gautierbb836ee2018-07-16 17:55:07 +020037
38/* Voltage tables in mV */
39static const uint16_t buck1_voltage_table[] = {
Yann Gautieref85e532019-01-17 14:27:50 +010040 725,
41 725,
42 725,
43 725,
44 725,
Yann Gautierbb836ee2018-07-16 17:55:07 +020045 725,
46 750,
47 775,
48 800,
49 825,
50 850,
51 875,
52 900,
53 925,
54 950,
55 975,
56 1000,
57 1025,
58 1050,
59 1075,
60 1100,
61 1125,
62 1150,
63 1175,
64 1200,
65 1225,
66 1250,
67 1275,
68 1300,
69 1325,
70 1350,
Yann Gautieref85e532019-01-17 14:27:50 +010071 1375,
72 1400,
73 1425,
74 1450,
75 1475,
76 1500,
77 1500,
78 1500,
79 1500,
80 1500,
81 1500,
82 1500,
83 1500,
84 1500,
85 1500,
86 1500,
87 1500,
88 1500,
89 1500,
90 1500,
91 1500,
92 1500,
93 1500,
94 1500,
95 1500,
96 1500,
97 1500,
98 1500,
99 1500,
100 1500,
101 1500,
102 1500,
103 1500,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200104};
105
106static const uint16_t buck2_voltage_table[] = {
107 1000,
108 1000,
109 1000,
110 1000,
111 1000,
112 1000,
113 1000,
114 1000,
115 1000,
116 1000,
117 1000,
118 1000,
119 1000,
120 1000,
121 1000,
122 1000,
123 1000,
124 1000,
125 1050,
126 1050,
127 1100,
128 1100,
129 1150,
130 1150,
131 1200,
132 1200,
133 1250,
134 1250,
135 1300,
136 1300,
137 1350,
138 1350,
139 1400,
140 1400,
141 1450,
142 1450,
143 1500,
144};
145
146static const uint16_t buck3_voltage_table[] = {
147 1000,
148 1000,
149 1000,
150 1000,
151 1000,
152 1000,
153 1000,
154 1000,
155 1000,
156 1000,
157 1000,
158 1000,
159 1000,
160 1000,
161 1000,
162 1000,
163 1000,
164 1000,
165 1000,
166 1000,
167 1100,
168 1100,
169 1100,
170 1100,
171 1200,
172 1200,
173 1200,
174 1200,
175 1300,
176 1300,
177 1300,
178 1300,
179 1400,
180 1400,
181 1400,
182 1400,
183 1500,
184 1600,
185 1700,
186 1800,
187 1900,
188 2000,
189 2100,
190 2200,
191 2300,
192 2400,
193 2500,
194 2600,
195 2700,
196 2800,
197 2900,
198 3000,
199 3100,
200 3200,
201 3300,
202 3400,
203};
204
205static const uint16_t buck4_voltage_table[] = {
206 600,
207 625,
208 650,
209 675,
210 700,
211 725,
212 750,
213 775,
214 800,
215 825,
216 850,
217 875,
218 900,
219 925,
220 950,
221 975,
222 1000,
223 1025,
224 1050,
225 1075,
226 1100,
227 1125,
228 1150,
229 1175,
230 1200,
231 1225,
232 1250,
233 1275,
234 1300,
235 1300,
236 1350,
237 1350,
238 1400,
239 1400,
240 1450,
241 1450,
242 1500,
243 1600,
244 1700,
245 1800,
246 1900,
247 2000,
248 2100,
249 2200,
250 2300,
251 2400,
252 2500,
253 2600,
254 2700,
255 2800,
256 2900,
257 3000,
258 3100,
259 3200,
260 3300,
261 3400,
262 3500,
263 3600,
264 3700,
265 3800,
266 3900,
267};
268
269static const uint16_t ldo1_voltage_table[] = {
270 1700,
271 1700,
272 1700,
273 1700,
274 1700,
275 1700,
276 1700,
277 1700,
278 1700,
279 1800,
280 1900,
281 2000,
282 2100,
283 2200,
284 2300,
285 2400,
286 2500,
287 2600,
288 2700,
289 2800,
290 2900,
291 3000,
292 3100,
293 3200,
294 3300,
295};
296
297static const uint16_t ldo2_voltage_table[] = {
298 1700,
299 1700,
300 1700,
301 1700,
302 1700,
303 1700,
304 1700,
305 1700,
306 1700,
307 1800,
308 1900,
309 2000,
310 2100,
311 2200,
312 2300,
313 2400,
314 2500,
315 2600,
316 2700,
317 2800,
318 2900,
319 3000,
320 3100,
321 3200,
322 3300,
323};
324
325static const uint16_t ldo3_voltage_table[] = {
326 1700,
327 1700,
328 1700,
329 1700,
330 1700,
331 1700,
332 1700,
333 1700,
334 1700,
335 1800,
336 1900,
337 2000,
338 2100,
339 2200,
340 2300,
341 2400,
342 2500,
343 2600,
344 2700,
345 2800,
346 2900,
347 3000,
348 3100,
349 3200,
350 3300,
351 3300,
352 3300,
353 3300,
354 3300,
355 3300,
356 3300,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200357};
358
Pascal Pailletc18c4542020-12-15 18:28:34 +0100359/* Special mode table is used for sink source OR bypass mode */
360static const uint16_t ldo3_special_mode_table[] = {
361 0,
362};
363
Yann Gautierbb836ee2018-07-16 17:55:07 +0200364static const uint16_t ldo5_voltage_table[] = {
365 1700,
366 1700,
367 1700,
368 1700,
369 1700,
370 1700,
371 1700,
372 1700,
373 1700,
374 1800,
375 1900,
376 2000,
377 2100,
378 2200,
379 2300,
380 2400,
381 2500,
382 2600,
383 2700,
384 2800,
385 2900,
386 3000,
387 3100,
388 3200,
389 3300,
390 3400,
391 3500,
392 3600,
393 3700,
394 3800,
395 3900,
396};
397
398static const uint16_t ldo6_voltage_table[] = {
399 900,
400 1000,
401 1100,
402 1200,
403 1300,
404 1400,
405 1500,
406 1600,
407 1700,
408 1800,
409 1900,
410 2000,
411 2100,
412 2200,
413 2300,
414 2400,
415 2500,
416 2600,
417 2700,
418 2800,
419 2900,
420 3000,
421 3100,
422 3200,
423 3300,
424};
425
426static const uint16_t ldo4_voltage_table[] = {
427 3300,
428};
429
430static const uint16_t vref_ddr_voltage_table[] = {
431 3300,
432};
433
Etienne Carrieref76731f2020-01-10 08:31:13 +0100434static const uint16_t fixed_5v_voltage_table[] = {
435 5000,
436};
437
Yann Gautierbb836ee2018-07-16 17:55:07 +0200438/* Table of Regulators in PMIC SoC */
439static const struct regul_struct regulators_table[] = {
440 {
441 .dt_node_name = "buck1",
442 .voltage_table = buck1_voltage_table,
443 .voltage_table_size = ARRAY_SIZE(buck1_voltage_table),
444 .control_reg = BUCK1_CONTROL_REG,
Pascal Paillet84bca882021-03-10 14:37:03 +0100445 .enable_mask = LDO_BUCK_ENABLE_MASK,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200446 .low_power_reg = BUCK1_PWRCTRL_REG,
Yann Gautieref85e532019-01-17 14:27:50 +0100447 .pull_down_reg = BUCK_PULL_DOWN_REG,
448 .pull_down = BUCK1_PULL_DOWN_SHIFT,
449 .mask_reset_reg = MASK_RESET_BUCK_REG,
450 .mask_reset = BUCK1_MASK_RESET,
Pascal Pailletc18c4542020-12-15 18:28:34 +0100451 .icc_reg = BUCK_ICC_TURNOFF_REG,
452 .icc_mask = BUCK1_ICC_SHIFT,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200453 },
454 {
455 .dt_node_name = "buck2",
456 .voltage_table = buck2_voltage_table,
457 .voltage_table_size = ARRAY_SIZE(buck2_voltage_table),
458 .control_reg = BUCK2_CONTROL_REG,
Pascal Paillet84bca882021-03-10 14:37:03 +0100459 .enable_mask = LDO_BUCK_ENABLE_MASK,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200460 .low_power_reg = BUCK2_PWRCTRL_REG,
Yann Gautieref85e532019-01-17 14:27:50 +0100461 .pull_down_reg = BUCK_PULL_DOWN_REG,
462 .pull_down = BUCK2_PULL_DOWN_SHIFT,
463 .mask_reset_reg = MASK_RESET_BUCK_REG,
464 .mask_reset = BUCK2_MASK_RESET,
Pascal Pailletc18c4542020-12-15 18:28:34 +0100465 .icc_reg = BUCK_ICC_TURNOFF_REG,
466 .icc_mask = BUCK2_ICC_SHIFT,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200467 },
468 {
469 .dt_node_name = "buck3",
470 .voltage_table = buck3_voltage_table,
471 .voltage_table_size = ARRAY_SIZE(buck3_voltage_table),
472 .control_reg = BUCK3_CONTROL_REG,
Pascal Paillet84bca882021-03-10 14:37:03 +0100473 .enable_mask = LDO_BUCK_ENABLE_MASK,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200474 .low_power_reg = BUCK3_PWRCTRL_REG,
Yann Gautieref85e532019-01-17 14:27:50 +0100475 .pull_down_reg = BUCK_PULL_DOWN_REG,
476 .pull_down = BUCK3_PULL_DOWN_SHIFT,
477 .mask_reset_reg = MASK_RESET_BUCK_REG,
478 .mask_reset = BUCK3_MASK_RESET,
Pascal Pailletc18c4542020-12-15 18:28:34 +0100479 .icc_reg = BUCK_ICC_TURNOFF_REG,
480 .icc_mask = BUCK3_ICC_SHIFT,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200481 },
482 {
483 .dt_node_name = "buck4",
484 .voltage_table = buck4_voltage_table,
485 .voltage_table_size = ARRAY_SIZE(buck4_voltage_table),
486 .control_reg = BUCK4_CONTROL_REG,
Pascal Paillet84bca882021-03-10 14:37:03 +0100487 .enable_mask = LDO_BUCK_ENABLE_MASK,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200488 .low_power_reg = BUCK4_PWRCTRL_REG,
Yann Gautieref85e532019-01-17 14:27:50 +0100489 .pull_down_reg = BUCK_PULL_DOWN_REG,
490 .pull_down = BUCK4_PULL_DOWN_SHIFT,
491 .mask_reset_reg = MASK_RESET_BUCK_REG,
492 .mask_reset = BUCK4_MASK_RESET,
Pascal Pailletc18c4542020-12-15 18:28:34 +0100493 .icc_reg = BUCK_ICC_TURNOFF_REG,
494 .icc_mask = BUCK4_ICC_SHIFT,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200495 },
496 {
497 .dt_node_name = "ldo1",
498 .voltage_table = ldo1_voltage_table,
499 .voltage_table_size = ARRAY_SIZE(ldo1_voltage_table),
500 .control_reg = LDO1_CONTROL_REG,
Pascal Paillet84bca882021-03-10 14:37:03 +0100501 .enable_mask = LDO_BUCK_ENABLE_MASK,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200502 .low_power_reg = LDO1_PWRCTRL_REG,
Yann Gautieref85e532019-01-17 14:27:50 +0100503 .mask_reset_reg = MASK_RESET_LDO_REG,
504 .mask_reset = LDO1_MASK_RESET,
Pascal Pailletc18c4542020-12-15 18:28:34 +0100505 .icc_reg = LDO_ICC_TURNOFF_REG,
506 .icc_mask = LDO1_ICC_SHIFT,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200507 },
508 {
509 .dt_node_name = "ldo2",
510 .voltage_table = ldo2_voltage_table,
511 .voltage_table_size = ARRAY_SIZE(ldo2_voltage_table),
512 .control_reg = LDO2_CONTROL_REG,
Pascal Paillet84bca882021-03-10 14:37:03 +0100513 .enable_mask = LDO_BUCK_ENABLE_MASK,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200514 .low_power_reg = LDO2_PWRCTRL_REG,
Yann Gautieref85e532019-01-17 14:27:50 +0100515 .mask_reset_reg = MASK_RESET_LDO_REG,
516 .mask_reset = LDO2_MASK_RESET,
Pascal Pailletc18c4542020-12-15 18:28:34 +0100517 .icc_reg = LDO_ICC_TURNOFF_REG,
518 .icc_mask = LDO2_ICC_SHIFT,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200519 },
520 {
521 .dt_node_name = "ldo3",
522 .voltage_table = ldo3_voltage_table,
523 .voltage_table_size = ARRAY_SIZE(ldo3_voltage_table),
524 .control_reg = LDO3_CONTROL_REG,
Pascal Paillet84bca882021-03-10 14:37:03 +0100525 .enable_mask = LDO_BUCK_ENABLE_MASK,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200526 .low_power_reg = LDO3_PWRCTRL_REG,
Yann Gautieref85e532019-01-17 14:27:50 +0100527 .mask_reset_reg = MASK_RESET_LDO_REG,
528 .mask_reset = LDO3_MASK_RESET,
Pascal Pailletc18c4542020-12-15 18:28:34 +0100529 .icc_reg = LDO_ICC_TURNOFF_REG,
530 .icc_mask = LDO3_ICC_SHIFT,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200531 },
532 {
533 .dt_node_name = "ldo4",
534 .voltage_table = ldo4_voltage_table,
535 .voltage_table_size = ARRAY_SIZE(ldo4_voltage_table),
536 .control_reg = LDO4_CONTROL_REG,
Pascal Paillet84bca882021-03-10 14:37:03 +0100537 .enable_mask = LDO_BUCK_ENABLE_MASK,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200538 .low_power_reg = LDO4_PWRCTRL_REG,
Yann Gautieref85e532019-01-17 14:27:50 +0100539 .mask_reset_reg = MASK_RESET_LDO_REG,
540 .mask_reset = LDO4_MASK_RESET,
Pascal Pailletc18c4542020-12-15 18:28:34 +0100541 .icc_reg = LDO_ICC_TURNOFF_REG,
542 .icc_mask = LDO4_ICC_SHIFT,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200543 },
544 {
545 .dt_node_name = "ldo5",
546 .voltage_table = ldo5_voltage_table,
547 .voltage_table_size = ARRAY_SIZE(ldo5_voltage_table),
548 .control_reg = LDO5_CONTROL_REG,
Pascal Paillet84bca882021-03-10 14:37:03 +0100549 .enable_mask = LDO_BUCK_ENABLE_MASK,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200550 .low_power_reg = LDO5_PWRCTRL_REG,
Yann Gautieref85e532019-01-17 14:27:50 +0100551 .mask_reset_reg = MASK_RESET_LDO_REG,
552 .mask_reset = LDO5_MASK_RESET,
Pascal Pailletc18c4542020-12-15 18:28:34 +0100553 .icc_reg = LDO_ICC_TURNOFF_REG,
554 .icc_mask = LDO5_ICC_SHIFT,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200555 },
556 {
557 .dt_node_name = "ldo6",
558 .voltage_table = ldo6_voltage_table,
559 .voltage_table_size = ARRAY_SIZE(ldo6_voltage_table),
560 .control_reg = LDO6_CONTROL_REG,
Pascal Paillet84bca882021-03-10 14:37:03 +0100561 .enable_mask = LDO_BUCK_ENABLE_MASK,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200562 .low_power_reg = LDO6_PWRCTRL_REG,
Yann Gautieref85e532019-01-17 14:27:50 +0100563 .mask_reset_reg = MASK_RESET_LDO_REG,
564 .mask_reset = LDO6_MASK_RESET,
Pascal Pailletc18c4542020-12-15 18:28:34 +0100565 .icc_reg = LDO_ICC_TURNOFF_REG,
566 .icc_mask = LDO6_ICC_SHIFT,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200567 },
568 {
569 .dt_node_name = "vref_ddr",
570 .voltage_table = vref_ddr_voltage_table,
571 .voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table),
572 .control_reg = VREF_DDR_CONTROL_REG,
Pascal Paillet84bca882021-03-10 14:37:03 +0100573 .enable_mask = LDO_BUCK_ENABLE_MASK,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200574 .low_power_reg = VREF_DDR_PWRCTRL_REG,
Yann Gautieref85e532019-01-17 14:27:50 +0100575 .mask_reset_reg = MASK_RESET_LDO_REG,
576 .mask_reset = VREF_DDR_MASK_RESET,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200577 },
Etienne Carrieref76731f2020-01-10 08:31:13 +0100578 {
579 .dt_node_name = "boost",
580 .voltage_table = fixed_5v_voltage_table,
581 .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
582 .control_reg = USB_CONTROL_REG,
583 .enable_mask = BOOST_ENABLED,
Pascal Pailletc18c4542020-12-15 18:28:34 +0100584 .icc_reg = BUCK_ICC_TURNOFF_REG,
585 .icc_mask = BOOST_ICC_SHIFT,
Etienne Carrieref76731f2020-01-10 08:31:13 +0100586 },
587 {
588 .dt_node_name = "pwr_sw1",
589 .voltage_table = fixed_5v_voltage_table,
590 .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
591 .control_reg = USB_CONTROL_REG,
592 .enable_mask = USBSW_OTG_SWITCH_ENABLED,
Pascal Pailletc18c4542020-12-15 18:28:34 +0100593 .icc_reg = BUCK_ICC_TURNOFF_REG,
594 .icc_mask = PWR_SW1_ICC_SHIFT,
Etienne Carrieref76731f2020-01-10 08:31:13 +0100595 },
596 {
597 .dt_node_name = "pwr_sw2",
598 .voltage_table = fixed_5v_voltage_table,
599 .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
600 .control_reg = USB_CONTROL_REG,
601 .enable_mask = SWIN_SWOUT_ENABLED,
Pascal Pailletc18c4542020-12-15 18:28:34 +0100602 .icc_reg = BUCK_ICC_TURNOFF_REG,
603 .icc_mask = PWR_SW2_ICC_SHIFT,
Etienne Carrieref76731f2020-01-10 08:31:13 +0100604 },
Yann Gautierbb836ee2018-07-16 17:55:07 +0200605};
606
Yann Gautiera45433b2019-01-16 18:31:00 +0100607#define MAX_REGUL ARRAY_SIZE(regulators_table)
Yann Gautierbb836ee2018-07-16 17:55:07 +0200608
Yann Gautiera45433b2019-01-16 18:31:00 +0100609static const struct regul_struct *get_regulator_data(const char *name)
Yann Gautierbb836ee2018-07-16 17:55:07 +0200610{
611 uint8_t i;
612
613 for (i = 0 ; i < MAX_REGUL ; i++) {
614 if (strncmp(name, regulators_table[i].dt_node_name,
615 strlen(regulators_table[i].dt_node_name)) == 0) {
616 return &regulators_table[i];
617 }
618 }
619
620 /* Regulator not found */
621 panic();
622 return NULL;
623}
624
Yann Gautiera45433b2019-01-16 18:31:00 +0100625static uint8_t voltage_to_index(const char *name, uint16_t millivolts)
Yann Gautierbb836ee2018-07-16 17:55:07 +0200626{
Yann Gautiera45433b2019-01-16 18:31:00 +0100627 const struct regul_struct *regul = get_regulator_data(name);
Yann Gautierbb836ee2018-07-16 17:55:07 +0200628 uint8_t i;
629
630 for (i = 0 ; i < regul->voltage_table_size ; i++) {
631 if (regul->voltage_table[i] == millivolts) {
632 return i;
633 }
634 }
635
636 /* Voltage not found */
637 panic();
638
639 return 0;
640}
641
Yann Gautieref85e532019-01-17 14:27:50 +0100642int stpmic1_powerctrl_on(void)
643{
644 return stpmic1_register_update(MAIN_CONTROL_REG, PWRCTRL_PIN_VALID,
645 PWRCTRL_PIN_VALID);
646}
647
Yann Gautiera45433b2019-01-16 18:31:00 +0100648int stpmic1_switch_off(void)
Yann Gautierbb836ee2018-07-16 17:55:07 +0200649{
Yann Gautiera45433b2019-01-16 18:31:00 +0100650 return stpmic1_register_update(MAIN_CONTROL_REG, 1,
651 SOFTWARE_SWITCH_OFF_ENABLED);
Yann Gautierbb836ee2018-07-16 17:55:07 +0200652}
653
Yann Gautiera45433b2019-01-16 18:31:00 +0100654int stpmic1_regulator_enable(const char *name)
Yann Gautierbb836ee2018-07-16 17:55:07 +0200655{
Yann Gautiera45433b2019-01-16 18:31:00 +0100656 const struct regul_struct *regul = get_regulator_data(name);
Yann Gautierbb836ee2018-07-16 17:55:07 +0200657
Pascal Paillet84bca882021-03-10 14:37:03 +0100658 return stpmic1_register_update(regul->control_reg, regul->enable_mask,
659 regul->enable_mask);
Yann Gautierbb836ee2018-07-16 17:55:07 +0200660}
661
Yann Gautiera45433b2019-01-16 18:31:00 +0100662int stpmic1_regulator_disable(const char *name)
Yann Gautierbb836ee2018-07-16 17:55:07 +0200663{
Yann Gautiera45433b2019-01-16 18:31:00 +0100664 const struct regul_struct *regul = get_regulator_data(name);
Yann Gautierbb836ee2018-07-16 17:55:07 +0200665
Pascal Paillet84bca882021-03-10 14:37:03 +0100666 return stpmic1_register_update(regul->control_reg, 0,
667 regul->enable_mask);
Yann Gautierbb836ee2018-07-16 17:55:07 +0200668}
669
Nicolas Le Bayonf5188ee2019-09-19 11:24:50 +0200670bool stpmic1_is_regulator_enabled(const char *name)
Yann Gautierbb836ee2018-07-16 17:55:07 +0200671{
672 uint8_t val;
Yann Gautiera45433b2019-01-16 18:31:00 +0100673 const struct regul_struct *regul = get_regulator_data(name);
Yann Gautierbb836ee2018-07-16 17:55:07 +0200674
Yann Gautiera45433b2019-01-16 18:31:00 +0100675 if (stpmic1_register_read(regul->control_reg, &val) != 0) {
Yann Gautierbb836ee2018-07-16 17:55:07 +0200676 panic();
677 }
678
Nicolas Le Bayonf5188ee2019-09-19 11:24:50 +0200679 return (val & regul->enable_mask) == regul->enable_mask;
Yann Gautierbb836ee2018-07-16 17:55:07 +0200680}
681
Yann Gautiera45433b2019-01-16 18:31:00 +0100682int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts)
Yann Gautierbb836ee2018-07-16 17:55:07 +0200683{
Yann Gautiera45433b2019-01-16 18:31:00 +0100684 uint8_t voltage_index = voltage_to_index(name, millivolts);
685 const struct regul_struct *regul = get_regulator_data(name);
Yann Gautieref85e532019-01-17 14:27:50 +0100686 uint8_t mask;
687
Pascal Pailletc18c4542020-12-15 18:28:34 +0100688 if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
689 /*
690 * when the LDO3 is in special mode, we do not change voltage,
691 * because by setting voltage, the LDO would leaves sink-source
692 * mode. There is obviously no reason to leave sink-source mode
693 * at runtime.
694 */
695 return 0;
696 }
697
Yann Gautieref85e532019-01-17 14:27:50 +0100698 /* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
699 if (strncmp(name, "buck", 4) == 0) {
700 mask = BUCK_VOLTAGE_MASK;
701 } else if ((strncmp(name, "ldo", 3) == 0) &&
Pascal Pailletc18c4542020-12-15 18:28:34 +0100702 (strncmp(name, "ldo4", 5) != 0)) {
Yann Gautieref85e532019-01-17 14:27:50 +0100703 mask = LDO_VOLTAGE_MASK;
704 } else {
705 return 0;
706 }
707
708 return stpmic1_register_update(regul->control_reg,
709 voltage_index << LDO_BUCK_VOLTAGE_SHIFT,
710 mask);
711}
712
713int stpmic1_regulator_pull_down_set(const char *name)
714{
715 const struct regul_struct *regul = get_regulator_data(name);
716
717 if (regul->pull_down_reg != 0) {
718 return stpmic1_register_update(regul->pull_down_reg,
719 BIT(regul->pull_down),
720 LDO_BUCK_PULL_DOWN_MASK <<
721 regul->pull_down);
722 }
723
724 return 0;
725}
726
727int stpmic1_regulator_mask_reset_set(const char *name)
728{
729 const struct regul_struct *regul = get_regulator_data(name);
730
Pascal Pailletc18c4542020-12-15 18:28:34 +0100731 if (regul->mask_reset_reg == 0U) {
732 return -EPERM;
733 }
734
Yann Gautieref85e532019-01-17 14:27:50 +0100735 return stpmic1_register_update(regul->mask_reset_reg,
736 BIT(regul->mask_reset),
737 LDO_BUCK_RESET_MASK <<
738 regul->mask_reset);
739}
740
Pascal Pailletc18c4542020-12-15 18:28:34 +0100741int stpmic1_regulator_icc_set(const char *name)
742{
743 const struct regul_struct *regul = get_regulator_data(name);
744
745 if (regul->mask_reset_reg == 0U) {
746 return -EPERM;
747 }
748
749 return stpmic1_register_update(regul->icc_reg,
750 BIT(regul->icc_mask),
751 BIT(regul->icc_mask));
752}
753
754int stpmic1_regulator_sink_mode_set(const char *name)
755{
756 if (strncmp(name, "ldo3", 5) != 0) {
757 return -EPERM;
758 }
759
760 ldo3_special_mode = true;
761
762 /* disable bypass mode, enable sink mode */
763 return stpmic1_register_update(LDO3_CONTROL_REG,
764 LDO3_DDR_SEL << LDO_BUCK_VOLTAGE_SHIFT,
765 LDO3_BYPASS | LDO_VOLTAGE_MASK);
766}
767
768int stpmic1_regulator_bypass_mode_set(const char *name)
769{
770 if (strncmp(name, "ldo3", 5) != 0) {
771 return -EPERM;
772 }
773
774 ldo3_special_mode = true;
775
776 /* enable bypass mode, disable sink mode */
777 return stpmic1_register_update(LDO3_CONTROL_REG,
778 LDO3_BYPASS,
779 LDO3_BYPASS | LDO_VOLTAGE_MASK);
780}
781
782int stpmic1_active_discharge_mode_set(const char *name)
783{
784 if (strncmp(name, "pwr_sw1", 8) == 0) {
785 return stpmic1_register_update(USB_CONTROL_REG,
786 VBUS_OTG_DISCHARGE,
787 VBUS_OTG_DISCHARGE);
788 }
789
790 if (strncmp(name, "pwr_sw2", 8) == 0) {
791 return stpmic1_register_update(USB_CONTROL_REG,
792 SW_OUT_DISCHARGE,
793 SW_OUT_DISCHARGE);
794 }
795
796 return -EPERM;
797}
798
799int stpmic1_regulator_levels_mv(const char *name, const uint16_t **levels,
800 size_t *levels_count)
801{
802 const struct regul_struct *regul = get_regulator_data(name);
803
804 if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
805 *levels_count = ARRAY_SIZE(ldo3_special_mode_table);
806 *levels = ldo3_special_mode_table;
807 } else {
808 *levels_count = regul->voltage_table_size;
809 *levels = regul->voltage_table;
810 }
811
812 return 0;
813}
814
Yann Gautieref85e532019-01-17 14:27:50 +0100815int stpmic1_regulator_voltage_get(const char *name)
816{
817 const struct regul_struct *regul = get_regulator_data(name);
818 uint8_t value;
819 uint8_t mask;
Yann Gautier328bba62020-03-23 17:44:30 +0100820 int status;
Yann Gautierbb836ee2018-07-16 17:55:07 +0200821
Pascal Pailletc18c4542020-12-15 18:28:34 +0100822 if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
823 return 0;
824 }
825
Yann Gautieref85e532019-01-17 14:27:50 +0100826 /* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
827 if (strncmp(name, "buck", 4) == 0) {
828 mask = BUCK_VOLTAGE_MASK;
829 } else if ((strncmp(name, "ldo", 3) == 0) &&
Pascal Pailletc18c4542020-12-15 18:28:34 +0100830 (strncmp(name, "ldo4", 5) != 0)) {
Yann Gautieref85e532019-01-17 14:27:50 +0100831 mask = LDO_VOLTAGE_MASK;
832 } else {
833 return 0;
834 }
835
Yann Gautier328bba62020-03-23 17:44:30 +0100836 status = stpmic1_register_read(regul->control_reg, &value);
837 if (status < 0) {
838 return status;
839 }
Yann Gautieref85e532019-01-17 14:27:50 +0100840
841 value = (value & mask) >> LDO_BUCK_VOLTAGE_SHIFT;
842
Yann Gautier328bba62020-03-23 17:44:30 +0100843 if (value > regul->voltage_table_size) {
844 return -ERANGE;
845 }
Yann Gautieref85e532019-01-17 14:27:50 +0100846
847 return (int)regul->voltage_table[value];
Yann Gautierbb836ee2018-07-16 17:55:07 +0200848}
849
Yann Gautiera45433b2019-01-16 18:31:00 +0100850int stpmic1_register_read(uint8_t register_id, uint8_t *value)
Yann Gautierbb836ee2018-07-16 17:55:07 +0200851{
Yann Gautiera45433b2019-01-16 18:31:00 +0100852 return stm32_i2c_mem_read(pmic_i2c_handle, pmic_i2c_addr,
Yann Gautierf3928f62019-02-14 11:15:03 +0100853 (uint16_t)register_id,
854 I2C_MEMADD_SIZE_8BIT, value,
855 1, I2C_TIMEOUT_MS);
Yann Gautierbb836ee2018-07-16 17:55:07 +0200856}
857
Yann Gautiera45433b2019-01-16 18:31:00 +0100858int stpmic1_register_write(uint8_t register_id, uint8_t value)
Yann Gautierbb836ee2018-07-16 17:55:07 +0200859{
860 int status;
861
Yann Gautiera45433b2019-01-16 18:31:00 +0100862 status = stm32_i2c_mem_write(pmic_i2c_handle, pmic_i2c_addr,
Yann Gautierbb836ee2018-07-16 17:55:07 +0200863 (uint16_t)register_id,
Yann Gautierf3928f62019-02-14 11:15:03 +0100864 I2C_MEMADD_SIZE_8BIT, &value,
865 1, I2C_TIMEOUT_MS);
Yann Gautierbb836ee2018-07-16 17:55:07 +0200866
Yann Gautieref85e532019-01-17 14:27:50 +0100867#if ENABLE_ASSERTIONS
Yann Gautierbb836ee2018-07-16 17:55:07 +0200868 if (status != 0) {
869 return status;
870 }
871
872 if ((register_id != WATCHDOG_CONTROL_REG) && (register_id <= 0x40U)) {
873 uint8_t readval;
874
Yann Gautiera45433b2019-01-16 18:31:00 +0100875 status = stpmic1_register_read(register_id, &readval);
Yann Gautierbb836ee2018-07-16 17:55:07 +0200876 if (status != 0) {
877 return status;
878 }
879
880 if (readval != value) {
Yann Gautier328bba62020-03-23 17:44:30 +0100881 return -EIO;
Yann Gautierbb836ee2018-07-16 17:55:07 +0200882 }
883 }
Yann Gautieref85e532019-01-17 14:27:50 +0100884#endif
Yann Gautierbb836ee2018-07-16 17:55:07 +0200885
Yann Gautieref85e532019-01-17 14:27:50 +0100886 return status;
Yann Gautierbb836ee2018-07-16 17:55:07 +0200887}
888
Yann Gautiera45433b2019-01-16 18:31:00 +0100889int stpmic1_register_update(uint8_t register_id, uint8_t value, uint8_t mask)
Yann Gautierbb836ee2018-07-16 17:55:07 +0200890{
891 int status;
892 uint8_t val;
893
Yann Gautiera45433b2019-01-16 18:31:00 +0100894 status = stpmic1_register_read(register_id, &val);
Yann Gautierbb836ee2018-07-16 17:55:07 +0200895 if (status != 0) {
896 return status;
897 }
898
Yann Gautieref85e532019-01-17 14:27:50 +0100899 val = (val & ~mask) | (value & mask);
Yann Gautierbb836ee2018-07-16 17:55:07 +0200900
Yann Gautiera45433b2019-01-16 18:31:00 +0100901 return stpmic1_register_write(register_id, val);
Yann Gautierbb836ee2018-07-16 17:55:07 +0200902}
903
Yann Gautiera45433b2019-01-16 18:31:00 +0100904void stpmic1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr)
Yann Gautierbb836ee2018-07-16 17:55:07 +0200905{
Yann Gautiera45433b2019-01-16 18:31:00 +0100906 pmic_i2c_handle = i2c_handle;
907 pmic_i2c_addr = i2c_addr;
Yann Gautierbb836ee2018-07-16 17:55:07 +0200908}
Yann Gautieref85e532019-01-17 14:27:50 +0100909
910void stpmic1_dump_regulators(void)
911{
912 uint32_t i;
913
914 for (i = 0U; i < MAX_REGUL; i++) {
915 const char *name __unused = regulators_table[i].dt_node_name;
916
917 VERBOSE("PMIC regul %s: %sable, %dmV",
918 name,
919 stpmic1_is_regulator_enabled(name) ? "en" : "dis",
920 stpmic1_regulator_voltage_get(name));
921 }
922}
923
924int stpmic1_get_version(unsigned long *version)
925{
Yann Gautieref85e532019-01-17 14:27:50 +0100926 uint8_t read_val;
Yann Gautier328bba62020-03-23 17:44:30 +0100927 int status;
Yann Gautieref85e532019-01-17 14:27:50 +0100928
Yann Gautier328bba62020-03-23 17:44:30 +0100929 status = stpmic1_register_read(VERSION_STATUS_REG, &read_val);
930 if (status < 0) {
931 return status;
Yann Gautieref85e532019-01-17 14:27:50 +0100932 }
933
934 *version = (unsigned long)read_val;
935
936 return 0;
937}