xref: /freebsd/sys/dev/gpio/gpioregulator.c (revision 72f1cf0446d98bd3a87f54da039694490ced8af6)
1*72f1cf04SJared McNeill /*-
2*72f1cf04SJared McNeill  * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
3*72f1cf04SJared McNeill  * All rights reserved.
4*72f1cf04SJared McNeill  *
5*72f1cf04SJared McNeill  * Redistribution and use in source and binary forms, with or without
6*72f1cf04SJared McNeill  * modification, are permitted provided that the following conditions
7*72f1cf04SJared McNeill  * are met:
8*72f1cf04SJared McNeill  * 1. Redistributions of source code must retain the above copyright
9*72f1cf04SJared McNeill  *    notice, this list of conditions and the following disclaimer.
10*72f1cf04SJared McNeill  * 2. Redistributions in binary form must reproduce the above copyright
11*72f1cf04SJared McNeill  *    notice, this list of conditions and the following disclaimer in the
12*72f1cf04SJared McNeill  *    documentation and/or other materials provided with the distribution.
13*72f1cf04SJared McNeill  *
14*72f1cf04SJared McNeill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*72f1cf04SJared McNeill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16*72f1cf04SJared McNeill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17*72f1cf04SJared McNeill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18*72f1cf04SJared McNeill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19*72f1cf04SJared McNeill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20*72f1cf04SJared McNeill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21*72f1cf04SJared McNeill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22*72f1cf04SJared McNeill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*72f1cf04SJared McNeill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*72f1cf04SJared McNeill  * SUCH DAMAGE.
25*72f1cf04SJared McNeill  *
26*72f1cf04SJared McNeill  * $FreeBSD$
27*72f1cf04SJared McNeill  */
28*72f1cf04SJared McNeill 
29*72f1cf04SJared McNeill /*
30*72f1cf04SJared McNeill  * GPIO controlled regulators
31*72f1cf04SJared McNeill  */
32*72f1cf04SJared McNeill 
33*72f1cf04SJared McNeill #include <sys/cdefs.h>
34*72f1cf04SJared McNeill __FBSDID("$FreeBSD$");
35*72f1cf04SJared McNeill 
36*72f1cf04SJared McNeill #include <sys/param.h>
37*72f1cf04SJared McNeill #include <sys/systm.h>
38*72f1cf04SJared McNeill #include <sys/bus.h>
39*72f1cf04SJared McNeill #include <sys/rman.h>
40*72f1cf04SJared McNeill #include <sys/kernel.h>
41*72f1cf04SJared McNeill #include <sys/module.h>
42*72f1cf04SJared McNeill #include <sys/gpio.h>
43*72f1cf04SJared McNeill 
44*72f1cf04SJared McNeill #include <dev/ofw/ofw_bus.h>
45*72f1cf04SJared McNeill #include <dev/ofw/ofw_bus_subr.h>
46*72f1cf04SJared McNeill 
47*72f1cf04SJared McNeill #include <dev/gpio/gpiobusvar.h>
48*72f1cf04SJared McNeill 
49*72f1cf04SJared McNeill #include <dev/extres/regulator/regulator.h>
50*72f1cf04SJared McNeill 
51*72f1cf04SJared McNeill #include "regdev_if.h"
52*72f1cf04SJared McNeill 
53*72f1cf04SJared McNeill struct gpioregulator_state {
54*72f1cf04SJared McNeill 	int			val;
55*72f1cf04SJared McNeill 	uint32_t		mask;
56*72f1cf04SJared McNeill };
57*72f1cf04SJared McNeill 
58*72f1cf04SJared McNeill struct gpioregulator_init_def {
59*72f1cf04SJared McNeill 	struct regnode_init_def		reg_init_def;
60*72f1cf04SJared McNeill 	struct gpiobus_pin		*enable_pin;
61*72f1cf04SJared McNeill 	int				enable_pin_valid;
62*72f1cf04SJared McNeill 	int				startup_delay_us;
63*72f1cf04SJared McNeill 	int				nstates;
64*72f1cf04SJared McNeill 	struct gpioregulator_state	*states;
65*72f1cf04SJared McNeill 	int				npins;
66*72f1cf04SJared McNeill 	struct gpiobus_pin		**pins;
67*72f1cf04SJared McNeill };
68*72f1cf04SJared McNeill 
69*72f1cf04SJared McNeill struct gpioregulator_reg_sc {
70*72f1cf04SJared McNeill 	struct regnode			*regnode;
71*72f1cf04SJared McNeill 	device_t			base_dev;
72*72f1cf04SJared McNeill 	struct regnode_std_param	*param;
73*72f1cf04SJared McNeill 	struct gpioregulator_init_def	*def;
74*72f1cf04SJared McNeill };
75*72f1cf04SJared McNeill 
76*72f1cf04SJared McNeill struct gpioregulator_softc {
77*72f1cf04SJared McNeill 	device_t			dev;
78*72f1cf04SJared McNeill 	struct gpioregulator_reg_sc	*reg_sc;
79*72f1cf04SJared McNeill 	struct gpioregulator_init_def	init_def;
80*72f1cf04SJared McNeill };
81*72f1cf04SJared McNeill 
82*72f1cf04SJared McNeill static int
83*72f1cf04SJared McNeill gpioregulator_regnode_init(struct regnode *regnode)
84*72f1cf04SJared McNeill {
85*72f1cf04SJared McNeill 	struct gpioregulator_reg_sc *sc;
86*72f1cf04SJared McNeill 	int error, n;
87*72f1cf04SJared McNeill 
88*72f1cf04SJared McNeill 	sc = regnode_get_softc(regnode);
89*72f1cf04SJared McNeill 
90*72f1cf04SJared McNeill 	if (sc->def->enable_pin_valid == 1) {
91*72f1cf04SJared McNeill 		error = gpio_pin_setflags(sc->def->enable_pin, GPIO_PIN_OUTPUT);
92*72f1cf04SJared McNeill 		if (error != 0)
93*72f1cf04SJared McNeill 			return (error);
94*72f1cf04SJared McNeill 	}
95*72f1cf04SJared McNeill 
96*72f1cf04SJared McNeill 	for (n = 0; n < sc->def->npins; n++) {
97*72f1cf04SJared McNeill 		error = gpio_pin_setflags(sc->def->pins[n], GPIO_PIN_OUTPUT);
98*72f1cf04SJared McNeill 		if (error != 0)
99*72f1cf04SJared McNeill 			return (error);
100*72f1cf04SJared McNeill 	}
101*72f1cf04SJared McNeill 
102*72f1cf04SJared McNeill 	return (0);
103*72f1cf04SJared McNeill }
104*72f1cf04SJared McNeill 
105*72f1cf04SJared McNeill static int
106*72f1cf04SJared McNeill gpioregulator_regnode_enable(struct regnode *regnode, bool enable, int *udelay)
107*72f1cf04SJared McNeill {
108*72f1cf04SJared McNeill 	struct gpioregulator_reg_sc *sc;
109*72f1cf04SJared McNeill 	bool active;
110*72f1cf04SJared McNeill 	int error;
111*72f1cf04SJared McNeill 
112*72f1cf04SJared McNeill 	sc = regnode_get_softc(regnode);
113*72f1cf04SJared McNeill 
114*72f1cf04SJared McNeill 	if (sc->def->enable_pin_valid == 1) {
115*72f1cf04SJared McNeill 		active = enable;
116*72f1cf04SJared McNeill 		if (!sc->param->enable_active_high)
117*72f1cf04SJared McNeill 			active = !active;
118*72f1cf04SJared McNeill 		error = gpio_pin_set_active(sc->def->enable_pin, active);
119*72f1cf04SJared McNeill 		if (error != 0)
120*72f1cf04SJared McNeill 			return (error);
121*72f1cf04SJared McNeill 	}
122*72f1cf04SJared McNeill 
123*72f1cf04SJared McNeill 	*udelay = sc->def->startup_delay_us;
124*72f1cf04SJared McNeill 
125*72f1cf04SJared McNeill 	return (0);
126*72f1cf04SJared McNeill }
127*72f1cf04SJared McNeill 
128*72f1cf04SJared McNeill static int
129*72f1cf04SJared McNeill gpioregulator_regnode_set_voltage(struct regnode *regnode, int min_uvolt,
130*72f1cf04SJared McNeill     int max_uvolt, int *udelay)
131*72f1cf04SJared McNeill {
132*72f1cf04SJared McNeill 	struct gpioregulator_reg_sc *sc;
133*72f1cf04SJared McNeill 	const struct gpioregulator_state *state;
134*72f1cf04SJared McNeill 	int error, n;
135*72f1cf04SJared McNeill 
136*72f1cf04SJared McNeill 	sc = regnode_get_softc(regnode);
137*72f1cf04SJared McNeill 	state = NULL;
138*72f1cf04SJared McNeill 
139*72f1cf04SJared McNeill 	for (n = 0; n < sc->def->nstates; n++) {
140*72f1cf04SJared McNeill 		if (sc->def->states[n].val >= min_uvolt &&
141*72f1cf04SJared McNeill 		    sc->def->states[n].val <= max_uvolt) {
142*72f1cf04SJared McNeill 			state = &sc->def->states[n];
143*72f1cf04SJared McNeill 			break;
144*72f1cf04SJared McNeill 		}
145*72f1cf04SJared McNeill 	}
146*72f1cf04SJared McNeill 	if (state == NULL)
147*72f1cf04SJared McNeill 		return (EINVAL);
148*72f1cf04SJared McNeill 
149*72f1cf04SJared McNeill 	for (n = 0; n < sc->def->npins; n++) {
150*72f1cf04SJared McNeill 		error = gpio_pin_set_active(sc->def->pins[n],
151*72f1cf04SJared McNeill 		    (state->mask >> n) & 1);
152*72f1cf04SJared McNeill 		if (error != 0)
153*72f1cf04SJared McNeill 			return (error);
154*72f1cf04SJared McNeill 	}
155*72f1cf04SJared McNeill 
156*72f1cf04SJared McNeill 	*udelay = sc->def->startup_delay_us;
157*72f1cf04SJared McNeill 
158*72f1cf04SJared McNeill 	return (0);
159*72f1cf04SJared McNeill }
160*72f1cf04SJared McNeill 
161*72f1cf04SJared McNeill static int
162*72f1cf04SJared McNeill gpioregulator_regnode_get_voltage(struct regnode *regnode, int *uvolt)
163*72f1cf04SJared McNeill {
164*72f1cf04SJared McNeill 	struct gpioregulator_reg_sc *sc;
165*72f1cf04SJared McNeill 	uint32_t mask;
166*72f1cf04SJared McNeill 	int error, n;
167*72f1cf04SJared McNeill 	bool active;
168*72f1cf04SJared McNeill 
169*72f1cf04SJared McNeill 	sc = regnode_get_softc(regnode);
170*72f1cf04SJared McNeill 	mask = 0;
171*72f1cf04SJared McNeill 
172*72f1cf04SJared McNeill 	for (n = 0; n < sc->def->npins; n++) {
173*72f1cf04SJared McNeill 		error = gpio_pin_is_active(sc->def->pins[n], &active);
174*72f1cf04SJared McNeill 		if (error != 0)
175*72f1cf04SJared McNeill 			return (error);
176*72f1cf04SJared McNeill 		mask |= (active << n);
177*72f1cf04SJared McNeill 	}
178*72f1cf04SJared McNeill 
179*72f1cf04SJared McNeill 	for (n = 0; n < sc->def->nstates; n++) {
180*72f1cf04SJared McNeill 		if (sc->def->states[n].mask == mask) {
181*72f1cf04SJared McNeill 			*uvolt = sc->def->states[n].val;
182*72f1cf04SJared McNeill 			return (0);
183*72f1cf04SJared McNeill 		}
184*72f1cf04SJared McNeill 	}
185*72f1cf04SJared McNeill 
186*72f1cf04SJared McNeill 	return (EIO);
187*72f1cf04SJared McNeill }
188*72f1cf04SJared McNeill 
189*72f1cf04SJared McNeill static regnode_method_t gpioregulator_regnode_methods[] = {
190*72f1cf04SJared McNeill 	/* Regulator interface */
191*72f1cf04SJared McNeill 	REGNODEMETHOD(regnode_init,	gpioregulator_regnode_init),
192*72f1cf04SJared McNeill 	REGNODEMETHOD(regnode_enable,	gpioregulator_regnode_enable),
193*72f1cf04SJared McNeill 	REGNODEMETHOD(regnode_set_voltage, gpioregulator_regnode_set_voltage),
194*72f1cf04SJared McNeill 	REGNODEMETHOD(regnode_get_voltage, gpioregulator_regnode_get_voltage),
195*72f1cf04SJared McNeill 	REGNODEMETHOD_END
196*72f1cf04SJared McNeill };
197*72f1cf04SJared McNeill DEFINE_CLASS_1(gpioregulator_regnode, gpioregulator_regnode_class,
198*72f1cf04SJared McNeill     gpioregulator_regnode_methods, sizeof(struct gpioregulator_reg_sc),
199*72f1cf04SJared McNeill     regnode_class);
200*72f1cf04SJared McNeill 
201*72f1cf04SJared McNeill static int
202*72f1cf04SJared McNeill gpioregulator_parse_fdt(struct gpioregulator_softc *sc)
203*72f1cf04SJared McNeill {
204*72f1cf04SJared McNeill 	uint32_t *pstates, mask;
205*72f1cf04SJared McNeill 	phandle_t node;
206*72f1cf04SJared McNeill 	ssize_t len;
207*72f1cf04SJared McNeill 	int error, n;
208*72f1cf04SJared McNeill 
209*72f1cf04SJared McNeill 	node = ofw_bus_get_node(sc->dev);
210*72f1cf04SJared McNeill 	pstates = NULL;
211*72f1cf04SJared McNeill 	mask = 0;
212*72f1cf04SJared McNeill 
213*72f1cf04SJared McNeill 	error = regulator_parse_ofw_stdparam(sc->dev, node,
214*72f1cf04SJared McNeill 	    &sc->init_def.reg_init_def);
215*72f1cf04SJared McNeill 	if (error != 0)
216*72f1cf04SJared McNeill 		return (error);
217*72f1cf04SJared McNeill 
218*72f1cf04SJared McNeill 	/* "states" property (required) */
219*72f1cf04SJared McNeill 	len = OF_getencprop_alloc(node, "states", sizeof(*pstates),
220*72f1cf04SJared McNeill 	    (void **)&pstates);
221*72f1cf04SJared McNeill 	if (len < 2) {
222*72f1cf04SJared McNeill 		device_printf(sc->dev, "invalid 'states' property\n");
223*72f1cf04SJared McNeill 		error = EINVAL;
224*72f1cf04SJared McNeill 		goto done;
225*72f1cf04SJared McNeill 	}
226*72f1cf04SJared McNeill 	sc->init_def.nstates = len / 2;
227*72f1cf04SJared McNeill 	sc->init_def.states = malloc(sc->init_def.nstates *
228*72f1cf04SJared McNeill 	    sizeof(*sc->init_def.states), M_DEVBUF, M_WAITOK);
229*72f1cf04SJared McNeill 	for (n = 0; n < sc->init_def.nstates; n++) {
230*72f1cf04SJared McNeill 		sc->init_def.states[n].val = pstates[n * 2 + 0];
231*72f1cf04SJared McNeill 		sc->init_def.states[n].mask = pstates[n * 2 + 1];
232*72f1cf04SJared McNeill 		mask |= sc->init_def.states[n].mask;
233*72f1cf04SJared McNeill 	}
234*72f1cf04SJared McNeill 
235*72f1cf04SJared McNeill 	/* "startup-delay-us" property (optional) */
236*72f1cf04SJared McNeill 	len = OF_getencprop(node, "startup-delay-us",
237*72f1cf04SJared McNeill 	    &sc->init_def.startup_delay_us,
238*72f1cf04SJared McNeill 	    sizeof(sc->init_def.startup_delay_us));
239*72f1cf04SJared McNeill 	if (len <= 0)
240*72f1cf04SJared McNeill 		sc->init_def.startup_delay_us = 0;
241*72f1cf04SJared McNeill 
242*72f1cf04SJared McNeill 	/* "enable-gpio" property (optional) */
243*72f1cf04SJared McNeill 	error = gpio_pin_get_by_ofw_property(sc->dev, node, "enable-gpio",
244*72f1cf04SJared McNeill 	    &sc->init_def.enable_pin);
245*72f1cf04SJared McNeill 	if (error == 0)
246*72f1cf04SJared McNeill 		sc->init_def.enable_pin_valid = 1;
247*72f1cf04SJared McNeill 
248*72f1cf04SJared McNeill 	/* "gpios" property */
249*72f1cf04SJared McNeill 	sc->init_def.npins = 32 - __builtin_clz(mask);
250*72f1cf04SJared McNeill 	sc->init_def.pins = malloc(sc->init_def.npins *
251*72f1cf04SJared McNeill 	    sizeof(sc->init_def.pins), M_DEVBUF, M_WAITOK);
252*72f1cf04SJared McNeill 	for (n = 0; n < sc->init_def.npins; n++) {
253*72f1cf04SJared McNeill 		error = gpio_pin_get_by_ofw_idx(sc->dev, node, n,
254*72f1cf04SJared McNeill 		    &sc->init_def.pins[n]);
255*72f1cf04SJared McNeill 		if (error != 0) {
256*72f1cf04SJared McNeill 			device_printf(sc->dev, "cannot get pin %d\n", n);
257*72f1cf04SJared McNeill 			goto done;
258*72f1cf04SJared McNeill 		}
259*72f1cf04SJared McNeill 	}
260*72f1cf04SJared McNeill 
261*72f1cf04SJared McNeill done:
262*72f1cf04SJared McNeill 	if (error != 0) {
263*72f1cf04SJared McNeill 		for (n = 0; n < sc->init_def.npins; n++) {
264*72f1cf04SJared McNeill 			if (sc->init_def.pins[n] != NULL)
265*72f1cf04SJared McNeill 				gpio_pin_release(sc->init_def.pins[n]);
266*72f1cf04SJared McNeill 		}
267*72f1cf04SJared McNeill 
268*72f1cf04SJared McNeill 		free(sc->init_def.states, M_DEVBUF);
269*72f1cf04SJared McNeill 		free(sc->init_def.pins, M_DEVBUF);
270*72f1cf04SJared McNeill 
271*72f1cf04SJared McNeill 	}
272*72f1cf04SJared McNeill 	OF_prop_free(pstates);
273*72f1cf04SJared McNeill 
274*72f1cf04SJared McNeill 	return (error);
275*72f1cf04SJared McNeill }
276*72f1cf04SJared McNeill 
277*72f1cf04SJared McNeill static int
278*72f1cf04SJared McNeill gpioregulator_probe(device_t dev)
279*72f1cf04SJared McNeill {
280*72f1cf04SJared McNeill 
281*72f1cf04SJared McNeill 	if (!ofw_bus_is_compatible(dev, "regulator-gpio"))
282*72f1cf04SJared McNeill 		return (ENXIO);
283*72f1cf04SJared McNeill 
284*72f1cf04SJared McNeill 	device_set_desc(dev, "GPIO controlled regulator");
285*72f1cf04SJared McNeill 	return (BUS_PROBE_GENERIC);
286*72f1cf04SJared McNeill }
287*72f1cf04SJared McNeill 
288*72f1cf04SJared McNeill static int
289*72f1cf04SJared McNeill gpioregulator_attach(device_t dev)
290*72f1cf04SJared McNeill {
291*72f1cf04SJared McNeill 	struct gpioregulator_softc *sc;
292*72f1cf04SJared McNeill 	struct regnode *regnode;
293*72f1cf04SJared McNeill 	phandle_t node;
294*72f1cf04SJared McNeill 	int error;
295*72f1cf04SJared McNeill 
296*72f1cf04SJared McNeill 	sc = device_get_softc(dev);
297*72f1cf04SJared McNeill 	sc->dev = dev;
298*72f1cf04SJared McNeill 	node = ofw_bus_get_node(dev);
299*72f1cf04SJared McNeill 
300*72f1cf04SJared McNeill 	error = gpioregulator_parse_fdt(sc);
301*72f1cf04SJared McNeill 	if (error != 0) {
302*72f1cf04SJared McNeill 		device_printf(dev, "cannot parse parameters\n");
303*72f1cf04SJared McNeill 		return (ENXIO);
304*72f1cf04SJared McNeill 	}
305*72f1cf04SJared McNeill 	sc->init_def.reg_init_def.id = 1;
306*72f1cf04SJared McNeill 	sc->init_def.reg_init_def.ofw_node = node;
307*72f1cf04SJared McNeill 
308*72f1cf04SJared McNeill 	regnode = regnode_create(dev, &gpioregulator_regnode_class,
309*72f1cf04SJared McNeill 	    &sc->init_def.reg_init_def);
310*72f1cf04SJared McNeill 	if (regnode == NULL) {
311*72f1cf04SJared McNeill 		device_printf(dev, "cannot create regulator\n");
312*72f1cf04SJared McNeill 		return (ENXIO);
313*72f1cf04SJared McNeill 	}
314*72f1cf04SJared McNeill 
315*72f1cf04SJared McNeill 	sc->reg_sc = regnode_get_softc(regnode);
316*72f1cf04SJared McNeill 	sc->reg_sc->regnode = regnode;
317*72f1cf04SJared McNeill 	sc->reg_sc->base_dev = dev;
318*72f1cf04SJared McNeill 	sc->reg_sc->param = regnode_get_stdparam(regnode);
319*72f1cf04SJared McNeill 	sc->reg_sc->def = &sc->init_def;
320*72f1cf04SJared McNeill 
321*72f1cf04SJared McNeill 	regnode_register(regnode);
322*72f1cf04SJared McNeill 
323*72f1cf04SJared McNeill 	return (0);
324*72f1cf04SJared McNeill }
325*72f1cf04SJared McNeill 
326*72f1cf04SJared McNeill 
327*72f1cf04SJared McNeill static device_method_t gpioregulator_methods[] = {
328*72f1cf04SJared McNeill 	/* Device interface */
329*72f1cf04SJared McNeill 	DEVMETHOD(device_probe,		gpioregulator_probe),
330*72f1cf04SJared McNeill 	DEVMETHOD(device_attach,	gpioregulator_attach),
331*72f1cf04SJared McNeill 
332*72f1cf04SJared McNeill 	/* Regdev interface */
333*72f1cf04SJared McNeill 	DEVMETHOD(regdev_map,		regdev_default_ofw_map),
334*72f1cf04SJared McNeill 
335*72f1cf04SJared McNeill 	DEVMETHOD_END
336*72f1cf04SJared McNeill };
337*72f1cf04SJared McNeill 
338*72f1cf04SJared McNeill static driver_t gpioregulator_driver = {
339*72f1cf04SJared McNeill 	"gpioregulator",
340*72f1cf04SJared McNeill 	gpioregulator_methods,
341*72f1cf04SJared McNeill 	sizeof(struct gpioregulator_softc),
342*72f1cf04SJared McNeill };
343*72f1cf04SJared McNeill 
344*72f1cf04SJared McNeill static devclass_t gpioregulator_devclass;
345*72f1cf04SJared McNeill 
346*72f1cf04SJared McNeill EARLY_DRIVER_MODULE(gpioregulator, simplebus, gpioregulator_driver,
347*72f1cf04SJared McNeill     gpioregulator_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST);
348*72f1cf04SJared McNeill MODULE_VERSION(gpioregulator, 1);
349