1 /*
2 * Copyright (C) 2024-2026, STMicroelectronics - All Rights Reserved
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <string.h>
10
11 #include <common/debug.h>
12 #include <drivers/st/stpmic2.h>
13
14 #define RET_SUCCESS 0
15 #define RET_ERROR_NOT_SUPPORTED -1
16 #define RET_ERROR_GENERIC -2
17 #define RET_ERROR_BAD_PARAMETERS -3
18
19 #define I2C_TIMEOUT_MS 25
20
21 #define VOLTAGE_INDEX_INVALID ((size_t)~0U)
22
23 struct regul_struct {
24 const char *name;
25 const uint16_t *volt_table;
26 uint8_t volt_table_size;
27 uint8_t volt_cr;
28 uint8_t volt_shift;
29 uint8_t en_cr;
30 uint8_t alt_en_cr;
31 uint8_t msrt_reg;
32 uint8_t msrt_mask;
33 uint8_t pd_reg;
34 uint8_t pd_val;
35 uint8_t ocp_reg;
36 uint8_t ocp_mask;
37 };
38
39 /* Voltage tables in mV */
40 static const uint16_t buck_low_volt_table[] = {
41 500U, 510U, 520U, 530U, 540U, 550U, 560U, 570U, 580U, 590U,
42 600U, 610U, 620U, 630U, 640U, 650U, 660U, 670U, 680U, 690U,
43 700U, 710U, 720U, 730U, 740U, 750U, 760U, 770U, 780U, 790U,
44 800U, 810U, 820U, 830U, 840U, 850U, 860U, 870U, 880U, 890U,
45 900U, 910U, 920U, 930U, 940U, 950U, 960U, 970U, 980U, 990U,
46 1000U, 1010U, 1020U, 1030U, 1040U, 1050U, 1060U, 1070U, 1080U, 1090U,
47 1100U, 1110U, 1120U, 1130U, 1140U, 1150U, 1160U, 1170U, 1180U, 1190U,
48 1200U, 1210U, 1220U, 1230U, 1240U, 1250U, 1260U, 1270U, 1280U, 1290U,
49 1300U, 1310U, 1320U, 1330U, 1340U, 1350U, 1360U, 1370U, 1380U, 1390U,
50 1400U, 1410U, 1420U, 1430U, 1440U, 1450U, 1460U, 1470U, 1480U, 1490U,
51 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
52 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
53 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U
54 };
55
56 static const uint16_t buck_high_volt_table[] = {
57 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
58 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
59 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
60 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
61 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
62 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
63 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
64 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
65 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
66 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
67 1500U, 1600U, 1700U, 1800U, 1900U, 2000U, 2100U, 2200U, 2300U, 2400U,
68 2500U, 2600U, 2700U, 2800U, 2900U, 3000U, 3100U, 3200U, 3300U, 3400U,
69 3500U, 3600U, 3700U, 3800U, 3900U, 4000U, 4100U, 4200U
70 };
71
72 static const uint16_t ldo235678_volt_table[] = {
73 900U, 1000U, 1100U, 1200U, 1300U, 1400U, 1500U, 1600U, 1700U, 1800U,
74 1900U, 2000U, 2100U, 2200U, 2300U, 2400U, 2500U, 2600U, 2700U, 2800U,
75 2900U, 3000U, 3100U, 3200U, 3300U, 3400U, 3500U, 3600U, 3700U, 3800U,
76 3900U, 4000U
77 };
78
79 static const uint16_t ldo1_volt_table[] = {
80 1800U,
81 };
82
83 static const uint16_t ldo4_volt_table[] = {
84 3300U,
85 };
86
87 static const uint16_t refddr_volt_table[] = {
88 0,
89 };
90
91 #define DEFINE_BUCK(regu_name, ID, pd, table) { \
92 .name = regu_name, \
93 .volt_table = table, \
94 .volt_table_size = ARRAY_SIZE(table), \
95 .en_cr = ID ## _MAIN_CR2, \
96 .volt_cr = ID ## _MAIN_CR1, \
97 .alt_en_cr = ID ## _ALT_CR2, \
98 .msrt_reg = BUCKS_MRST_CR, \
99 .msrt_mask = ID ## _MRST, \
100 .pd_reg = pd, \
101 .pd_val = ID ## _PD_FAST, \
102 .ocp_reg = FS_OCP_CR1, \
103 .ocp_mask = FS_OCP_ ## ID, \
104 }
105
106 #define DEFINE_LDOx(regu_name, ID, table) { \
107 .name = regu_name, \
108 .volt_table = table, \
109 .volt_table_size = ARRAY_SIZE(table), \
110 .volt_shift = LDO_VOLT_SHIFT, \
111 .en_cr = ID ## _MAIN_CR, \
112 .volt_cr = ID ## _MAIN_CR, \
113 .alt_en_cr = ID ## _ALT_CR, \
114 .msrt_reg = LDOS_MRST_CR, \
115 .msrt_mask = ID ## _MRST, \
116 .pd_reg = LDOS_PD_CR1, \
117 .pd_val = ID ## _PD, \
118 .ocp_reg = FS_OCP_CR2, \
119 .ocp_mask = FS_OCP_ ## ID, \
120 }
121
122 #define DEFINE_GPOx(regu_name, ID) { \
123 .name = regu_name, \
124 .en_cr = ID ## _MAIN_CR, \
125 .alt_en_cr = ID ## _ALT_CR, \
126 .msrt_reg = GPO_MRST_CR, \
127 .msrt_mask = ID ## _MRST, \
128 }
129
130 #define DEFINE_REFDDR(regu_name, ID, table) { \
131 .name = regu_name, \
132 .volt_table = table, \
133 .volt_table_size = ARRAY_SIZE(table), \
134 .en_cr = ID ## _MAIN_CR, \
135 .volt_cr = ID ## _MAIN_CR, \
136 .alt_en_cr = ID ## _ALT_CR, \
137 .msrt_reg = BUCKS_MRST_CR, \
138 .msrt_mask = ID ## _MRST, \
139 .pd_reg = LDOS_PD_CR2, \
140 .pd_val = ID ## _PD, \
141 .ocp_reg = FS_OCP_CR1, \
142 .ocp_mask = FS_OCP_ ## ID, \
143 }
144
145 /* Table of Regulators in PMIC SoC */
146 static const struct regul_struct regul_table[STPMIC2_NB_REG] = {
147 [STPMIC2_BUCK1] = DEFINE_BUCK("buck1", BUCK1, BUCKS_PD_CR1,
148 buck_low_volt_table),
149 [STPMIC2_BUCK1H] = DEFINE_BUCK("buck1h", BUCK1, BUCKS_PD_CR1,
150 buck_high_volt_table),
151 [STPMIC2_BUCK2] = DEFINE_BUCK("buck2", BUCK2, BUCKS_PD_CR1,
152 buck_low_volt_table),
153 [STPMIC2_BUCK3] = DEFINE_BUCK("buck3", BUCK3, BUCKS_PD_CR1,
154 buck_low_volt_table),
155 [STPMIC2_BUCK4] = DEFINE_BUCK("buck4", BUCK4, BUCKS_PD_CR1,
156 buck_high_volt_table),
157 [STPMIC2_BUCK5] = DEFINE_BUCK("buck5", BUCK5, BUCKS_PD_CR2,
158 buck_high_volt_table),
159 [STPMIC2_BUCK6] = DEFINE_BUCK("buck6", BUCK6, BUCKS_PD_CR2,
160 buck_low_volt_table),
161 [STPMIC2_BUCK7] = DEFINE_BUCK("buck7", BUCK7, BUCKS_PD_CR2,
162 buck_high_volt_table),
163
164 [STPMIC2_REFDDR] = DEFINE_REFDDR("refddr", REFDDR, refddr_volt_table),
165
166 [STPMIC2_LDO1] = DEFINE_LDOx("ldo1", LDO1, ldo1_volt_table),
167 [STPMIC2_LDO2] = DEFINE_LDOx("ldo2", LDO2, ldo235678_volt_table),
168 [STPMIC2_LDO3] = DEFINE_LDOx("ldo3", LDO3, ldo235678_volt_table),
169 [STPMIC2_LDO4] = DEFINE_LDOx("ldo4", LDO4, ldo4_volt_table),
170 [STPMIC2_LDO5] = DEFINE_LDOx("ldo5", LDO5, ldo235678_volt_table),
171 [STPMIC2_LDO6] = DEFINE_LDOx("ldo6", LDO6, ldo235678_volt_table),
172 [STPMIC2_LDO7] = DEFINE_LDOx("ldo7", LDO7, ldo235678_volt_table),
173 [STPMIC2_LDO8] = DEFINE_LDOx("ldo8", LDO8, ldo235678_volt_table),
174
175 [STPMIC2_GPO1] = DEFINE_GPOx("gpo1", GPO1),
176 [STPMIC2_GPO2] = DEFINE_GPOx("gpo2", GPO2),
177 [STPMIC2_GPO3] = DEFINE_GPOx("gpo3", GPO3),
178 [STPMIC2_GPO4] = DEFINE_GPOx("gpo4", GPO4),
179 [STPMIC2_GPO5] = DEFINE_GPOx("gpo5", GPO5),
180
181 };
182
stpmic2_register_read(struct pmic_handle_s * pmic,uint8_t register_id,uint8_t * value)183 int stpmic2_register_read(struct pmic_handle_s *pmic,
184 uint8_t register_id, uint8_t *value)
185 {
186 int ret = stm32_i2c_mem_read(pmic->i2c_handle,
187 pmic->i2c_addr,
188 (uint16_t)register_id,
189 I2C_MEMADD_SIZE_8BIT, value,
190 1, I2C_TIMEOUT_MS);
191 if (ret != 0) {
192 ERROR("Failed to read reg:0x%x\n", register_id);
193 }
194
195 return ret;
196 }
197
stpmic2_register_write(struct pmic_handle_s * pmic,uint8_t register_id,uint8_t value)198 int stpmic2_register_write(struct pmic_handle_s *pmic,
199 uint8_t register_id, uint8_t value)
200 {
201 uint8_t val = value;
202 int ret = stm32_i2c_mem_write(pmic->i2c_handle,
203 pmic->i2c_addr,
204 (uint16_t)register_id,
205 I2C_MEMADD_SIZE_8BIT, &val,
206 1, I2C_TIMEOUT_MS);
207 if (ret != 0) {
208 ERROR("Failed to write reg:0x%x\n", register_id);
209 }
210
211 return ret;
212 }
213
stpmic2_register_update(struct pmic_handle_s * pmic,uint8_t register_id,uint8_t value,uint8_t mask)214 int stpmic2_register_update(struct pmic_handle_s *pmic,
215 uint8_t register_id, uint8_t value, uint8_t mask)
216 {
217 int status;
218 uint8_t val = 0U;
219
220 status = stpmic2_register_read(pmic, register_id, &val);
221 if (status != 0) {
222 return status;
223 }
224
225 val = (val & ((uint8_t)~mask)) | (value & mask);
226
227 VERBOSE("REG:0x%x v=0x%x mask=0x%x -> 0x%x\n",
228 register_id, value, mask, val);
229
230 return stpmic2_register_write(pmic, register_id, val);
231 }
232
stpmic2_regulator_set_state(struct pmic_handle_s * pmic,uint8_t id,bool enable)233 int stpmic2_regulator_set_state(struct pmic_handle_s *pmic,
234 uint8_t id, bool enable)
235 {
236 const struct regul_struct *regul = ®ul_table[id];
237
238 if (enable) {
239 return stpmic2_register_update(pmic, regul->en_cr, 1U, 1U);
240 } else {
241 return stpmic2_register_update(pmic, regul->en_cr, 0, 1U);
242 }
243 }
244
stpmic2_regulator_get_state(struct pmic_handle_s * pmic,uint8_t id,bool * enabled)245 int stpmic2_regulator_get_state(struct pmic_handle_s *pmic,
246 uint8_t id, bool *enabled)
247 {
248 const struct regul_struct *regul = ®ul_table[id];
249 uint8_t val;
250
251 if (stpmic2_register_read(pmic, regul->en_cr, &val) != 0) {
252 return RET_ERROR_GENERIC;
253 }
254
255 *enabled = (val & 1U) == 1U;
256
257 return RET_SUCCESS;
258 }
259
stpmic2_regulator_levels_mv(struct pmic_handle_s * pmic,uint8_t id,const uint16_t ** levels,size_t * levels_count)260 int stpmic2_regulator_levels_mv(struct pmic_handle_s *pmic,
261 uint8_t id, const uint16_t **levels,
262 size_t *levels_count)
263 {
264 const struct regul_struct *regul = ®ul_table[id];
265
266 if (levels_count != NULL) {
267 *levels_count = regul->volt_table_size;
268 }
269 if (levels != NULL) {
270 *levels = regul->volt_table;
271 }
272
273 return RET_SUCCESS;
274 }
275
stpmic2_regulator_get_voltage(struct pmic_handle_s * pmic,uint8_t id,uint16_t * val)276 int stpmic2_regulator_get_voltage(struct pmic_handle_s *pmic,
277 uint8_t id, uint16_t *val)
278 {
279 const struct regul_struct *regul = ®ul_table[id];
280 uint8_t value = 0U;
281 uint8_t mask;
282
283 if (regul->volt_table_size == 0U) {
284 return RET_ERROR_GENERIC;
285 }
286
287 mask = regul->volt_table_size - 1U;
288 if (mask != 0U) {
289 if (stpmic2_register_read(pmic, regul->volt_cr, &value) != 0) {
290 return RET_ERROR_GENERIC;
291 }
292
293 value = (value >> regul->volt_shift) & mask;
294 }
295
296 if (value > regul->volt_table_size) {
297 return RET_ERROR_GENERIC;
298 }
299
300 *val = regul->volt_table[value];
301
302 return RET_SUCCESS;
303 }
304
voltage_to_index(const struct regul_struct * regul,uint16_t millivolts)305 static size_t voltage_to_index(const struct regul_struct *regul,
306 uint16_t millivolts)
307 {
308 unsigned int i;
309
310 assert(regul->volt_table);
311 for (i = 0U; i < regul->volt_table_size; i++) {
312 if (regul->volt_table[i] == millivolts) {
313 return i;
314 }
315 }
316
317 return VOLTAGE_INDEX_INVALID;
318 }
319
stpmic2_regulator_set_voltage(struct pmic_handle_s * pmic,uint8_t id,uint16_t millivolts)320 int stpmic2_regulator_set_voltage(struct pmic_handle_s *pmic,
321 uint8_t id, uint16_t millivolts)
322 {
323 const struct regul_struct *regul = ®ul_table[id];
324 size_t index;
325 uint8_t mask;
326
327 if (!regul->volt_table_size) {
328 return RET_SUCCESS;
329 }
330
331 mask = regul->volt_table_size - 1U;
332
333 index = voltage_to_index(regul, millivolts);
334 if (index == VOLTAGE_INDEX_INVALID) {
335 return RET_ERROR_GENERIC;
336 }
337
338 return stpmic2_register_update(pmic, regul->volt_cr,
339 index << regul->volt_shift,
340 mask << regul->volt_shift);
341 }
342
343 /* update both normal and alternate register */
stpmic2_update_en_crs(struct pmic_handle_s * pmic,uint8_t id,uint8_t value,uint8_t mask)344 static int stpmic2_update_en_crs(struct pmic_handle_s *pmic, uint8_t id,
345 uint8_t value, uint8_t mask)
346 {
347 const struct regul_struct *regul = ®ul_table[id];
348
349 if (stpmic2_register_update(pmic, regul->en_cr, value, mask) != 0) {
350 return RET_ERROR_GENERIC;
351 }
352
353 if (stpmic2_register_update(pmic, regul->alt_en_cr, value, mask) != 0) {
354 return RET_ERROR_GENERIC;
355 }
356
357 return RET_SUCCESS;
358 }
359
stpmic2_regulator_get_prop(struct pmic_handle_s * pmic,uint8_t id,enum stpmic2_prop_id prop)360 int stpmic2_regulator_get_prop(struct pmic_handle_s *pmic, uint8_t id,
361 enum stpmic2_prop_id prop)
362 {
363 const struct regul_struct *regul = ®ul_table[id];
364 uint8_t val;
365
366 VERBOSE("%s: get prop 0x%x\n", regul->name, prop);
367
368 switch (prop) {
369 case STPMIC2_BYPASS:
370 if ((id <= STPMIC2_BUCK7) || (id == STPMIC2_LDO1) ||
371 (id == STPMIC2_LDO4) || (id == STPMIC2_REFDDR) ||
372 (pmic->ref_id != PMIC_REF_ID_STPMIC25)) {
373 return 0;
374 }
375
376 if (stpmic2_register_read(pmic, regul->en_cr, &val) != 0) {
377 return -EIO;
378 }
379
380 if ((val & LDO_BYPASS) != 0) {
381 return 1;
382 }
383
384 break;
385 default:
386 ERROR("Invalid prop %u\n", prop);
387 panic();
388 }
389
390 return 0;
391 }
392
stpmic2_regulator_set_prop(struct pmic_handle_s * pmic,uint8_t id,enum stpmic2_prop_id prop,uint32_t arg)393 int stpmic2_regulator_set_prop(struct pmic_handle_s *pmic, uint8_t id,
394 enum stpmic2_prop_id prop, uint32_t arg)
395 {
396 const struct regul_struct *regul = ®ul_table[id];
397
398 VERBOSE("%s: set prop 0x%x arg=%u\n", regul->name, prop, arg);
399
400 switch (prop) {
401 case STPMIC2_PULL_DOWN:
402 return stpmic2_register_update(pmic, regul->pd_reg,
403 regul->pd_val,
404 regul->pd_val);
405 case STPMIC2_MASK_RESET:
406 if (!regul->msrt_mask) {
407 return RET_ERROR_NOT_SUPPORTED;
408 }
409 /* enable mask reset */
410 return stpmic2_register_update(pmic, regul->msrt_reg,
411 regul->msrt_mask,
412 regul->msrt_mask);
413 case STPMIC2_BYPASS:
414 if ((id <= STPMIC2_BUCK7) || (id == STPMIC2_LDO1) ||
415 (id == STPMIC2_LDO4) || (id == STPMIC2_REFDDR) ||
416 (pmic->ref_id != PMIC_REF_ID_STPMIC25)) {
417 return RET_ERROR_NOT_SUPPORTED;
418 }
419
420 /* clear sink source mode */
421 if ((id == STPMIC2_LDO3) && (arg != 0U)) {
422 if (stpmic2_update_en_crs(pmic, id, 0, LDO3_SNK_SRC) != 0) {
423 return RET_ERROR_GENERIC;
424 }
425 }
426
427 /* enable bypass mode */
428 return stpmic2_update_en_crs(pmic, id,
429 (arg != 0U) ? LDO_BYPASS : 0,
430 LDO_BYPASS);
431 case STPMIC2_SINK_SOURCE:
432 if (id != STPMIC2_LDO3) {
433 return RET_ERROR_NOT_SUPPORTED;
434 }
435
436 /* clear bypass mode */
437 if (stpmic2_update_en_crs(pmic, id, 0, LDO_BYPASS) != 0) {
438 return RET_ERROR_GENERIC;
439 }
440
441 return stpmic2_update_en_crs(pmic, id, LDO3_SNK_SRC,
442 LDO3_SNK_SRC);
443 case STPMIC2_OCP:
444 return stpmic2_register_update(pmic, regul->ocp_reg,
445 regul->ocp_mask,
446 regul->ocp_mask);
447 default:
448 ERROR("Invalid prop %u\n", prop);
449 panic();
450 }
451
452 return -EPERM;
453 }
454
stpmic2_switch_off(struct pmic_handle_s * pmic)455 int stpmic2_switch_off(struct pmic_handle_s *pmic)
456 {
457 return stpmic2_register_update(pmic, MAIN_CR, SWOFF, SWOFF);
458 }
459
stpmic2_dump_regulators(struct pmic_handle_s * pmic)460 void stpmic2_dump_regulators(struct pmic_handle_s *pmic)
461 {
462 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE
463 size_t i;
464 char const *name;
465
466 for (i = 0U; i < ARRAY_SIZE(regul_table); i++) {
467 uint16_t val;
468 bool state;
469
470 if (!regul_table[i].volt_cr) {
471 continue;
472 }
473
474 stpmic2_regulator_get_voltage(pmic, i, &val);
475 stpmic2_regulator_get_state(pmic, i, &state);
476
477 name = regul_table[i].name;
478
479 VERBOSE("PMIC regul %s: %s, %dmV\n",
480 name, state ? "EN" : "DIS", val);
481 }
482 #endif
483 }
484
stpmic2_get_version(struct pmic_handle_s * pmic,uint8_t * val)485 int stpmic2_get_version(struct pmic_handle_s *pmic, uint8_t *val)
486 {
487 return stpmic2_register_read(pmic, VERSION_SR, val);
488 }
489
stpmic2_get_product_id(struct pmic_handle_s * pmic,uint8_t * val)490 int stpmic2_get_product_id(struct pmic_handle_s *pmic, uint8_t *val)
491 {
492 return stpmic2_register_read(pmic, PRODUCT_ID, val);
493 }
494
stpmic2_is_buck1_high_voltage(struct pmic_handle_s * pmic,bool * high)495 int stpmic2_is_buck1_high_voltage(struct pmic_handle_s *pmic, bool *high)
496 {
497 int ret;
498 uint8_t val = 0;
499
500 if (pmic->ref_id == PMIC_REF_ID_STPMIC25) {
501 *high = false;
502 return 0;
503 }
504
505 ret = stpmic2_register_read(pmic, NVM_BUCK1_VOUT_SHR, &val);
506
507 *high = val & BUCK1_VRAN_GE_CFG;
508
509 return ret;
510 }
511