xref: /netbsd-src/sys/dev/ic/igpio.c (revision 9a10a09ad11c72abf92d5989782ae95659b24951)
1*9a10a09aSmsaitoh /* $NetBSD: igpio.c,v 1.5 2023/01/07 03:27:01 msaitoh Exp $ */
2b3307332Smanu 
3b3307332Smanu /*
4b3307332Smanu  * Copyright (c) 2021,2022 Emmanuel Dreyfus
5b3307332Smanu  * All rights reserved.
6b3307332Smanu  *
7b3307332Smanu  * Redistribution and use in source and binary forms, with or without
8b3307332Smanu  * modification, are permitted provided that the following conditions
9b3307332Smanu  * are met:
10b3307332Smanu  * 1. Redistributions of source code must retain the above copyright
11b3307332Smanu  *    notice, this list of conditions and the following disclaimer.
12b3307332Smanu  * 2. Redistributions in binary form must reproduce the above copyright
13b3307332Smanu  *    notice, this list of conditions and the following disclaimer in the
14b3307332Smanu  *    documentation and/or other materials provided with the distribution.
15b3307332Smanu  *
16b3307332Smanu  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17b3307332Smanu  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18b3307332Smanu  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19b3307332Smanu  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20b3307332Smanu  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21b3307332Smanu  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22b3307332Smanu  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23b3307332Smanu  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24b3307332Smanu  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25b3307332Smanu  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26b3307332Smanu  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27b3307332Smanu  */
28b3307332Smanu 
29b3307332Smanu #include <sys/cdefs.h>
30b3307332Smanu 
31b3307332Smanu #include <sys/param.h>
32b3307332Smanu #include <sys/bus.h>
33b3307332Smanu #include <sys/device.h>
34b3307332Smanu #include <sys/intr.h>
35b3307332Smanu #include <sys/systm.h>
36b3307332Smanu #include <sys/kernel.h>
37b3307332Smanu #include <sys/kmem.h>
38b3307332Smanu #include <sys/endian.h>
39b3307332Smanu #include <sys/gpio.h>
40b3307332Smanu 
41b3307332Smanu #include <dev/gpio/gpiovar.h>
42b3307332Smanu #include "gpio.h"
43b3307332Smanu 
44b3307332Smanu #include <dev/ic/igpiovar.h>
45b3307332Smanu #include <dev/ic/igpioreg.h>
46b3307332Smanu 
47b3307332Smanu struct igpio_intr {
48b3307332Smanu 	int (*ii_func)(void *);
49b3307332Smanu 	void *ii_arg;
50b3307332Smanu 	struct igpio_bank *ii_bank;
51b3307332Smanu 	int ii_pin;
52b3307332Smanu };
53b3307332Smanu 
54b3307332Smanu struct igpio_bank {
55b3307332Smanu 	int ib_barno;
56b3307332Smanu 	int ib_revid;
57b3307332Smanu 	int ib_cap;
58b3307332Smanu 	int ib_padbar;
59b3307332Smanu 	struct igpio_bank_setup *ib_setup;
60b3307332Smanu 	struct igpio_softc *ib_sc;
61b3307332Smanu 	struct igpio_intr *ib_intr;
62b3307332Smanu 	kmutex_t ib_mtx;
63b3307332Smanu };
64b3307332Smanu 
65b3307332Smanu 
66b3307332Smanu static int igpio_debug = 0;
67b3307332Smanu #define DPRINTF(x) if (igpio_debug) printf x;
68b3307332Smanu 
69b3307332Smanu static char *
igpio_padcfg0_print(uint32_t val,int idx)70b3307332Smanu igpio_padcfg0_print(uint32_t val, int idx)
71b3307332Smanu {
72b3307332Smanu 	uint32_t rxev, pmode;
73b3307332Smanu 	static char buf0[256];
74b3307332Smanu 	static char buf1[256];
75b3307332Smanu 	char *buf = (idx % 2) ? &buf0[0] : &buf1[0];
76b3307332Smanu 	size_t len = sizeof(buf0) - 1;
77b3307332Smanu 	size_t wr = 0;
78b3307332Smanu 	uint32_t unknown_bits =
79b3307332Smanu 	    __BITS(3,7)|__BITS(14,16)|__BITS(21,22)|__BITS(27,31);
80b3307332Smanu 	int b;
81b3307332Smanu 
82b3307332Smanu 	rxev =
83b3307332Smanu 	    (val & IGPIO_PADCFG0_RXEVCFG_MASK) >> IGPIO_PADCFG0_RXEVCFG_SHIFT;
84b3307332Smanu 	wr += snprintf(buf + wr, len - wr, "rxev ");
85b3307332Smanu 	switch (rxev) {
86b3307332Smanu 	case IGPIO_PADCFG0_RXEVCFG_LEVEL:
87b3307332Smanu 		wr += snprintf(buf + wr, len - wr, "level");
88b3307332Smanu 		break;
89b3307332Smanu 	case IGPIO_PADCFG0_RXEVCFG_EDGE:
90b3307332Smanu 		wr += snprintf(buf + wr, len - wr, "edge");
91b3307332Smanu 		break;
92b3307332Smanu 	case IGPIO_PADCFG0_RXEVCFG_DISABLED:
93b3307332Smanu 		wr += snprintf(buf + wr, len - wr, "disabled");
94b3307332Smanu 		break;
95b3307332Smanu 	case IGPIO_PADCFG0_RXEVCFG_EDGE_BOTH:
96b3307332Smanu 		wr += snprintf(buf + wr, len - wr, "edge both");
97b3307332Smanu 		break;
98b3307332Smanu 	default:
99b3307332Smanu 		break;
100b3307332Smanu 	}
101b3307332Smanu 
102b3307332Smanu 	if (val & IGPIO_PADCFG0_PREGFRXSEL)
103b3307332Smanu 		wr += snprintf(buf + wr, len - wr, ", pregfrxsel");
104b3307332Smanu 
105b3307332Smanu 	if (val & IGPIO_PADCFG0_RXINV)
106b3307332Smanu 		wr += snprintf(buf + wr, len - wr, ", rxinv");
107b3307332Smanu 
108b3307332Smanu 	if (val & (IGPIO_PADCFG0_GPIROUTIOXAPIC|IGPIO_PADCFG0_GPIROUTSCI|
109b3307332Smanu 		   IGPIO_PADCFG0_GPIROUTSMI|IGPIO_PADCFG0_GPIROUTNMI)) {
110b3307332Smanu 		wr += snprintf(buf + wr, len - wr, ", gpirout");
111b3307332Smanu 
112b3307332Smanu 		if (val & IGPIO_PADCFG0_GPIROUTIOXAPIC)
113b3307332Smanu 			wr += snprintf(buf + wr, len - wr, " ioxapic");
114b3307332Smanu 
115b3307332Smanu 		if (val & IGPIO_PADCFG0_GPIROUTSCI)
116b3307332Smanu 			wr += snprintf(buf + wr, len - wr, " sci");
117b3307332Smanu 
118b3307332Smanu 		if (val & IGPIO_PADCFG0_GPIROUTSMI)
119b3307332Smanu 			wr += snprintf(buf + wr, len - wr, " smi");
120b3307332Smanu 
121b3307332Smanu 		if (val & IGPIO_PADCFG0_GPIROUTNMI)
122b3307332Smanu 			wr += snprintf(buf + wr, len - wr, " nmi");
123b3307332Smanu 	}
124b3307332Smanu 
125b3307332Smanu 	pmode =
126b3307332Smanu 	    (val & IGPIO_PADCFG0_PMODE_MASK) >> IGPIO_PADCFG0_PMODE_SHIFT;
127b3307332Smanu 	switch (pmode) {
128b3307332Smanu 	case IGPIO_PADCFG0_PMODE_GPIO:
129b3307332Smanu 		wr += snprintf(buf + wr, len - wr, ", pmode gpio");
130b3307332Smanu 		break;
131b3307332Smanu 	default:
132b3307332Smanu 		wr += snprintf(buf + wr, len - wr, ", pmode %d", pmode);
133b3307332Smanu 		break;
134b3307332Smanu 	}
135b3307332Smanu 
136b3307332Smanu 	if (val & IGPIO_PADCFG0_GPIORXDIS)
137b3307332Smanu 		wr += snprintf(buf + wr, len - wr, ", rx disabled");
138b3307332Smanu 	else
139b3307332Smanu 		wr += snprintf(buf + wr, len - wr, ", rx %d",
140b3307332Smanu 		    !!(val & IGPIO_PADCFG0_GPIORXSTATE));
141b3307332Smanu 
142b3307332Smanu 	if (val & IGPIO_PADCFG0_GPIOTXDIS)
143b3307332Smanu 		wr += snprintf(buf + wr, len - wr, ", tx disabled");
144b3307332Smanu 	else
145b3307332Smanu 		wr += snprintf(buf + wr, len - wr, ", tx %d",
146b3307332Smanu 		    !!(val & IGPIO_PADCFG0_GPIOTXSTATE));
147b3307332Smanu 
148b3307332Smanu 	if (val & unknown_bits) {
149b3307332Smanu 		wr += snprintf(buf + wr, len - wr, ", unknown bits");
150b3307332Smanu 		for (b = 0; b < 32; b++) {
151b3307332Smanu 			if (!(__BIT(b) & unknown_bits & val))
152b3307332Smanu 				continue;
153b3307332Smanu 			wr += snprintf(buf + wr, len - wr, " %d", b);
154b3307332Smanu 		}
155b3307332Smanu 	}
156b3307332Smanu 
157b3307332Smanu 	return buf;
158b3307332Smanu }
159b3307332Smanu 
160b3307332Smanu 
161b3307332Smanu static struct igpio_bank_setup *
igpio_find_bank_setup(struct igpio_bank * ib,int barno)162b3307332Smanu igpio_find_bank_setup(struct igpio_bank *ib, int barno)
163b3307332Smanu {
164b3307332Smanu 	struct igpio_bank_setup *ibs;
165b3307332Smanu 
166b3307332Smanu 	for (ibs = igpio_bank_setup; ibs->ibs_acpi_hid; ibs++) {
167b3307332Smanu 		if (strcmp(ib->ib_sc->sc_acpi_hid, ibs->ibs_acpi_hid) != 0)
168b3307332Smanu 			continue;
169b3307332Smanu 		if (ibs->ibs_barno != barno)
170b3307332Smanu 			continue;
171b3307332Smanu 
172b3307332Smanu 		return ibs;
173b3307332Smanu 	}
174b3307332Smanu 
175b3307332Smanu 	return NULL;
176b3307332Smanu }
177b3307332Smanu 
178b3307332Smanu static struct igpio_bank *
igpio_find_bank(struct igpio_softc * sc,int pin)179b3307332Smanu igpio_find_bank(struct igpio_softc *sc, int pin)
180b3307332Smanu {
181b3307332Smanu 	int i;
182b3307332Smanu 	struct igpio_bank *ib;
183b3307332Smanu 
184b3307332Smanu 	for (i = 0; i < sc->sc_nbar; i++) {
185b3307332Smanu 		ib = &sc->sc_banks[i];
186b3307332Smanu 		if (pin >= ib->ib_setup->ibs_first_pin &&
187b3307332Smanu 		    pin <= ib->ib_setup->ibs_last_pin)
188b3307332Smanu 			goto out;
189b3307332Smanu 	}
190b3307332Smanu 
191b3307332Smanu 	ib = NULL;
192b3307332Smanu out:
193b3307332Smanu 	return ib;
194b3307332Smanu }
195b3307332Smanu 
196b3307332Smanu static int
igpio_bank_pin(struct igpio_bank * ib,int pin)197b3307332Smanu igpio_bank_pin(struct igpio_bank *ib, int pin)
198b3307332Smanu {
199b3307332Smanu 	return pin - ib->ib_setup->ibs_first_pin;
200b3307332Smanu }
201b3307332Smanu 
202b3307332Smanu #if 0
203b3307332Smanu static void
204b3307332Smanu igpio_hexdump(struct igpio_softc *sc, int n)
205b3307332Smanu {
206b3307332Smanu 	int i, j;
207b3307332Smanu 	uint8_t v;
208b3307332Smanu 	size_t len = MIN(sc->sc_length[n], 2048);
209b3307332Smanu 
210b3307332Smanu 	printf("bar %d\n", n);
211b3307332Smanu 	for (j = 0; j < len; j += 16) {
212b3307332Smanu 		printf("%04x ", j);
213b3307332Smanu 		for (i = 0; i < 16 && i + j < len; i++) {
214b3307332Smanu 			v = bus_space_read_1(sc->sc_bst, sc->sc_bsh[n], i + j);
215b3307332Smanu 			printf("%02x ", v);
216b3307332Smanu 		}
217b3307332Smanu 		printf("\n");
218b3307332Smanu 	}
219b3307332Smanu }
220b3307332Smanu #endif
221b3307332Smanu 
222b3307332Smanu void
igpio_attach(struct igpio_softc * sc)223b3307332Smanu igpio_attach(struct igpio_softc *sc)
224b3307332Smanu {
225b3307332Smanu 	device_t self = sc->sc_dev;
226b3307332Smanu 	int i,j;
227b3307332Smanu 	struct gpiobus_attach_args gba;
228b3307332Smanu 	int success = 0;
229b3307332Smanu 
230b3307332Smanu 	sc->sc_banks =
231b3307332Smanu 	    kmem_zalloc(sizeof(*sc->sc_banks) * sc->sc_nbar, KM_SLEEP);
232b3307332Smanu 
233b3307332Smanu 	sc->sc_npins = 0;
234b3307332Smanu 
235b3307332Smanu 	for (i = 0; i < sc->sc_nbar; i++) {
236b3307332Smanu 		struct igpio_bank *ib = &sc->sc_banks[i];
237b3307332Smanu 		struct igpio_bank_setup *ibs;
238b3307332Smanu 		bus_size_t reg;
239b3307332Smanu 		uint32_t val;
240b3307332Smanu 		int error;
241b3307332Smanu 		int npins;
242b3307332Smanu 
243b3307332Smanu 		ib->ib_barno = i;
244b3307332Smanu 		ib->ib_sc = sc;
245b3307332Smanu 
246b3307332Smanu 		mutex_init(&ib->ib_mtx, MUTEX_DEFAULT, IPL_VM);
247b3307332Smanu 
248b3307332Smanu 		error = bus_space_map(sc->sc_bst, sc->sc_base[i],
249b3307332Smanu 		    sc->sc_length[i], 0, &sc->sc_bsh[i]);
250b3307332Smanu 		if (error) {
251b3307332Smanu 			aprint_error_dev(self, "couldn't map registers\n");
252b3307332Smanu 			goto out;
253b3307332Smanu 		}
254b3307332Smanu 
255b3307332Smanu 		reg = IGPIO_REVID;
256b3307332Smanu 		val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[i], reg);
257b3307332Smanu 		if (val == 0) {
258b3307332Smanu 			aprint_error_dev(self, "couldn't find revid\n");
259b3307332Smanu 			goto out;
260b3307332Smanu 		}
261b3307332Smanu 		ib->ib_revid = val >> 16;
262b3307332Smanu 
263b3307332Smanu 		DPRINTF(("revid[%d] = #%x\n", i, ib->ib_revid));
264b3307332Smanu 
265b3307332Smanu 		if (ib->ib_revid > 0x94) {
266b3307332Smanu 			ib->ib_cap |= IGPIO_PINCTRL_FEATURE_DEBOUNCE;
267b3307332Smanu 			ib->ib_cap |= IGPIO_PINCTRL_FEATURE_1K_PD;
268b3307332Smanu 		}
269b3307332Smanu 
270b3307332Smanu 		reg = IGPIO_CAPLIST;
271b3307332Smanu 		do {
272b3307332Smanu 			/* higher 16 bits: value, lower 16 bits, next reg */
273b3307332Smanu 			val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[i], reg);
274b3307332Smanu 
275b3307332Smanu 			reg = val & 0xffff;
276b3307332Smanu 			val = val >> 16;
277b3307332Smanu 
278b3307332Smanu 			switch (val) {
279b3307332Smanu 			case IGPIO_CAPLIST_ID_GPIO_HW_INFO:
280b3307332Smanu 				ib->ib_cap |=
281b3307332Smanu 				    IGPIO_PINCTRL_FEATURE_GPIO_HW_INFO;
282b3307332Smanu 				break;
283b3307332Smanu 			case IGPIO_CAPLIST_ID_PWM:
284b3307332Smanu 				ib->ib_cap |= IGPIO_PINCTRL_FEATURE_PWM;
285b3307332Smanu 				break;
286b3307332Smanu 			case IGPIO_CAPLIST_ID_BLINK:
287b3307332Smanu 				ib->ib_cap |= IGPIO_PINCTRL_FEATURE_BLINK;
288b3307332Smanu 				break;
289b3307332Smanu 			case IGPIO_CAPLIST_ID_EXP:
290b3307332Smanu 				ib->ib_cap |= IGPIO_PINCTRL_FEATURE_EXP;
291b3307332Smanu 				break;
292b3307332Smanu 			default:
293b3307332Smanu 				break;
294b3307332Smanu 			}
295b3307332Smanu 		} while (reg);
296b3307332Smanu 		DPRINTF(("cap[%d] = #%x\n", i, ib->ib_cap));
297b3307332Smanu 
298b3307332Smanu 		reg = IGPIO_PADBAR;
299b3307332Smanu 		val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[i], reg);
300b3307332Smanu 		ib->ib_padbar = val;
301b3307332Smanu 		DPRINTF(("padbar[%d] = #%x\n", i, ib->ib_padbar));
302b3307332Smanu 		if (ib->ib_padbar > sc->sc_length[i]) {
303b3307332Smanu 			printf("PADBAR = #%x higher than max #%lx\n",
304b3307332Smanu 			    ib->ib_padbar, sc->sc_length[i]);
305b3307332Smanu 			goto out;
306b3307332Smanu 		}
307b3307332Smanu 
308b3307332Smanu 		ib->ib_setup = igpio_find_bank_setup(ib, i);
309b3307332Smanu 		if (ib->ib_setup == NULL) {
310b3307332Smanu 			printf("Missing BAR %d\n", i);
311b3307332Smanu 			goto out;
312b3307332Smanu 		}
313b3307332Smanu 
314b3307332Smanu 		ibs = ib->ib_setup;
315b3307332Smanu 
316b3307332Smanu 		DPRINTF(("setup[%d] = "
317b3307332Smanu 		    "{ barno = %d, first_pin = %d, last_pin = %d }\n",
318b3307332Smanu 		    i, ibs->ibs_barno, ibs->ibs_first_pin, ibs->ibs_last_pin));
319b3307332Smanu 
320b3307332Smanu 		npins = 1 + ibs->ibs_last_pin - ibs->ibs_first_pin;
321b3307332Smanu 
322b3307332Smanu 		ib->ib_intr =
323b3307332Smanu 		    kmem_zalloc(sizeof(*ib->ib_intr) * npins, KM_SLEEP);
324b3307332Smanu 
325b3307332Smanu 		sc->sc_npins += npins;
326b3307332Smanu 	}
327b3307332Smanu 
328b3307332Smanu 	if (sc->sc_npins < 1 || sc->sc_npins > 4096) {
329b3307332Smanu 		printf("Unexpected pin count %d\n", sc->sc_npins);
330b3307332Smanu 		goto out;
331b3307332Smanu 	}
332b3307332Smanu 
333b3307332Smanu 	sc->sc_pins =
334b3307332Smanu 	    kmem_zalloc(sizeof(*sc->sc_pins) * sc->sc_npins, KM_SLEEP);
335b3307332Smanu 
336b3307332Smanu 	for (j = 0; j < sc->sc_npins; j++) {
337b3307332Smanu 		sc->sc_pins[j].pin_num = j;
338b3307332Smanu 		sc->sc_pins[j].pin_caps =
339b3307332Smanu 		    GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_INOUT |
340b3307332Smanu 		    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_PIN_INVIN;
341b3307332Smanu 		sc->sc_pins[j].pin_intrcaps =
342b3307332Smanu 		    GPIO_INTR_POS_EDGE | GPIO_INTR_NEG_EDGE |
343b3307332Smanu 		    GPIO_INTR_DOUBLE_EDGE | GPIO_INTR_HIGH_LEVEL |
344b3307332Smanu 		    GPIO_INTR_LOW_LEVEL | GPIO_INTR_MPSAFE;
345b3307332Smanu 		sc->sc_pins[j].pin_state = igpio_pin_read(sc, j);
346b3307332Smanu 	}
347b3307332Smanu 
348b3307332Smanu 	sc->sc_gc.gp_cookie = sc;
349b3307332Smanu 	sc->sc_gc.gp_pin_read = igpio_pin_read;
350b3307332Smanu 	sc->sc_gc.gp_pin_write = igpio_pin_write;
351b3307332Smanu 	sc->sc_gc.gp_pin_ctl = igpio_pin_ctl;
352b3307332Smanu 	sc->sc_gc.gp_intr_establish = igpio_intr_establish;
353b3307332Smanu 	sc->sc_gc.gp_intr_disestablish = igpio_intr_disestablish;
354b3307332Smanu 	sc->sc_gc.gp_intr_str = igpio_intr_str;
355b3307332Smanu 
356b3307332Smanu 	memset(&gba, 0, sizeof(gba));
357b3307332Smanu 	gba.gba_gc = &sc->sc_gc;
358b3307332Smanu 	gba.gba_pins = sc->sc_pins;
359b3307332Smanu 	gba.gba_npins = sc->sc_npins;
360b3307332Smanu 
361b3307332Smanu #if NGPIO > 0
362b3307332Smanu 	config_found(sc->sc_dev, &gba, gpiobus_print, CFARGS_NONE);
363b3307332Smanu #endif
364b3307332Smanu 
365b3307332Smanu 	success = 1;
366b3307332Smanu out:
367b3307332Smanu 	if (!success)
368b3307332Smanu 		igpio_detach(sc);
369b3307332Smanu 
370b3307332Smanu 	return;
371b3307332Smanu }
372b3307332Smanu 
373b3307332Smanu void
igpio_detach(struct igpio_softc * sc)374b3307332Smanu igpio_detach(struct igpio_softc *sc)
375b3307332Smanu {
376b3307332Smanu 	int i;
377b3307332Smanu 
378b3307332Smanu 	for (i = 0; i < sc->sc_nbar; i++) {
379b3307332Smanu 		struct igpio_bank *ib = &sc->sc_banks[i];
380b3307332Smanu 		struct igpio_bank_setup *ibs = ib->ib_setup;
381b3307332Smanu 		int npins = 1 + ibs->ibs_last_pin - ibs->ibs_first_pin;
382b3307332Smanu 
383b3307332Smanu 		if (ib->ib_intr != NULL) {
384b3307332Smanu 			kmem_free(ib->ib_intr, sizeof(*ib->ib_intr) * npins);
385b3307332Smanu 			ib->ib_intr = NULL;
386b3307332Smanu 		}
387b3307332Smanu 	}
388b3307332Smanu 
389b3307332Smanu 	if (sc->sc_pins != NULL) {
390b3307332Smanu 		kmem_free(sc->sc_pins, sizeof(*sc->sc_pins) * sc->sc_npins);
391b3307332Smanu 		sc->sc_pins = NULL;
392b3307332Smanu 	}
393b3307332Smanu 
394b3307332Smanu 	if (sc->sc_banks != NULL) {
395b3307332Smanu 		kmem_free(sc->sc_banks, sizeof(*sc->sc_banks) * sc->sc_nbar);
396b3307332Smanu 		sc->sc_banks = NULL;
397b3307332Smanu 	}
398b3307332Smanu 
399b3307332Smanu 	return;
400b3307332Smanu }
401b3307332Smanu 
402b3307332Smanu static bus_addr_t
igpio_pincfg(struct igpio_bank * ib,int pin,int reg)403b3307332Smanu igpio_pincfg(struct igpio_bank *ib, int pin, int reg)
404b3307332Smanu {
405b3307332Smanu 	int nregs = (ib->ib_cap & IGPIO_PINCTRL_FEATURE_DEBOUNCE) ? 4 : 2;
406b3307332Smanu 	bus_addr_t pincfg;
407b3307332Smanu 
408b3307332Smanu 	pincfg = ib->ib_padbar + reg + (pin * nregs * 4);
409b3307332Smanu #if 0
410b3307332Smanu 	DPRINTF(("%s bar %d pin %d reg #%x pincfg = %p\n",
411b3307332Smanu 	    __func__, ib->ib_barno, pin, reg, (void *)pincfg));
412b3307332Smanu #endif
413b3307332Smanu 	return pincfg;
414b3307332Smanu }
415b3307332Smanu 
416b3307332Smanu #if notyet
417b3307332Smanu static struct igpio_pin_group *
igpio_find_group(struct igpio_bank * ib,int pin)418b3307332Smanu igpio_find_group(struct igpio_bank *ib, int pin)
419b3307332Smanu {
420b3307332Smanu 	struct igpio_bank_setup *ibs = ib->ib_setup;
421b3307332Smanu 	struct igpio_pin_group *found_ipg = NULL;
422b3307332Smanu 	struct igpio_pin_group *ipg;
423b3307332Smanu 
424b3307332Smanu 	if (pin > ibs->ibs_last_pin) {
425b3307332Smanu 		DPRINTF(("%s: barno %d, pin = %d > past pin = %d\n", __func__,
426b3307332Smanu 		    ibs->ibs_barno, pin, ibs->ibs_last_pin));
427b3307332Smanu 		return NULL;
428b3307332Smanu 	}
429b3307332Smanu 
430b3307332Smanu 	for (ipg = igpio_pin_group; ipg->ipg_acpi_hid; ipg++) {
431b3307332Smanu 		if (strcmp(ipg->ipg_acpi_hid, ibs->ibs_acpi_hid) != 0)
432b3307332Smanu 			continue;
433b3307332Smanu 
434b3307332Smanu 		if (pin > ipg->ipg_first_pin) {
435b3307332Smanu 			found_ipg = ipg;
436b3307332Smanu 			continue;
437b3307332Smanu 		}
438b3307332Smanu 	}
439b3307332Smanu 
440b3307332Smanu 	return found_ipg;
441b3307332Smanu }
442b3307332Smanu 
443b3307332Smanu static bus_addr_t
igpio_groupcfg(struct igpio_bank * ib,int pin)444b3307332Smanu igpio_groupcfg(struct igpio_bank *ib, int pin)
445b3307332Smanu {
446b3307332Smanu 	struct igpio_bank_setup *ibs = ib->ib_setup;
447b3307332Smanu 	struct igpio_pin_group *ipg;
448b3307332Smanu 	bus_addr_t groupcfg;
449b3307332Smanu 
450b3307332Smanu 	if ((ipg = igpio_find_group(ib, pin)) == NULL)
451b3307332Smanu 		return (bus_addr_t)NULL;
452b3307332Smanu 
453b3307332Smanu 	groupcfg = ib->ib_padbar
454b3307332Smanu 		 + (ipg->ipg_groupno * 4)
455b3307332Smanu 		 + (pin - ipg->ipg_first_pin) / 2;
456b3307332Smanu 
457b3307332Smanu 	DPRINTF(("%s: barno %d, pin = %d, found group %d \"%s\", cfg %p\n", \
458b3307332Smanu 	    __func__, ibs->ibs_barno, pin, ipg->ipg_groupno,		    \
459b3307332Smanu 	    ipg->ipg_name, (void *)groupcfg));
460b3307332Smanu 
461b3307332Smanu 	return groupcfg;
462b3307332Smanu }
463b3307332Smanu #endif
464b3307332Smanu 
465b3307332Smanu 
466b3307332Smanu int
igpio_pin_read(void * priv,int pin)467b3307332Smanu igpio_pin_read(void *priv, int pin)
468b3307332Smanu {
469b3307332Smanu 	struct igpio_softc *sc = priv;
470b3307332Smanu 	struct igpio_bank *ib = igpio_find_bank(sc, pin);
471b3307332Smanu 	bus_addr_t cfg0;
472b3307332Smanu 	uint32_t val;
473b3307332Smanu 
474b3307332Smanu 	pin = igpio_bank_pin(ib, pin);
475b3307332Smanu 	cfg0  = igpio_pincfg(ib, pin, IGPIO_PADCFG0);
476b3307332Smanu 
477b3307332Smanu 	mutex_enter(&ib->ib_mtx);
478b3307332Smanu 
479b3307332Smanu 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0);
480b3307332Smanu 	DPRINTF(("%s: bar %d pin %d val #%x (%s)\n", __func__,
481b3307332Smanu 	    ib->ib_barno, pin, val, igpio_padcfg0_print(val, 0)));
482b3307332Smanu 
483b3307332Smanu 	if (val & IGPIO_PADCFG0_GPIOTXDIS)
484b3307332Smanu 		val = (val & IGPIO_PADCFG0_GPIORXSTATE) ? 1 : 0;
485b3307332Smanu 	else
486b3307332Smanu 		val = (val & IGPIO_PADCFG0_GPIOTXSTATE) ? 1 : 0;
487b3307332Smanu 
488b3307332Smanu 	mutex_exit(&ib->ib_mtx);
489b3307332Smanu 
490b3307332Smanu 	return val;
491b3307332Smanu }
492b3307332Smanu 
493b3307332Smanu void
igpio_pin_write(void * priv,int pin,int value)494b3307332Smanu igpio_pin_write(void *priv, int pin, int value)
495b3307332Smanu {
496b3307332Smanu 	struct igpio_softc *sc = priv;
497b3307332Smanu 	struct igpio_bank *ib = igpio_find_bank(sc, pin);
498b3307332Smanu 	bus_addr_t cfg0;
499b3307332Smanu 	uint32_t val, newval;
500b3307332Smanu 
501b3307332Smanu 	pin = igpio_bank_pin(ib, pin);
502b3307332Smanu 	cfg0 = igpio_pincfg(ib, pin, IGPIO_PADCFG0);
503b3307332Smanu 
504b3307332Smanu 	mutex_enter(&ib->ib_mtx);
505b3307332Smanu 
506b3307332Smanu 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0);
507b3307332Smanu 
508b3307332Smanu 	if (value)
509b3307332Smanu 		newval = val |  IGPIO_PADCFG0_GPIOTXSTATE;
510b3307332Smanu 	else
511b3307332Smanu 		newval = val & ~IGPIO_PADCFG0_GPIOTXSTATE;
512b3307332Smanu 
513b3307332Smanu 	DPRINTF(("%s: bar %d pin %d value %d val #%x (%s) -> #%x (%s)\n",
514b3307332Smanu 	    __func__, ib->ib_barno, pin, value,
515b3307332Smanu 	    val, igpio_padcfg0_print(val, 0),
516b3307332Smanu 	    newval, igpio_padcfg0_print(newval, 1)));
517b3307332Smanu 
518b3307332Smanu 	bus_space_write_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0, newval);
519b3307332Smanu 
520b3307332Smanu 	mutex_exit(&ib->ib_mtx);
521b3307332Smanu 
522b3307332Smanu 	return;
523b3307332Smanu }
524b3307332Smanu 
525b3307332Smanu void
igpio_pin_ctl(void * priv,int pin,int flags)526b3307332Smanu igpio_pin_ctl(void *priv, int pin, int flags)
527b3307332Smanu {
528b3307332Smanu 	struct igpio_softc *sc = priv;
529b3307332Smanu 	struct igpio_bank *ib = igpio_find_bank(sc, pin);
530b3307332Smanu 	bus_addr_t cfg0, cfg1;
531b3307332Smanu 	uint32_t val0, newval0;
532b3307332Smanu 	uint32_t val1, newval1;
533b3307332Smanu 
534b3307332Smanu 	pin = igpio_bank_pin(ib, pin);
535b3307332Smanu 	cfg0  = igpio_pincfg(ib, pin, IGPIO_PADCFG0);
536b3307332Smanu 	cfg1  = igpio_pincfg(ib, pin, IGPIO_PADCFG1);
537b3307332Smanu 
538b3307332Smanu 	mutex_enter(&ib->ib_mtx);
539b3307332Smanu 
540b3307332Smanu 	val0 = bus_space_read_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0);
541b3307332Smanu 	val1 = bus_space_read_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg1);
542b3307332Smanu 
543b3307332Smanu 	newval0 = val0;
544b3307332Smanu 	newval1 = val1;
545b3307332Smanu 
546b3307332Smanu 	newval0 &= ~IGPIO_PADCFG0_PMODE_MASK;
547b3307332Smanu 	newval0 |=  IGPIO_PADCFG0_PMODE_GPIO;
548b3307332Smanu 
549b3307332Smanu 	newval0 |= IGPIO_PADCFG0_GPIORXDIS;
550b3307332Smanu 	newval0 |= IGPIO_PADCFG0_GPIOTXDIS;
551b3307332Smanu 
552b3307332Smanu 	newval0 &= ~(IGPIO_PADCFG0_GPIROUTIOXAPIC | IGPIO_PADCFG0_GPIROUTSCI);
553b3307332Smanu 	newval0 &= ~(IGPIO_PADCFG0_GPIROUTSMI | IGPIO_PADCFG0_GPIROUTNMI);
554b3307332Smanu 
555b3307332Smanu 	if (flags & GPIO_PIN_INPUT) {
556b3307332Smanu 		newval0 &= ~IGPIO_PADCFG0_GPIORXDIS;
557b3307332Smanu 		newval0 |=  IGPIO_PADCFG0_GPIOTXDIS;
558b3307332Smanu 	}
559b3307332Smanu 
560b3307332Smanu 	if (flags & GPIO_PIN_OUTPUT) {
561b3307332Smanu 		newval0 &= ~IGPIO_PADCFG0_GPIOTXDIS;
562b3307332Smanu 		newval0 |=  IGPIO_PADCFG0_GPIORXDIS;
563b3307332Smanu 	}
564b3307332Smanu 
565b3307332Smanu 	if (flags & GPIO_PIN_INOUT) {
566b3307332Smanu 		newval0 &= ~IGPIO_PADCFG0_GPIOTXDIS;
567b3307332Smanu 		newval0 &= ~IGPIO_PADCFG0_GPIORXDIS;
568b3307332Smanu 	}
569b3307332Smanu 
570b3307332Smanu 	if (flags & GPIO_PIN_INVIN)
571b3307332Smanu 		newval0 |=  IGPIO_PADCFG0_RXINV;
572b3307332Smanu 	else
573b3307332Smanu 		newval0 &= ~IGPIO_PADCFG0_RXINV;
574b3307332Smanu 
575b3307332Smanu 	newval1 &= ~IGPIO_PADCFG1_TERM_MASK;
576b3307332Smanu 	if (flags & GPIO_PIN_PULLUP) {
577b3307332Smanu 		newval1 |=  IGPIO_PADCFG1_TERM_UP;
578b3307332Smanu 		newval1 |=  IGPIO_PADCFG1_TERM_5K;
579b3307332Smanu 	}
580b3307332Smanu 
581b3307332Smanu 	if (flags & GPIO_PIN_PULLDOWN) {
582b3307332Smanu 		newval1 &= ~IGPIO_PADCFG1_TERM_UP;
583b3307332Smanu 		newval1 |=  IGPIO_PADCFG1_TERM_5K;
584b3307332Smanu 	}
585b3307332Smanu 
586b3307332Smanu 	DPRINTF(("%s: bar %d pin %d flags #%x val0 #%x (%s) -> #%x (%s), "
587b3307332Smanu 	    "val1 #%x -> #%x\n", __func__, ib->ib_barno, pin, flags,
588b3307332Smanu 	    val0, igpio_padcfg0_print(val0, 0),
589b3307332Smanu 	    newval0, igpio_padcfg0_print(newval0, 1),
590b3307332Smanu 	    val1, newval1));
591b3307332Smanu 
592b3307332Smanu 	bus_space_write_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0, newval0);
593b3307332Smanu 	bus_space_write_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg1, newval1);
594b3307332Smanu 
595b3307332Smanu 	mutex_exit(&ib->ib_mtx);
596b3307332Smanu 
597b3307332Smanu 	return;
598b3307332Smanu }
599b3307332Smanu 
600b3307332Smanu void *
igpio_intr_establish(void * priv,int pin,int ipl,int irqmode,int (* func)(void *),void * arg)601b3307332Smanu igpio_intr_establish(void *priv, int pin, int ipl, int irqmode,
602b3307332Smanu     int (*func)(void *), void *arg)
603b3307332Smanu {
604b3307332Smanu 	struct igpio_softc *sc = priv;
605b3307332Smanu 	struct igpio_bank *ib = igpio_find_bank(sc, pin);
606b3307332Smanu 	bus_addr_t cfg0;
607b3307332Smanu 	uint32_t val, newval;
608b3307332Smanu 	struct igpio_intr *ii;
609b3307332Smanu 
610b3307332Smanu 	pin = igpio_bank_pin(ib, pin);
611b3307332Smanu 	cfg0 = igpio_pincfg(ib, pin, IGPIO_PADCFG0);
612b3307332Smanu 
613b3307332Smanu 	ii = &ib->ib_intr[pin];
614b3307332Smanu 	ii->ii_func = func;
615b3307332Smanu 	ii->ii_arg = arg;
616b3307332Smanu 	ii->ii_pin = pin;
617b3307332Smanu 	ii->ii_bank = ib;
618b3307332Smanu 
619b3307332Smanu 	mutex_enter(&ib->ib_mtx);
620b3307332Smanu 
621b3307332Smanu 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0);
622b3307332Smanu 	newval = val;
623b3307332Smanu 
624b3307332Smanu 	newval &= ~IGPIO_PADCFG0_PMODE_MASK;
625b3307332Smanu 	newval |=  IGPIO_PADCFG0_PMODE_GPIO;
626b3307332Smanu 
627b3307332Smanu 	newval &= ~IGPIO_PADCFG0_GPIORXDIS;
628b3307332Smanu 	newval |=  IGPIO_PADCFG0_GPIOTXDIS;
629b3307332Smanu 
630b3307332Smanu 	newval |= (IGPIO_PADCFG0_GPIROUTIOXAPIC | IGPIO_PADCFG0_GPIROUTSCI);
631b3307332Smanu 	newval |= (IGPIO_PADCFG0_GPIROUTSMI | IGPIO_PADCFG0_GPIROUTNMI);
632b3307332Smanu 
633b3307332Smanu 	newval &= ~IGPIO_PADCFG0_RXINV;
634b3307332Smanu 	newval &= ~IGPIO_PADCFG0_RXEVCFG_EDGE;
635b3307332Smanu 	newval &= ~IGPIO_PADCFG0_RXEVCFG_LEVEL;
636b3307332Smanu 	newval &= ~IGPIO_PADCFG0_RXEVCFG_DISABLED;
637b3307332Smanu 
638b3307332Smanu 	switch (irqmode & GPIO_INTR_EDGE_MASK) {
639b3307332Smanu 	case GPIO_INTR_DOUBLE_EDGE:
640b3307332Smanu 		newval |= IGPIO_PADCFG0_RXEVCFG_EDGE_BOTH;
641b3307332Smanu 		break;
642b3307332Smanu 	case GPIO_INTR_NEG_EDGE:
643b3307332Smanu 		newval |= IGPIO_PADCFG0_RXEVCFG_EDGE;
644b3307332Smanu 		newval |= IGPIO_PADCFG0_RXINV;
645b3307332Smanu 		break;
646b3307332Smanu 	case GPIO_INTR_POS_EDGE:
647b3307332Smanu 		newval |= IGPIO_PADCFG0_RXEVCFG_EDGE;
648b3307332Smanu 		break;
649b3307332Smanu 	default:
650b3307332Smanu 		switch (irqmode & GPIO_INTR_LEVEL_MASK) {
651b3307332Smanu 		case GPIO_INTR_HIGH_LEVEL:
652b3307332Smanu 			newval |= IGPIO_PADCFG0_RXEVCFG_LEVEL;
653b3307332Smanu 			break;
654b3307332Smanu 		case GPIO_INTR_LOW_LEVEL:
655b3307332Smanu 			newval |= IGPIO_PADCFG0_RXEVCFG_LEVEL;
656b3307332Smanu 			newval |= IGPIO_PADCFG0_RXINV;
657b3307332Smanu 			break;
658b3307332Smanu 		default:
659b3307332Smanu 			newval |= IGPIO_PADCFG0_RXEVCFG_DISABLED;
660b3307332Smanu 			break;
661b3307332Smanu 		}
662b3307332Smanu 		break;
663b3307332Smanu 	}
664b3307332Smanu 
665b3307332Smanu 
666b3307332Smanu 	DPRINTF(("%s: bar %d pin %d val #%x (%s) -> #%x (%s)\n",
667b3307332Smanu 	    __func__, ib->ib_barno, pin,
668b3307332Smanu 	    val, igpio_padcfg0_print(val, 0),
669b3307332Smanu 	    newval, igpio_padcfg0_print(newval, 1)));
670b3307332Smanu 
671b3307332Smanu 	bus_space_write_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0, newval);
672b3307332Smanu 
673b3307332Smanu 	mutex_exit(&ib->ib_mtx);
674b3307332Smanu 
675b3307332Smanu 	return ii;
676b3307332Smanu }
677b3307332Smanu 
678b3307332Smanu void
igpio_intr_disestablish(void * priv,void * ih)679b3307332Smanu igpio_intr_disestablish(void *priv, void *ih)
680b3307332Smanu {
681b3307332Smanu 	struct igpio_softc *sc = priv;
682b3307332Smanu 	struct igpio_bank *ib;
683b3307332Smanu 	struct igpio_intr *ii = ih;
684b3307332Smanu 	int pin;
685b3307332Smanu 	bus_addr_t cfg0;
686b3307332Smanu 	uint32_t val, newval;
687b3307332Smanu 
688b3307332Smanu 	if (ih == NULL)
689b3307332Smanu 		return;
690b3307332Smanu 
691b3307332Smanu 	pin = ii->ii_pin;
692b3307332Smanu 	ib = igpio_find_bank(sc, pin);
693b3307332Smanu 	pin = igpio_bank_pin(ib, pin);
694b3307332Smanu 	cfg0  = igpio_pincfg(ib, pin, IGPIO_PADCFG0);
695b3307332Smanu 
696b3307332Smanu 	mutex_enter(&ib->ib_mtx);
697b3307332Smanu 
698b3307332Smanu 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0);
699b3307332Smanu 	newval = val;
700b3307332Smanu 
701b3307332Smanu 	newval &= ~IGPIO_PADCFG0_PMODE_MASK;
702b3307332Smanu 	newval |=  IGPIO_PADCFG0_PMODE_GPIO;
703b3307332Smanu 
704b3307332Smanu 	newval &= ~(IGPIO_PADCFG0_GPIROUTIOXAPIC | IGPIO_PADCFG0_GPIROUTSCI);
705b3307332Smanu 	newval &= ~(IGPIO_PADCFG0_GPIROUTSMI | IGPIO_PADCFG0_GPIROUTNMI);
706b3307332Smanu 
707b3307332Smanu 	DPRINTF(("%s: bar %d pin %d val #%x (%s) -> #%x (%s)\n", \
708b3307332Smanu 	    __func__, ib->ib_barno, pin,
709b3307332Smanu 	    val, igpio_padcfg0_print(val, 0),
710b3307332Smanu 	    newval, igpio_padcfg0_print(newval, 1)));
711b3307332Smanu 
712b3307332Smanu 	bus_space_write_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0, newval);
713b3307332Smanu 
714b3307332Smanu 	mutex_exit(&ib->ib_mtx);
715b3307332Smanu 
716b3307332Smanu 	ii->ii_func = NULL;
717b3307332Smanu 	ii->ii_arg = NULL;
718b3307332Smanu 
719b3307332Smanu 	return;
720b3307332Smanu }
721b3307332Smanu 
722b3307332Smanu bool
igpio_intr_str(void * priv,int pin,int irqmode,char * buf,size_t buflen)723b3307332Smanu igpio_intr_str(void *priv, int pin, int irqmode,
724b3307332Smanu     char *buf, size_t buflen)
725b3307332Smanu {
726b3307332Smanu 	struct igpio_softc *sc = priv;
72776498653Sriastradh 	const char *name = device_xname(sc->sc_dev);
728b3307332Smanu 	int rv;
729b3307332Smanu 
730b3307332Smanu 	rv = snprintf(buf, buflen, "%s pin %d", name, pin);
731b3307332Smanu 
732b3307332Smanu 	return (rv < buflen);
733b3307332Smanu }
734b3307332Smanu 
735b3307332Smanu int
igpio_intr(void * priv)736b3307332Smanu igpio_intr(void *priv)
737b3307332Smanu {
738b3307332Smanu 	struct igpio_softc *sc = priv;
739b3307332Smanu 	int i;
740b3307332Smanu 	int ret = 0;
741b3307332Smanu 
742b3307332Smanu 	for (i = 0; i < sc->sc_nbar; i++) {
743b3307332Smanu 		struct igpio_bank *ib = &sc->sc_banks[i];
744b3307332Smanu 		struct igpio_bank_setup *ibs = ib->ib_setup;
745b3307332Smanu 		bus_space_handle_t bsh = sc->sc_bsh[i];
746b3307332Smanu 		struct igpio_pin_group *ipg;
747b3307332Smanu 
748b3307332Smanu 		mutex_enter(&ib->ib_mtx);
749b3307332Smanu 
750b3307332Smanu 		for (ipg = igpio_pin_group; ipg->ipg_acpi_hid; ipg++) {
751b3307332Smanu 			int offset;
752b3307332Smanu 			bus_addr_t is_reg;
753b3307332Smanu 			bus_addr_t ie_reg;
754b3307332Smanu 			uint32_t raised;
755b3307332Smanu 			uint32_t pending;
756b3307332Smanu 			uint32_t enabled;
757b3307332Smanu 			int b;
758b3307332Smanu 
759b3307332Smanu 			if (strcmp(ipg->ipg_acpi_hid,
760b3307332Smanu 			    ibs->ibs_acpi_hid) != 0)
761b3307332Smanu 				continue;
762b3307332Smanu 
763b3307332Smanu 			offset = ib->ib_padbar + ipg->ipg_groupno * 4;
764b3307332Smanu 			is_reg = offset + ibs->ibs_gpi_is;
765b3307332Smanu 			ie_reg = offset + ibs->ibs_gpi_ie;
766b3307332Smanu 
767b3307332Smanu 			raised = bus_space_read_4(sc->sc_bst, bsh, is_reg);
768b3307332Smanu 			enabled = bus_space_read_4(sc->sc_bst, bsh, ie_reg);
769b3307332Smanu 
770b3307332Smanu 			/*
771a960b269Sandvar 			 * find pins for which interrupt is pending
772b3307332Smanu 			 * and enabled
773b3307332Smanu 			 */
774b3307332Smanu 			pending = raised & enabled;
775b3307332Smanu 
776b3307332Smanu 			for (b = 0; b < 32; b++) {
777b3307332Smanu 				int pin;
778b3307332Smanu 				int (*func)(void *);
779b3307332Smanu 				void *arg;
780b3307332Smanu 
781b3307332Smanu 				if ((pending & (1 << b)) == 0)
782b3307332Smanu 					continue;
783b3307332Smanu 
784b3307332Smanu 				pin = ipg->ipg_first_pin + b;
785b3307332Smanu 				func = ib->ib_intr[pin].ii_func;
786b3307332Smanu 				arg = ib->ib_intr[pin].ii_arg;
787b3307332Smanu 
788b3307332Smanu 				/* XXX ack intr, handled or not? */
789b3307332Smanu 				raised &= ~(1 << b);
790b3307332Smanu 
791b3307332Smanu 				if (func == NULL)
792b3307332Smanu 					continue;
793b3307332Smanu 
794b3307332Smanu 				ret |= func(arg);
795b3307332Smanu 			}
796b3307332Smanu 
797b3307332Smanu 			bus_space_write_4(sc->sc_bst, bsh, is_reg, raised);
798b3307332Smanu 
799b3307332Smanu 		}
800b3307332Smanu 
801b3307332Smanu 		mutex_exit(&ib->ib_mtx);
802b3307332Smanu 
803b3307332Smanu 	}
804b3307332Smanu 
805b3307332Smanu 	return ret;
806b3307332Smanu }
807