xref: /openbsd/sys/dev/ofw/ofw_regulator.c (revision 097a140d)
1 /*	$OpenBSD: ofw_regulator.c,v 1.15 2020/12/23 11:58:36 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2016 Mark Kettenis
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/types.h>
19 #include <sys/systm.h>
20 #include <sys/malloc.h>
21 
22 #include <dev/ofw/openfirm.h>
23 #include <dev/ofw/ofw_gpio.h>
24 #include <dev/ofw/ofw_pinctrl.h>
25 #include <dev/ofw/ofw_regulator.h>
26 
27 #define REGULATOR_VOLTAGE	0
28 #define REGULATOR_CURRENT	1
29 
30 LIST_HEAD(, regulator_device) regulator_devices =
31 	LIST_HEAD_INITIALIZER(regulator_devices);
32 
33 int regulator_type(int);
34 uint32_t regulator_gpio_get(int);
35 int regulator_gpio_set(int, uint32_t);
36 
37 void
38 regulator_register(struct regulator_device *rd)
39 {
40 	rd->rd_volt_min = OF_getpropint(rd->rd_node,
41 	    "regulator-min-microvolt", 0);
42 	rd->rd_volt_max = OF_getpropint(rd->rd_node,
43 	    "regulator-max-microvolt", ~0);
44 	KASSERT(rd->rd_volt_min <= rd->rd_volt_max);
45 
46 	rd->rd_amp_min = OF_getpropint(rd->rd_node,
47 	    "regulator-min-microamp", 0);
48 	rd->rd_amp_max = OF_getpropint(rd->rd_node,
49 	    "regulator-max-microamp", ~0);
50 	KASSERT(rd->rd_amp_min <= rd->rd_amp_max);
51 
52 	rd->rd_ramp_delay =
53 	    OF_getpropint(rd->rd_node, "regulator-ramp-delay", 0);
54 
55 	if (rd->rd_get_voltage && rd->rd_set_voltage) {
56 		uint32_t voltage = rd->rd_get_voltage(rd->rd_cookie);
57 		if (voltage < rd->rd_volt_min)
58 			rd->rd_set_voltage(rd->rd_cookie, rd->rd_volt_min);
59 		if (voltage > rd->rd_volt_max)
60 			rd->rd_set_voltage(rd->rd_cookie, rd->rd_volt_max);
61 	}
62 
63 	if (rd->rd_get_current && rd->rd_set_current) {
64 		uint32_t current = rd->rd_get_current(rd->rd_cookie);
65 		if (current < rd->rd_amp_min)
66 			rd->rd_set_current(rd->rd_cookie, rd->rd_amp_min);
67 		if (current > rd->rd_amp_max)
68 			rd->rd_set_current(rd->rd_cookie, rd->rd_amp_max);
69 	}
70 
71 	rd->rd_phandle = OF_getpropint(rd->rd_node, "phandle", 0);
72 	if (rd->rd_phandle == 0)
73 		return;
74 
75 	LIST_INSERT_HEAD(&regulator_devices, rd, rd_list);
76 }
77 
78 int
79 regulator_type(int node)
80 {
81 	char type[16] = { 0 };
82 
83 	OF_getprop(node, "regulator-type", type, sizeof(type));
84 	if (strcmp(type, "current") == 0)
85 		return REGULATOR_CURRENT;
86 
87 	return REGULATOR_VOLTAGE;
88 }
89 
90 int
91 regulator_fixed_set(int node, int enable)
92 {
93 	uint32_t *gpio;
94 	uint32_t startup_delay;
95 	int len;
96 
97 	pinctrl_byname(node, "default");
98 
99 	/* The "gpio" property is optional. */
100 	len = OF_getproplen(node, "gpio");
101 	if (len < 0)
102 		return 0;
103 
104 	/*
105 	 * We deliberately ignore the "enable-active-high" property
106 	 * here.  Its presence (or absence) is used to override the
107 	 * polarity encoded by the GPIO flags in the device tree.  But
108 	 * supporting this behaviour is awkward since it would require
109 	 * interpreting the GPIO flags here which would be a layer
110 	 * violation since those flags may be driver-specific.  In
111 	 * practice the presence of "enable-active-high" is always
112 	 * aligned with the polarity encoded by the GPIO flags and any
113 	 * discrepancy is considered to be a bug by the Linux device
114 	 * tree maintainers.
115 	 */
116 
117 	gpio = malloc(len, M_TEMP, M_WAITOK);
118 	OF_getpropintarray(node, "gpio", gpio, len);
119 	gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT);
120 	if (enable)
121 		gpio_controller_set_pin(gpio, 1);
122 	else
123 		gpio_controller_set_pin(gpio, 0);
124 	free(gpio, M_TEMP, len);
125 
126 	startup_delay = OF_getpropint(node, "startup-delay-us", 0);
127 	if (enable && startup_delay > 0)
128 		delay(startup_delay);
129 
130 	return 0;
131 }
132 
133 int
134 regulator_set(uint32_t phandle, int enable)
135 {
136 	struct regulator_device *rd;
137 	int node;
138 
139 	if (phandle == 0)
140 		return ENODEV;
141 
142 	node = OF_getnodebyphandle(phandle);
143 	if (node == 0)
144 		return ENODEV;
145 
146 	/* Never turn off regulators that should always be on. */
147 	if (OF_getproplen(node, "regulator-always-on") == 0 && !enable)
148 		return 0;
149 
150 	LIST_FOREACH(rd, &regulator_devices, rd_list) {
151 		if (rd->rd_phandle == phandle)
152 			break;
153 	}
154 
155 	if (rd && rd->rd_enable)
156 		return rd->rd_enable(rd->rd_cookie, enable);
157 
158 	if (OF_is_compatible(node, "regulator-fixed"))
159 		return regulator_fixed_set(node, enable);
160 
161 	return ENODEV;
162 }
163 
164 int
165 regulator_enable(uint32_t phandle)
166 {
167 	return regulator_set(phandle, 1);
168 }
169 
170 int
171 regulator_disable(uint32_t phandle)
172 {
173 	return regulator_set(phandle, 0);
174 }
175 
176 uint32_t
177 regulator_get_voltage(uint32_t phandle)
178 {
179 	struct regulator_device *rd;
180 	int node;
181 
182 	if (phandle == 0)
183 		return 0;
184 
185 	LIST_FOREACH(rd, &regulator_devices, rd_list) {
186 		if (rd->rd_phandle == phandle)
187 			break;
188 	}
189 
190 	if (rd && rd->rd_get_voltage)
191 		return rd->rd_get_voltage(rd->rd_cookie);
192 
193 	node = OF_getnodebyphandle(phandle);
194 	if (node == 0)
195 		return 0;
196 
197 	if (OF_is_compatible(node, "regulator-fixed"))
198 		return OF_getpropint(node, "regulator-min-microvolt", 0);
199 
200 	if (OF_is_compatible(node, "regulator-gpio") &&
201 	    regulator_type(node) == REGULATOR_VOLTAGE)
202 		return regulator_gpio_get(node);
203 
204 	return 0;
205 }
206 
207 int
208 regulator_set_voltage(uint32_t phandle, uint32_t voltage)
209 {
210 	struct regulator_device *rd;
211 	uint32_t old, delta;
212 	int error, node;
213 
214 	if (phandle == 0)
215 		return ENODEV;
216 
217 	LIST_FOREACH(rd, &regulator_devices, rd_list) {
218 		if (rd->rd_phandle == phandle)
219 			break;
220 	}
221 
222 	/* Check limits. */
223 	if (rd && (voltage < rd->rd_volt_min || voltage > rd->rd_volt_max))
224 		return EINVAL;
225 
226 	if (rd && rd->rd_set_voltage) {
227 		old = rd->rd_get_voltage(rd->rd_cookie);
228 		error = rd->rd_set_voltage(rd->rd_cookie, voltage);
229 		if (voltage > old && rd->rd_ramp_delay > 0) {
230 			delta = voltage - old;
231 			delay(howmany(delta, rd->rd_ramp_delay));
232 		}
233 		return error;
234 	}
235 
236 	node = OF_getnodebyphandle(phandle);
237 	if (node == 0)
238 		return ENODEV;
239 
240 	if (OF_is_compatible(node, "regulator-fixed") &&
241 	    OF_getpropint(node, "regulator-min-microvolt", 0) == voltage)
242 		return 0;
243 
244 	if (OF_is_compatible(node, "regulator-gpio") &&
245 	    regulator_type(node) == REGULATOR_VOLTAGE)
246 		return regulator_gpio_set(node, voltage);
247 
248 	return ENODEV;
249 }
250 
251 uint32_t
252 regulator_get_current(uint32_t phandle)
253 {
254 	struct regulator_device *rd;
255 	int node;
256 
257 	if (phandle == 0)
258 		return 0;
259 
260 	LIST_FOREACH(rd, &regulator_devices, rd_list) {
261 		if (rd->rd_phandle == phandle)
262 			break;
263 	}
264 
265 	if (rd && rd->rd_get_current)
266 		return rd->rd_get_current(rd->rd_cookie);
267 
268 	node = OF_getnodebyphandle(phandle);
269 	if (node == 0)
270 		return 0;
271 
272 	if (OF_is_compatible(node, "regulator-fixed"))
273 		return OF_getpropint(node, "regulator-min-microamp", 0);
274 
275 	if (OF_is_compatible(node, "regulator-gpio") &&
276 	    regulator_type(node) == REGULATOR_CURRENT)
277 		return regulator_gpio_get(node);
278 
279 	return 0;
280 }
281 
282 int
283 regulator_set_current(uint32_t phandle, uint32_t current)
284 {
285 	struct regulator_device *rd;
286 	uint32_t old, delta;
287 	int error, node;
288 
289 	if (phandle == 0)
290 		return ENODEV;
291 
292 	LIST_FOREACH(rd, &regulator_devices, rd_list) {
293 		if (rd->rd_phandle == phandle)
294 			break;
295 	}
296 
297 	/* Check limits. */
298 	if (rd && (current < rd->rd_amp_min || current > rd->rd_amp_max))
299 		return EINVAL;
300 
301 	if (rd && rd->rd_set_current) {
302 		old = rd->rd_get_current(rd->rd_cookie);
303 		error = rd->rd_set_current(rd->rd_cookie, current);
304 		if (current > old && rd->rd_ramp_delay > 0) {
305 			delta = current - old;
306 			delay(howmany(delta, rd->rd_ramp_delay));
307 		}
308 		return error;
309 	}
310 
311 	node = OF_getnodebyphandle(phandle);
312 	if (node == 0)
313 		return ENODEV;
314 
315 	if (OF_is_compatible(node, "regulator-fixed") &&
316 	    OF_getpropint(node, "regulator-min-microamp", 0) == current)
317 		return 0;
318 
319 	if (OF_is_compatible(node, "regulator-gpio") &&
320 	    regulator_type(node) == REGULATOR_CURRENT)
321 		return regulator_gpio_set(node, current);
322 
323 	return ENODEV;
324 }
325 
326 uint32_t
327 regulator_gpio_get(int node)
328 {
329 	uint32_t *gpio, *gpios, *states;
330 	uint32_t idx, value;
331 	size_t glen, slen;
332 	int i;
333 
334 	pinctrl_byname(node, "default");
335 
336 	if ((glen = OF_getproplen(node, "gpios")) <= 0)
337 		return EINVAL;
338 	if ((slen = OF_getproplen(node, "states")) <= 0)
339 		return EINVAL;
340 
341 	if (slen % (2 * sizeof(uint32_t)) != 0)
342 		return EINVAL;
343 
344 	gpios = malloc(glen, M_TEMP, M_WAITOK);
345 	states = malloc(slen, M_TEMP, M_WAITOK);
346 
347 	OF_getpropintarray(node, "gpios", gpios, glen);
348 	OF_getpropintarray(node, "states", states, slen);
349 
350 	i = 0;
351 	idx = 0;
352 	gpio = gpios;
353 	while (gpio && gpio < gpios + (glen / sizeof(uint32_t))) {
354 		if (gpio_controller_get_pin(gpio))
355 			idx |= (1 << i);
356 		gpio = gpio_controller_next_pin(gpio);
357 		i++;
358 	}
359 
360 	value = 0;
361 	for (i = 0; i < slen / (2 * sizeof(uint32_t)); i++) {
362 		if (states[2 * i + 1] == idx) {
363 			value = states[2 * i];
364 			break;
365 		}
366 	}
367 	if (i >= slen / (2 * sizeof(uint32_t)))
368 		return 0;
369 
370 	free(gpios, M_TEMP, glen);
371 	free(states, M_TEMP, slen);
372 
373 	return value;
374 }
375 
376 int
377 regulator_gpio_set(int node, uint32_t value)
378 {
379 	uint32_t *gpio, *gpios, *states;
380 	size_t glen, slen;
381 	uint32_t min, max;
382 	uint32_t idx;
383 	int i;
384 
385 	pinctrl_byname(node, "default");
386 
387 	if (regulator_type(node) == REGULATOR_VOLTAGE) {
388 		min = OF_getpropint(node, "regulator-min-microvolt", 0);
389 		max = OF_getpropint(node, "regulator-max-microvolt", 0);
390 	}
391 
392 	if (regulator_type(node) == REGULATOR_CURRENT) {
393 		min = OF_getpropint(node, "regulator-min-microamp", 0);
394 		max = OF_getpropint(node, "regulator-max-microamp", 0);
395 	}
396 
397 	/* Check limits. */
398 	if (value < min || value > max)
399 		return EINVAL;
400 
401 	if ((glen = OF_getproplen(node, "gpios")) <= 0)
402 		return EINVAL;
403 	if ((slen = OF_getproplen(node, "states")) <= 0)
404 		return EINVAL;
405 
406 	if (slen % (2 * sizeof(uint32_t)) != 0)
407 		return EINVAL;
408 
409 	gpios = malloc(glen, M_TEMP, M_WAITOK);
410 	states = malloc(slen, M_TEMP, M_WAITOK);
411 
412 	OF_getpropintarray(node, "gpios", gpios, glen);
413 	OF_getpropintarray(node, "states", states, slen);
414 
415 	idx = 0;
416 	for (i = 0; i < slen / (2 * sizeof(uint32_t)); i++) {
417 		if (states[2 * i] < min || states[2 * i] > max)
418 			continue;
419 		if (states[2 * i] == value) {
420 			idx = states[2 * i + 1];
421 			break;
422 		}
423 	}
424 	if (i >= slen / (2 * sizeof(uint32_t)))
425 		return EINVAL;
426 
427 	i = 0;
428 	gpio = gpios;
429 	while (gpio && gpio < gpios + (glen / sizeof(uint32_t))) {
430 		gpio_controller_set_pin(gpio, !!(idx & (1 << i)));
431 		gpio = gpio_controller_next_pin(gpio);
432 		i++;
433 	}
434 
435 	free(gpios, M_TEMP, glen);
436 	free(states, M_TEMP, slen);
437 
438 	return 0;
439 }
440