xref: /optee_os/core/drivers/regulator/regulator.c (revision e3830fc7605181399b826cf538e94da5fac95d26)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2023, STMicroelectronics
4  */
5 
6 #include <assert.h>
7 #include <compiler.h>
8 #include <config.h>
9 #include <drivers/regulator.h>
10 #include <initcall.h>
11 #include <keep.h>
12 #include <kernel/boot.h>
13 #include <kernel/delay.h>
14 #include <kernel/mutex.h>
15 #include <kernel/panic.h>
16 #include <kernel/pm.h>
17 #include <kernel/tee_time.h>
18 #include <kernel/thread.h>
19 #include <libfdt.h>
20 #include <limits.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <util.h>
25 
26 static SLIST_HEAD(, regulator) regulator_device_list =
27 	SLIST_HEAD_INITIALIZER(regulator);
28 
29 static void lock_regulator(struct regulator *regulator)
30 {
31 	/*
32 	 * Regulator operation may occur at runtime and during specific
33 	 * system power transition: power off, PM suspend and resume.
34 	 * These operate upon fastcall entries, under PSCI services
35 	 * execution, where non-secure world is not operational. In these
36 	 * cases we cannot take a mutex and will expect the mutex is
37 	 * unlocked.
38 	 */
39 	if (thread_get_id_may_fail() == THREAD_ID_INVALID) {
40 		assert(!regulator->lock.state);
41 		return;
42 	}
43 
44 	mutex_lock(&regulator->lock);
45 }
46 
47 static void unlock_regulator(struct regulator *regulator)
48 {
49 	if (thread_get_id_may_fail() == THREAD_ID_INVALID) {
50 		/* Path for PM sequences when with local Monitor */
51 		return;
52 	}
53 
54 	mutex_unlock(&regulator->lock);
55 }
56 
57 static TEE_Result set_state(struct regulator *regulator, bool on_not_off)
58 {
59 	if (!regulator->ops->set_state)
60 		return TEE_SUCCESS;
61 
62 	return regulator->ops->set_state(regulator, on_not_off);
63 }
64 
65 static TEE_Result regulator_refcnt_enable(struct regulator *regulator)
66 {
67 	TEE_Result res = TEE_ERROR_GENERIC;
68 
69 	FMSG("%s", regulator_name(regulator));
70 
71 	if (regulator->supply) {
72 		res = regulator_enable(regulator->supply);
73 		if (res)
74 			return res;
75 	}
76 
77 	lock_regulator(regulator);
78 
79 	if (!regulator->refcount) {
80 		res = set_state(regulator, true);
81 		if (res) {
82 			EMSG("regul %s set state failed with %#"PRIx32,
83 			     regulator_name(regulator), res);
84 
85 			unlock_regulator(regulator);
86 
87 			if (regulator->supply &&
88 			    regulator_disable(regulator->supply))
89 				panic();
90 
91 			return res;
92 		}
93 	}
94 
95 	regulator->refcount++;
96 	if (!regulator->refcount)
97 		panic();
98 
99 	FMSG("%s refcount: %u", regulator_name(regulator), regulator->refcount);
100 
101 	unlock_regulator(regulator);
102 
103 	return TEE_SUCCESS;
104 }
105 
106 TEE_Result regulator_enable(struct regulator *regulator)
107 {
108 	assert(regulator);
109 	FMSG("%s", regulator_name(regulator));
110 
111 	if (regulator_is_always_on(regulator))
112 		return TEE_SUCCESS;
113 
114 	return regulator_refcnt_enable(regulator);
115 }
116 
117 static TEE_Result regulator_refcnt_disable(struct regulator *regulator)
118 {
119 	FMSG("%s", regulator_name(regulator));
120 
121 	lock_regulator(regulator);
122 
123 	if (regulator->refcount == 1) {
124 		TEE_Result res = set_state(regulator, false);
125 
126 		if (res) {
127 			EMSG("regul %s set state failed with %#"PRIx32,
128 			     regulator_name(regulator), res);
129 			unlock_regulator(regulator);
130 			return res;
131 		}
132 	}
133 
134 	if (!regulator->refcount) {
135 		EMSG("Unbalanced %s", regulator_name(regulator));
136 		panic();
137 	}
138 
139 	regulator->refcount--;
140 
141 	FMSG("%s refcount: %u", regulator_name(regulator), regulator->refcount);
142 
143 	unlock_regulator(regulator);
144 
145 	if (regulator->supply && regulator_disable(regulator->supply)) {
146 		/* We can't leave this unbalanced */
147 		EMSG("Can't disable %s", regulator_name(regulator->supply));
148 		panic();
149 	}
150 
151 	return TEE_SUCCESS;
152 }
153 
154 TEE_Result regulator_disable(struct regulator *regulator)
155 {
156 	assert(regulator);
157 	FMSG("%s", regulator_name(regulator));
158 
159 	if (regulator_is_always_on(regulator))
160 		return TEE_SUCCESS;
161 
162 	return regulator_refcnt_disable(regulator);
163 }
164 
165 bool regulator_is_enabled(struct regulator *regulator)
166 {
167 	TEE_Result res = TEE_SUCCESS;
168 	bool enabled = false;
169 
170 	if (!regulator->ops->get_state)
171 		return true;
172 
173 	lock_regulator(regulator);
174 	res = regulator->ops->get_state(regulator, &enabled);
175 	unlock_regulator(regulator);
176 
177 	if (res)
178 		EMSG("regul %s get state failed with %#"PRIx32,
179 		     regulator_name(regulator), res);
180 
181 	return !res && enabled;
182 }
183 
184 TEE_Result regulator_set_voltage(struct regulator *regulator, int level_uv)
185 {
186 	TEE_Result res = TEE_ERROR_GENERIC;
187 
188 	assert(regulator);
189 	FMSG("%s %duV", regulator_name(regulator), level_uv);
190 
191 	if (level_uv < regulator->min_uv || level_uv > regulator->max_uv)
192 		return TEE_ERROR_BAD_PARAMETERS;
193 
194 	if (level_uv == regulator->cur_uv)
195 		return TEE_SUCCESS;
196 
197 	if (!regulator->ops->set_voltage)
198 		return TEE_ERROR_NOT_SUPPORTED;
199 
200 	lock_regulator(regulator);
201 	res = regulator->ops->set_voltage(regulator, level_uv);
202 	unlock_regulator(regulator);
203 
204 	if (res) {
205 		EMSG("regul %s set volt failed with %#"PRIx32,
206 		     regulator_name(regulator), res);
207 		return res;
208 	}
209 
210 	regulator->cur_uv = level_uv;
211 
212 	return TEE_SUCCESS;
213 }
214 
215 TEE_Result regulator_register(struct regulator *regulator)
216 {
217 	TEE_Result res = TEE_SUCCESS;
218 	int min_uv = 0;
219 	int max_uv = 0;
220 	int uv = 0;
221 
222 	if (!regulator || !regulator->ops ||
223 	    regulator->flags & ~REGULATOR_FLAGS_MASK)
224 		return TEE_ERROR_BAD_PARAMETERS;
225 
226 	regulator_get_range(regulator, &min_uv, &max_uv);
227 	if (min_uv > max_uv)
228 		return TEE_ERROR_BAD_PARAMETERS;
229 
230 	/* Sanitize regulator effective level */
231 	if (regulator->ops->get_voltage) {
232 		res = regulator->ops->get_voltage(regulator, &uv);
233 		if (res)
234 			return res;
235 	} else {
236 		uv = min_uv;
237 	}
238 	regulator->cur_uv = uv;
239 
240 	if (uv < min_uv || uv > max_uv) {
241 		res = regulator_set_voltage(regulator, min_uv);
242 		if (res)
243 			return res;
244 	}
245 
246 	/* Unbalanced enable refcount to keep always-on regulators enabled */
247 	if (regulator_is_always_on(regulator)) {
248 		res = regulator_refcnt_enable(regulator);
249 		if (res)
250 			return res;
251 	}
252 
253 	SLIST_INSERT_HEAD(&regulator_device_list, regulator, link);
254 
255 	return TEE_SUCCESS;
256 }
257 
258 /*
259  * Log regulators state
260  */
261 void regulator_print_state(const char *message __maybe_unused)
262 {
263 	struct regulator *regulator = NULL;
264 
265 	DMSG("Regulator state: %s", message);
266 	DMSG("name     use\ten\tuV\tmin\tmax\tflags\tsupply");
267 
268 	SLIST_FOREACH(regulator, &regulator_device_list, link)
269 		DMSG("%8s %u\t%d\t%d\t%d\t%d\t%#x\t%s\n",
270 		     regulator->name, regulator->refcount,
271 		     regulator_is_enabled(regulator),
272 		     regulator_get_voltage(regulator),
273 		     regulator->min_uv, regulator->max_uv, regulator->flags,
274 		     regulator->supply ? regulator_name(regulator->supply) :
275 		     "<none>");
276 }
277 
278 /*
279  * Clean-up regulators that are not used.
280  */
281 static TEE_Result regulator_core_cleanup(void)
282 {
283 	struct regulator *regulator = NULL;
284 
285 	SLIST_FOREACH(regulator, &regulator_device_list, link) {
286 		if (!regulator->refcount) {
287 			DMSG("disable %s", regulator_name(regulator));
288 			lock_regulator(regulator);
289 			set_state(regulator, false /* disable */);
290 			unlock_regulator(regulator);
291 		}
292 	}
293 
294 	regulator_print_state(__func__);
295 
296 	return TEE_SUCCESS;
297 }
298 
299 release_init_resource(regulator_core_cleanup);
300