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, ®node_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