• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024, 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 buck1236_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 buck457_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_REFDDR(regu_name, ID, table) { \
123 	.name			= regu_name, \
124 	.volt_table		= table, \
125 	.volt_table_size	= ARRAY_SIZE(table), \
126 	.en_cr			= ID ## _MAIN_CR, \
127 	.volt_cr		= ID ## _MAIN_CR, \
128 	.alt_en_cr		= ID ## _ALT_CR, \
129 	.msrt_reg		= BUCKS_MRST_CR, \
130 	.msrt_mask		= ID ## _MRST, \
131 	.pd_reg			= LDOS_PD_CR2, \
132 	.pd_val			= ID ## _PD, \
133 	.ocp_reg		= FS_OCP_CR1, \
134 	.ocp_mask		= FS_OCP_ ## ID, \
135 }
136 
137 /* Table of Regulators in PMIC SoC */
138 static const struct regul_struct regul_table[STPMIC2_NB_REG] = {
139 	[STPMIC2_BUCK1] = DEFINE_BUCK("buck1", BUCK1, BUCKS_PD_CR1,
140 				      buck1236_volt_table),
141 	[STPMIC2_BUCK2] = DEFINE_BUCK("buck2", BUCK2, BUCKS_PD_CR1,
142 				      buck1236_volt_table),
143 	[STPMIC2_BUCK3] = DEFINE_BUCK("buck3", BUCK3, BUCKS_PD_CR1,
144 				      buck1236_volt_table),
145 	[STPMIC2_BUCK4] = DEFINE_BUCK("buck4", BUCK4, BUCKS_PD_CR1,
146 				      buck457_volt_table),
147 	[STPMIC2_BUCK5] = DEFINE_BUCK("buck5", BUCK5, BUCKS_PD_CR2,
148 				      buck457_volt_table),
149 	[STPMIC2_BUCK6] = DEFINE_BUCK("buck6", BUCK6, BUCKS_PD_CR2,
150 				      buck1236_volt_table),
151 	[STPMIC2_BUCK7] = DEFINE_BUCK("buck7", BUCK7, BUCKS_PD_CR2,
152 				      buck457_volt_table),
153 
154 	[STPMIC2_REFDDR] = DEFINE_REFDDR("refddr", REFDDR, refddr_volt_table),
155 
156 	[STPMIC2_LDO1] = DEFINE_LDOx("ldo1", LDO1, ldo1_volt_table),
157 	[STPMIC2_LDO2] = DEFINE_LDOx("ldo2", LDO2, ldo235678_volt_table),
158 	[STPMIC2_LDO3] = DEFINE_LDOx("ldo3", LDO3, ldo235678_volt_table),
159 	[STPMIC2_LDO4] = DEFINE_LDOx("ldo4", LDO4, ldo4_volt_table),
160 	[STPMIC2_LDO5] = DEFINE_LDOx("ldo5", LDO5, ldo235678_volt_table),
161 	[STPMIC2_LDO6] = DEFINE_LDOx("ldo6", LDO6, ldo235678_volt_table),
162 	[STPMIC2_LDO7] = DEFINE_LDOx("ldo7", LDO7, ldo235678_volt_table),
163 	[STPMIC2_LDO8] = DEFINE_LDOx("ldo8", LDO8, ldo235678_volt_table),
164 
165 };
166 
stpmic2_register_read(struct pmic_handle_s * pmic,uint8_t register_id,uint8_t * value)167 int stpmic2_register_read(struct pmic_handle_s *pmic,
168 			  uint8_t register_id, uint8_t *value)
169 {
170 	int ret = stm32_i2c_mem_read(pmic->i2c_handle,
171 				     pmic->i2c_addr,
172 				     (uint16_t)register_id,
173 				     I2C_MEMADD_SIZE_8BIT, value,
174 				     1, I2C_TIMEOUT_MS);
175 	if (ret != 0) {
176 		ERROR("Failed to read reg:0x%x\n", register_id);
177 	}
178 
179 	return ret;
180 }
181 
stpmic2_register_write(struct pmic_handle_s * pmic,uint8_t register_id,uint8_t value)182 int stpmic2_register_write(struct pmic_handle_s *pmic,
183 			   uint8_t register_id, uint8_t value)
184 {
185 	uint8_t val = value;
186 	int ret = stm32_i2c_mem_write(pmic->i2c_handle,
187 				      pmic->i2c_addr,
188 				      (uint16_t)register_id,
189 				      I2C_MEMADD_SIZE_8BIT, &val,
190 				      1, I2C_TIMEOUT_MS);
191 	if (ret != 0) {
192 		ERROR("Failed to write reg:0x%x\n", register_id);
193 	}
194 
195 	return ret;
196 }
197 
stpmic2_register_update(struct pmic_handle_s * pmic,uint8_t register_id,uint8_t value,uint8_t mask)198 int stpmic2_register_update(struct pmic_handle_s *pmic,
199 			    uint8_t register_id, uint8_t value, uint8_t mask)
200 {
201 	int status;
202 	uint8_t val = 0U;
203 
204 	status = stpmic2_register_read(pmic, register_id, &val);
205 	if (status != 0) {
206 		return status;
207 	}
208 
209 	val = (val & ((uint8_t)~mask)) | (value & mask);
210 
211 	VERBOSE("REG:0x%x v=0x%x mask=0x%x -> 0x%x\n",
212 		register_id, value, mask, val);
213 
214 	return stpmic2_register_write(pmic, register_id, val);
215 }
216 
stpmic2_regulator_set_state(struct pmic_handle_s * pmic,uint8_t id,bool enable)217 int stpmic2_regulator_set_state(struct pmic_handle_s *pmic,
218 				uint8_t id, bool enable)
219 {
220 	const struct regul_struct *regul = &regul_table[id];
221 
222 	if (enable) {
223 		return stpmic2_register_update(pmic, regul->en_cr, 1U, 1U);
224 	} else {
225 		return stpmic2_register_update(pmic, regul->en_cr, 0, 1U);
226 	}
227 }
228 
stpmic2_regulator_get_state(struct pmic_handle_s * pmic,uint8_t id,bool * enabled)229 int stpmic2_regulator_get_state(struct pmic_handle_s *pmic,
230 				uint8_t id, bool *enabled)
231 {
232 	const struct regul_struct *regul = &regul_table[id];
233 	uint8_t val;
234 
235 	if (stpmic2_register_read(pmic, regul->en_cr, &val) != 0) {
236 		return RET_ERROR_GENERIC;
237 	}
238 
239 	*enabled = (val & 1U) == 1U;
240 
241 	return RET_SUCCESS;
242 }
243 
stpmic2_regulator_levels_mv(struct pmic_handle_s * pmic,uint8_t id,const uint16_t ** levels,size_t * levels_count)244 int stpmic2_regulator_levels_mv(struct pmic_handle_s *pmic,
245 				uint8_t id, const uint16_t **levels,
246 				size_t *levels_count)
247 {
248 	const struct regul_struct *regul = &regul_table[id];
249 
250 	if (regul == NULL) {
251 		return RET_ERROR_BAD_PARAMETERS;
252 	}
253 
254 	if (levels_count != NULL) {
255 		*levels_count = regul->volt_table_size;
256 	}
257 	if (levels != NULL) {
258 		*levels = regul->volt_table;
259 	}
260 
261 	return RET_SUCCESS;
262 }
263 
stpmic2_regulator_get_voltage(struct pmic_handle_s * pmic,uint8_t id,uint16_t * val)264 int stpmic2_regulator_get_voltage(struct pmic_handle_s *pmic,
265 				  uint8_t id, uint16_t *val)
266 {
267 	const struct regul_struct *regul = &regul_table[id];
268 	uint8_t value = 0U;
269 	uint8_t mask;
270 
271 	if (regul->volt_table_size == 0U) {
272 		return RET_ERROR_GENERIC;
273 	}
274 
275 	mask = regul->volt_table_size - 1U;
276 	if (mask != 0U) {
277 		if (stpmic2_register_read(pmic, regul->volt_cr, &value) != 0) {
278 			return RET_ERROR_GENERIC;
279 		}
280 
281 		value = (value >> regul->volt_shift) & mask;
282 	}
283 
284 	if (value > regul->volt_table_size) {
285 		return RET_ERROR_GENERIC;
286 	}
287 
288 	*val = regul->volt_table[value];
289 
290 	return RET_SUCCESS;
291 }
292 
voltage_to_index(const struct regul_struct * regul,uint16_t millivolts)293 static size_t voltage_to_index(const struct regul_struct *regul,
294 			       uint16_t millivolts)
295 {
296 	unsigned int i;
297 
298 	assert(regul->volt_table);
299 	for (i = 0U; i < regul->volt_table_size; i++) {
300 		if (regul->volt_table[i] == millivolts) {
301 			return i;
302 		}
303 	}
304 
305 	return VOLTAGE_INDEX_INVALID;
306 }
307 
stpmic2_regulator_set_voltage(struct pmic_handle_s * pmic,uint8_t id,uint16_t millivolts)308 int stpmic2_regulator_set_voltage(struct pmic_handle_s *pmic,
309 				  uint8_t id, uint16_t millivolts)
310 {
311 	const struct regul_struct *regul = &regul_table[id];
312 	size_t index;
313 	uint8_t mask;
314 
315 	if (!regul->volt_table_size) {
316 		return RET_SUCCESS;
317 	}
318 
319 	mask = regul->volt_table_size - 1U;
320 
321 	index = voltage_to_index(regul, millivolts);
322 	if (index == VOLTAGE_INDEX_INVALID) {
323 		return RET_ERROR_GENERIC;
324 	}
325 
326 	return stpmic2_register_update(pmic, regul->volt_cr,
327 				       index << regul->volt_shift,
328 				       mask << regul->volt_shift);
329 }
330 
331 /* update both normal and alternate register */
stpmic2_update_en_crs(struct pmic_handle_s * pmic,uint8_t id,uint8_t value,uint8_t mask)332 static int stpmic2_update_en_crs(struct pmic_handle_s *pmic, uint8_t id,
333 				 uint8_t value, uint8_t mask)
334 {
335 	const struct regul_struct *regul = &regul_table[id];
336 
337 	if (stpmic2_register_update(pmic, regul->en_cr, value, mask) != 0) {
338 		return RET_ERROR_GENERIC;
339 	}
340 
341 	if (stpmic2_register_update(pmic, regul->alt_en_cr, value, mask) != 0) {
342 		return RET_ERROR_GENERIC;
343 	}
344 
345 	return RET_SUCCESS;
346 }
347 
stpmic2_regulator_get_prop(struct pmic_handle_s * pmic,uint8_t id,enum stpmic2_prop_id prop)348 int stpmic2_regulator_get_prop(struct pmic_handle_s *pmic, uint8_t id,
349 			       enum stpmic2_prop_id prop)
350 {
351 	const struct regul_struct *regul = &regul_table[id];
352 	uint8_t val;
353 
354 	VERBOSE("%s: get prop 0x%x\n", regul->name, prop);
355 
356 	switch (prop) {
357 	case STPMIC2_BYPASS:
358 		if ((id <= STPMIC2_BUCK7) || (id == STPMIC2_LDO1) ||
359 		    (id == STPMIC2_LDO4) || (id == STPMIC2_REFDDR)) {
360 			return 0;
361 		}
362 
363 		if (stpmic2_register_read(pmic, regul->en_cr, &val) != 0) {
364 			return -EIO;
365 		}
366 
367 		if ((val & LDO_BYPASS) != 0) {
368 			return 1;
369 		}
370 
371 		break;
372 	default:
373 		ERROR("Invalid prop %u\n", prop);
374 		panic();
375 	}
376 
377 	return 0;
378 }
379 
stpmic2_regulator_set_prop(struct pmic_handle_s * pmic,uint8_t id,enum stpmic2_prop_id prop,uint32_t arg)380 int stpmic2_regulator_set_prop(struct pmic_handle_s *pmic, uint8_t id,
381 			       enum stpmic2_prop_id prop, uint32_t arg)
382 {
383 	const struct regul_struct *regul = &regul_table[id];
384 
385 	VERBOSE("%s: set prop 0x%x arg=%u\n", regul->name, prop, arg);
386 
387 	switch (prop) {
388 	case STPMIC2_PULL_DOWN:
389 		return stpmic2_register_update(pmic, regul->pd_reg,
390 					       regul->pd_val,
391 					       regul->pd_val);
392 	case STPMIC2_MASK_RESET:
393 		if (!regul->msrt_mask) {
394 			return RET_ERROR_NOT_SUPPORTED;
395 		}
396 		/* enable mask reset */
397 		return stpmic2_register_update(pmic, regul->msrt_reg,
398 					       regul->msrt_mask,
399 					       regul->msrt_mask);
400 	case STPMIC2_BYPASS:
401 		if ((id <= STPMIC2_BUCK7) || (id == STPMIC2_LDO1) ||
402 		    (id == STPMIC2_LDO4) || (id == STPMIC2_REFDDR)) {
403 			return RET_ERROR_NOT_SUPPORTED;
404 		}
405 
406 		/* clear sink source mode */
407 		if ((id == STPMIC2_LDO3) && (arg != 0U)) {
408 			if (stpmic2_update_en_crs(pmic, id, 0, LDO3_SNK_SRC) != 0) {
409 				return RET_ERROR_GENERIC;
410 			}
411 		}
412 
413 		/* enable bypass mode */
414 		return stpmic2_update_en_crs(pmic, id,
415 					     (arg != 0U) ? LDO_BYPASS : 0,
416 					     LDO_BYPASS);
417 	case STPMIC2_SINK_SOURCE:
418 		if (id != STPMIC2_LDO3) {
419 			return RET_ERROR_NOT_SUPPORTED;
420 		}
421 
422 		/* clear bypass mode */
423 		if (stpmic2_update_en_crs(pmic, id, 0, LDO_BYPASS) != 0) {
424 			return RET_ERROR_GENERIC;
425 		}
426 
427 		return stpmic2_update_en_crs(pmic, id, LDO3_SNK_SRC,
428 					     LDO3_SNK_SRC);
429 	case STPMIC2_OCP:
430 		return stpmic2_register_update(pmic, regul->ocp_reg,
431 					       regul->ocp_mask,
432 					       regul->ocp_mask);
433 	default:
434 		ERROR("Invalid prop %u\n", prop);
435 		panic();
436 	}
437 
438 	return -EPERM;
439 }
440 
441 #if EVENT_LOG_LEVEL == LOG_LEVEL_VERBOSE
stpmic2_dump_regulators(struct pmic_handle_s * pmic)442 void stpmic2_dump_regulators(struct pmic_handle_s *pmic)
443 {
444 	size_t i;
445 	char const *name;
446 
447 	for (i = 0U; i < ARRAY_SIZE(regul_table); i++) {
448 		uint16_t val;
449 		bool state;
450 
451 		if (!regul_table[i].volt_cr) {
452 			continue;
453 		}
454 
455 		stpmic2_regulator_get_voltage(pmic, i, &val);
456 		stpmic2_regulator_get_state(pmic, i, &state);
457 
458 		name = regul_table[i].name;
459 
460 		VERBOSE("PMIC regul %s: %s, %dmV\n",
461 			name, state ? "EN" : "DIS", val);
462 	}
463 }
464 #endif
465 
stpmic2_get_version(struct pmic_handle_s * pmic,uint8_t * val)466 int stpmic2_get_version(struct pmic_handle_s *pmic, uint8_t *val)
467 {
468 	return stpmic2_register_read(pmic, VERSION_SR, val);
469 }
470 
stpmic2_get_product_id(struct pmic_handle_s * pmic,uint8_t * val)471 int stpmic2_get_product_id(struct pmic_handle_s *pmic, uint8_t *val)
472 {
473 	return stpmic2_register_read(pmic, PRODUCT_ID, val);
474 }
475