xref: /freebsd/sys/dev/gpio/intel/intelgpio.c (revision 5349a46babc03453b0e6679bf867272e7ef7ea22)
1*5349a46bSYannickV /*-
2*5349a46bSYannickV  * SPDX-License-Identifier: BSD-2-Clause
3*5349a46bSYannickV  *
4*5349a46bSYannickV  * Copyright (c) 2026 Beckhoff Automation GmbH & Co. KG
5*5349a46bSYannickV  */
6*5349a46bSYannickV 
7*5349a46bSYannickV #include <sys/param.h>
8*5349a46bSYannickV #include <sys/systm.h>
9*5349a46bSYannickV #include <sys/bus.h>
10*5349a46bSYannickV #include <sys/gpio.h>
11*5349a46bSYannickV #include <sys/kernel.h>
12*5349a46bSYannickV #include <sys/module.h>
13*5349a46bSYannickV #include <sys/rman.h>
14*5349a46bSYannickV 
15*5349a46bSYannickV #include <machine/bus.h>
16*5349a46bSYannickV #include <machine/resource.h>
17*5349a46bSYannickV 
18*5349a46bSYannickV #include <contrib/dev/acpica/include/acpi.h>
19*5349a46bSYannickV #include <contrib/dev/acpica/include/accommon.h>
20*5349a46bSYannickV 
21*5349a46bSYannickV #include <dev/acpica/acpivar.h>
22*5349a46bSYannickV #include <dev/gpio/gpiobusvar.h>
23*5349a46bSYannickV 
24*5349a46bSYannickV #include "intelgpio.h"
25*5349a46bSYannickV 
26*5349a46bSYannickV #include "gpio_if.h"
27*5349a46bSYannickV #include "opt_acpi.h"
28*5349a46bSYannickV 
29*5349a46bSYannickV #define INTELGPIO_LOCK(_sc)   mtx_lock_spin(&(_sc)->sc_mtx)
30*5349a46bSYannickV #define INTELGPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx)
31*5349a46bSYannickV #define INTELGPIO_LOCK_INIT(_sc)                                     \
32*5349a46bSYannickV 	mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \
33*5349a46bSYannickV 	    "intelgpio", MTX_SPIN)
34*5349a46bSYannickV #define INTELGPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx)
35*5349a46bSYannickV 
36*5349a46bSYannickV static int
intelgpio_gpio_to_pad(struct intelgpio_softc * sc,uint32_t pin,struct resource ** res,bus_size_t * pad_off,const struct intelgpio_padgroup ** pgp)37*5349a46bSYannickV intelgpio_gpio_to_pad(struct intelgpio_softc *sc, uint32_t pin,
38*5349a46bSYannickV     struct resource **res, bus_size_t *pad_off,
39*5349a46bSYannickV     const struct intelgpio_padgroup **pgp)
40*5349a46bSYannickV {
41*5349a46bSYannickV 	const struct intelgpio_platform *plat = sc->sc_plat;
42*5349a46bSYannickV 	const struct intelgpio_community *com;
43*5349a46bSYannickV 	const struct intelgpio_padgroup *pg;
44*5349a46bSYannickV 	int i, j, offset, local_pad;
45*5349a46bSYannickV 
46*5349a46bSYannickV 	for (i = 0; i < plat->ncommunities; i++) {
47*5349a46bSYannickV 		com = &plat->communities[i];
48*5349a46bSYannickV 		for (j = 0; j < com->ngroups; j++) {
49*5349a46bSYannickV 			pg = &com->groups[j];
50*5349a46bSYannickV 			if (pg->gpio_base == INTELGPIO_GPIO_NOMAP)
51*5349a46bSYannickV 				continue;
52*5349a46bSYannickV 			if (pin >= pg->gpio_base &&
53*5349a46bSYannickV 			    pin < pg->gpio_base + pg->npads) {
54*5349a46bSYannickV 				if (res != NULL)
55*5349a46bSYannickV 					*res = sc->sc_mem_res[i];
56*5349a46bSYannickV 				if (pad_off != NULL) {
57*5349a46bSYannickV 					offset = pin - pg->gpio_base;
58*5349a46bSYannickV 					local_pad = (pg->first_pad + offset) -
59*5349a46bSYannickV 					    com->groups[0].first_pad;
60*5349a46bSYannickV 					*pad_off = sc->sc_padbar[i] +
61*5349a46bSYannickV 					    (local_pad * INTELGPIO_PAD_SIZE);
62*5349a46bSYannickV 				}
63*5349a46bSYannickV 				if (pgp != NULL)
64*5349a46bSYannickV 					*pgp = pg;
65*5349a46bSYannickV 				return (0);
66*5349a46bSYannickV 			}
67*5349a46bSYannickV 		}
68*5349a46bSYannickV 	}
69*5349a46bSYannickV 	return (-1);
70*5349a46bSYannickV }
71*5349a46bSYannickV 
72*5349a46bSYannickV static device_t
intelgpio_get_bus(device_t dev)73*5349a46bSYannickV intelgpio_get_bus(device_t dev)
74*5349a46bSYannickV {
75*5349a46bSYannickV 	struct intelgpio_softc *sc;
76*5349a46bSYannickV 
77*5349a46bSYannickV 	sc = device_get_softc(dev);
78*5349a46bSYannickV 	return (sc->sc_busdev);
79*5349a46bSYannickV }
80*5349a46bSYannickV 
81*5349a46bSYannickV static int
intelgpio_pin_max(device_t dev,int * maxpin)82*5349a46bSYannickV intelgpio_pin_max(device_t dev, int *maxpin)
83*5349a46bSYannickV {
84*5349a46bSYannickV 	struct intelgpio_softc *sc;
85*5349a46bSYannickV 	const struct intelgpio_platform *plat;
86*5349a46bSYannickV 	const struct intelgpio_community *com;
87*5349a46bSYannickV 	const struct intelgpio_padgroup *pg;
88*5349a46bSYannickV 	int i, j;
89*5349a46bSYannickV 
90*5349a46bSYannickV 	if (maxpin == NULL)
91*5349a46bSYannickV 		return (EINVAL);
92*5349a46bSYannickV 
93*5349a46bSYannickV 	sc = device_get_softc(dev);
94*5349a46bSYannickV 	plat = sc->sc_plat;
95*5349a46bSYannickV 
96*5349a46bSYannickV 	/* Find the last group with a valid gpio_base, skipping NOMAP */
97*5349a46bSYannickV 	*maxpin = 0;
98*5349a46bSYannickV 	for (i = 0; i < plat->ncommunities; i++) {
99*5349a46bSYannickV 		com = &plat->communities[i];
100*5349a46bSYannickV 		for (j = 0; j < com->ngroups; j++) {
101*5349a46bSYannickV 			pg = &com->groups[j];
102*5349a46bSYannickV 			if (pg->gpio_base == INTELGPIO_GPIO_NOMAP)
103*5349a46bSYannickV 				continue;
104*5349a46bSYannickV 			*maxpin = pg->gpio_base + (pg->npads - 1);
105*5349a46bSYannickV 		}
106*5349a46bSYannickV 	}
107*5349a46bSYannickV 	return (0);
108*5349a46bSYannickV }
109*5349a46bSYannickV 
110*5349a46bSYannickV static int
intelgpio_pin_getname(device_t dev,uint32_t pin,char * name)111*5349a46bSYannickV intelgpio_pin_getname(device_t dev, uint32_t pin, char *name)
112*5349a46bSYannickV {
113*5349a46bSYannickV 	struct intelgpio_softc *sc;
114*5349a46bSYannickV 	const struct intelgpio_padgroup *pg;
115*5349a46bSYannickV 	int offset;
116*5349a46bSYannickV 
117*5349a46bSYannickV 	sc = device_get_softc(dev);
118*5349a46bSYannickV 	if (intelgpio_gpio_to_pad(sc, pin, NULL, NULL, &pg) != 0)
119*5349a46bSYannickV 		return (EINVAL);
120*5349a46bSYannickV 
121*5349a46bSYannickV 	offset = pin - pg->gpio_base;
122*5349a46bSYannickV 	snprintf(name, GPIOMAXNAME, "%s%d", pg->name, offset);
123*5349a46bSYannickV 	return (0);
124*5349a46bSYannickV }
125*5349a46bSYannickV 
126*5349a46bSYannickV static int
intelgpio_pin_getcaps(device_t dev,uint32_t pin,uint32_t * caps)127*5349a46bSYannickV intelgpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
128*5349a46bSYannickV {
129*5349a46bSYannickV 	struct intelgpio_softc *sc;
130*5349a46bSYannickV 
131*5349a46bSYannickV 	sc = device_get_softc(dev);
132*5349a46bSYannickV 
133*5349a46bSYannickV 	/*
134*5349a46bSYannickV 	 * The getcaps function is expected to return the capabilities
135*5349a46bSYannickV 	 * of the pin. Validate that the pin number maps to an existing
136*5349a46bSYannickV 	 * pad first.
137*5349a46bSYannickV 	 */
138*5349a46bSYannickV 	if (intelgpio_gpio_to_pad(sc, pin, NULL, NULL, NULL) != 0)
139*5349a46bSYannickV 		return (EINVAL);
140*5349a46bSYannickV 
141*5349a46bSYannickV 	*caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
142*5349a46bSYannickV 	return (0);
143*5349a46bSYannickV }
144*5349a46bSYannickV 
145*5349a46bSYannickV static int
intelgpio_pin_getflags(device_t dev,uint32_t pin,uint32_t * flags)146*5349a46bSYannickV intelgpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
147*5349a46bSYannickV {
148*5349a46bSYannickV 	struct intelgpio_softc *sc;
149*5349a46bSYannickV 	struct resource *res;
150*5349a46bSYannickV 	bus_size_t pad_off;
151*5349a46bSYannickV 	uint32_t val;
152*5349a46bSYannickV 
153*5349a46bSYannickV 	sc = device_get_softc(dev);
154*5349a46bSYannickV 	if (intelgpio_gpio_to_pad(sc, pin, &res, &pad_off, NULL) != 0)
155*5349a46bSYannickV 		return (EINVAL);
156*5349a46bSYannickV 	if (res == NULL)
157*5349a46bSYannickV 		return (EINVAL);
158*5349a46bSYannickV 
159*5349a46bSYannickV 	*flags = 0;
160*5349a46bSYannickV 
161*5349a46bSYannickV 	INTELGPIO_LOCK(sc);
162*5349a46bSYannickV 	val = bus_read_4(res, pad_off);
163*5349a46bSYannickV 	INTELGPIO_UNLOCK(sc);
164*5349a46bSYannickV 
165*5349a46bSYannickV 	/*
166*5349a46bSYannickV 	 * If the pad is not in GPIO mode (i.e. configured for a native
167*5349a46bSYannickV 	 * function like PCIe, UART, I2C, etc.), report no flags. The pin
168*5349a46bSYannickV 	 * cannot be used as GPIO without first switching it via setflags.
169*5349a46bSYannickV 	 */
170*5349a46bSYannickV 	if ((val & INTELGPIO_PADCFG0_PMODE_MASK) !=
171*5349a46bSYannickV 	    INTELGPIO_PADCFG0_PMODE_GPIO)
172*5349a46bSYannickV 		return (0);
173*5349a46bSYannickV 
174*5349a46bSYannickV 	/*
175*5349a46bSYannickV 	 * Report OUTPUT only if TX is explicitly enabled. Default to INPUT
176*5349a46bSYannickV 	 * otherwise: a non-driving pin is considered an input from the user's
177*5349a46bSYannickV 	 * perspective.
178*5349a46bSYannickV 	 */
179*5349a46bSYannickV 	if (!(val & INTELGPIO_PADCFG0_GPIOTXDIS))
180*5349a46bSYannickV 		*flags = GPIO_PIN_OUTPUT;
181*5349a46bSYannickV 	else
182*5349a46bSYannickV 		*flags = GPIO_PIN_INPUT;
183*5349a46bSYannickV 
184*5349a46bSYannickV 	return (0);
185*5349a46bSYannickV }
186*5349a46bSYannickV 
187*5349a46bSYannickV static int
intelgpio_pin_setflags(device_t dev,uint32_t pin,uint32_t flags)188*5349a46bSYannickV intelgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
189*5349a46bSYannickV {
190*5349a46bSYannickV 	struct intelgpio_softc *sc;
191*5349a46bSYannickV 	struct resource *res;
192*5349a46bSYannickV 	bus_size_t pad_off;
193*5349a46bSYannickV 	uint32_t val;
194*5349a46bSYannickV 
195*5349a46bSYannickV 	sc = device_get_softc(dev);
196*5349a46bSYannickV 	if (intelgpio_gpio_to_pad(sc, pin, &res, &pad_off, NULL) != 0)
197*5349a46bSYannickV 		return (EINVAL);
198*5349a46bSYannickV 	if (res == NULL)
199*5349a46bSYannickV 		return (EINVAL);
200*5349a46bSYannickV 
201*5349a46bSYannickV 	/*
202*5349a46bSYannickV 	 * We currently only support input and output, not both simultaneously
203*5349a46bSYannickV 	 */
204*5349a46bSYannickV 	if (flags & ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
205*5349a46bSYannickV 		return (EINVAL);
206*5349a46bSYannickV 	if ((flags & GPIO_PIN_INPUT) && (flags & GPIO_PIN_OUTPUT))
207*5349a46bSYannickV 		return (EINVAL);
208*5349a46bSYannickV 
209*5349a46bSYannickV 	INTELGPIO_LOCK(sc);
210*5349a46bSYannickV 	val = bus_read_4(res, pad_off);
211*5349a46bSYannickV 
212*5349a46bSYannickV 	/*
213*5349a46bSYannickV 	 * Switch the pad to GPIO mode. Intel pads can operate in different
214*5349a46bSYannickV 	 * modes (native function 1-15 or GPIO). Since setflags is only called
215*5349a46bSYannickV 	 * when userspace or a consumer explicitly wants to use the pin as a
216*5349a46bSYannickV 	 * GPIO, we force the pad into GPIO mode here so the direction bits
217*5349a46bSYannickV 	 * (TXDIS/RXDIS) below take effect.
218*5349a46bSYannickV 	 */
219*5349a46bSYannickV 	val &= ~INTELGPIO_PADCFG0_PMODE_MASK;
220*5349a46bSYannickV 	val |= INTELGPIO_PADCFG0_PMODE_GPIO;
221*5349a46bSYannickV 
222*5349a46bSYannickV 	if (flags & GPIO_PIN_INPUT)
223*5349a46bSYannickV 		val &= ~INTELGPIO_PADCFG0_GPIORXDIS;
224*5349a46bSYannickV 	else
225*5349a46bSYannickV 		val |= INTELGPIO_PADCFG0_GPIORXDIS;
226*5349a46bSYannickV 
227*5349a46bSYannickV 	if (flags & GPIO_PIN_OUTPUT)
228*5349a46bSYannickV 		val &= ~INTELGPIO_PADCFG0_GPIOTXDIS;
229*5349a46bSYannickV 	else
230*5349a46bSYannickV 		val |= INTELGPIO_PADCFG0_GPIOTXDIS;
231*5349a46bSYannickV 
232*5349a46bSYannickV 	bus_write_4(res, pad_off, val);
233*5349a46bSYannickV 	INTELGPIO_UNLOCK(sc);
234*5349a46bSYannickV 
235*5349a46bSYannickV 	return (0);
236*5349a46bSYannickV }
237*5349a46bSYannickV 
238*5349a46bSYannickV static int
intelgpio_pin_get(device_t dev,uint32_t pin,unsigned int * value)239*5349a46bSYannickV intelgpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
240*5349a46bSYannickV {
241*5349a46bSYannickV 	struct intelgpio_softc *sc;
242*5349a46bSYannickV 	struct resource *res;
243*5349a46bSYannickV 	bus_size_t pad_off;
244*5349a46bSYannickV 	uint32_t val;
245*5349a46bSYannickV 
246*5349a46bSYannickV 	sc = device_get_softc(dev);
247*5349a46bSYannickV 	if (intelgpio_gpio_to_pad(sc, pin, &res, &pad_off, NULL) != 0)
248*5349a46bSYannickV 		return (EINVAL);
249*5349a46bSYannickV 	if (res == NULL)
250*5349a46bSYannickV 		return (EINVAL);
251*5349a46bSYannickV 
252*5349a46bSYannickV 	INTELGPIO_LOCK(sc);
253*5349a46bSYannickV 	val = bus_read_4(res, pad_off);
254*5349a46bSYannickV 	INTELGPIO_UNLOCK(sc);
255*5349a46bSYannickV 
256*5349a46bSYannickV 	*value = (val & INTELGPIO_PADCFG0_GPIORXSTATE) ?
257*5349a46bSYannickV 	    GPIO_PIN_HIGH : GPIO_PIN_LOW;
258*5349a46bSYannickV 
259*5349a46bSYannickV 	return (0);
260*5349a46bSYannickV }
261*5349a46bSYannickV 
262*5349a46bSYannickV static int
intelgpio_pin_set(device_t dev,uint32_t pin,unsigned int value)263*5349a46bSYannickV intelgpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
264*5349a46bSYannickV {
265*5349a46bSYannickV 	struct intelgpio_softc *sc;
266*5349a46bSYannickV 	struct resource *res;
267*5349a46bSYannickV 	bus_size_t pad_off;
268*5349a46bSYannickV 	uint32_t val;
269*5349a46bSYannickV 
270*5349a46bSYannickV 	sc = device_get_softc(dev);
271*5349a46bSYannickV 	if (intelgpio_gpio_to_pad(sc, pin, &res, &pad_off, NULL) != 0)
272*5349a46bSYannickV 		return (EINVAL);
273*5349a46bSYannickV 	if (res == NULL)
274*5349a46bSYannickV 		return (EINVAL);
275*5349a46bSYannickV 
276*5349a46bSYannickV 	INTELGPIO_LOCK(sc);
277*5349a46bSYannickV 	val = bus_read_4(res, pad_off);
278*5349a46bSYannickV 	if (value == GPIO_PIN_LOW)
279*5349a46bSYannickV 		val &= ~INTELGPIO_PADCFG0_GPIOTXSTATE;
280*5349a46bSYannickV 	else
281*5349a46bSYannickV 		val |= INTELGPIO_PADCFG0_GPIOTXSTATE;
282*5349a46bSYannickV 	bus_write_4(res, pad_off, val);
283*5349a46bSYannickV 	INTELGPIO_UNLOCK(sc);
284*5349a46bSYannickV 
285*5349a46bSYannickV 	return (0);
286*5349a46bSYannickV }
287*5349a46bSYannickV 
288*5349a46bSYannickV static int
intelgpio_pin_toggle(device_t dev,uint32_t pin)289*5349a46bSYannickV intelgpio_pin_toggle(device_t dev, uint32_t pin)
290*5349a46bSYannickV {
291*5349a46bSYannickV 	struct intelgpio_softc *sc;
292*5349a46bSYannickV 	struct resource *res;
293*5349a46bSYannickV 	bus_size_t pad_off;
294*5349a46bSYannickV 	uint32_t val;
295*5349a46bSYannickV 
296*5349a46bSYannickV 	sc = device_get_softc(dev);
297*5349a46bSYannickV 	if (intelgpio_gpio_to_pad(sc, pin, &res, &pad_off, NULL) != 0)
298*5349a46bSYannickV 		return (EINVAL);
299*5349a46bSYannickV 	if (res == NULL)
300*5349a46bSYannickV 		return (EINVAL);
301*5349a46bSYannickV 
302*5349a46bSYannickV 	INTELGPIO_LOCK(sc);
303*5349a46bSYannickV 	val = bus_read_4(res, pad_off);
304*5349a46bSYannickV 	val ^= INTELGPIO_PADCFG0_GPIOTXSTATE;
305*5349a46bSYannickV 	bus_write_4(res, pad_off, val);
306*5349a46bSYannickV 	INTELGPIO_UNLOCK(sc);
307*5349a46bSYannickV 
308*5349a46bSYannickV 	return (0);
309*5349a46bSYannickV }
310*5349a46bSYannickV 
311*5349a46bSYannickV int
intelgpio_probe(device_t dev,const struct intelgpio_platform * plat)312*5349a46bSYannickV intelgpio_probe(device_t dev, const struct intelgpio_platform *plat)
313*5349a46bSYannickV {
314*5349a46bSYannickV 	int rv;
315*5349a46bSYannickV 
316*5349a46bSYannickV 	if (acpi_disabled("intelgpio"))
317*5349a46bSYannickV 		return (ENXIO);
318*5349a46bSYannickV 
319*5349a46bSYannickV 	rv = ACPI_ID_PROBE(device_get_parent(dev), dev, plat->hids, NULL);
320*5349a46bSYannickV 	if (rv <= 0)
321*5349a46bSYannickV 		device_set_desc(dev, plat->desc);
322*5349a46bSYannickV 	return (rv);
323*5349a46bSYannickV }
324*5349a46bSYannickV 
325*5349a46bSYannickV static int
intelgpio_detach(device_t dev)326*5349a46bSYannickV intelgpio_detach(device_t dev)
327*5349a46bSYannickV {
328*5349a46bSYannickV 	struct intelgpio_softc *sc;
329*5349a46bSYannickV 	int i;
330*5349a46bSYannickV 
331*5349a46bSYannickV 	sc = device_get_softc(dev);
332*5349a46bSYannickV 
333*5349a46bSYannickV 	if (sc->sc_busdev != NULL)
334*5349a46bSYannickV 		gpiobus_detach_bus(dev);
335*5349a46bSYannickV 
336*5349a46bSYannickV 	for (i = 0; i < sc->sc_plat->ncommunities; i++) {
337*5349a46bSYannickV 		if (sc->sc_mem_res[i] != NULL)
338*5349a46bSYannickV 			bus_release_resource(dev, SYS_RES_MEMORY, i,
339*5349a46bSYannickV 			    sc->sc_mem_res[i]);
340*5349a46bSYannickV 	}
341*5349a46bSYannickV 
342*5349a46bSYannickV 	INTELGPIO_LOCK_DESTROY(sc);
343*5349a46bSYannickV 	return (0);
344*5349a46bSYannickV }
345*5349a46bSYannickV 
346*5349a46bSYannickV int
intelgpio_attach(device_t dev,const struct intelgpio_platform * plat)347*5349a46bSYannickV intelgpio_attach(device_t dev, const struct intelgpio_platform *plat)
348*5349a46bSYannickV {
349*5349a46bSYannickV 	struct intelgpio_softc *sc;
350*5349a46bSYannickV 	bool have_res;
351*5349a46bSYannickV 	int i;
352*5349a46bSYannickV 
353*5349a46bSYannickV 	sc = device_get_softc(dev);
354*5349a46bSYannickV 	sc->sc_dev = dev;
355*5349a46bSYannickV 	sc->sc_plat = plat;
356*5349a46bSYannickV 
357*5349a46bSYannickV 	KASSERT(plat->ncommunities <= INTELGPIO_MAX_COMMUNITIES,
358*5349a46bSYannickV 	    ("too many communities: %d > %d", plat->ncommunities,
359*5349a46bSYannickV 		INTELGPIO_MAX_COMMUNITIES));
360*5349a46bSYannickV 
361*5349a46bSYannickV 	INTELGPIO_LOCK_INIT(sc);
362*5349a46bSYannickV 
363*5349a46bSYannickV 	have_res = false;
364*5349a46bSYannickV 	for (i = 0; i < plat->ncommunities; i++) {
365*5349a46bSYannickV 		sc->sc_mem_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
366*5349a46bSYannickV 		    &i, RF_ACTIVE);
367*5349a46bSYannickV 		if (sc->sc_mem_res[i] == NULL) {
368*5349a46bSYannickV 			device_printf(dev,
369*5349a46bSYannickV 			    "failed to allocate memory resource "
370*5349a46bSYannickV 			    "for community %d\n",
371*5349a46bSYannickV 			    i);
372*5349a46bSYannickV 			continue;
373*5349a46bSYannickV 		}
374*5349a46bSYannickV 		sc->sc_padbar[i] = bus_read_4(sc->sc_mem_res[i],
375*5349a46bSYannickV 		    INTELGPIO_PADBAR_REG);
376*5349a46bSYannickV 		have_res = true;
377*5349a46bSYannickV 	}
378*5349a46bSYannickV 
379*5349a46bSYannickV 	if (!have_res) {
380*5349a46bSYannickV 		device_printf(dev, "no memory resources found\n");
381*5349a46bSYannickV 		INTELGPIO_LOCK_DESTROY(sc);
382*5349a46bSYannickV 		return (ENXIO);
383*5349a46bSYannickV 	}
384*5349a46bSYannickV 
385*5349a46bSYannickV 	sc->sc_busdev = gpiobus_add_bus(dev);
386*5349a46bSYannickV 	if (sc->sc_busdev == NULL) {
387*5349a46bSYannickV 		device_printf(dev, "failed to add gpiobus\n");
388*5349a46bSYannickV 		intelgpio_detach(dev);
389*5349a46bSYannickV 		return (ENXIO);
390*5349a46bSYannickV 	}
391*5349a46bSYannickV 
392*5349a46bSYannickV 	bus_attach_children(dev);
393*5349a46bSYannickV 
394*5349a46bSYannickV 	return (0);
395*5349a46bSYannickV }
396*5349a46bSYannickV 
397*5349a46bSYannickV 
398*5349a46bSYannickV static device_method_t intelgpio_methods[] = {
399*5349a46bSYannickV 	DEVMETHOD(device_detach, intelgpio_detach),
400*5349a46bSYannickV 
401*5349a46bSYannickV 	DEVMETHOD(gpio_get_bus, intelgpio_get_bus),
402*5349a46bSYannickV 	DEVMETHOD(gpio_pin_max, intelgpio_pin_max),
403*5349a46bSYannickV 	DEVMETHOD(gpio_pin_getname, intelgpio_pin_getname),
404*5349a46bSYannickV 	DEVMETHOD(gpio_pin_getcaps, intelgpio_pin_getcaps),
405*5349a46bSYannickV 	DEVMETHOD(gpio_pin_getflags, intelgpio_pin_getflags),
406*5349a46bSYannickV 	DEVMETHOD(gpio_pin_setflags, intelgpio_pin_setflags),
407*5349a46bSYannickV 	DEVMETHOD(gpio_pin_get, intelgpio_pin_get),
408*5349a46bSYannickV 	DEVMETHOD(gpio_pin_set, intelgpio_pin_set),
409*5349a46bSYannickV 	DEVMETHOD(gpio_pin_toggle, intelgpio_pin_toggle),
410*5349a46bSYannickV 
411*5349a46bSYannickV 	DEVMETHOD_END
412*5349a46bSYannickV };
413*5349a46bSYannickV 
414*5349a46bSYannickV DEFINE_CLASS_0(intelgpio, intelgpio_driver, intelgpio_methods,
415*5349a46bSYannickV     sizeof(struct intelgpio_softc));
416