xref: /optee_os/core/drivers/regulator/regulator_dt.c (revision 4e51bea94caee316c36c2c52a31177d0e385c6cb)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2022-2023, STMicroelectronics
4  */
5 
6 #include <assert.h>
7 #include <compiler.h>
8 #include <drivers/regulator.h>
9 #include <initcall.h>
10 #include <kernel/dt_driver.h>
11 #include <kernel/panic.h>
12 #include <libfdt.h>
13 #include <stdbool.h>
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <tee_api_defines_extensions.h>
18 #include <util.h>
19 
20 /*
21  * struct regulator_property - DT binding boolean property names
22  * @name: Property name in the regulator DT node
23  * @flag: Mask of the related REGULATOR_* boolean property
24  */
25 struct regulator_property {
26 	const char *name;
27 	unsigned int flag;
28 };
29 
30 static struct regulator_property flag_prop[] = {
31 	{
32 		.name = "regulator-always-on",
33 		.flag = REGULATOR_ALWAYS_ON,
34 	},
35 	{
36 		.name = "regulator-pull-down",
37 		.flag = REGULATOR_PULL_DOWN,
38 	},
39 	{
40 		.name = "regulator-boot-on",
41 		.flag = REGULATOR_BOOT_ON,
42 	},
43 	{
44 		.name = "regulator-over-current-protection",
45 		.flag = REGULATOR_OVER_CURRENT,
46 	},
47 };
48 
49 /*
50  * struct pending_regu - Regulators waiting for their supply to be ready
51  *
52  * @fdt: DT to work on
53  * @node: Node of the regulator in @fdt
54  * @supply_phandle: Phandle in @fdt of the regulator supply, or 0 if no supply
55  * @regulator_allocated: True if framework allocates and frees @regulator
56  * @regulator: Regulator device instance
57  * @link: Link in pending regulators list
58  *
59  * When calling regulator_dt_register(), either the regulator depends on a
60  * supply that is not initialized, or this dependency is resolved (there is
61  * no supply or the supply is ready to use).
62  *
63  * In the former case, the regulator is placed in a pending regulator list.
64  * Each time a new regulator is successfully registered, we process the
65  * pending regulator list in case some pending regulators find their
66  * supply and finalize their registration and initialization.
67  *
68  * In the latter case, the regulator registration and initialization
69  * are processed.
70  */
71 struct pending_regu {
72 	const void *fdt;
73 	int node;
74 	int supply_phandle;
75 	bool regulator_allocated;
76 	struct regulator *regulator;
77 	SLIST_ENTRY(pending_regu) link;
78 };
79 
80 static SLIST_HEAD(, pending_regu) pending_regu_list =
81 	SLIST_HEAD_INITIALIZER(pending_regu);
82 
83 /* Helper to find the phandle of a regulator supply */
get_supply_phandle(const void * fdt,int node,const char * supply_name,uint32_t * supply_phandle)84 static TEE_Result get_supply_phandle(const void *fdt, int node,
85 				     const char *supply_name,
86 				     uint32_t *supply_phandle)
87 {
88 	char *supply_prop = NULL;
89 	size_t prop_len = 0;
90 	const fdt32_t *cuint = NULL;
91 	int len = 0;
92 
93 	prop_len = strlen(supply_name) + strlen("-supply") + 1;
94 	supply_prop = calloc(1, prop_len);
95 	if (!supply_prop)
96 		return TEE_ERROR_OUT_OF_MEMORY;
97 
98 	len = snprintf(supply_prop, prop_len, "%s-supply", supply_name);
99 	assert(len > 0 && (size_t)len == prop_len - 1);
100 
101 	cuint = fdt_getprop(fdt, node, supply_prop, &len);
102 	free(supply_prop);
103 	if (!cuint || (size_t)len != sizeof(*cuint)) {
104 		if (len != -FDT_ERR_NOTFOUND)
105 			return TEE_ERROR_GENERIC;
106 
107 		*supply_phandle = 0;
108 
109 		return TEE_SUCCESS;
110 	}
111 
112 	*supply_phandle = fdt32_to_cpu(*cuint);
113 	assert(*supply_phandle);
114 
115 	return TEE_SUCCESS;
116 }
117 
regulator_dt_get_supply(const void * fdt,int node,const char * supply_name,struct regulator ** regulator)118 TEE_Result regulator_dt_get_supply(const void *fdt, int node,
119 				   const char *supply_name,
120 				   struct regulator **regulator)
121 {
122 	struct dt_driver_provider *provider = NULL;
123 	TEE_Result res = TEE_ERROR_GENERIC;
124 	uint32_t supply_phandle = 0;
125 
126 	res = get_supply_phandle(fdt, node, supply_name, &supply_phandle);
127 	if (res)
128 		return res;
129 
130 	provider = dt_driver_get_provider_by_phandle(supply_phandle,
131 						     DT_DRIVER_REGULATOR);
132 	if (!provider)
133 		return TEE_ERROR_DEFER_DRIVER_INIT;
134 
135 	*regulator = dt_driver_provider_priv_data(provider);
136 	assert(*regulator);
137 
138 	return TEE_SUCCESS;
139 }
140 
141 /* Helper function to register a regulator provider instance */
regulator_register_provider(const void * fdt,int node,struct regulator * regulator)142 static TEE_Result regulator_register_provider(const void *fdt, int node,
143 					      struct regulator *regulator)
144 {
145 	TEE_Result res = TEE_ERROR_GENERIC;
146 	uint32_t phandle = 0;
147 
148 	phandle = fdt_get_phandle(fdt, node);
149 	switch (phandle) {
150 	case 0:
151 		/* We can ignore regulators without any phandle */
152 		return TEE_SUCCESS;
153 	case (uint32_t)-1:
154 		DMSG("Failed to find provider phandle");
155 		return TEE_ERROR_GENERIC;
156 	default:
157 		res = dt_driver_register_provider(fdt, node, NULL, regulator,
158 						  DT_DRIVER_REGULATOR);
159 		if (res)
160 			EMSG("Can't register regulator provider %s: %#"PRIx32,
161 			     regulator_name(regulator), res);
162 
163 		return res;
164 	}
165 }
166 
register_final(const void * fdt,int node,struct regulator * regulator)167 static TEE_Result register_final(const void *fdt, int node,
168 				 struct regulator *regulator)
169 {
170 	TEE_Result res = TEE_ERROR_GENERIC;
171 
172 	FMSG("Regulator: finalize %s registering", regulator_name(regulator));
173 
174 	res = regulator_register(regulator);
175 	if (res)
176 		return res;
177 
178 	if (regulator->ops->supplied_init) {
179 		res = regulator->ops->supplied_init(regulator, fdt, node);
180 		if (res)
181 			return res;
182 	}
183 
184 	return regulator_register_provider(fdt, node, regulator);
185 }
186 
187 /*
188  * Pending regulators list: stores all regulator devices registered by their
189  * driver but not yet available to consumers as their dependency on their
190  * regulator supply is not yet resolved (supply has not been initialized yet).
191  */
192 
print_pending_regulators(void)193 static void __maybe_unused print_pending_regulators(void)
194 {
195 	struct pending_regu *pending = NULL;
196 
197 	SLIST_FOREACH(pending, &pending_regu_list, link)
198 		DMSG("Pending regulator %s",
199 		     regulator_name(pending->regulator));
200 }
201 
202 /*
203  * Returns true if at least 1 regulator found its supply and finalized its
204  * registration.
205  */
process_pending_list(void)206 static bool process_pending_list(void)
207 {
208 	struct dt_driver_provider *p = NULL;
209 	struct pending_regu *pending = NULL;
210 	struct pending_regu *next = NULL;
211 	bool supplied = false;
212 
213 	SLIST_FOREACH_SAFE(pending, &pending_regu_list, link, next) {
214 		p = dt_driver_get_provider_by_phandle(pending->supply_phandle,
215 						      DT_DRIVER_REGULATOR);
216 		if (!p)
217 			continue;
218 
219 		pending->regulator->supply = dt_driver_provider_priv_data(p);
220 
221 		if (register_final(pending->fdt, pending->node,
222 				   pending->regulator))
223 			panic();
224 
225 		SLIST_REMOVE(&pending_regu_list, pending, pending_regu, link);
226 		free(pending);
227 
228 		supplied = true;
229 	}
230 
231 	return supplied;
232 }
233 
234 /*
235  * Attempt to register pending regulators once their supply is found.
236  * Return true if pending regulator list is empty upon processing.
237  */
resolve_pending_list(void)238 static bool resolve_pending_list(void)
239 {
240 	while (process_pending_list())
241 		;
242 
243 	return SLIST_EMPTY(&pending_regu_list);
244 }
245 
246 /* Adds a regulator to the pending list: those waiting for their supply */
add_to_pending_list(const void * fdt,int node,struct regulator * regulator,uint32_t supply_phandle,bool regulator_allocated)247 static TEE_Result add_to_pending_list(const void *fdt, int node,
248 				      struct regulator *regulator,
249 				      uint32_t supply_phandle,
250 				      bool regulator_allocated)
251 {
252 	struct pending_regu *pending = NULL;
253 
254 	pending = calloc(1, sizeof(*pending));
255 	if (!pending)
256 		return TEE_ERROR_OUT_OF_MEMORY;
257 
258 	*pending = (struct pending_regu){
259 		.fdt = fdt,
260 		.node = node,
261 		.supply_phandle = supply_phandle,
262 		.regulator = regulator,
263 		.regulator_allocated = regulator_allocated,
264 	};
265 
266 	SLIST_INSERT_HEAD(&pending_regu_list, pending, link);
267 
268 	return TEE_SUCCESS;
269 }
270 
parse_dt(const void * fdt,int node,struct regulator * regulator)271 static TEE_Result parse_dt(const void *fdt, int node,
272 			   struct regulator *regulator)
273 {
274 	struct regulator_property *fp = NULL;
275 	const fdt32_t *cuint = NULL;
276 	int len = 0;
277 
278 	FMSG("Regulator: parse DT node %s", fdt_get_name(fdt, node, NULL));
279 
280 	cuint = fdt_getprop(fdt, node, "regulator-name", NULL);
281 	if (cuint) {
282 		/* Replace name with the one found from the DT node */
283 		char *name = (char *)cuint;
284 
285 		free(regulator->name);
286 		regulator->name = strdup(name);
287 		if (!regulator->name)
288 			return TEE_ERROR_OUT_OF_MEMORY;
289 	}
290 
291 	for (fp = flag_prop; fp < (flag_prop + ARRAY_SIZE(flag_prop)); fp++)
292 		if (fdt_getprop(fdt, node, fp->name, NULL))
293 			regulator->flags |= fp->flag;
294 
295 	cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", &len);
296 	if (cuint && len == sizeof(*cuint))
297 		regulator->min_uv = fdt32_to_cpu(*cuint);
298 	else if (cuint || len != -FDT_ERR_NOTFOUND)
299 		panic();
300 
301 	cuint = fdt_getprop(fdt, node, "regulator-max-microvolt", &len);
302 	if (cuint && len == sizeof(*cuint)) {
303 		regulator->max_uv = fdt32_to_cpu(*cuint);
304 
305 		if (regulator->max_uv < regulator->min_uv) {
306 			EMSG("Regulator %s max_uv %d < %d",
307 			     regulator_name(regulator), regulator->max_uv,
308 			     regulator->min_uv);
309 
310 			return TEE_ERROR_GENERIC;
311 		}
312 	} else if (cuint || len != -FDT_ERR_NOTFOUND) {
313 		panic();
314 	} else {
315 		regulator->max_uv = INT_MAX;
316 	}
317 
318 	cuint = fdt_getprop(fdt, node, "regulator-ramp-delay", NULL);
319 	if (cuint) {
320 		regulator->ramp_delay_uv_per_us = fdt32_to_cpu(*cuint);
321 		FMSG("%s: ramp delay = %"PRIu32" (uV/us)",
322 		     regulator_name(regulator),
323 		     regulator->ramp_delay_uv_per_us);
324 	}
325 
326 	cuint = fdt_getprop(fdt, node, "regulator-enable-ramp-delay", NULL);
327 	if (cuint) {
328 		regulator->enable_ramp_delay_us = fdt32_to_cpu(*cuint);
329 		FMSG("%s: enable ramp delay = %u (us)",
330 		     regulator_name(regulator),
331 		     regulator->enable_ramp_delay_us);
332 	}
333 
334 	return TEE_SUCCESS;
335 }
336 
337 /*
338  * API function to register a DRIVER_REGULATOR provider instance.
339  * The registration can be deferred if the regulator supply (if any)
340  * is not yet registered, in which case the regulator is placed in
341  * a regulator pending list.
342  */
regulator_dt_register(const void * fdt,int node,int provider_node,const struct regu_dt_desc * desc)343 TEE_Result regulator_dt_register(const void *fdt, int node, int provider_node,
344 				 const struct regu_dt_desc *desc)
345 {
346 	TEE_Result res = TEE_ERROR_OUT_OF_MEMORY;
347 	struct regulator *regulator = NULL;
348 	uint32_t supply_phandle = 0;
349 	char *name = NULL;
350 
351 	assert(desc);
352 
353 	if (!desc->regulator) {
354 		regulator = calloc(1, sizeof(*regulator));
355 		if (!regulator)
356 			return TEE_ERROR_OUT_OF_MEMORY;
357 	} else {
358 		regulator = desc->regulator;
359 		memset(regulator, 0, sizeof(*regulator));
360 	}
361 
362 	if (desc->name) {
363 		/* Will be freed if overridden by DT node content */
364 		name = strdup(desc->name);
365 		if (!name)
366 			goto err_free;
367 	}
368 
369 	*regulator = (struct regulator){
370 		.name = name,
371 		.ops = desc->ops,
372 		.priv = desc->priv,
373 	};
374 
375 	res = parse_dt(fdt, node, regulator);
376 	if (res)
377 		goto err_free;
378 
379 	if (desc->supply_name) {
380 		res = get_supply_phandle(fdt, provider_node, desc->supply_name,
381 					 &supply_phandle);
382 		if (res)
383 			goto err_free;
384 	}
385 
386 	if (supply_phandle) {
387 		res = add_to_pending_list(fdt, node, regulator, supply_phandle,
388 					  !desc->regulator);
389 		if (res)
390 			goto err_free;
391 	} else {
392 		res = register_final(fdt, node, regulator);
393 		if (res)
394 			goto err_free;
395 	}
396 
397 	resolve_pending_list();
398 
399 	return TEE_SUCCESS;
400 
401 err_free:
402 	/* This function cannot return TEE_ERROR_DEFER_DRIVER_INIT */
403 	assert(res != TEE_ERROR_DEFER_DRIVER_INIT);
404 
405 	free(regulator->name);
406 	if (!desc->regulator)
407 		free(regulator);
408 
409 	return res;
410 }
411 
release_regulator_pending_lists(void)412 static TEE_Result release_regulator_pending_lists(void)
413 {
414 	struct pending_regu *pending = NULL;
415 	struct pending_regu *next = NULL;
416 
417 	if (!SLIST_EMPTY(&pending_regu_list))
418 		DMSG("Some regulators were not supplied:");
419 
420 	SLIST_FOREACH_SAFE(pending, &pending_regu_list, link, next) {
421 		DMSG(" Unsupplied regulator %s",
422 		     regulator_name(pending->regulator));
423 
424 		SLIST_REMOVE(&pending_regu_list, pending, pending_regu, link);
425 		if (pending->regulator_allocated)
426 			free(pending->regulator);
427 		free(pending);
428 	}
429 
430 	return TEE_SUCCESS;
431 }
432 
433 release_init_resource(release_regulator_pending_lists);
434