1b47e5c5dSJessica Clarke /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3b47e5c5dSJessica Clarke *
4b47e5c5dSJessica Clarke * Copyright (c) 2021 Jessica Clarke <jrtc27@FreeBSD.org>
5b47e5c5dSJessica Clarke *
6b47e5c5dSJessica Clarke * Redistribution and use in source and binary forms, with or without
7b47e5c5dSJessica Clarke * modification, are permitted provided that the following conditions
8b47e5c5dSJessica Clarke * are met:
9b47e5c5dSJessica Clarke * 1. Redistributions of source code must retain the above copyright
10b47e5c5dSJessica Clarke * notice, this list of conditions and the following disclaimer.
11b47e5c5dSJessica Clarke * 2. Redistributions in binary form must reproduce the above copyright
12b47e5c5dSJessica Clarke * notice, this list of conditions and the following disclaimer in the
13b47e5c5dSJessica Clarke * documentation and/or other materials provided with the distribution.
14b47e5c5dSJessica Clarke *
15b47e5c5dSJessica Clarke * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16b47e5c5dSJessica Clarke * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17b47e5c5dSJessica Clarke * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18b47e5c5dSJessica Clarke * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19b47e5c5dSJessica Clarke * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20b47e5c5dSJessica Clarke * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21b47e5c5dSJessica Clarke * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22b47e5c5dSJessica Clarke * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23b47e5c5dSJessica Clarke * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24b47e5c5dSJessica Clarke * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25b47e5c5dSJessica Clarke * SUCH DAMAGE.
26b47e5c5dSJessica Clarke *
27b47e5c5dSJessica Clarke */
28b47e5c5dSJessica Clarke
29b47e5c5dSJessica Clarke /* TODO: Provide interrupt controller interface */
30b47e5c5dSJessica Clarke
31b47e5c5dSJessica Clarke #include <sys/param.h>
32b47e5c5dSJessica Clarke #include <sys/systm.h>
33b47e5c5dSJessica Clarke #include <sys/bus.h>
34b47e5c5dSJessica Clarke #include <sys/kernel.h>
35b47e5c5dSJessica Clarke #include <sys/module.h>
36b47e5c5dSJessica Clarke #include <sys/rman.h>
37b47e5c5dSJessica Clarke #include <sys/lock.h>
38b47e5c5dSJessica Clarke #include <sys/mutex.h>
39b47e5c5dSJessica Clarke #include <sys/gpio.h>
40b47e5c5dSJessica Clarke
41b47e5c5dSJessica Clarke #include <dev/gpio/gpiobusvar.h>
42b47e5c5dSJessica Clarke #include <dev/ofw/ofw_bus.h>
43b47e5c5dSJessica Clarke #include <dev/ofw/ofw_bus_subr.h>
44b47e5c5dSJessica Clarke
45b47e5c5dSJessica Clarke #include <machine/bus.h>
46b47e5c5dSJessica Clarke
47b47e5c5dSJessica Clarke /* Registers are 32-bit so can only fit 32 pins */
48b47e5c5dSJessica Clarke #define SFGPIO_MAX_PINS 32
49b47e5c5dSJessica Clarke
50b47e5c5dSJessica Clarke #define SFGPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
51b47e5c5dSJessica Clarke
52b47e5c5dSJessica Clarke #define SFGPIO_INPUT_VAL 0x0
53b47e5c5dSJessica Clarke #define SFGPIO_INPUT_EN 0x4
54b47e5c5dSJessica Clarke #define SFGPIO_OUTPUT_EN 0x8
55b47e5c5dSJessica Clarke #define SFGPIO_OUTPUT_VAL 0xc
56b47e5c5dSJessica Clarke #define SFGPIO_RISE_IE 0x18
57b47e5c5dSJessica Clarke #define SFGPIO_RISE_IP 0x1c
58b47e5c5dSJessica Clarke #define SFGPIO_FALL_IE 0x20
59b47e5c5dSJessica Clarke #define SFGPIO_FALL_IP 0x24
60b47e5c5dSJessica Clarke #define SFGPIO_HIGH_IE 0x28
61b47e5c5dSJessica Clarke #define SFGPIO_HIGH_IP 0x2c
62b47e5c5dSJessica Clarke #define SFGPIO_LOW_IE 0x30
63b47e5c5dSJessica Clarke #define SFGPIO_LOW_IP 0x34
64b47e5c5dSJessica Clarke
65b47e5c5dSJessica Clarke struct sfgpio_softc {
66b47e5c5dSJessica Clarke device_t dev;
67b47e5c5dSJessica Clarke device_t busdev;
68b47e5c5dSJessica Clarke struct mtx mtx;
69b47e5c5dSJessica Clarke struct resource *mem_res;
70b47e5c5dSJessica Clarke int mem_rid;
71b47e5c5dSJessica Clarke struct resource *irq_res;
72b47e5c5dSJessica Clarke int irq_rid;
73b47e5c5dSJessica Clarke int npins;
74b47e5c5dSJessica Clarke struct gpio_pin gpio_pins[SFGPIO_MAX_PINS];
75b47e5c5dSJessica Clarke };
76b47e5c5dSJessica Clarke
77b47e5c5dSJessica Clarke #define SFGPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx)
78b47e5c5dSJessica Clarke #define SFGPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
79b47e5c5dSJessica Clarke
80b47e5c5dSJessica Clarke #define SFGPIO_READ(_sc, _off) \
81b47e5c5dSJessica Clarke bus_read_4((_sc)->mem_res, (_off))
82b47e5c5dSJessica Clarke #define SFGPIO_WRITE(_sc, _off, _val) \
83b47e5c5dSJessica Clarke bus_write_4((_sc)->mem_res, (_off), (_val))
84b47e5c5dSJessica Clarke
85b47e5c5dSJessica Clarke static struct ofw_compat_data compat_data[] = {
86b47e5c5dSJessica Clarke { "sifive,gpio0", 1 },
87b47e5c5dSJessica Clarke { NULL, 0 },
88b47e5c5dSJessica Clarke };
89b47e5c5dSJessica Clarke
90b47e5c5dSJessica Clarke static int
sfgpio_probe(device_t dev)91b47e5c5dSJessica Clarke sfgpio_probe(device_t dev)
92b47e5c5dSJessica Clarke {
93b47e5c5dSJessica Clarke if (!ofw_bus_status_okay(dev))
94b47e5c5dSJessica Clarke return (ENXIO);
95b47e5c5dSJessica Clarke
96b47e5c5dSJessica Clarke if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
97b47e5c5dSJessica Clarke return (ENXIO);
98b47e5c5dSJessica Clarke
99b47e5c5dSJessica Clarke device_set_desc(dev, "SiFive GPIO Controller");
100b47e5c5dSJessica Clarke
101b47e5c5dSJessica Clarke return (BUS_PROBE_DEFAULT);
102b47e5c5dSJessica Clarke }
103b47e5c5dSJessica Clarke
104b47e5c5dSJessica Clarke static int
sfgpio_attach(device_t dev)105b47e5c5dSJessica Clarke sfgpio_attach(device_t dev)
106b47e5c5dSJessica Clarke {
107b47e5c5dSJessica Clarke struct sfgpio_softc *sc;
108b47e5c5dSJessica Clarke phandle_t node;
109b47e5c5dSJessica Clarke int error, i;
110b47e5c5dSJessica Clarke pcell_t npins;
111b47e5c5dSJessica Clarke uint32_t input_en, output_en;
112b47e5c5dSJessica Clarke
113b47e5c5dSJessica Clarke sc = device_get_softc(dev);
114b47e5c5dSJessica Clarke sc->dev = dev;
115b47e5c5dSJessica Clarke
116b47e5c5dSJessica Clarke node = ofw_bus_get_node(dev);
117b47e5c5dSJessica Clarke
118b47e5c5dSJessica Clarke mtx_init(&sc->mtx, device_get_nameunit(sc->dev), NULL, MTX_DEF);
119b47e5c5dSJessica Clarke
120b47e5c5dSJessica Clarke sc->mem_rid = 0;
121b47e5c5dSJessica Clarke sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
122b47e5c5dSJessica Clarke &sc->mem_rid, RF_ACTIVE);
123b47e5c5dSJessica Clarke if (sc->mem_res == NULL) {
124b47e5c5dSJessica Clarke device_printf(dev, "Cannot allocate memory resource\n");
125b47e5c5dSJessica Clarke error = ENXIO;
126b47e5c5dSJessica Clarke goto fail;
127b47e5c5dSJessica Clarke }
128b47e5c5dSJessica Clarke
129b47e5c5dSJessica Clarke if (OF_getencprop(node, "ngpios", &npins, sizeof(npins)) <= 0) {
130b47e5c5dSJessica Clarke /* Optional; defaults to 16 */
131b47e5c5dSJessica Clarke npins = 16;
132b47e5c5dSJessica Clarke } else if (npins > SFGPIO_MAX_PINS) {
133b47e5c5dSJessica Clarke device_printf(dev, "Too many pins: %d\n", npins);
134b47e5c5dSJessica Clarke error = ENXIO;
135b47e5c5dSJessica Clarke goto fail;
136b47e5c5dSJessica Clarke }
137b47e5c5dSJessica Clarke sc->npins = npins;
138b47e5c5dSJessica Clarke
139b47e5c5dSJessica Clarke sc->irq_rid = 0;
140b47e5c5dSJessica Clarke sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
141b47e5c5dSJessica Clarke RF_ACTIVE);
142b47e5c5dSJessica Clarke if (sc->irq_res == NULL) {
143b47e5c5dSJessica Clarke device_printf(dev, "Cannot allocate IRQ resource\n");
144b47e5c5dSJessica Clarke error = ENXIO;
145b47e5c5dSJessica Clarke goto fail;
146b47e5c5dSJessica Clarke }
147b47e5c5dSJessica Clarke
148b47e5c5dSJessica Clarke input_en = SFGPIO_READ(sc, SFGPIO_INPUT_EN);
149b47e5c5dSJessica Clarke output_en = SFGPIO_READ(sc, SFGPIO_OUTPUT_EN);
150b47e5c5dSJessica Clarke for (i = 0; i < sc->npins; ++i) {
151b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_pin = i;
152b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_caps = SFGPIO_DEFAULT_CAPS;
153b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_flags =
154b47e5c5dSJessica Clarke ((input_en & (1u << i)) ? GPIO_PIN_INPUT : 0) |
155b47e5c5dSJessica Clarke ((output_en & (1u << i)) ? GPIO_PIN_OUTPUT : 0);
156b47e5c5dSJessica Clarke snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, "GPIO%d", i);
157b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_name[GPIOMAXNAME - 1] = '\0';
158b47e5c5dSJessica Clarke }
159b47e5c5dSJessica Clarke
160b47e5c5dSJessica Clarke sc->busdev = gpiobus_attach_bus(dev);
161b47e5c5dSJessica Clarke if (sc->busdev == NULL) {
162b47e5c5dSJessica Clarke device_printf(dev, "Cannot attach gpiobus\n");
163b47e5c5dSJessica Clarke error = ENXIO;
164b47e5c5dSJessica Clarke goto fail;
165b47e5c5dSJessica Clarke }
166b47e5c5dSJessica Clarke
167b47e5c5dSJessica Clarke return (0);
168b47e5c5dSJessica Clarke
169b47e5c5dSJessica Clarke fail:
170b47e5c5dSJessica Clarke if (sc->busdev != NULL)
171b47e5c5dSJessica Clarke gpiobus_detach_bus(dev);
172b47e5c5dSJessica Clarke if (sc->irq_res != NULL)
173b47e5c5dSJessica Clarke bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid,
174b47e5c5dSJessica Clarke sc->irq_res);
175b47e5c5dSJessica Clarke if (sc->mem_res != NULL)
176b47e5c5dSJessica Clarke bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid,
177b47e5c5dSJessica Clarke sc->mem_res);
178b47e5c5dSJessica Clarke mtx_destroy(&sc->mtx);
179b47e5c5dSJessica Clarke return (error);
180b47e5c5dSJessica Clarke }
181b47e5c5dSJessica Clarke
182b47e5c5dSJessica Clarke static device_t
sfgpio_get_bus(device_t dev)183b47e5c5dSJessica Clarke sfgpio_get_bus(device_t dev)
184b47e5c5dSJessica Clarke {
185b47e5c5dSJessica Clarke struct sfgpio_softc *sc;
186b47e5c5dSJessica Clarke
187b47e5c5dSJessica Clarke sc = device_get_softc(dev);
188b47e5c5dSJessica Clarke
189b47e5c5dSJessica Clarke return (sc->busdev);
190b47e5c5dSJessica Clarke }
191b47e5c5dSJessica Clarke
192b47e5c5dSJessica Clarke static int
sfgpio_pin_max(device_t dev,int * maxpin)193b47e5c5dSJessica Clarke sfgpio_pin_max(device_t dev, int *maxpin)
194b47e5c5dSJessica Clarke {
195b47e5c5dSJessica Clarke struct sfgpio_softc *sc;
196b47e5c5dSJessica Clarke
197b47e5c5dSJessica Clarke sc = device_get_softc(dev);
198b47e5c5dSJessica Clarke
199b47e5c5dSJessica Clarke *maxpin = sc->npins - 1;
200b47e5c5dSJessica Clarke
201b47e5c5dSJessica Clarke return (0);
202b47e5c5dSJessica Clarke }
203b47e5c5dSJessica Clarke
204b47e5c5dSJessica Clarke static int
sfgpio_pin_set(device_t dev,uint32_t pin,unsigned int val)205b47e5c5dSJessica Clarke sfgpio_pin_set(device_t dev, uint32_t pin, unsigned int val)
206b47e5c5dSJessica Clarke {
207b47e5c5dSJessica Clarke struct sfgpio_softc *sc;
208b47e5c5dSJessica Clarke uint32_t reg;
209b47e5c5dSJessica Clarke
210b47e5c5dSJessica Clarke sc = device_get_softc(dev);
211b47e5c5dSJessica Clarke
212b47e5c5dSJessica Clarke if (pin >= sc->npins)
213b47e5c5dSJessica Clarke return (EINVAL);
214b47e5c5dSJessica Clarke
215b47e5c5dSJessica Clarke SFGPIO_LOCK(sc);
216b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL);
217b47e5c5dSJessica Clarke if (val)
218b47e5c5dSJessica Clarke reg |= (1u << pin);
219b47e5c5dSJessica Clarke else
220b47e5c5dSJessica Clarke reg &= ~(1u << pin);
221b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_OUTPUT_VAL, reg);
222b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc);
223b47e5c5dSJessica Clarke
224b47e5c5dSJessica Clarke return (0);
225b47e5c5dSJessica Clarke }
226b47e5c5dSJessica Clarke
227b47e5c5dSJessica Clarke static int
sfgpio_pin_get(device_t dev,uint32_t pin,unsigned int * val)228b47e5c5dSJessica Clarke sfgpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
229b47e5c5dSJessica Clarke {
230b47e5c5dSJessica Clarke struct sfgpio_softc *sc;
231b47e5c5dSJessica Clarke uint32_t reg;
232b47e5c5dSJessica Clarke
233b47e5c5dSJessica Clarke sc = device_get_softc(dev);
234b47e5c5dSJessica Clarke
235b47e5c5dSJessica Clarke if (pin >= sc->npins)
236b47e5c5dSJessica Clarke return (EINVAL);
237b47e5c5dSJessica Clarke
238b47e5c5dSJessica Clarke SFGPIO_LOCK(sc);
239b47e5c5dSJessica Clarke if (sc->gpio_pins[pin].gp_flags & GPIO_PIN_OUTPUT)
240b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL);
241b47e5c5dSJessica Clarke else
242b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_INPUT_VAL);
243b47e5c5dSJessica Clarke *val = (reg & (1u << pin)) ? 1 : 0;
244b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc);
245b47e5c5dSJessica Clarke
246b47e5c5dSJessica Clarke return (0);
247b47e5c5dSJessica Clarke }
248b47e5c5dSJessica Clarke
249b47e5c5dSJessica Clarke static int
sfgpio_pin_toggle(device_t dev,uint32_t pin)250b47e5c5dSJessica Clarke sfgpio_pin_toggle(device_t dev, uint32_t pin)
251b47e5c5dSJessica Clarke {
252b47e5c5dSJessica Clarke struct sfgpio_softc *sc;
253b47e5c5dSJessica Clarke uint32_t reg;
254b47e5c5dSJessica Clarke
255b47e5c5dSJessica Clarke sc = device_get_softc(dev);
256b47e5c5dSJessica Clarke
257b47e5c5dSJessica Clarke if (pin >= sc->npins)
258b47e5c5dSJessica Clarke return (EINVAL);
259b47e5c5dSJessica Clarke
260b47e5c5dSJessica Clarke SFGPIO_LOCK(sc);
261b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL);
262b47e5c5dSJessica Clarke reg ^= (1u << pin);
263b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_OUTPUT_VAL, reg);
264b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc);
265b47e5c5dSJessica Clarke
266b47e5c5dSJessica Clarke return (0);
267b47e5c5dSJessica Clarke }
268b47e5c5dSJessica Clarke
269b47e5c5dSJessica Clarke static int
sfgpio_pin_getcaps(device_t dev,uint32_t pin,uint32_t * caps)270b47e5c5dSJessica Clarke sfgpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
271b47e5c5dSJessica Clarke {
272b47e5c5dSJessica Clarke struct sfgpio_softc *sc;
273b47e5c5dSJessica Clarke
274b47e5c5dSJessica Clarke sc = device_get_softc(dev);
275b47e5c5dSJessica Clarke
276b47e5c5dSJessica Clarke if (pin >= sc->npins)
277b47e5c5dSJessica Clarke return (EINVAL);
278b47e5c5dSJessica Clarke
279b47e5c5dSJessica Clarke SFGPIO_LOCK(sc);
280b47e5c5dSJessica Clarke *caps = sc->gpio_pins[pin].gp_caps;
281b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc);
282b47e5c5dSJessica Clarke
283b47e5c5dSJessica Clarke return (0);
284b47e5c5dSJessica Clarke }
285b47e5c5dSJessica Clarke
286b47e5c5dSJessica Clarke static int
sfgpio_pin_getflags(device_t dev,uint32_t pin,uint32_t * flags)287b47e5c5dSJessica Clarke sfgpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
288b47e5c5dSJessica Clarke {
289b47e5c5dSJessica Clarke struct sfgpio_softc *sc;
290b47e5c5dSJessica Clarke
291b47e5c5dSJessica Clarke sc = device_get_softc(dev);
292b47e5c5dSJessica Clarke
293b47e5c5dSJessica Clarke if (pin >= sc->npins)
294b47e5c5dSJessica Clarke return (EINVAL);
295b47e5c5dSJessica Clarke
296b47e5c5dSJessica Clarke SFGPIO_LOCK(sc);
297b47e5c5dSJessica Clarke *flags = sc->gpio_pins[pin].gp_flags;
298b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc);
299b47e5c5dSJessica Clarke
300b47e5c5dSJessica Clarke return (0);
301b47e5c5dSJessica Clarke }
302b47e5c5dSJessica Clarke
303b47e5c5dSJessica Clarke static int
sfgpio_pin_getname(device_t dev,uint32_t pin,char * name)304b47e5c5dSJessica Clarke sfgpio_pin_getname(device_t dev, uint32_t pin, char *name)
305b47e5c5dSJessica Clarke {
306b47e5c5dSJessica Clarke struct sfgpio_softc *sc;
307b47e5c5dSJessica Clarke
308b47e5c5dSJessica Clarke sc = device_get_softc(dev);
309b47e5c5dSJessica Clarke
310b47e5c5dSJessica Clarke if (pin >= sc->npins)
311b47e5c5dSJessica Clarke return (EINVAL);
312b47e5c5dSJessica Clarke
313b47e5c5dSJessica Clarke SFGPIO_LOCK(sc);
314b47e5c5dSJessica Clarke memcpy(name, sc->gpio_pins[pin].gp_name, GPIOMAXNAME);
315b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc);
316b47e5c5dSJessica Clarke
317b47e5c5dSJessica Clarke return (0);
318b47e5c5dSJessica Clarke }
319b47e5c5dSJessica Clarke
320b47e5c5dSJessica Clarke static int
sfgpio_pin_setflags(device_t dev,uint32_t pin,uint32_t flags)321b47e5c5dSJessica Clarke sfgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
322b47e5c5dSJessica Clarke {
323b47e5c5dSJessica Clarke struct sfgpio_softc *sc;
324b47e5c5dSJessica Clarke uint32_t reg;
325b47e5c5dSJessica Clarke
326b47e5c5dSJessica Clarke sc = device_get_softc(dev);
327b47e5c5dSJessica Clarke
328b47e5c5dSJessica Clarke if (pin >= sc->npins)
329b47e5c5dSJessica Clarke return (EINVAL);
330b47e5c5dSJessica Clarke
331b47e5c5dSJessica Clarke SFGPIO_LOCK(sc);
332b47e5c5dSJessica Clarke
333b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_INPUT_EN);
334b47e5c5dSJessica Clarke if (flags & GPIO_PIN_INPUT) {
335b47e5c5dSJessica Clarke reg |= (1u << pin);
336b47e5c5dSJessica Clarke sc->gpio_pins[pin].gp_flags |= GPIO_PIN_INPUT;
337b47e5c5dSJessica Clarke } else {
338b47e5c5dSJessica Clarke reg &= ~(1u << pin);
339b47e5c5dSJessica Clarke sc->gpio_pins[pin].gp_flags &= ~GPIO_PIN_INPUT;
340b47e5c5dSJessica Clarke }
341b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_INPUT_EN, reg);
342b47e5c5dSJessica Clarke
343b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_EN);
344b47e5c5dSJessica Clarke if (flags & GPIO_PIN_OUTPUT) {
345b47e5c5dSJessica Clarke reg |= (1u << pin);
346b47e5c5dSJessica Clarke sc->gpio_pins[pin].gp_flags |= GPIO_PIN_OUTPUT;
347b47e5c5dSJessica Clarke } else {
348b47e5c5dSJessica Clarke reg &= ~(1u << pin);
349b47e5c5dSJessica Clarke sc->gpio_pins[pin].gp_flags &= ~GPIO_PIN_OUTPUT;
350b47e5c5dSJessica Clarke }
351b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_OUTPUT_EN, reg);
352b47e5c5dSJessica Clarke
353b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc);
354b47e5c5dSJessica Clarke
355b47e5c5dSJessica Clarke return (0);
356b47e5c5dSJessica Clarke }
357b47e5c5dSJessica Clarke
358b47e5c5dSJessica Clarke static int
sfgpio_pin_access_32(device_t dev,uint32_t first_pin,uint32_t clear_pins,uint32_t change_pins,uint32_t * orig_pins)359b47e5c5dSJessica Clarke sfgpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins,
360b47e5c5dSJessica Clarke uint32_t change_pins, uint32_t *orig_pins)
361b47e5c5dSJessica Clarke {
362b47e5c5dSJessica Clarke struct sfgpio_softc *sc;
363b47e5c5dSJessica Clarke uint32_t reg;
364b47e5c5dSJessica Clarke
365b47e5c5dSJessica Clarke if (first_pin != 0)
366b47e5c5dSJessica Clarke return (EINVAL);
367b47e5c5dSJessica Clarke
368b47e5c5dSJessica Clarke sc = device_get_softc(dev);
369b47e5c5dSJessica Clarke
370b47e5c5dSJessica Clarke SFGPIO_LOCK(sc);
371b47e5c5dSJessica Clarke
372b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL);
373b47e5c5dSJessica Clarke
374b47e5c5dSJessica Clarke if (orig_pins != NULL)
375b47e5c5dSJessica Clarke /* Only input_val is implicitly masked by input_en */
376b47e5c5dSJessica Clarke *orig_pins = SFGPIO_READ(sc, SFGPIO_INPUT_VAL) |
377b47e5c5dSJessica Clarke (reg & SFGPIO_READ(sc, SFGPIO_OUTPUT_EN));
378b47e5c5dSJessica Clarke
379b47e5c5dSJessica Clarke if ((clear_pins | change_pins) != 0)
380b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_OUTPUT_VAL,
381b47e5c5dSJessica Clarke (reg & ~clear_pins) ^ change_pins);
382b47e5c5dSJessica Clarke
383b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc);
384b47e5c5dSJessica Clarke
385b47e5c5dSJessica Clarke return (0);
386b47e5c5dSJessica Clarke }
387b47e5c5dSJessica Clarke
388b47e5c5dSJessica Clarke static int
sfgpio_pin_config_32(device_t dev,uint32_t first_pin,uint32_t num_pins,uint32_t * pin_flags)389b47e5c5dSJessica Clarke sfgpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins,
390b47e5c5dSJessica Clarke uint32_t *pin_flags)
391b47e5c5dSJessica Clarke {
392b47e5c5dSJessica Clarke struct sfgpio_softc *sc;
393b47e5c5dSJessica Clarke uint32_t ireg, oreg;
394b47e5c5dSJessica Clarke int i;
395b47e5c5dSJessica Clarke
396b47e5c5dSJessica Clarke sc = device_get_softc(dev);
397b47e5c5dSJessica Clarke
398b47e5c5dSJessica Clarke if (first_pin != 0 || num_pins > sc->npins)
399b47e5c5dSJessica Clarke return (EINVAL);
400b47e5c5dSJessica Clarke
401b47e5c5dSJessica Clarke SFGPIO_LOCK(sc);
402b47e5c5dSJessica Clarke
403b47e5c5dSJessica Clarke ireg = SFGPIO_READ(sc, SFGPIO_INPUT_EN);
404b47e5c5dSJessica Clarke oreg = SFGPIO_READ(sc, SFGPIO_OUTPUT_EN);
405b47e5c5dSJessica Clarke for (i = 0; i < num_pins; ++i) {
406b47e5c5dSJessica Clarke if (pin_flags[i] & GPIO_PIN_INPUT) {
407b47e5c5dSJessica Clarke ireg |= (1u << i);
408b47e5c5dSJessica Clarke oreg &= ~(1u << i);
409b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_flags |= GPIO_PIN_INPUT;
410b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_flags &= ~GPIO_PIN_OUTPUT;
411b47e5c5dSJessica Clarke } else if (pin_flags[i] & GPIO_PIN_OUTPUT) {
412b47e5c5dSJessica Clarke ireg &= ~(1u << i);
413b47e5c5dSJessica Clarke oreg |= (1u << i);
414b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_flags &= ~GPIO_PIN_INPUT;
415b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_flags |= GPIO_PIN_OUTPUT;
416b47e5c5dSJessica Clarke }
417b47e5c5dSJessica Clarke }
418b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_INPUT_EN, ireg);
419b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_OUTPUT_EN, oreg);
420b47e5c5dSJessica Clarke
421b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc);
422b47e5c5dSJessica Clarke
423b47e5c5dSJessica Clarke return (0);
424b47e5c5dSJessica Clarke }
425b47e5c5dSJessica Clarke
426b47e5c5dSJessica Clarke static phandle_t
sfgpio_get_node(device_t bus,device_t dev)427b47e5c5dSJessica Clarke sfgpio_get_node(device_t bus, device_t dev)
428b47e5c5dSJessica Clarke {
429b47e5c5dSJessica Clarke return (ofw_bus_get_node(bus));
430b47e5c5dSJessica Clarke }
431b47e5c5dSJessica Clarke
432b47e5c5dSJessica Clarke static device_method_t sfgpio_methods[] = {
433b47e5c5dSJessica Clarke /* Device interface */
434b47e5c5dSJessica Clarke DEVMETHOD(device_probe, sfgpio_probe),
435b47e5c5dSJessica Clarke DEVMETHOD(device_attach, sfgpio_attach),
436b47e5c5dSJessica Clarke
437b47e5c5dSJessica Clarke /* GPIO protocol */
438b47e5c5dSJessica Clarke DEVMETHOD(gpio_get_bus, sfgpio_get_bus),
439b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_max, sfgpio_pin_max),
440b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_set, sfgpio_pin_set),
441b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_get, sfgpio_pin_get),
442b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_toggle, sfgpio_pin_toggle),
443b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_getcaps, sfgpio_pin_getcaps),
444b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_getflags, sfgpio_pin_getflags),
445b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_getname, sfgpio_pin_getname),
446b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_setflags, sfgpio_pin_setflags),
447b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_access_32, sfgpio_pin_access_32),
448b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_config_32, sfgpio_pin_config_32),
449b47e5c5dSJessica Clarke
450b47e5c5dSJessica Clarke /* ofw_bus interface */
451b47e5c5dSJessica Clarke DEVMETHOD(ofw_bus_get_node, sfgpio_get_node),
452b47e5c5dSJessica Clarke
453b47e5c5dSJessica Clarke DEVMETHOD_END
454b47e5c5dSJessica Clarke };
455b47e5c5dSJessica Clarke
456b47e5c5dSJessica Clarke DEFINE_CLASS_0(gpio, sfgpio_driver, sfgpio_methods,
457b47e5c5dSJessica Clarke sizeof(struct sfgpio_softc));
458bb32809bSJohn Baldwin EARLY_DRIVER_MODULE(gpio, simplebus, sfgpio_driver, 0, 0,
459b47e5c5dSJessica Clarke BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
460b47e5c5dSJessica Clarke MODULE_DEPEND(sfgpio, gpiobus, 1, 1, 1);
461