ofw_regulator.c revision 1.2
1/*	$OpenBSD: ofw_regulator.c,v 1.2 2017/11/18 13:48:50 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
27LIST_HEAD(, regulator_device) regulator_devices =
28	LIST_HEAD_INITIALIZER(regulator_devices);
29
30void
31regulator_register(struct regulator_device *rd)
32{
33	rd->rd_phandle = OF_getpropint(rd->rd_node, "phandle", 0);
34	if (rd->rd_phandle == 0)
35		return;
36
37	LIST_INSERT_HEAD(&regulator_devices, rd, rd_list);
38}
39
40int
41regulator_set(uint32_t phandle, int enable)
42{
43	uint32_t *gpio;
44	uint32_t startup_delay;
45	int active;
46	int node;
47	int len;
48
49	node = OF_getnodebyphandle(phandle);
50	if (node == 0)
51		return -1;
52
53	if (!OF_is_compatible(node, "regulator-fixed"))
54		return -1;
55
56	pinctrl_byname(node, "default");
57
58	if (OF_getproplen(node, "enable-active-high") == 0)
59		active = 1;
60	else
61		active = 0;
62
63	/* The "gpio" property is optional. */
64	len = OF_getproplen(node, "gpio");
65	if (len < 0)
66		return 0;
67
68	gpio = malloc(len, M_TEMP, M_WAITOK);
69	OF_getpropintarray(node, "gpio", gpio, len);
70	gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT);
71	if (enable)
72		gpio_controller_set_pin(gpio, active);
73	else
74		gpio_controller_set_pin(gpio, !active);
75	free(gpio, M_TEMP, len);
76
77	startup_delay = OF_getpropint(node, "startup-delay-us", 0);
78	if (enable && startup_delay > 0)
79		delay(startup_delay);
80
81	return 0;
82}
83
84int
85regulator_enable(uint32_t phandle)
86{
87	return regulator_set(phandle, 1);
88}
89
90int
91regulator_disable(uint32_t phandle)
92{
93	return regulator_set(phandle, 0);
94}
95
96uint32_t
97regulator_get_voltage(uint32_t phandle)
98{
99	struct regulator_device *rd;
100	int node;
101
102	LIST_FOREACH(rd, &regulator_devices, rd_list) {
103		if (rd->rd_phandle == phandle)
104			break;
105	}
106
107	if (rd && rd->rd_get_voltage)
108		return rd->rd_get_voltage(rd->rd_cookie);
109
110	node = OF_getnodebyphandle(phandle);
111	if (node == 0)
112		return 0;
113
114	if (OF_is_compatible(node, "regulator-fixed"))
115		return OF_getpropint(node, "regulator-min-voltage", 0);
116
117	return 0;
118}
119
120int
121regulator_set_voltage(uint32_t phandle, uint32_t voltage)
122{
123	struct regulator_device *rd;
124
125	LIST_FOREACH(rd, &regulator_devices, rd_list) {
126		if (rd->rd_phandle == phandle)
127			break;
128	}
129
130	if (rd && rd->rd_set_voltage)
131		return rd->rd_set_voltage(rd->rd_cookie, voltage);
132
133	return -1;
134}
135