xref: /openbsd/sys/dev/fdt/bcm2835_gpio.c (revision 471aeecf)
1*471aeecfSnaddy /*	$OpenBSD: bcm2835_gpio.c,v 1.5 2022/04/06 18:59:28 naddy Exp $	*/
2368dbbc4Skettenis /*
3368dbbc4Skettenis  * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
4368dbbc4Skettenis  *
5368dbbc4Skettenis  * Permission to use, copy, modify, and distribute this software for any
6368dbbc4Skettenis  * purpose with or without fee is hereby granted, provided that the above
7368dbbc4Skettenis  * copyright notice and this permission notice appear in all copies.
8368dbbc4Skettenis  *
9368dbbc4Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10368dbbc4Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11368dbbc4Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12368dbbc4Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13368dbbc4Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14368dbbc4Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15368dbbc4Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16368dbbc4Skettenis  */
17368dbbc4Skettenis 
18368dbbc4Skettenis #include <sys/param.h>
19368dbbc4Skettenis #include <sys/device.h>
2026df77a0Skettenis #include <sys/gpio.h>
21368dbbc4Skettenis #include <sys/malloc.h>
22368dbbc4Skettenis #include <sys/systm.h>
23368dbbc4Skettenis 
24368dbbc4Skettenis #include <machine/bus.h>
25368dbbc4Skettenis #include <machine/fdt.h>
26368dbbc4Skettenis 
2726df77a0Skettenis #include <dev/gpio/gpiovar.h>
28368dbbc4Skettenis #include <dev/ofw/openfirm.h>
2926df77a0Skettenis #include <dev/ofw/ofw_gpio.h>
30368dbbc4Skettenis #include <dev/ofw/ofw_pinctrl.h>
31368dbbc4Skettenis #include <dev/ofw/fdt.h>
32368dbbc4Skettenis 
3326df77a0Skettenis #include "gpio.h"
3426df77a0Skettenis 
35368dbbc4Skettenis /* Registers */
36368dbbc4Skettenis #define GPFSEL(n)		(0x00 + ((n) * 4))
37368dbbc4Skettenis #define  GPFSEL_MASK		0x7
38368dbbc4Skettenis #define  GPFSEL_GPIO_IN		0x0
39368dbbc4Skettenis #define  GPFSEL_GPIO_OUT	0x1
40368dbbc4Skettenis #define  GPFSEL_ALT0		0x4
41368dbbc4Skettenis #define  GPFSEL_ALT1		0x5
42368dbbc4Skettenis #define  GPFSEL_ALT2		0x6
43368dbbc4Skettenis #define  GPFSEL_ALT3		0x7
44368dbbc4Skettenis #define  GPFSEL_ALT4		0x3
45368dbbc4Skettenis #define  GPFSEL_ALT5		0x2
4626df77a0Skettenis #define GPSET(n)		(0x1c + ((n) * 4))
4726df77a0Skettenis #define GPCLR(n)		(0x28 + ((n) * 4))
4826df77a0Skettenis #define GPLEV(n)		(0x34 + ((n) * 4))
49368dbbc4Skettenis #define GPPUD			0x94
50368dbbc4Skettenis #define  GPPUD_PUD		0x3
51368dbbc4Skettenis #define  GPPUD_PUD_OFF		0x0
52368dbbc4Skettenis #define  GPPUD_PUD_DOWN		0x1
53368dbbc4Skettenis #define  GPPUD_PUD_UP		0x2
54368dbbc4Skettenis #define GPPUDCLK(n)		(0x98 + ((n) * 4))
55368dbbc4Skettenis #define GPPULL(n)		(0xe4 + ((n) * 4))
56368dbbc4Skettenis #define  GPPULL_MASK		0x3
57368dbbc4Skettenis 
5826df77a0Skettenis #define BCMGPIO_MAX_PINS	58
5926df77a0Skettenis 
60368dbbc4Skettenis #define HREAD4(sc, reg)							\
61368dbbc4Skettenis 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
62368dbbc4Skettenis #define HWRITE4(sc, reg, val)						\
63368dbbc4Skettenis 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
64368dbbc4Skettenis 
65368dbbc4Skettenis struct bcmgpio_softc {
66368dbbc4Skettenis 	struct device		sc_dev;
67368dbbc4Skettenis 	bus_space_tag_t		sc_iot;
68368dbbc4Skettenis 	bus_space_handle_t	sc_ioh;
69368dbbc4Skettenis 
70368dbbc4Skettenis 	void	(*sc_config_pull)(struct bcmgpio_softc *, int, int);
7126df77a0Skettenis 	int			sc_num_pins;
7226df77a0Skettenis 
7326df77a0Skettenis 	struct gpio_controller	sc_gc;
7426df77a0Skettenis 
7526df77a0Skettenis 	struct gpio_chipset_tag	sc_gpio_tag;
7626df77a0Skettenis 	gpio_pin_t		sc_gpio_pins[BCMGPIO_MAX_PINS];
7726df77a0Skettenis 	int			sc_gpio_claimed[BCMGPIO_MAX_PINS];
78368dbbc4Skettenis };
79368dbbc4Skettenis 
80368dbbc4Skettenis int	bcmgpio_match(struct device *, void *, void *);
81368dbbc4Skettenis void	bcmgpio_attach(struct device *, struct device *, void *);
82368dbbc4Skettenis 
83*471aeecfSnaddy const struct cfattach bcmgpio_ca = {
84368dbbc4Skettenis 	sizeof (struct bcmgpio_softc), bcmgpio_match, bcmgpio_attach
85368dbbc4Skettenis };
86368dbbc4Skettenis 
87368dbbc4Skettenis struct cfdriver bcmgpio_cd = {
88368dbbc4Skettenis 	NULL, "bcmgpio", DV_DULL
89368dbbc4Skettenis };
90368dbbc4Skettenis 
91368dbbc4Skettenis void	bcm2711_config_pull(struct bcmgpio_softc *, int, int);
92368dbbc4Skettenis void	bcm2835_config_pull(struct bcmgpio_softc *, int, int);
93368dbbc4Skettenis int	bcmgpio_pinctrl(uint32_t, void *);
9426df77a0Skettenis void	bcmgpio_config_pin(void *, uint32_t *, int);
9526df77a0Skettenis int	bcmgpio_get_pin(void *, uint32_t *);
9626df77a0Skettenis void	bcmgpio_set_pin(void *, uint32_t *, int);
9726df77a0Skettenis void	bcmgpio_attach_gpio(struct device *);
98368dbbc4Skettenis 
99368dbbc4Skettenis int
bcmgpio_match(struct device * parent,void * match,void * aux)100368dbbc4Skettenis bcmgpio_match(struct device *parent, void *match, void *aux)
101368dbbc4Skettenis {
102368dbbc4Skettenis 	struct fdt_attach_args *faa = aux;
103368dbbc4Skettenis 
104368dbbc4Skettenis 	return (OF_is_compatible(faa->fa_node, "brcm,bcm2711-gpio") ||
105368dbbc4Skettenis 	    OF_is_compatible(faa->fa_node, "brcm,bcm2835-gpio"));
106368dbbc4Skettenis }
107368dbbc4Skettenis 
108368dbbc4Skettenis void
bcmgpio_attach(struct device * parent,struct device * self,void * aux)109368dbbc4Skettenis bcmgpio_attach(struct device *parent, struct device *self, void *aux)
110368dbbc4Skettenis {
111368dbbc4Skettenis 	struct bcmgpio_softc *sc = (struct bcmgpio_softc *)self;
112368dbbc4Skettenis 	struct fdt_attach_args *faa = aux;
113368dbbc4Skettenis 
114368dbbc4Skettenis 	if (faa->fa_nreg < 1) {
115368dbbc4Skettenis 		printf(": no registers\n");
116368dbbc4Skettenis 		return;
117368dbbc4Skettenis 	}
118368dbbc4Skettenis 
119368dbbc4Skettenis 	sc->sc_iot = faa->fa_iot;
120368dbbc4Skettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
121368dbbc4Skettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
122368dbbc4Skettenis 		printf(": can't map registers\n");
123368dbbc4Skettenis 		return;
124368dbbc4Skettenis 	}
125368dbbc4Skettenis 
126368dbbc4Skettenis 	printf("\n");
127368dbbc4Skettenis 
12826df77a0Skettenis 	if (OF_is_compatible(faa->fa_node, "brcm,bcm2711-gpio")) {
129368dbbc4Skettenis 	    sc->sc_config_pull = bcm2711_config_pull;
13026df77a0Skettenis 	    sc->sc_num_pins = 58;
13126df77a0Skettenis 	} else {
132368dbbc4Skettenis 	    sc->sc_config_pull = bcm2835_config_pull;
13326df77a0Skettenis 	    sc->sc_num_pins = 54;
13426df77a0Skettenis 	}
135368dbbc4Skettenis 
136368dbbc4Skettenis 	pinctrl_register(faa->fa_node, bcmgpio_pinctrl, sc);
13726df77a0Skettenis 
13826df77a0Skettenis 	sc->sc_gc.gc_node = faa->fa_node;
13926df77a0Skettenis 	sc->sc_gc.gc_cookie = sc;
14026df77a0Skettenis 	sc->sc_gc.gc_config_pin = bcmgpio_config_pin;
14126df77a0Skettenis 	sc->sc_gc.gc_get_pin = bcmgpio_get_pin;
14226df77a0Skettenis 	sc->sc_gc.gc_set_pin = bcmgpio_set_pin;
14326df77a0Skettenis 	gpio_controller_register(&sc->sc_gc);
14426df77a0Skettenis 
14526df77a0Skettenis 	config_mountroot(self, bcmgpio_attach_gpio);
146368dbbc4Skettenis }
147368dbbc4Skettenis 
148368dbbc4Skettenis void
bcmgpio_config_func(struct bcmgpio_softc * sc,int pin,int func)149368dbbc4Skettenis bcmgpio_config_func(struct bcmgpio_softc *sc, int pin, int func)
150368dbbc4Skettenis {
151368dbbc4Skettenis 	int reg = (pin / 10);
152368dbbc4Skettenis 	int shift = (pin % 10) * 3;
153368dbbc4Skettenis 	uint32_t val;
154368dbbc4Skettenis 
155368dbbc4Skettenis 	val = HREAD4(sc, GPFSEL(reg));
156368dbbc4Skettenis 	val &= ~(GPFSEL_MASK << shift);
157368dbbc4Skettenis 	HWRITE4(sc, GPFSEL(reg), val);
158368dbbc4Skettenis 	val |= ((func & GPFSEL_MASK) << shift);
159368dbbc4Skettenis 	HWRITE4(sc, GPFSEL(reg), val);
160368dbbc4Skettenis }
161368dbbc4Skettenis 
162368dbbc4Skettenis void
bcm2711_config_pull(struct bcmgpio_softc * sc,int pin,int pull)163368dbbc4Skettenis bcm2711_config_pull(struct bcmgpio_softc *sc, int pin, int pull)
164368dbbc4Skettenis {
165368dbbc4Skettenis 	int reg = (pin / 16);
166368dbbc4Skettenis 	int shift = (pin % 16) * 2;
167368dbbc4Skettenis 	uint32_t val;
168368dbbc4Skettenis 
169368dbbc4Skettenis 	val = HREAD4(sc, GPPULL(reg));
170368dbbc4Skettenis 	val &= ~(GPPULL_MASK << shift);
171368dbbc4Skettenis 	pull = ((pull & 1) << 1) | ((pull & 2) >> 1);
172368dbbc4Skettenis 	val |= (pull << shift);
173368dbbc4Skettenis 	HWRITE4(sc, GPPULL(reg), val);
174368dbbc4Skettenis }
175368dbbc4Skettenis 
176368dbbc4Skettenis void
bcm2835_config_pull(struct bcmgpio_softc * sc,int pin,int pull)177368dbbc4Skettenis bcm2835_config_pull(struct bcmgpio_softc *sc, int pin, int pull)
178368dbbc4Skettenis {
179368dbbc4Skettenis 	int reg = (pin / 32);
180368dbbc4Skettenis 	int shift = (pin % 32);
181368dbbc4Skettenis 
182368dbbc4Skettenis 	HWRITE4(sc, GPPUD, pull & GPPUD_PUD);
183368dbbc4Skettenis 	delay(1);
184368dbbc4Skettenis 	HWRITE4(sc, GPPUDCLK(reg), 1 << shift);
185368dbbc4Skettenis 	delay(1);
186368dbbc4Skettenis 	HWRITE4(sc, GPPUDCLK(reg), 0);
187368dbbc4Skettenis }
188368dbbc4Skettenis 
189368dbbc4Skettenis int
bcmgpio_pinctrl(uint32_t phandle,void * cookie)190368dbbc4Skettenis bcmgpio_pinctrl(uint32_t phandle, void *cookie)
191368dbbc4Skettenis {
192368dbbc4Skettenis 	struct bcmgpio_softc *sc = cookie;
193368dbbc4Skettenis 	uint32_t *pins, *pull = NULL;
194368dbbc4Skettenis 	int len, plen = 0;
195368dbbc4Skettenis 	int node, i;
196368dbbc4Skettenis 	int func;
197368dbbc4Skettenis 
198368dbbc4Skettenis 	node = OF_getnodebyphandle(phandle);
199368dbbc4Skettenis 	if (node == 0)
200368dbbc4Skettenis 		return -1;
201368dbbc4Skettenis 
202368dbbc4Skettenis 	len = OF_getproplen(node, "brcm,pins");
203368dbbc4Skettenis 	if (len <= 0)
204368dbbc4Skettenis 		return -1;
205368dbbc4Skettenis 
206368dbbc4Skettenis 	pins = malloc(len, M_TEMP, M_WAITOK);
207368dbbc4Skettenis 	if (OF_getpropintarray(node, "brcm,pins", pins, len) != len)
208368dbbc4Skettenis 		goto fail;
209368dbbc4Skettenis 	func = OF_getpropint(node, "brcm,function", -1);
210368dbbc4Skettenis 
211368dbbc4Skettenis 	plen = OF_getproplen(node, "brcm,pull");
212368dbbc4Skettenis 	if (plen > 0) {
213368dbbc4Skettenis 		pull = malloc(len, M_TEMP, M_WAITOK);
214368dbbc4Skettenis 		if (OF_getpropintarray(node, "brcm,pull", pull, plen) != plen)
215368dbbc4Skettenis 			goto fail;
216368dbbc4Skettenis 	}
217368dbbc4Skettenis 
218368dbbc4Skettenis 	for (i = 0; i < len / sizeof(uint32_t); i++) {
219368dbbc4Skettenis 		bcmgpio_config_func(sc, pins[i], func);
22004e84c75Skettenis 		if (plen > 0 && i < plen / sizeof(uint32_t))
221368dbbc4Skettenis 			sc->sc_config_pull(sc, pins[i], pull[i]);
22226df77a0Skettenis 		sc->sc_gpio_claimed[pins[i]] = 1;
223368dbbc4Skettenis 	}
224368dbbc4Skettenis 
225368dbbc4Skettenis 	free(pull, M_TEMP, plen);
226368dbbc4Skettenis 	free(pins, M_TEMP, len);
227368dbbc4Skettenis 	return 0;
228368dbbc4Skettenis 
229368dbbc4Skettenis fail:
230368dbbc4Skettenis 	free(pull, M_TEMP, plen);
231368dbbc4Skettenis 	free(pins, M_TEMP, len);
232368dbbc4Skettenis 	return -1;
233368dbbc4Skettenis }
23426df77a0Skettenis 
23526df77a0Skettenis void
bcmgpio_config_pin(void * cookie,uint32_t * cells,int config)23626df77a0Skettenis bcmgpio_config_pin(void *cookie, uint32_t *cells, int config)
23726df77a0Skettenis {
23826df77a0Skettenis 	struct bcmgpio_softc *sc = cookie;
23926df77a0Skettenis 	uint32_t pin = cells[0];
24026df77a0Skettenis 
24126df77a0Skettenis 	if (pin >= sc->sc_num_pins)
24226df77a0Skettenis 		return;
24326df77a0Skettenis 
24426df77a0Skettenis 	if (config & GPIO_CONFIG_OUTPUT)
24526df77a0Skettenis 		bcmgpio_config_func(sc, pin, GPFSEL_GPIO_OUT);
24626df77a0Skettenis 	else
247624a2475Skettenis 		bcmgpio_config_func(sc, pin, GPFSEL_GPIO_IN);
24826df77a0Skettenis 	if (config & GPIO_CONFIG_PULL_UP)
24926df77a0Skettenis 		sc->sc_config_pull(sc, pin, GPPUD_PUD_UP);
25026df77a0Skettenis 	else if (config & GPIO_CONFIG_PULL_DOWN)
25126df77a0Skettenis 		sc->sc_config_pull(sc, pin, GPPUD_PUD_DOWN);
25226df77a0Skettenis 	else
25326df77a0Skettenis 		sc->sc_config_pull(sc, pin, GPPUD_PUD_OFF);
25426df77a0Skettenis }
25526df77a0Skettenis 
25626df77a0Skettenis int
bcmgpio_get_pin(void * cookie,uint32_t * cells)25726df77a0Skettenis bcmgpio_get_pin(void *cookie, uint32_t *cells)
25826df77a0Skettenis {
25926df77a0Skettenis 	struct bcmgpio_softc *sc = cookie;
26026df77a0Skettenis 	uint32_t pin = cells[0];
26126df77a0Skettenis 	uint32_t flags = cells[1];
26226df77a0Skettenis 	uint32_t reg;
26326df77a0Skettenis 	int val;
26426df77a0Skettenis 
26526df77a0Skettenis 	if (pin >= sc->sc_num_pins)
26626df77a0Skettenis 		return 0;
26726df77a0Skettenis 
26826df77a0Skettenis 	reg = HREAD4(sc, GPLEV(pin / 32));
26926df77a0Skettenis 	val = (reg >> (pin % 32)) & 1;
27026df77a0Skettenis 	if (flags & GPIO_ACTIVE_LOW)
27126df77a0Skettenis 		val = !val;
27226df77a0Skettenis 	return val;
27326df77a0Skettenis }
27426df77a0Skettenis 
27526df77a0Skettenis void
bcmgpio_set_pin(void * cookie,uint32_t * cells,int val)27626df77a0Skettenis bcmgpio_set_pin(void *cookie, uint32_t *cells, int val)
27726df77a0Skettenis {
27826df77a0Skettenis 	struct bcmgpio_softc *sc = cookie;
27926df77a0Skettenis 	uint32_t pin = cells[0];
28026df77a0Skettenis 	uint32_t flags = cells[1];
28126df77a0Skettenis 
28226df77a0Skettenis 	if (pin >= sc->sc_num_pins)
28326df77a0Skettenis 		return;
28426df77a0Skettenis 
28526df77a0Skettenis 	if (flags & GPIO_ACTIVE_LOW)
28626df77a0Skettenis 		val = !val;
28726df77a0Skettenis 	if (val)
28826df77a0Skettenis 		HWRITE4(sc, GPSET(pin / 32), (1 << (pin % 32)));
28926df77a0Skettenis 	else
29026df77a0Skettenis 		HWRITE4(sc, GPCLR(pin / 32), (1 << (pin % 32)));
29126df77a0Skettenis }
29226df77a0Skettenis 
29326df77a0Skettenis /*
29426df77a0Skettenis  * GPIO support code
29526df77a0Skettenis  */
29626df77a0Skettenis 
29726df77a0Skettenis int	bcmgpio_pin_read(void *, int);
29826df77a0Skettenis void	bcmgpio_pin_write(void *, int, int);
29926df77a0Skettenis void	bcmgpio_pin_ctl(void *, int, int);
30026df77a0Skettenis 
30126df77a0Skettenis static const struct gpio_chipset_tag bcmgpio_gpio_tag = {
30226df77a0Skettenis 	.gp_pin_read = bcmgpio_pin_read,
30326df77a0Skettenis 	.gp_pin_write = bcmgpio_pin_write,
30426df77a0Skettenis 	.gp_pin_ctl = bcmgpio_pin_ctl
30526df77a0Skettenis };
30626df77a0Skettenis 
30726df77a0Skettenis int
bcmgpio_pin_read(void * cookie,int pin)30826df77a0Skettenis bcmgpio_pin_read(void *cookie, int pin)
30926df77a0Skettenis {
31026df77a0Skettenis 	struct bcmgpio_softc *sc = cookie;
31126df77a0Skettenis 	uint32_t cells[2];
31226df77a0Skettenis 
31326df77a0Skettenis 	cells[0] = pin;
31426df77a0Skettenis 	cells[1] = 0;
31526df77a0Skettenis 
31626df77a0Skettenis 	return bcmgpio_get_pin(sc, cells) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
31726df77a0Skettenis }
31826df77a0Skettenis 
31926df77a0Skettenis void
bcmgpio_pin_write(void * cookie,int pin,int val)32026df77a0Skettenis bcmgpio_pin_write(void *cookie, int pin, int val)
32126df77a0Skettenis {
32226df77a0Skettenis 	struct bcmgpio_softc *sc = cookie;
32326df77a0Skettenis 	uint32_t cells[2];
32426df77a0Skettenis 
32526df77a0Skettenis 	cells[0] = pin;
32626df77a0Skettenis 	cells[1] = 0;
32726df77a0Skettenis 
32826df77a0Skettenis 	bcmgpio_set_pin(sc, cells, val);
32926df77a0Skettenis }
33026df77a0Skettenis 
33126df77a0Skettenis void
bcmgpio_pin_ctl(void * cookie,int pin,int flags)33226df77a0Skettenis bcmgpio_pin_ctl(void *cookie, int pin, int flags)
33326df77a0Skettenis {
33426df77a0Skettenis 	struct bcmgpio_softc *sc = cookie;
33526df77a0Skettenis 	uint32_t cells[2];
33626df77a0Skettenis 	uint32_t config;
33726df77a0Skettenis 
33826df77a0Skettenis 	cells[0] = pin;
33926df77a0Skettenis 	cells[1] = 0;
34026df77a0Skettenis 
34126df77a0Skettenis 	config = 0;
34226df77a0Skettenis 	if (ISSET(flags, GPIO_PIN_OUTPUT))
34326df77a0Skettenis 		config |= GPIO_CONFIG_OUTPUT;
34426df77a0Skettenis 	if (ISSET(flags, GPIO_PIN_PULLUP))
34526df77a0Skettenis 		config |= GPIO_CONFIG_PULL_UP;
34626df77a0Skettenis 	if (ISSET(flags, GPIO_PIN_PULLDOWN))
34726df77a0Skettenis 		config |= GPIO_CONFIG_PULL_DOWN;
34826df77a0Skettenis 
34926df77a0Skettenis 	bcmgpio_config_pin(sc, cells, config);
35026df77a0Skettenis }
35126df77a0Skettenis 
35226df77a0Skettenis void
bcmgpio_attach_gpio(struct device * parent)35326df77a0Skettenis bcmgpio_attach_gpio(struct device *parent)
35426df77a0Skettenis {
35526df77a0Skettenis 	struct bcmgpio_softc *sc = (struct bcmgpio_softc *)parent;
35626df77a0Skettenis 	struct gpiobus_attach_args gba;
35726df77a0Skettenis 	uint32_t reg;
35826df77a0Skettenis 	int func, state, flags;
35926df77a0Skettenis 	int pin;
36026df77a0Skettenis 
36126df77a0Skettenis 	for (pin = 0; pin < sc->sc_num_pins; pin++) {
36226df77a0Skettenis 		/* Skip pins claimed by other devices. */
36326df77a0Skettenis 		if (sc->sc_gpio_claimed[pin])
36426df77a0Skettenis 			continue;
36526df77a0Skettenis 
36626df77a0Skettenis 		/* Get pin configuration. */
36726df77a0Skettenis 		reg = HREAD4(sc, GPFSEL(pin / 10));
36826df77a0Skettenis 		func = (reg >> ((pin % 10) * 3)) & GPFSEL_MASK;
36926df77a0Skettenis 
37026df77a0Skettenis 		switch (func) {
37126df77a0Skettenis 		case GPFSEL_GPIO_IN:
37226df77a0Skettenis 			flags = GPIO_PIN_SET | GPIO_PIN_INPUT;
37326df77a0Skettenis 			break;
37426df77a0Skettenis 		case GPFSEL_GPIO_OUT:
37526df77a0Skettenis 			flags = GPIO_PIN_SET | GPIO_PIN_OUTPUT;
37626df77a0Skettenis 			break;
37726df77a0Skettenis 		default:
37826df77a0Skettenis 			/* Ignore pins with an assigned function. */
37926df77a0Skettenis 			continue;
38026df77a0Skettenis 		}
38126df77a0Skettenis 
38226df77a0Skettenis 		/* Get pin state. */
38326df77a0Skettenis 		reg = HREAD4(sc, GPLEV(pin / 32));
38426df77a0Skettenis 		state = (reg >> (pin % 32)) & 1;
38526df77a0Skettenis 
38626df77a0Skettenis 		sc->sc_gpio_pins[pin].pin_caps =
38726df77a0Skettenis 		    GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |
38826df77a0Skettenis 		    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN;
38926df77a0Skettenis 		sc->sc_gpio_pins[pin].pin_flags = flags;
39026df77a0Skettenis 		sc->sc_gpio_pins[pin].pin_state = state;
39126df77a0Skettenis 		sc->sc_gpio_pins[pin].pin_num = pin;
39226df77a0Skettenis 	}
39326df77a0Skettenis 
39426df77a0Skettenis 	memcpy(&sc->sc_gpio_tag, &bcmgpio_gpio_tag, sizeof(bcmgpio_gpio_tag));
39526df77a0Skettenis 	sc->sc_gpio_tag.gp_cookie = sc;
39626df77a0Skettenis 
39726df77a0Skettenis 	gba.gba_name = "gpio";
39826df77a0Skettenis 	gba.gba_gc = &sc->sc_gpio_tag;
39926df77a0Skettenis 	gba.gba_pins = &sc->sc_gpio_pins[0];
40026df77a0Skettenis 	gba.gba_npins = sc->sc_num_pins;
40126df77a0Skettenis 
40226df77a0Skettenis #if NGPIO > 0
40326df77a0Skettenis 	config_found(&sc->sc_dev, &gba, gpiobus_print);
40426df77a0Skettenis #endif
40526df77a0Skettenis }
406