1*84c68dbbSTetsuya Uemura /*
2*84c68dbbSTetsuya Uemura * SPDX-License-Identifier: BSD-2-Clause
3*84c68dbbSTetsuya Uemura *
4*84c68dbbSTetsuya Uemura * Copyright (c) 2025 Tetsuya Uemura <t_uemura@macome.co.jp>
5*84c68dbbSTetsuya Uemura *
6*84c68dbbSTetsuya Uemura * Redistribution and use in source and binary forms, with or without
7*84c68dbbSTetsuya Uemura * modification, are permitted provided that the following conditions
8*84c68dbbSTetsuya Uemura * are met:
9*84c68dbbSTetsuya Uemura * 1. Redistributions of source code must retain the above copyright
10*84c68dbbSTetsuya Uemura * notice, this list of conditions and the following disclaimer.
11*84c68dbbSTetsuya Uemura * 2. Redistributions in binary form must reproduce the above copyright
12*84c68dbbSTetsuya Uemura * notice, this list of conditions and the following disclaimer in the
13*84c68dbbSTetsuya Uemura * documentation and/or other materials provided with the distribution.
14*84c68dbbSTetsuya Uemura *
15*84c68dbbSTetsuya Uemura * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*84c68dbbSTetsuya Uemura * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*84c68dbbSTetsuya Uemura * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*84c68dbbSTetsuya Uemura * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*84c68dbbSTetsuya Uemura * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*84c68dbbSTetsuya Uemura * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*84c68dbbSTetsuya Uemura * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*84c68dbbSTetsuya Uemura * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*84c68dbbSTetsuya Uemura * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*84c68dbbSTetsuya Uemura * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*84c68dbbSTetsuya Uemura * SUCH DAMAGE.
26*84c68dbbSTetsuya Uemura */
27*84c68dbbSTetsuya Uemura
28*84c68dbbSTetsuya Uemura /*
29*84c68dbbSTetsuya Uemura * This is a driver for bcm2835-virtgpio GPIO controller device found on some
30*84c68dbbSTetsuya Uemura * Raspberry Pi models (listed below but not limited to). On which, the green
31*84c68dbbSTetsuya Uemura * LED (ACT) is connected to this controller. With the help of this driver, a
32*84c68dbbSTetsuya Uemura * node corresponding to the green LED will be created under /dev/led, allowing
33*84c68dbbSTetsuya Uemura * us to control it.
34*84c68dbbSTetsuya Uemura *
35*84c68dbbSTetsuya Uemura * Applicable models (according to the FDTs of those models):
36*84c68dbbSTetsuya Uemura * Compute Module 2 (CM2)
37*84c68dbbSTetsuya Uemura * 3 Model B (not 3B+)
38*84c68dbbSTetsuya Uemura * Compute Module 3 (CM3) and possibly 3+ (CM3+)
39*84c68dbbSTetsuya Uemura * Compute Module 4 SODIMM (CM4S)
40*84c68dbbSTetsuya Uemura */
41*84c68dbbSTetsuya Uemura
42*84c68dbbSTetsuya Uemura #include "opt_platform.h"
43*84c68dbbSTetsuya Uemura
44*84c68dbbSTetsuya Uemura #include <sys/param.h>
45*84c68dbbSTetsuya Uemura #include <sys/systm.h>
46*84c68dbbSTetsuya Uemura #include <sys/gpio.h>
47*84c68dbbSTetsuya Uemura #include <sys/kernel.h>
48*84c68dbbSTetsuya Uemura #include <sys/malloc.h>
49*84c68dbbSTetsuya Uemura #include <sys/module.h>
50*84c68dbbSTetsuya Uemura #include <sys/mutex.h>
51*84c68dbbSTetsuya Uemura
52*84c68dbbSTetsuya Uemura #include <vm/vm.h>
53*84c68dbbSTetsuya Uemura #include <vm/pmap.h>
54*84c68dbbSTetsuya Uemura
55*84c68dbbSTetsuya Uemura #include <dev/gpio/gpiobusvar.h>
56*84c68dbbSTetsuya Uemura #include <dev/ofw/ofw_bus.h>
57*84c68dbbSTetsuya Uemura
58*84c68dbbSTetsuya Uemura #include <arm/broadcom/bcm2835/bcm2835_firmware.h>
59*84c68dbbSTetsuya Uemura #include <arm/broadcom/bcm2835/bcm2835_vcbus.h>
60*84c68dbbSTetsuya Uemura
61*84c68dbbSTetsuya Uemura #include "gpio_if.h"
62*84c68dbbSTetsuya Uemura
63*84c68dbbSTetsuya Uemura #define RPI_VIRT_GPIO_PINS 2
64*84c68dbbSTetsuya Uemura
65*84c68dbbSTetsuya Uemura struct rpi_virt_gpio_softc {
66*84c68dbbSTetsuya Uemura device_t busdev;
67*84c68dbbSTetsuya Uemura device_t firmware;
68*84c68dbbSTetsuya Uemura struct mtx sc_mtx;
69*84c68dbbSTetsuya Uemura
70*84c68dbbSTetsuya Uemura void *vaddr; /* Virtual address. */
71*84c68dbbSTetsuya Uemura vm_paddr_t paddr; /* Physical address. */
72*84c68dbbSTetsuya Uemura
73*84c68dbbSTetsuya Uemura struct gpio_pin gpio_pins[RPI_VIRT_GPIO_PINS];
74*84c68dbbSTetsuya Uemura uint32_t state[RPI_VIRT_GPIO_PINS];
75*84c68dbbSTetsuya Uemura };
76*84c68dbbSTetsuya Uemura
77*84c68dbbSTetsuya Uemura #define RPI_VIRT_GPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx)
78*84c68dbbSTetsuya Uemura #define RPI_VIRT_GPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx)
79*84c68dbbSTetsuya Uemura
80*84c68dbbSTetsuya Uemura static struct ofw_compat_data compat_data[] = {
81*84c68dbbSTetsuya Uemura {"brcm,bcm2835-virtgpio", 1},
82*84c68dbbSTetsuya Uemura {NULL, 0}
83*84c68dbbSTetsuya Uemura };
84*84c68dbbSTetsuya Uemura
85*84c68dbbSTetsuya Uemura static device_t
rpi_virt_gpio_get_bus(device_t dev)86*84c68dbbSTetsuya Uemura rpi_virt_gpio_get_bus(device_t dev)
87*84c68dbbSTetsuya Uemura {
88*84c68dbbSTetsuya Uemura struct rpi_virt_gpio_softc *sc;
89*84c68dbbSTetsuya Uemura
90*84c68dbbSTetsuya Uemura sc = device_get_softc(dev);
91*84c68dbbSTetsuya Uemura
92*84c68dbbSTetsuya Uemura return (sc->busdev);
93*84c68dbbSTetsuya Uemura }
94*84c68dbbSTetsuya Uemura
95*84c68dbbSTetsuya Uemura static int
rpi_virt_gpio_pin_max(device_t dev,int * maxpin)96*84c68dbbSTetsuya Uemura rpi_virt_gpio_pin_max(device_t dev, int *maxpin)
97*84c68dbbSTetsuya Uemura {
98*84c68dbbSTetsuya Uemura *maxpin = RPI_VIRT_GPIO_PINS - 1;
99*84c68dbbSTetsuya Uemura
100*84c68dbbSTetsuya Uemura return (0);
101*84c68dbbSTetsuya Uemura }
102*84c68dbbSTetsuya Uemura
103*84c68dbbSTetsuya Uemura static int
rpi_virt_gpio_pin_getcaps(device_t dev,uint32_t pin,uint32_t * caps)104*84c68dbbSTetsuya Uemura rpi_virt_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
105*84c68dbbSTetsuya Uemura {
106*84c68dbbSTetsuya Uemura if (pin >= RPI_VIRT_GPIO_PINS)
107*84c68dbbSTetsuya Uemura return (EINVAL);
108*84c68dbbSTetsuya Uemura
109*84c68dbbSTetsuya Uemura *caps = GPIO_PIN_OUTPUT;
110*84c68dbbSTetsuya Uemura
111*84c68dbbSTetsuya Uemura return (0);
112*84c68dbbSTetsuya Uemura }
113*84c68dbbSTetsuya Uemura
114*84c68dbbSTetsuya Uemura static int
rpi_virt_gpio_pin_getflags(device_t dev,uint32_t pin,uint32_t * flags)115*84c68dbbSTetsuya Uemura rpi_virt_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
116*84c68dbbSTetsuya Uemura {
117*84c68dbbSTetsuya Uemura if (pin >= RPI_VIRT_GPIO_PINS)
118*84c68dbbSTetsuya Uemura return (EINVAL);
119*84c68dbbSTetsuya Uemura
120*84c68dbbSTetsuya Uemura *flags = GPIO_PIN_OUTPUT;
121*84c68dbbSTetsuya Uemura
122*84c68dbbSTetsuya Uemura return (0);
123*84c68dbbSTetsuya Uemura }
124*84c68dbbSTetsuya Uemura
125*84c68dbbSTetsuya Uemura static int
rpi_virt_gpio_pin_set(device_t dev,uint32_t pin,uint32_t value)126*84c68dbbSTetsuya Uemura rpi_virt_gpio_pin_set(device_t dev, uint32_t pin, uint32_t value)
127*84c68dbbSTetsuya Uemura {
128*84c68dbbSTetsuya Uemura struct rpi_virt_gpio_softc *sc;
129*84c68dbbSTetsuya Uemura uint32_t *ptr;
130*84c68dbbSTetsuya Uemura uint16_t on, off;
131*84c68dbbSTetsuya Uemura
132*84c68dbbSTetsuya Uemura if (pin >= RPI_VIRT_GPIO_PINS)
133*84c68dbbSTetsuya Uemura return (EINVAL);
134*84c68dbbSTetsuya Uemura
135*84c68dbbSTetsuya Uemura sc = device_get_softc(dev);
136*84c68dbbSTetsuya Uemura
137*84c68dbbSTetsuya Uemura RPI_VIRT_GPIO_LOCK(sc);
138*84c68dbbSTetsuya Uemura on = (uint16_t)(sc->state[pin] >> 16);
139*84c68dbbSTetsuya Uemura off = (uint16_t)sc->state[pin];
140*84c68dbbSTetsuya Uemura
141*84c68dbbSTetsuya Uemura if (bootverbose)
142*84c68dbbSTetsuya Uemura device_printf(dev, "on: %hu, off: %hu, now: %d -> %u\n",
143*84c68dbbSTetsuya Uemura on, off, on - off, value);
144*84c68dbbSTetsuya Uemura
145*84c68dbbSTetsuya Uemura if ((value > 0 && on - off != 0) || (value == 0 && on - off == 0)) {
146*84c68dbbSTetsuya Uemura RPI_VIRT_GPIO_UNLOCK(sc);
147*84c68dbbSTetsuya Uemura return (0);
148*84c68dbbSTetsuya Uemura }
149*84c68dbbSTetsuya Uemura
150*84c68dbbSTetsuya Uemura if (value > 0)
151*84c68dbbSTetsuya Uemura ++on;
152*84c68dbbSTetsuya Uemura else
153*84c68dbbSTetsuya Uemura ++off;
154*84c68dbbSTetsuya Uemura
155*84c68dbbSTetsuya Uemura sc->state[pin] = (on << 16 | off);
156*84c68dbbSTetsuya Uemura ptr = (uint32_t *)sc->vaddr;
157*84c68dbbSTetsuya Uemura ptr[pin] = sc->state[pin];
158*84c68dbbSTetsuya Uemura RPI_VIRT_GPIO_UNLOCK(sc);
159*84c68dbbSTetsuya Uemura
160*84c68dbbSTetsuya Uemura return (0);
161*84c68dbbSTetsuya Uemura }
162*84c68dbbSTetsuya Uemura
163*84c68dbbSTetsuya Uemura static int
rpi_virt_gpio_pin_get(device_t dev,uint32_t pin,uint32_t * val)164*84c68dbbSTetsuya Uemura rpi_virt_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *val)
165*84c68dbbSTetsuya Uemura {
166*84c68dbbSTetsuya Uemura struct rpi_virt_gpio_softc *sc;
167*84c68dbbSTetsuya Uemura uint32_t *ptr, v;
168*84c68dbbSTetsuya Uemura
169*84c68dbbSTetsuya Uemura if (pin >= RPI_VIRT_GPIO_PINS)
170*84c68dbbSTetsuya Uemura return (EINVAL);
171*84c68dbbSTetsuya Uemura
172*84c68dbbSTetsuya Uemura sc = device_get_softc(dev);
173*84c68dbbSTetsuya Uemura
174*84c68dbbSTetsuya Uemura ptr = (uint32_t *)sc->vaddr;
175*84c68dbbSTetsuya Uemura RPI_VIRT_GPIO_LOCK(sc);
176*84c68dbbSTetsuya Uemura v = ptr[pin];
177*84c68dbbSTetsuya Uemura RPI_VIRT_GPIO_UNLOCK(sc);
178*84c68dbbSTetsuya Uemura *val = ((uint16_t)(v >> 16) - (uint16_t)v) == 0 ? 0 : 1;
179*84c68dbbSTetsuya Uemura
180*84c68dbbSTetsuya Uemura return (0);
181*84c68dbbSTetsuya Uemura }
182*84c68dbbSTetsuya Uemura
183*84c68dbbSTetsuya Uemura static int
rpi_virt_gpio_pin_toggle(device_t dev,uint32_t pin)184*84c68dbbSTetsuya Uemura rpi_virt_gpio_pin_toggle(device_t dev, uint32_t pin)
185*84c68dbbSTetsuya Uemura {
186*84c68dbbSTetsuya Uemura int rv;
187*84c68dbbSTetsuya Uemura unsigned int val;
188*84c68dbbSTetsuya Uemura
189*84c68dbbSTetsuya Uemura if (pin >= RPI_VIRT_GPIO_PINS)
190*84c68dbbSTetsuya Uemura return (EINVAL);
191*84c68dbbSTetsuya Uemura
192*84c68dbbSTetsuya Uemura rv = rpi_virt_gpio_pin_get(dev, pin, &val);
193*84c68dbbSTetsuya Uemura if (rv != 0)
194*84c68dbbSTetsuya Uemura return (rv);
195*84c68dbbSTetsuya Uemura
196*84c68dbbSTetsuya Uemura rv = rpi_virt_gpio_pin_set(dev, pin, val == 0 ? 1 : 0);
197*84c68dbbSTetsuya Uemura
198*84c68dbbSTetsuya Uemura return (rv);
199*84c68dbbSTetsuya Uemura }
200*84c68dbbSTetsuya Uemura
201*84c68dbbSTetsuya Uemura static int
rpi_virt_gpio_probe(device_t dev)202*84c68dbbSTetsuya Uemura rpi_virt_gpio_probe(device_t dev)
203*84c68dbbSTetsuya Uemura {
204*84c68dbbSTetsuya Uemura device_t firmware;
205*84c68dbbSTetsuya Uemura phandle_t gpio;
206*84c68dbbSTetsuya Uemura union msg_gpiovirtbuf cfg;
207*84c68dbbSTetsuya Uemura int rv;
208*84c68dbbSTetsuya Uemura
209*84c68dbbSTetsuya Uemura if (ofw_bus_status_okay(dev) == 0)
210*84c68dbbSTetsuya Uemura return (ENXIO);
211*84c68dbbSTetsuya Uemura
212*84c68dbbSTetsuya Uemura if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
213*84c68dbbSTetsuya Uemura return (ENXIO);
214*84c68dbbSTetsuya Uemura
215*84c68dbbSTetsuya Uemura gpio = ofw_bus_get_node(dev);
216*84c68dbbSTetsuya Uemura if (OF_hasprop(gpio, "gpio-controller") == 0)
217*84c68dbbSTetsuya Uemura return (ENXIO);
218*84c68dbbSTetsuya Uemura
219*84c68dbbSTetsuya Uemura /* Check whether the firmware is ready. */
220*84c68dbbSTetsuya Uemura firmware = device_get_parent(dev);
221*84c68dbbSTetsuya Uemura rv = bcm2835_firmware_property(firmware,
222*84c68dbbSTetsuya Uemura BCM2835_FIRMWARE_TAG_GET_GPIOVIRTBUF, &cfg, sizeof(cfg));
223*84c68dbbSTetsuya Uemura if (rv != 0)
224*84c68dbbSTetsuya Uemura return (ENXIO);
225*84c68dbbSTetsuya Uemura
226*84c68dbbSTetsuya Uemura device_set_desc(dev, "Raspberry Pi Virtual GPIO controller");
227*84c68dbbSTetsuya Uemura
228*84c68dbbSTetsuya Uemura return (BUS_PROBE_DEFAULT);
229*84c68dbbSTetsuya Uemura }
230*84c68dbbSTetsuya Uemura
231*84c68dbbSTetsuya Uemura static int
rpi_virt_gpio_attach(device_t dev)232*84c68dbbSTetsuya Uemura rpi_virt_gpio_attach(device_t dev)
233*84c68dbbSTetsuya Uemura {
234*84c68dbbSTetsuya Uemura struct rpi_virt_gpio_softc *sc;
235*84c68dbbSTetsuya Uemura union msg_gpiovirtbuf cfg;
236*84c68dbbSTetsuya Uemura int i, rv;
237*84c68dbbSTetsuya Uemura
238*84c68dbbSTetsuya Uemura sc = device_get_softc(dev);
239*84c68dbbSTetsuya Uemura sc->firmware = device_get_parent(dev);
240*84c68dbbSTetsuya Uemura mtx_init(&sc->sc_mtx, "Raspberry Pi virtgpio", NULL, MTX_SPIN);
241*84c68dbbSTetsuya Uemura
242*84c68dbbSTetsuya Uemura /*
243*84c68dbbSTetsuya Uemura * According to the Linux source at:
244*84c68dbbSTetsuya Uemura * https://github.com/raspberrypi/linux/blob/rpi-6.12.y/drivers/gpio/gpio-bcm-virt.c
245*84c68dbbSTetsuya Uemura * it first attempts to set the pre-allocated physical memory address
246*84c68dbbSTetsuya Uemura * in the firmware. If it is successfully acquired, access virtgpio via
247*84c68dbbSTetsuya Uemura * the virtual memory address mapped to that physical address.
248*84c68dbbSTetsuya Uemura *
249*84c68dbbSTetsuya Uemura * If the above fails, then as a fallback, attempts to obtain a
250*84c68dbbSTetsuya Uemura * physical memory address for accessing virtgpio from the firmware.
251*84c68dbbSTetsuya Uemura * And if obtained, link it to a virtual memory address and access
252*84c68dbbSTetsuya Uemura * virtgpio via it.
253*84c68dbbSTetsuya Uemura *
254*84c68dbbSTetsuya Uemura * An OpenWRT virtgpio driver I happened to see at first only
255*84c68dbbSTetsuya Uemura * implemented the fallback method. Then I implemented this method on
256*84c68dbbSTetsuya Uemura * FreeBSD and tested it with the 20240429 firmware, but it didn't
257*84c68dbbSTetsuya Uemura * work.
258*84c68dbbSTetsuya Uemura *
259*84c68dbbSTetsuya Uemura * At this point, I realised the first method in the source above. So I
260*84c68dbbSTetsuya Uemura * implemented this method on FreeBSD and tested it, and it worked. In
261*84c68dbbSTetsuya Uemura * my opinion, the second method was used until some time prior to
262*84c68dbbSTetsuya Uemura * 20240429, and then the firmware was modified and the first method
263*84c68dbbSTetsuya Uemura * was introduced. In my driver, only the first method exists.
264*84c68dbbSTetsuya Uemura */
265*84c68dbbSTetsuya Uemura
266*84c68dbbSTetsuya Uemura /* Allocate a physical memory range for accessing virtgpio. */
267*84c68dbbSTetsuya Uemura sc->vaddr = contigmalloc(
268*84c68dbbSTetsuya Uemura PAGE_SIZE, /* size */
269*84c68dbbSTetsuya Uemura M_DEVBUF, M_ZERO, /* type, flags */
270*84c68dbbSTetsuya Uemura 0, BCM2838_PERIPH_MAXADDR, /* low, high */
271*84c68dbbSTetsuya Uemura PAGE_SIZE, 0); /* alignment, boundary */
272*84c68dbbSTetsuya Uemura if (sc->vaddr == NULL) {
273*84c68dbbSTetsuya Uemura device_printf(dev, "Failed to allocate memory.\n");
274*84c68dbbSTetsuya Uemura return ENOMEM;
275*84c68dbbSTetsuya Uemura }
276*84c68dbbSTetsuya Uemura sc->paddr = vtophys(sc->vaddr);
277*84c68dbbSTetsuya Uemura /* Mark it uncacheable. */
278*84c68dbbSTetsuya Uemura pmap_change_attr((vm_offset_t)sc->vaddr, PAGE_SIZE,
279*84c68dbbSTetsuya Uemura VM_MEMATTR_UNCACHEABLE);
280*84c68dbbSTetsuya Uemura
281*84c68dbbSTetsuya Uemura if (bootverbose)
282*84c68dbbSTetsuya Uemura device_printf(dev,
283*84c68dbbSTetsuya Uemura "KVA alloc'd: virtual: %p, phys: %#jx\n",
284*84c68dbbSTetsuya Uemura sc->vaddr, (uintmax_t)sc->paddr);
285*84c68dbbSTetsuya Uemura
286*84c68dbbSTetsuya Uemura /* Set this address in firmware. */
287*84c68dbbSTetsuya Uemura cfg.req.addr = (uint32_t)sc->paddr;
288*84c68dbbSTetsuya Uemura rv = bcm2835_firmware_property(sc->firmware,
289*84c68dbbSTetsuya Uemura BCM2835_FIRMWARE_TAG_SET_GPIOVIRTBUF, &cfg, sizeof(cfg));
290*84c68dbbSTetsuya Uemura if (bootverbose)
291*84c68dbbSTetsuya Uemura device_printf(dev, "rv: %d, addr: 0x%x\n", rv, cfg.resp.addr);
292*84c68dbbSTetsuya Uemura if (rv != 0 || cfg.resp.addr != 0)
293*84c68dbbSTetsuya Uemura goto fail;
294*84c68dbbSTetsuya Uemura
295*84c68dbbSTetsuya Uemura /* Pins only support output. */
296*84c68dbbSTetsuya Uemura for (i = 0; i < RPI_VIRT_GPIO_PINS; i++) {
297*84c68dbbSTetsuya Uemura sc->gpio_pins[i].gp_pin = i;
298*84c68dbbSTetsuya Uemura sc->gpio_pins[i].gp_caps = sc->gpio_pins[i].gp_flags
299*84c68dbbSTetsuya Uemura = GPIO_PIN_OUTPUT;
300*84c68dbbSTetsuya Uemura }
301*84c68dbbSTetsuya Uemura sc->busdev = gpiobus_add_bus(dev);
302*84c68dbbSTetsuya Uemura if (sc->busdev == NULL)
303*84c68dbbSTetsuya Uemura goto fail;
304*84c68dbbSTetsuya Uemura
305*84c68dbbSTetsuya Uemura bus_attach_children(dev);
306*84c68dbbSTetsuya Uemura return (0);
307*84c68dbbSTetsuya Uemura
308*84c68dbbSTetsuya Uemura fail:
309*84c68dbbSTetsuya Uemura /* Release resource if necessary. */
310*84c68dbbSTetsuya Uemura free(sc->vaddr, M_DEVBUF);
311*84c68dbbSTetsuya Uemura mtx_destroy(&sc->sc_mtx);
312*84c68dbbSTetsuya Uemura
313*84c68dbbSTetsuya Uemura return (ENXIO);
314*84c68dbbSTetsuya Uemura }
315*84c68dbbSTetsuya Uemura
316*84c68dbbSTetsuya Uemura static int
rpi_virt_gpio_detach(device_t dev)317*84c68dbbSTetsuya Uemura rpi_virt_gpio_detach(device_t dev)
318*84c68dbbSTetsuya Uemura {
319*84c68dbbSTetsuya Uemura return (EBUSY);
320*84c68dbbSTetsuya Uemura }
321*84c68dbbSTetsuya Uemura
322*84c68dbbSTetsuya Uemura static device_method_t rpi_virt_gpio_methods[] = {
323*84c68dbbSTetsuya Uemura /* Device interface */
324*84c68dbbSTetsuya Uemura DEVMETHOD(device_probe, rpi_virt_gpio_probe),
325*84c68dbbSTetsuya Uemura DEVMETHOD(device_attach, rpi_virt_gpio_attach),
326*84c68dbbSTetsuya Uemura DEVMETHOD(device_detach, rpi_virt_gpio_detach),
327*84c68dbbSTetsuya Uemura
328*84c68dbbSTetsuya Uemura /* GPIO protocol */
329*84c68dbbSTetsuya Uemura DEVMETHOD(gpio_get_bus, rpi_virt_gpio_get_bus),
330*84c68dbbSTetsuya Uemura DEVMETHOD(gpio_pin_max, rpi_virt_gpio_pin_max),
331*84c68dbbSTetsuya Uemura DEVMETHOD(gpio_pin_getcaps, rpi_virt_gpio_pin_getcaps),
332*84c68dbbSTetsuya Uemura DEVMETHOD(gpio_pin_getflags, rpi_virt_gpio_pin_getflags),
333*84c68dbbSTetsuya Uemura DEVMETHOD(gpio_pin_set, rpi_virt_gpio_pin_set),
334*84c68dbbSTetsuya Uemura DEVMETHOD(gpio_pin_get, rpi_virt_gpio_pin_get),
335*84c68dbbSTetsuya Uemura DEVMETHOD(gpio_pin_toggle, rpi_virt_gpio_pin_toggle),
336*84c68dbbSTetsuya Uemura
337*84c68dbbSTetsuya Uemura DEVMETHOD_END
338*84c68dbbSTetsuya Uemura };
339*84c68dbbSTetsuya Uemura
340*84c68dbbSTetsuya Uemura static driver_t rpi_virt_gpio_driver = {
341*84c68dbbSTetsuya Uemura "gpio",
342*84c68dbbSTetsuya Uemura rpi_virt_gpio_methods,
343*84c68dbbSTetsuya Uemura sizeof(struct rpi_virt_gpio_softc),
344*84c68dbbSTetsuya Uemura };
345*84c68dbbSTetsuya Uemura
346*84c68dbbSTetsuya Uemura EARLY_DRIVER_MODULE(rpi_virt_gpio, bcm2835_firmware, rpi_virt_gpio_driver,
347*84c68dbbSTetsuya Uemura 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
348