xref: /freebsd/sys/dev/regulator/regulator_fixed.c (revision 18250ec6c089c0c50cbd9fd87d78e03ff89916df)
1b2f0caf1SEmmanuel Vadot /*-
2b2f0caf1SEmmanuel Vadot  * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
3b2f0caf1SEmmanuel Vadot  * All rights reserved.
4b2f0caf1SEmmanuel Vadot  *
5b2f0caf1SEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
6b2f0caf1SEmmanuel Vadot  * modification, are permitted provided that the following conditions
7b2f0caf1SEmmanuel Vadot  * are met:
8b2f0caf1SEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
9b2f0caf1SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
10b2f0caf1SEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
11b2f0caf1SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
12b2f0caf1SEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
13b2f0caf1SEmmanuel Vadot  *
14b2f0caf1SEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15b2f0caf1SEmmanuel Vadot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16b2f0caf1SEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17b2f0caf1SEmmanuel Vadot  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18b2f0caf1SEmmanuel Vadot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19b2f0caf1SEmmanuel Vadot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20b2f0caf1SEmmanuel Vadot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21b2f0caf1SEmmanuel Vadot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22b2f0caf1SEmmanuel Vadot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23b2f0caf1SEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24b2f0caf1SEmmanuel Vadot  * SUCH DAMAGE.
25b2f0caf1SEmmanuel Vadot  */
26b2f0caf1SEmmanuel Vadot 
27b2f0caf1SEmmanuel Vadot #include <sys/cdefs.h>
28b2f0caf1SEmmanuel Vadot #include "opt_platform.h"
29b2f0caf1SEmmanuel Vadot #include <sys/param.h>
30b2f0caf1SEmmanuel Vadot #include <sys/systm.h>
31b2f0caf1SEmmanuel Vadot #include <sys/bus.h>
32b2f0caf1SEmmanuel Vadot #include <sys/conf.h>
33b2f0caf1SEmmanuel Vadot #include <sys/gpio.h>
34b2f0caf1SEmmanuel Vadot #include <sys/kernel.h>
35b2f0caf1SEmmanuel Vadot #include <sys/kobj.h>
36b2f0caf1SEmmanuel Vadot #include <sys/module.h>
37b2f0caf1SEmmanuel Vadot #include <sys/mutex.h>
38b2f0caf1SEmmanuel Vadot 
39b2f0caf1SEmmanuel Vadot #ifdef FDT
40b2f0caf1SEmmanuel Vadot #include <dev/fdt/fdt_common.h>
41b2f0caf1SEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
42b2f0caf1SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
43b2f0caf1SEmmanuel Vadot #endif
44b2f0caf1SEmmanuel Vadot #include <dev/gpio/gpiobusvar.h>
45b2f0caf1SEmmanuel Vadot #include <dev/regulator/regulator_fixed.h>
46b2f0caf1SEmmanuel Vadot 
47b2f0caf1SEmmanuel Vadot #ifdef FDT
48b2f0caf1SEmmanuel Vadot #include "regdev_if.h"
49b2f0caf1SEmmanuel Vadot #endif
50b2f0caf1SEmmanuel Vadot 
51b2f0caf1SEmmanuel Vadot MALLOC_DEFINE(M_FIXEDREGULATOR, "fixedregulator", "Fixed regulator");
52b2f0caf1SEmmanuel Vadot 
53b2f0caf1SEmmanuel Vadot /* GPIO list for shared pins. */
54b2f0caf1SEmmanuel Vadot typedef TAILQ_HEAD(gpio_list, gpio_entry) gpio_list_t;
55b2f0caf1SEmmanuel Vadot struct gpio_entry {
56b2f0caf1SEmmanuel Vadot 	TAILQ_ENTRY(gpio_entry)	link;
57b2f0caf1SEmmanuel Vadot 	struct gpiobus_pin	gpio_pin;
58b2f0caf1SEmmanuel Vadot 	int 			use_cnt;
59b2f0caf1SEmmanuel Vadot 	int 			enable_cnt;
60b2f0caf1SEmmanuel Vadot 	bool			always_on;
61b2f0caf1SEmmanuel Vadot };
62b2f0caf1SEmmanuel Vadot static gpio_list_t gpio_list = TAILQ_HEAD_INITIALIZER(gpio_list);
63b2f0caf1SEmmanuel Vadot static struct mtx gpio_list_mtx;
64b2f0caf1SEmmanuel Vadot MTX_SYSINIT(gpio_list_lock, &gpio_list_mtx, "Regulator GPIO lock", MTX_DEF);
65b2f0caf1SEmmanuel Vadot 
66b2f0caf1SEmmanuel Vadot struct regnode_fixed_sc {
67b2f0caf1SEmmanuel Vadot 	struct regnode_std_param *param;
68b2f0caf1SEmmanuel Vadot 	bool			gpio_open_drain;
69b2f0caf1SEmmanuel Vadot 	struct gpio_entry	*gpio_entry;
70b2f0caf1SEmmanuel Vadot };
71b2f0caf1SEmmanuel Vadot 
72b2f0caf1SEmmanuel Vadot static int regnode_fixed_init(struct regnode *regnode);
73b2f0caf1SEmmanuel Vadot static int regnode_fixed_enable(struct regnode *regnode, bool enable,
74b2f0caf1SEmmanuel Vadot     int *udelay);
75b2f0caf1SEmmanuel Vadot static int regnode_fixed_status(struct regnode *regnode, int *status);
76b2f0caf1SEmmanuel Vadot static int regnode_fixed_stop(struct regnode *regnode, int *udelay);
77b2f0caf1SEmmanuel Vadot static int regnode_fixed_get_voltage(struct regnode *regnode, int *uvolt);
78b2f0caf1SEmmanuel Vadot 
79b2f0caf1SEmmanuel Vadot static regnode_method_t regnode_fixed_methods[] = {
80b2f0caf1SEmmanuel Vadot 	/* Regulator interface */
81b2f0caf1SEmmanuel Vadot 	REGNODEMETHOD(regnode_init,		regnode_fixed_init),
82b2f0caf1SEmmanuel Vadot 	REGNODEMETHOD(regnode_enable,		regnode_fixed_enable),
83b2f0caf1SEmmanuel Vadot 	REGNODEMETHOD(regnode_status,		regnode_fixed_status),
84b2f0caf1SEmmanuel Vadot 	REGNODEMETHOD(regnode_stop,		regnode_fixed_stop),
85b2f0caf1SEmmanuel Vadot 	REGNODEMETHOD(regnode_get_voltage,	regnode_fixed_get_voltage),
86b2f0caf1SEmmanuel Vadot 	REGNODEMETHOD(regnode_check_voltage,	regnode_method_check_voltage),
87b2f0caf1SEmmanuel Vadot 	REGNODEMETHOD_END
88b2f0caf1SEmmanuel Vadot };
89b2f0caf1SEmmanuel Vadot DEFINE_CLASS_1(regnode_fixed, regnode_fixed_class, regnode_fixed_methods,
90b2f0caf1SEmmanuel Vadot    sizeof(struct regnode_fixed_sc), regnode_class);
91b2f0caf1SEmmanuel Vadot 
92b2f0caf1SEmmanuel Vadot /*
93b2f0caf1SEmmanuel Vadot  * GPIO list functions.
94b2f0caf1SEmmanuel Vadot  * Two or more regulators can share single GPIO pins, so we must track all
95b2f0caf1SEmmanuel Vadot  * GPIOs in gpio_list.
96b2f0caf1SEmmanuel Vadot  * The GPIO pin is registerd and reseved for first consumer, all others share
97b2f0caf1SEmmanuel Vadot  * gpio_entry with it.
98b2f0caf1SEmmanuel Vadot  */
99b2f0caf1SEmmanuel Vadot static struct gpio_entry *
regnode_get_gpio_entry(struct gpiobus_pin * gpio_pin)100b2f0caf1SEmmanuel Vadot regnode_get_gpio_entry(struct gpiobus_pin *gpio_pin)
101b2f0caf1SEmmanuel Vadot {
102b2f0caf1SEmmanuel Vadot 	struct gpio_entry *entry, *tmp;
103b2f0caf1SEmmanuel Vadot 	device_t busdev;
104b2f0caf1SEmmanuel Vadot 	int rv;
105b2f0caf1SEmmanuel Vadot 
106b2f0caf1SEmmanuel Vadot 	busdev = GPIO_GET_BUS(gpio_pin->dev);
107b2f0caf1SEmmanuel Vadot 	if (busdev == NULL)
108b2f0caf1SEmmanuel Vadot 		return (NULL);
109b2f0caf1SEmmanuel Vadot 	entry = malloc(sizeof(struct gpio_entry), M_FIXEDREGULATOR,
110b2f0caf1SEmmanuel Vadot 	    M_WAITOK | M_ZERO);
111b2f0caf1SEmmanuel Vadot 
112b2f0caf1SEmmanuel Vadot 	mtx_lock(&gpio_list_mtx);
113b2f0caf1SEmmanuel Vadot 
114b2f0caf1SEmmanuel Vadot 	TAILQ_FOREACH(tmp, &gpio_list, link) {
115b2f0caf1SEmmanuel Vadot 		if (tmp->gpio_pin.dev == gpio_pin->dev &&
116b2f0caf1SEmmanuel Vadot 		    tmp->gpio_pin.pin == gpio_pin->pin) {
117b2f0caf1SEmmanuel Vadot 			tmp->use_cnt++;
118b2f0caf1SEmmanuel Vadot 			mtx_unlock(&gpio_list_mtx);
119b2f0caf1SEmmanuel Vadot 			free(entry, M_FIXEDREGULATOR);
120b2f0caf1SEmmanuel Vadot 			return (tmp);
121b2f0caf1SEmmanuel Vadot 		}
122b2f0caf1SEmmanuel Vadot 	}
123b2f0caf1SEmmanuel Vadot 
124b2f0caf1SEmmanuel Vadot 	/* Reserve pin. */
125b2f0caf1SEmmanuel Vadot 	/* XXX Can we call gpiobus_acquire_pin() with gpio_list_mtx held? */
126b2f0caf1SEmmanuel Vadot 	rv = gpiobus_acquire_pin(busdev, gpio_pin->pin);
127b2f0caf1SEmmanuel Vadot 	if (rv != 0) {
128b2f0caf1SEmmanuel Vadot 		mtx_unlock(&gpio_list_mtx);
129b2f0caf1SEmmanuel Vadot 		free(entry, M_FIXEDREGULATOR);
130b2f0caf1SEmmanuel Vadot 		return (NULL);
131b2f0caf1SEmmanuel Vadot 	}
132b2f0caf1SEmmanuel Vadot 	/* Everything is OK, build new entry and insert it to list. */
133b2f0caf1SEmmanuel Vadot 	entry->gpio_pin = *gpio_pin;
134b2f0caf1SEmmanuel Vadot 	entry->use_cnt = 1;
135b2f0caf1SEmmanuel Vadot 	TAILQ_INSERT_TAIL(&gpio_list, entry, link);
136b2f0caf1SEmmanuel Vadot 
137b2f0caf1SEmmanuel Vadot 	mtx_unlock(&gpio_list_mtx);
138b2f0caf1SEmmanuel Vadot 	return (entry);
139b2f0caf1SEmmanuel Vadot }
140b2f0caf1SEmmanuel Vadot 
141b2f0caf1SEmmanuel Vadot 
142b2f0caf1SEmmanuel Vadot /*
143b2f0caf1SEmmanuel Vadot  * Regulator class implementation.
144b2f0caf1SEmmanuel Vadot  */
145b2f0caf1SEmmanuel Vadot static int
regnode_fixed_init(struct regnode * regnode)146b2f0caf1SEmmanuel Vadot regnode_fixed_init(struct regnode *regnode)
147b2f0caf1SEmmanuel Vadot {
148b2f0caf1SEmmanuel Vadot 	device_t dev;
149b2f0caf1SEmmanuel Vadot 	struct regnode_fixed_sc *sc;
150b2f0caf1SEmmanuel Vadot 	struct gpiobus_pin *pin;
151b2f0caf1SEmmanuel Vadot 	uint32_t flags;
152b2f0caf1SEmmanuel Vadot 	int rv;
153b2f0caf1SEmmanuel Vadot 
154b2f0caf1SEmmanuel Vadot 	sc = regnode_get_softc(regnode);
155b2f0caf1SEmmanuel Vadot 	dev = regnode_get_device(regnode);
156b2f0caf1SEmmanuel Vadot 	sc->param = regnode_get_stdparam(regnode);
157b2f0caf1SEmmanuel Vadot 	if (sc->gpio_entry == NULL)
158b2f0caf1SEmmanuel Vadot 		return (0);
159b2f0caf1SEmmanuel Vadot 	pin = &sc->gpio_entry->gpio_pin;
160b2f0caf1SEmmanuel Vadot 
161b2f0caf1SEmmanuel Vadot 	flags = GPIO_PIN_OUTPUT;
162b2f0caf1SEmmanuel Vadot 	if (sc->gpio_open_drain)
163b2f0caf1SEmmanuel Vadot 		flags |= GPIO_PIN_OPENDRAIN;
164b2f0caf1SEmmanuel Vadot 	if (sc->param->boot_on || sc->param->always_on) {
165b2f0caf1SEmmanuel Vadot 		rv = GPIO_PIN_SET(pin->dev, pin->pin, sc->param->enable_active_high);
166b2f0caf1SEmmanuel Vadot 		if (rv != 0) {
167b2f0caf1SEmmanuel Vadot 			device_printf(dev, "Cannot set GPIO pin: %d\n",
168b2f0caf1SEmmanuel Vadot 			    pin->pin);
169b2f0caf1SEmmanuel Vadot 			return (rv);
170b2f0caf1SEmmanuel Vadot 		}
171b2f0caf1SEmmanuel Vadot 	}
172b2f0caf1SEmmanuel Vadot 
173b2f0caf1SEmmanuel Vadot 	rv = GPIO_PIN_SETFLAGS(pin->dev, pin->pin, flags);
174b2f0caf1SEmmanuel Vadot 	if (rv != 0) {
175b2f0caf1SEmmanuel Vadot 		device_printf(dev, "Cannot configure GPIO pin: %d\n", pin->pin);
176b2f0caf1SEmmanuel Vadot 		return (rv);
177b2f0caf1SEmmanuel Vadot 	}
178b2f0caf1SEmmanuel Vadot 
179b2f0caf1SEmmanuel Vadot 	return (0);
180b2f0caf1SEmmanuel Vadot }
181b2f0caf1SEmmanuel Vadot 
182b2f0caf1SEmmanuel Vadot /*
183b2f0caf1SEmmanuel Vadot  * Enable/disable regulator.
184b2f0caf1SEmmanuel Vadot  * Take shared GPIO pins in account
185b2f0caf1SEmmanuel Vadot  */
186b2f0caf1SEmmanuel Vadot static int
regnode_fixed_enable(struct regnode * regnode,bool enable,int * udelay)187b2f0caf1SEmmanuel Vadot regnode_fixed_enable(struct regnode *regnode, bool enable, int *udelay)
188b2f0caf1SEmmanuel Vadot {
189b2f0caf1SEmmanuel Vadot 	device_t dev;
190b2f0caf1SEmmanuel Vadot 	struct regnode_fixed_sc *sc;
191b2f0caf1SEmmanuel Vadot 	struct gpiobus_pin *pin;
192b2f0caf1SEmmanuel Vadot 	int rv;
193b2f0caf1SEmmanuel Vadot 
194b2f0caf1SEmmanuel Vadot 	sc = regnode_get_softc(regnode);
195b2f0caf1SEmmanuel Vadot 	dev = regnode_get_device(regnode);
196b2f0caf1SEmmanuel Vadot 
197b2f0caf1SEmmanuel Vadot 	*udelay = 0;
198b2f0caf1SEmmanuel Vadot 	if (sc->gpio_entry == NULL)
199b2f0caf1SEmmanuel Vadot 		return (0);
200b2f0caf1SEmmanuel Vadot 	pin = &sc->gpio_entry->gpio_pin;
201b2f0caf1SEmmanuel Vadot 	if (enable) {
202b2f0caf1SEmmanuel Vadot 		sc->gpio_entry->enable_cnt++;
203b2f0caf1SEmmanuel Vadot 		if (sc->gpio_entry->enable_cnt > 1)
204b2f0caf1SEmmanuel Vadot 			return (0);
205b2f0caf1SEmmanuel Vadot 	} else {
206b2f0caf1SEmmanuel Vadot 		KASSERT(sc->gpio_entry->enable_cnt > 0,
207b2f0caf1SEmmanuel Vadot 		    ("Invalid enable count"));
208b2f0caf1SEmmanuel Vadot 		sc->gpio_entry->enable_cnt--;
209b2f0caf1SEmmanuel Vadot 		if (sc->gpio_entry->enable_cnt >= 1)
210b2f0caf1SEmmanuel Vadot 			return (0);
211b2f0caf1SEmmanuel Vadot 	}
212b2f0caf1SEmmanuel Vadot 	if (sc->gpio_entry->always_on && !enable)
213b2f0caf1SEmmanuel Vadot 		return (0);
214b2f0caf1SEmmanuel Vadot 	if (!sc->param->enable_active_high)
215b2f0caf1SEmmanuel Vadot 		enable = !enable;
216b2f0caf1SEmmanuel Vadot 	rv = GPIO_PIN_SET(pin->dev, pin->pin, enable);
217b2f0caf1SEmmanuel Vadot 	if (rv != 0) {
218b2f0caf1SEmmanuel Vadot 		device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin);
219b2f0caf1SEmmanuel Vadot 		return (rv);
220b2f0caf1SEmmanuel Vadot 	}
221b2f0caf1SEmmanuel Vadot 	*udelay = sc->param->enable_delay;
222b2f0caf1SEmmanuel Vadot 	return (0);
223b2f0caf1SEmmanuel Vadot }
224b2f0caf1SEmmanuel Vadot 
225b2f0caf1SEmmanuel Vadot /*
226b2f0caf1SEmmanuel Vadot  * Stop (physicaly shutdown) regulator.
227b2f0caf1SEmmanuel Vadot  * Take shared GPIO pins in account
228b2f0caf1SEmmanuel Vadot  */
229b2f0caf1SEmmanuel Vadot static int
regnode_fixed_stop(struct regnode * regnode,int * udelay)230b2f0caf1SEmmanuel Vadot regnode_fixed_stop(struct regnode *regnode, int *udelay)
231b2f0caf1SEmmanuel Vadot {
232b2f0caf1SEmmanuel Vadot 	device_t dev;
233b2f0caf1SEmmanuel Vadot 	struct regnode_fixed_sc *sc;
234b2f0caf1SEmmanuel Vadot 	struct gpiobus_pin *pin;
235b2f0caf1SEmmanuel Vadot 	int rv;
236b2f0caf1SEmmanuel Vadot 
237b2f0caf1SEmmanuel Vadot 	sc = regnode_get_softc(regnode);
238b2f0caf1SEmmanuel Vadot 	dev = regnode_get_device(regnode);
239b2f0caf1SEmmanuel Vadot 
240b2f0caf1SEmmanuel Vadot 	*udelay = 0;
241b2f0caf1SEmmanuel Vadot 	if (sc->gpio_entry == NULL)
242b2f0caf1SEmmanuel Vadot 		return (0);
243b2f0caf1SEmmanuel Vadot 	if (sc->gpio_entry->always_on)
244b2f0caf1SEmmanuel Vadot 		return (0);
245b2f0caf1SEmmanuel Vadot 	pin = &sc->gpio_entry->gpio_pin;
246b2f0caf1SEmmanuel Vadot 	if (sc->gpio_entry->enable_cnt > 0) {
247b2f0caf1SEmmanuel Vadot 		/* Other regulator(s) are enabled. */
248b2f0caf1SEmmanuel Vadot 		/* XXXX Any diagnostic message? Or error? */
249b2f0caf1SEmmanuel Vadot 		return (0);
250b2f0caf1SEmmanuel Vadot 	}
251b2f0caf1SEmmanuel Vadot 	rv = GPIO_PIN_SET(pin->dev, pin->pin,
252b2f0caf1SEmmanuel Vadot 	    sc->param->enable_active_high ? false: true);
253b2f0caf1SEmmanuel Vadot 	if (rv != 0) {
254b2f0caf1SEmmanuel Vadot 		device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin);
255b2f0caf1SEmmanuel Vadot 		return (rv);
256b2f0caf1SEmmanuel Vadot 	}
257b2f0caf1SEmmanuel Vadot 	*udelay = sc->param->enable_delay;
258b2f0caf1SEmmanuel Vadot 	return (0);
259b2f0caf1SEmmanuel Vadot }
260b2f0caf1SEmmanuel Vadot 
261b2f0caf1SEmmanuel Vadot static int
regnode_fixed_status(struct regnode * regnode,int * status)262b2f0caf1SEmmanuel Vadot regnode_fixed_status(struct regnode *regnode, int *status)
263b2f0caf1SEmmanuel Vadot {
264b2f0caf1SEmmanuel Vadot 	struct regnode_fixed_sc *sc;
265b2f0caf1SEmmanuel Vadot 	struct gpiobus_pin *pin;
266b2f0caf1SEmmanuel Vadot 	uint32_t val;
267b2f0caf1SEmmanuel Vadot 	int rv;
268b2f0caf1SEmmanuel Vadot 
269b2f0caf1SEmmanuel Vadot 	sc = regnode_get_softc(regnode);
270b2f0caf1SEmmanuel Vadot 
271b2f0caf1SEmmanuel Vadot 	*status = 0;
272b2f0caf1SEmmanuel Vadot 	if (sc->gpio_entry == NULL) {
273b2f0caf1SEmmanuel Vadot 		*status = REGULATOR_STATUS_ENABLED;
274b2f0caf1SEmmanuel Vadot 		return (0);
275b2f0caf1SEmmanuel Vadot 	}
276b2f0caf1SEmmanuel Vadot 	pin = &sc->gpio_entry->gpio_pin;
277b2f0caf1SEmmanuel Vadot 
278b2f0caf1SEmmanuel Vadot 	rv = GPIO_PIN_GET(pin->dev, pin->pin, &val);
279b2f0caf1SEmmanuel Vadot 	if (rv == 0) {
280b2f0caf1SEmmanuel Vadot 		if (!sc->param->enable_active_high ^ (val != 0))
281b2f0caf1SEmmanuel Vadot 			*status = REGULATOR_STATUS_ENABLED;
282b2f0caf1SEmmanuel Vadot 	}
283b2f0caf1SEmmanuel Vadot 	return (rv);
284b2f0caf1SEmmanuel Vadot }
285b2f0caf1SEmmanuel Vadot 
286b2f0caf1SEmmanuel Vadot static int
regnode_fixed_get_voltage(struct regnode * regnode,int * uvolt)287b2f0caf1SEmmanuel Vadot regnode_fixed_get_voltage(struct regnode *regnode, int *uvolt)
288b2f0caf1SEmmanuel Vadot {
289b2f0caf1SEmmanuel Vadot 	struct regnode_fixed_sc *sc;
290b2f0caf1SEmmanuel Vadot 
291b2f0caf1SEmmanuel Vadot 	sc = regnode_get_softc(regnode);
292b2f0caf1SEmmanuel Vadot 	*uvolt = sc->param->min_uvolt;
293b2f0caf1SEmmanuel Vadot 	return (0);
294b2f0caf1SEmmanuel Vadot }
295b2f0caf1SEmmanuel Vadot 
296b2f0caf1SEmmanuel Vadot int
regnode_fixed_register(device_t dev,struct regnode_fixed_init_def * init_def)297b2f0caf1SEmmanuel Vadot regnode_fixed_register(device_t dev, struct regnode_fixed_init_def *init_def)
298b2f0caf1SEmmanuel Vadot {
299b2f0caf1SEmmanuel Vadot 	struct regnode *regnode;
300b2f0caf1SEmmanuel Vadot 	struct regnode_fixed_sc *sc;
301b2f0caf1SEmmanuel Vadot 
302b2f0caf1SEmmanuel Vadot 	regnode = regnode_create(dev, &regnode_fixed_class,
303b2f0caf1SEmmanuel Vadot 	    &init_def->reg_init_def);
304b2f0caf1SEmmanuel Vadot 	if (regnode == NULL) {
305b2f0caf1SEmmanuel Vadot 		device_printf(dev, "Cannot create regulator.\n");
306b2f0caf1SEmmanuel Vadot 		return(ENXIO);
307b2f0caf1SEmmanuel Vadot 	}
308b2f0caf1SEmmanuel Vadot 	sc = regnode_get_softc(regnode);
309b2f0caf1SEmmanuel Vadot 	sc->gpio_open_drain = init_def->gpio_open_drain;
310b2f0caf1SEmmanuel Vadot 	if (init_def->gpio_pin != NULL) {
311b2f0caf1SEmmanuel Vadot 		sc->gpio_entry = regnode_get_gpio_entry(init_def->gpio_pin);
312b2f0caf1SEmmanuel Vadot 		if (sc->gpio_entry == NULL)
313b2f0caf1SEmmanuel Vadot 			return(ENXIO);
314b2f0caf1SEmmanuel Vadot 	}
315b2f0caf1SEmmanuel Vadot 	regnode = regnode_register(regnode);
316b2f0caf1SEmmanuel Vadot 	if (regnode == NULL) {
317b2f0caf1SEmmanuel Vadot 		device_printf(dev, "Cannot register regulator.\n");
318b2f0caf1SEmmanuel Vadot 		return(ENXIO);
319b2f0caf1SEmmanuel Vadot 	}
320b2f0caf1SEmmanuel Vadot 
321b2f0caf1SEmmanuel Vadot 	if (sc->gpio_entry != NULL)
322b2f0caf1SEmmanuel Vadot 		sc->gpio_entry->always_on |= sc->param->always_on;
323b2f0caf1SEmmanuel Vadot 
324b2f0caf1SEmmanuel Vadot 	return (0);
325b2f0caf1SEmmanuel Vadot }
326b2f0caf1SEmmanuel Vadot 
327b2f0caf1SEmmanuel Vadot /*
328b2f0caf1SEmmanuel Vadot  * OFW Driver implementation.
329b2f0caf1SEmmanuel Vadot  */
330b2f0caf1SEmmanuel Vadot #ifdef FDT
331b2f0caf1SEmmanuel Vadot 
332b2f0caf1SEmmanuel Vadot struct  regfix_softc
333b2f0caf1SEmmanuel Vadot {
334b2f0caf1SEmmanuel Vadot 	device_t			dev;
335b2f0caf1SEmmanuel Vadot 	bool				attach_done;
336b2f0caf1SEmmanuel Vadot 	struct regnode_fixed_init_def	init_def;
337b2f0caf1SEmmanuel Vadot 	phandle_t			gpio_prodxref;
338b2f0caf1SEmmanuel Vadot 	pcell_t				*gpio_cells;
339b2f0caf1SEmmanuel Vadot 	int				gpio_ncells;
340b2f0caf1SEmmanuel Vadot 	struct gpiobus_pin		gpio_pin;
341b2f0caf1SEmmanuel Vadot };
342b2f0caf1SEmmanuel Vadot 
343b2f0caf1SEmmanuel Vadot static struct ofw_compat_data compat_data[] = {
344b2f0caf1SEmmanuel Vadot 	{"regulator-fixed",		1},
345b2f0caf1SEmmanuel Vadot 	{NULL,				0},
346b2f0caf1SEmmanuel Vadot };
347b2f0caf1SEmmanuel Vadot 
348b2f0caf1SEmmanuel Vadot static int
regfix_get_gpio(struct regfix_softc * sc)349b2f0caf1SEmmanuel Vadot regfix_get_gpio(struct regfix_softc * sc)
350b2f0caf1SEmmanuel Vadot {
351b2f0caf1SEmmanuel Vadot 	device_t busdev;
352b2f0caf1SEmmanuel Vadot 	phandle_t node;
353b2f0caf1SEmmanuel Vadot 
354b2f0caf1SEmmanuel Vadot 	int rv;
355b2f0caf1SEmmanuel Vadot 
356b2f0caf1SEmmanuel Vadot 	if (sc->gpio_prodxref == 0)
357b2f0caf1SEmmanuel Vadot 		return (0);
358b2f0caf1SEmmanuel Vadot 
359b2f0caf1SEmmanuel Vadot 	node = ofw_bus_get_node(sc->dev);
360b2f0caf1SEmmanuel Vadot 
361b2f0caf1SEmmanuel Vadot 	/* Test if controller exist. */
362b2f0caf1SEmmanuel Vadot 	sc->gpio_pin.dev = OF_device_from_xref(sc->gpio_prodxref);
363b2f0caf1SEmmanuel Vadot 	if (sc->gpio_pin.dev == NULL)
364b2f0caf1SEmmanuel Vadot 		return (ENODEV);
365b2f0caf1SEmmanuel Vadot 
366b2f0caf1SEmmanuel Vadot 	/* Test if GPIO bus already exist. */
367b2f0caf1SEmmanuel Vadot 	busdev = GPIO_GET_BUS(sc->gpio_pin.dev);
368b2f0caf1SEmmanuel Vadot 	if (busdev == NULL)
369b2f0caf1SEmmanuel Vadot 		return (ENODEV);
370b2f0caf1SEmmanuel Vadot 
371b2f0caf1SEmmanuel Vadot 	rv = gpio_map_gpios(sc->gpio_pin.dev, node,
372b2f0caf1SEmmanuel Vadot 	    OF_node_from_xref(sc->gpio_prodxref), sc->gpio_ncells,
373b2f0caf1SEmmanuel Vadot 	    sc->gpio_cells, &(sc->gpio_pin.pin), &(sc->gpio_pin.flags));
374b2f0caf1SEmmanuel Vadot 	if (rv != 0) {
375b2f0caf1SEmmanuel Vadot 		device_printf(sc->dev, "Cannot map the gpio property.\n");
376b2f0caf1SEmmanuel Vadot 		return (ENXIO);
377b2f0caf1SEmmanuel Vadot 	}
378b2f0caf1SEmmanuel Vadot 	sc->init_def.gpio_pin = &sc->gpio_pin;
379b2f0caf1SEmmanuel Vadot 	return (0);
380b2f0caf1SEmmanuel Vadot }
381b2f0caf1SEmmanuel Vadot 
382b2f0caf1SEmmanuel Vadot static int
regfix_parse_fdt(struct regfix_softc * sc)383b2f0caf1SEmmanuel Vadot regfix_parse_fdt(struct regfix_softc * sc)
384b2f0caf1SEmmanuel Vadot {
385b2f0caf1SEmmanuel Vadot 	phandle_t node;
386b2f0caf1SEmmanuel Vadot 	int rv;
387b2f0caf1SEmmanuel Vadot 	struct regnode_init_def *init_def;
388b2f0caf1SEmmanuel Vadot 
389b2f0caf1SEmmanuel Vadot 	node = ofw_bus_get_node(sc->dev);
390b2f0caf1SEmmanuel Vadot 	init_def = &sc->init_def.reg_init_def;
391b2f0caf1SEmmanuel Vadot 
392b2f0caf1SEmmanuel Vadot 	rv = regulator_parse_ofw_stdparam(sc->dev, node, init_def);
393b2f0caf1SEmmanuel Vadot 	if (rv != 0) {
394b2f0caf1SEmmanuel Vadot 		device_printf(sc->dev, "Cannot parse standard parameters.\n");
395b2f0caf1SEmmanuel Vadot 		return(rv);
396b2f0caf1SEmmanuel Vadot 	}
397b2f0caf1SEmmanuel Vadot 
398b2f0caf1SEmmanuel Vadot 	if (init_def->std_param.min_uvolt != init_def->std_param.max_uvolt) {
399b2f0caf1SEmmanuel Vadot 		device_printf(sc->dev, "min_uvolt != max_uvolt\n");
400b2f0caf1SEmmanuel Vadot 		return (ENXIO);
401b2f0caf1SEmmanuel Vadot 	}
402b2f0caf1SEmmanuel Vadot 	/* Fixed regulator uses 'startup-delay-us' property for enable_delay */
403b2f0caf1SEmmanuel Vadot 	rv = OF_getencprop(node, "startup-delay-us",
404b2f0caf1SEmmanuel Vadot 	   &init_def->std_param.enable_delay,
405b2f0caf1SEmmanuel Vadot 	   sizeof(init_def->std_param.enable_delay));
406b2f0caf1SEmmanuel Vadot 	if (rv <= 0)
407b2f0caf1SEmmanuel Vadot 		init_def->std_param.enable_delay = 0;
408b2f0caf1SEmmanuel Vadot 	/* GPIO pin */
409b2f0caf1SEmmanuel Vadot 	if (OF_hasprop(node, "gpio-open-drain"))
410b2f0caf1SEmmanuel Vadot 		sc->init_def.gpio_open_drain = true;
411b2f0caf1SEmmanuel Vadot 
412b2f0caf1SEmmanuel Vadot 	if (!OF_hasprop(node, "gpio"))
413b2f0caf1SEmmanuel Vadot 		return (0);
414b2f0caf1SEmmanuel Vadot 	rv = ofw_bus_parse_xref_list_alloc(node, "gpio", "#gpio-cells", 0,
415b2f0caf1SEmmanuel Vadot 	    &sc->gpio_prodxref, &sc->gpio_ncells, &sc->gpio_cells);
416b2f0caf1SEmmanuel Vadot 	if (rv != 0) {
417b2f0caf1SEmmanuel Vadot 		sc->gpio_prodxref = 0;
418b2f0caf1SEmmanuel Vadot 		device_printf(sc->dev, "Malformed gpio property\n");
419b2f0caf1SEmmanuel Vadot 		return (ENXIO);
420b2f0caf1SEmmanuel Vadot 	}
421b2f0caf1SEmmanuel Vadot 	return (0);
422b2f0caf1SEmmanuel Vadot }
423b2f0caf1SEmmanuel Vadot 
424b2f0caf1SEmmanuel Vadot static void
regfix_new_pass(device_t dev)425b2f0caf1SEmmanuel Vadot regfix_new_pass(device_t dev)
426b2f0caf1SEmmanuel Vadot {
427b2f0caf1SEmmanuel Vadot 	struct regfix_softc * sc;
428b2f0caf1SEmmanuel Vadot 	int rv;
429b2f0caf1SEmmanuel Vadot 
430b2f0caf1SEmmanuel Vadot 	sc = device_get_softc(dev);
431b2f0caf1SEmmanuel Vadot 	bus_generic_new_pass(dev);
432b2f0caf1SEmmanuel Vadot 
433b2f0caf1SEmmanuel Vadot 	if (sc->attach_done)
434b2f0caf1SEmmanuel Vadot 		return;
435b2f0caf1SEmmanuel Vadot 
436b2f0caf1SEmmanuel Vadot 	/* Try to get and configure GPIO. */
437b2f0caf1SEmmanuel Vadot 	rv = regfix_get_gpio(sc);
438b2f0caf1SEmmanuel Vadot 	if (rv != 0)
439b2f0caf1SEmmanuel Vadot 		return;
440b2f0caf1SEmmanuel Vadot 
441b2f0caf1SEmmanuel Vadot 	/* Register regulator. */
442b2f0caf1SEmmanuel Vadot 	regnode_fixed_register(sc->dev, &sc->init_def);
443b2f0caf1SEmmanuel Vadot 	sc->attach_done = true;
444b2f0caf1SEmmanuel Vadot }
445b2f0caf1SEmmanuel Vadot 
446b2f0caf1SEmmanuel Vadot static int
regfix_probe(device_t dev)447b2f0caf1SEmmanuel Vadot regfix_probe(device_t dev)
448b2f0caf1SEmmanuel Vadot {
449b2f0caf1SEmmanuel Vadot 
450b2f0caf1SEmmanuel Vadot 	if (!ofw_bus_status_okay(dev))
451b2f0caf1SEmmanuel Vadot 		return (ENXIO);
452b2f0caf1SEmmanuel Vadot 
453b2f0caf1SEmmanuel Vadot 	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
454b2f0caf1SEmmanuel Vadot 		return (ENXIO);
455b2f0caf1SEmmanuel Vadot 
456b2f0caf1SEmmanuel Vadot 	device_set_desc(dev, "Fixed Regulator");
457b2f0caf1SEmmanuel Vadot 	return (BUS_PROBE_DEFAULT);
458b2f0caf1SEmmanuel Vadot }
459b2f0caf1SEmmanuel Vadot 
460b2f0caf1SEmmanuel Vadot static int
regfix_detach(device_t dev)461b2f0caf1SEmmanuel Vadot regfix_detach(device_t dev)
462b2f0caf1SEmmanuel Vadot {
463b2f0caf1SEmmanuel Vadot 
464b2f0caf1SEmmanuel Vadot 	/* This device is always present. */
465b2f0caf1SEmmanuel Vadot 	return (EBUSY);
466b2f0caf1SEmmanuel Vadot }
467b2f0caf1SEmmanuel Vadot 
468b2f0caf1SEmmanuel Vadot static int
regfix_attach(device_t dev)469b2f0caf1SEmmanuel Vadot regfix_attach(device_t dev)
470b2f0caf1SEmmanuel Vadot {
471b2f0caf1SEmmanuel Vadot 	struct regfix_softc * sc;
472b2f0caf1SEmmanuel Vadot 	int rv;
473b2f0caf1SEmmanuel Vadot 
474b2f0caf1SEmmanuel Vadot 	sc = device_get_softc(dev);
475b2f0caf1SEmmanuel Vadot 	sc->dev = dev;
476b2f0caf1SEmmanuel Vadot 
477b2f0caf1SEmmanuel Vadot 	/* Parse FDT data. */
478b2f0caf1SEmmanuel Vadot 	rv = regfix_parse_fdt(sc);
479b2f0caf1SEmmanuel Vadot 	if (rv != 0)
480b2f0caf1SEmmanuel Vadot 		return(ENXIO);
481b2f0caf1SEmmanuel Vadot 
482b2f0caf1SEmmanuel Vadot 	/* Fill reset of init. */
483b2f0caf1SEmmanuel Vadot 	sc->init_def.reg_init_def.id = 1;
484b2f0caf1SEmmanuel Vadot 	sc->init_def.reg_init_def.flags = REGULATOR_FLAGS_STATIC;
485b2f0caf1SEmmanuel Vadot 
486b2f0caf1SEmmanuel Vadot 	/* Try to get and configure GPIO. */
487b2f0caf1SEmmanuel Vadot 	rv = regfix_get_gpio(sc);
488*18250ec6SJohn Baldwin 	if (rv != 0) {
489*18250ec6SJohn Baldwin 		bus_attach_children(dev);
490*18250ec6SJohn Baldwin 		return (0);
491*18250ec6SJohn Baldwin 	}
492b2f0caf1SEmmanuel Vadot 
493b2f0caf1SEmmanuel Vadot 	/* Register regulator. */
494b2f0caf1SEmmanuel Vadot 	regnode_fixed_register(sc->dev, &sc->init_def);
495b2f0caf1SEmmanuel Vadot 	sc->attach_done = true;
496b2f0caf1SEmmanuel Vadot 
497*18250ec6SJohn Baldwin 	bus_attach_children(dev);
498*18250ec6SJohn Baldwin 	return (0);
499b2f0caf1SEmmanuel Vadot }
500b2f0caf1SEmmanuel Vadot 
501b2f0caf1SEmmanuel Vadot static device_method_t regfix_methods[] = {
502b2f0caf1SEmmanuel Vadot 	/* Device interface */
503b2f0caf1SEmmanuel Vadot 	DEVMETHOD(device_probe,		regfix_probe),
504b2f0caf1SEmmanuel Vadot 	DEVMETHOD(device_attach,	regfix_attach),
505b2f0caf1SEmmanuel Vadot 	DEVMETHOD(device_detach,	regfix_detach),
506b2f0caf1SEmmanuel Vadot 	/* Bus interface */
507b2f0caf1SEmmanuel Vadot 	DEVMETHOD(bus_new_pass,		regfix_new_pass),
508b2f0caf1SEmmanuel Vadot 	/* Regdev interface */
509b2f0caf1SEmmanuel Vadot 	DEVMETHOD(regdev_map,		regdev_default_ofw_map),
510b2f0caf1SEmmanuel Vadot 
511b2f0caf1SEmmanuel Vadot 	DEVMETHOD_END
512b2f0caf1SEmmanuel Vadot };
513b2f0caf1SEmmanuel Vadot 
514b2f0caf1SEmmanuel Vadot DEFINE_CLASS_0(regfix, regfix_driver, regfix_methods,
515b2f0caf1SEmmanuel Vadot     sizeof(struct regfix_softc));
516b2f0caf1SEmmanuel Vadot EARLY_DRIVER_MODULE(regfix, simplebus, regfix_driver, 0, 0, BUS_PASS_BUS);
517b2f0caf1SEmmanuel Vadot 
518b2f0caf1SEmmanuel Vadot #endif /* FDT */
519