xref: /openbsd-src/sys/dev/acpi/qcgpio.c (revision a70ebb655327f63e102f6e667c257a494e0d846c)
1 /*	$OpenBSD: qcgpio.c,v 1.13 2024/12/22 21:55:20 mglocker Exp $	*/
2 /*
3  * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/malloc.h>
20 #include <sys/systm.h>
21 
22 #include <dev/acpi/acpireg.h>
23 #include <dev/acpi/acpivar.h>
24 #include <dev/acpi/acpidev.h>
25 #include <dev/acpi/amltypes.h>
26 #include <dev/acpi/dsdt.h>
27 
28 //#define QCGPIO_DEBUG
29 #ifdef QCGPIO_DEBUG
30 int qcgpio_debug = 1;
31 #define DPRINTF(l, x...) do { if ((l) <= qcgpio_debug) printf(x); } while (0)
32 #else
33 #define DPRINTF(l, x...)
34 #endif
35 
36 /* Registers. */
37 #define TLMM_GPIO_IN_OUT(pin)		(0x0004 + 0x1000 * (pin))
38 #define  TLMM_GPIO_IN_OUT_GPIO_IN			(1 << 0)
39 #define  TLMM_GPIO_IN_OUT_GPIO_OUT			(1 << 1)
40 #define TLMM_GPIO_INTR_CFG(pin)		(0x0008 + 0x1000 * (pin))
41 #define  TLMM_GPIO_INTR_CFG_TARGET_PROC_MASK		(0x7 << 5)
42 #define  TLMM_GPIO_INTR_CFG_TARGET_PROC_RPM		(0x3 << 5)
43 #define  TLMM_GPIO_INTR_CFG_INTR_RAW_STATUS_EN		(1 << 4)
44 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_MASK		(0x3 << 2)
45 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL		(0x0 << 2)
46 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_POS	(0x1 << 2)
47 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_NEG	(0x2 << 2)
48 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_BOTH	(0x3 << 2)
49 #define  TLMM_GPIO_INTR_CFG_INTR_POL_CTL		(1 << 1)
50 #define  TLMM_GPIO_INTR_CFG_INTR_ENABLE			(1 << 0)
51 #define TLMM_GPIO_INTR_STATUS(pin)	(0x000c + 0x1000 * (pin))
52 #define  TLMM_GPIO_INTR_STATUS_INTR_STATUS		(1 << 0)
53 
54 /* SC7180 has multiple tiles */
55 #define QCGPIO_SC7180_WEST	0x00100000
56 #define QCGPIO_SC7180_NORTH	0x00500000
57 #define QCGPIO_SC7180_SOUTH	0x00900000
58 
59 #define HREAD4(sc, reg)							\
60 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
61 #define HWRITE4(sc, reg, val)						\
62 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
63 #define HSET4(sc, reg, bits)						\
64 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
65 #define HCLR4(sc, reg, bits)						\
66 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
67 
68 struct qcgpio_intrhand {
69 	int (*ih_func)(void *);
70 	void *ih_arg;
71 };
72 
73 struct qcgpio_pdcmap {
74 	int		pm_pin;
75 	uint32_t	pm_irq;
76 };
77 
78 struct qcgpio_softc {
79 	struct device		sc_dev;
80 	struct acpi_softc	*sc_acpi;
81 	struct aml_node		*sc_node;
82 
83 	bus_space_tag_t		sc_iot;
84 	bus_space_handle_t	sc_ioh;
85 
86 	void			*sc_ih;
87 
88 	uint32_t		sc_npins;
89 	int			(*sc_pin_map)(struct qcgpio_softc *, int,
90 				    bus_size_t *);
91 	struct qcgpio_intrhand	*sc_pin_ih;
92 
93 	struct acpi_gpio sc_gpio;
94 
95 	struct qcgpio_pdcmap	*sc_pdcmap;
96 	uint32_t		 sc_npdcmap;
97 	uint32_t		 sc_ipdcmap;
98 };
99 
100 int	qcgpio_acpi_match(struct device *, void *, void *);
101 void	qcgpio_acpi_attach(struct device *, struct device *, void *);
102 
103 const struct cfattach qcgpio_acpi_ca = {
104 	sizeof(struct qcgpio_softc), qcgpio_acpi_match, qcgpio_acpi_attach
105 };
106 
107 struct cfdriver qcgpio_cd = {
108 	NULL, "qcgpio", DV_DULL
109 };
110 
111 const char *qcgpio_hids[] = {
112 	"QCOM060C",
113 	"QCOM080D",
114 	"QCOM0C0C",
115 	NULL
116 };
117 
118 /* 98b9b2a4-1663-4a5f-82f2-c6c99a394726 */
119 static uint8_t qcgpio_gpio_dsm_uuid[] = {
120 	0xa4, 0xb2, 0xb9, 0x98, 0x63, 0x16, 0x5f, 0x4a,
121 	0x82, 0xf2, 0xc6, 0xc9, 0x9a, 0x39, 0x47, 0x26
122 };
123 #define QCGPIO_GPIO_DSM_REV		0
124 #define QCGPIO_GPIO_DSM_FUNC_NUM_PINS	2
125 
126 /* 921b0fd4-567c-43a0-bb14-2648f7b2a18c */
127 static uint8_t qcgpio_pdc_dsm_uuid[] = {
128 	0xd4, 0x0f, 0x1b, 0x92, 0x7c, 0x56, 0xa0, 0x43,
129 	0xbb, 0x14, 0x26, 0x48, 0xf7, 0xb2, 0xa1, 0x8c
130 };
131 #define QCGPIO_PDC_DSM_REV		0
132 #define QCGPIO_PDC_DSM_FUNC_CIPR	2
133 
134 int	qcgpio_get_nirq(int, union acpi_resource *, void *);
135 int	qcgpio_get_irqs(int, union acpi_resource *, void *);
136 void	qcgpio_fill_pdcmap(struct qcgpio_softc *);
137 int	qcgpio_get_pin_count(struct acpi_softc *, struct aml_node *);
138 int	qcgpio_sc7180_pin_map(struct qcgpio_softc *, int, bus_size_t *);
139 int	qcgpio_sc8280xp_pin_map(struct qcgpio_softc *, int, bus_size_t *);
140 int	qcgpio_x1e80100_pin_map(struct qcgpio_softc *, int, bus_size_t *);
141 
142 int	qcgpio_read_pin(void *, int);
143 void	qcgpio_write_pin(void *, int, int);
144 void	qcgpio_intr_establish(void *, int, int, int (*)(void *), void *);
145 void	qcgpio_intr_enable(void *, int);
146 void	qcgpio_intr_disable(void *, int);
147 int	qcgpio_intr(void *);
148 
149 int
150 qcgpio_get_nirq(int crsidx, union acpi_resource *crs, void *arg)
151 {
152 	struct qcgpio_softc *sc = arg;
153 	int typ;
154 
155 	typ = AML_CRSTYPE(crs);
156 
157 	switch (typ) {
158 	case LR_EXTIRQ:
159 		sc->sc_npdcmap++;
160 		break;
161 	}
162 
163 	return 0;
164 }
165 
166 int
167 qcgpio_get_irqs(int crsidx, union acpi_resource *crs, void *arg)
168 {
169 	struct qcgpio_softc *sc = arg;
170 	int typ;
171 
172 	typ = AML_CRSTYPE(crs);
173 
174 	switch (typ) {
175 	case LR_EXTIRQ:
176 		sc->sc_pdcmap[sc->sc_ipdcmap].pm_irq = crs->lr_extirq.irq[0];
177 		sc->sc_pdcmap[sc->sc_ipdcmap].pm_pin = -1;
178 		DPRINTF(1, "%s: irq index %d: irq %d\n",
179 		    __func__, sc->sc_ipdcmap,
180 		    sc->sc_pdcmap[sc->sc_ipdcmap].pm_irq);
181 		sc->sc_ipdcmap++;
182 		break;
183 	}
184 
185 	return 0;
186 }
187 
188 void
189 qcgpio_fill_pdcmap(struct qcgpio_softc *sc)
190 {
191 	struct aml_value cmd[4], res, *ref;
192 	int i, j, pin;
193 	uint32_t irq;
194 
195 	bzero(&cmd, sizeof(cmd));
196 	cmd[0].type = AML_OBJTYPE_BUFFER;
197 	cmd[0].v_buffer = (uint8_t *)&qcgpio_pdc_dsm_uuid;
198 	cmd[0].length = sizeof(qcgpio_pdc_dsm_uuid);
199 	/* rev */
200 	cmd[1].type = AML_OBJTYPE_INTEGER;
201 	cmd[1].v_integer = QCGPIO_PDC_DSM_REV;
202 	cmd[1].length = 1;
203 	/* func */
204 	cmd[2].type = AML_OBJTYPE_INTEGER;
205 	cmd[2].v_integer = QCGPIO_PDC_DSM_FUNC_CIPR;
206 	cmd[2].length = 1;
207 	/* not used */
208 	cmd[3].type = AML_OBJTYPE_PACKAGE;
209 	cmd[3].v_integer = 0;
210 	cmd[3].length = 0;
211 
212 	if (aml_evalname(sc->sc_acpi, sc->sc_node, "_DSM", 4, cmd, &res)) {
213 		printf("%s: PDC _DSM failed\n", __func__);
214 		return;
215 	}
216 
217 	for (i = 0; i < res.length; i++) {
218 		ref = res.v_package[i];
219 
220 		if (ref->type != AML_OBJTYPE_PACKAGE ||
221 		    ref->length < 3 ||
222 		    ref->v_package[0]->type != AML_OBJTYPE_INTEGER ||
223 		    ref->v_package[1]->type != AML_OBJTYPE_INTEGER ||
224 		    ref->v_package[2]->type != AML_OBJTYPE_INTEGER) {
225 			continue;
226 		}
227 
228 		irq = ref->v_package[2]->v_integer;
229 		pin = ref->v_package[1]->v_integer;
230 		DPRINTF(1, "%s: pdc index %d: probing irq %d, pin %d\n",
231 		    __func__, i, irq, pin);
232 
233 		for (j = 0; j < sc->sc_npdcmap; j++) {
234 			if (sc->sc_pdcmap[j].pm_irq == irq) {
235 				sc->sc_pdcmap[j].pm_pin = pin;
236 				break;
237 			}
238 		}
239 	}
240 #ifdef QCGPIO_DEBUG
241 	for (i = 0; i < sc->sc_npdcmap; i++) {
242 		printf("%s: irq index %d: irq=%d, pin=%d\n",
243 		    __func__, i, sc->sc_pdcmap[i].pm_irq,
244 		    sc->sc_pdcmap[i].pm_pin);
245 	}
246 #endif
247 }
248 
249 int
250 qcgpio_get_pin_count(struct acpi_softc *sc, struct aml_node *node)
251 {
252 	struct aml_value cmd[4];
253 	int64_t npins;
254 
255 	bzero(&cmd, sizeof(cmd));
256 	cmd[0].type = AML_OBJTYPE_BUFFER;
257 	cmd[0].v_buffer = (uint8_t *)&qcgpio_gpio_dsm_uuid;
258 	cmd[0].length = sizeof(qcgpio_gpio_dsm_uuid);
259 	/* rev */
260 	cmd[1].type = AML_OBJTYPE_INTEGER;
261 	cmd[1].v_integer = QCGPIO_GPIO_DSM_REV;
262 	cmd[1].length = 1;
263 	/* func */
264 	cmd[2].type = AML_OBJTYPE_INTEGER;
265 	cmd[2].v_integer = QCGPIO_GPIO_DSM_FUNC_NUM_PINS;
266 	cmd[2].length = 1;
267 	/* not used */
268 	cmd[3].type = AML_OBJTYPE_PACKAGE;
269 	cmd[3].v_integer = 0;
270 	cmd[3].length = 0;
271 
272 	if (aml_evalinteger(sc, node, "_DSM", 4, cmd, &npins)) {
273 		printf("%s: GPIO _DSM failed\n", __func__);
274 		return 0;
275 	}
276 
277 	return (uint32_t)npins;
278 }
279 
280 int
281 qcgpio_acpi_match(struct device *parent, void *match, void *aux)
282 {
283 	struct acpi_attach_args *aaa = aux;
284 	struct cfdata *cf = match;
285 
286 	if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1)
287 		return 0;
288 	return acpi_matchhids(aaa, qcgpio_hids, cf->cf_driver->cd_name);
289 }
290 
291 void
292 qcgpio_acpi_attach(struct device *parent, struct device *self, void *aux)
293 {
294 	struct acpi_attach_args *aaa = aux;
295 	struct qcgpio_softc *sc = (struct qcgpio_softc *)self;
296 	struct aml_value res;
297 
298 	sc->sc_acpi = (struct acpi_softc *)parent;
299 	sc->sc_node = aaa->aaa_node;
300 	printf(" %s", sc->sc_node->name);
301 
302 	printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]);
303 
304 	sc->sc_iot = aaa->aaa_bst[0];
305 	if (bus_space_map(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0],
306 	    0, &sc->sc_ioh)) {
307 		printf(": can't map registers\n");
308 		return;
309 	}
310 
311 	if (strcmp(aaa->aaa_dev, "QCOM080D") == 0) {
312 		sc->sc_npins = 119;
313 		sc->sc_pin_map = qcgpio_sc7180_pin_map;
314 	} else if (strcmp(aaa->aaa_dev, "QCOM060C") == 0) {
315 		sc->sc_npins = 228;
316 		sc->sc_pin_map = qcgpio_sc8280xp_pin_map;
317 	} else if (strcmp(aaa->aaa_dev, "QCOM0C0C") == 0) {
318 		if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL,
319 		    &res)) {
320 			printf("no _CRS method\n");
321 			return;
322 		}
323 		if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
324 			printf("invalid _CRS object\n");
325 			aml_freevalue(&res);
326 			return;
327 		}
328 		aml_parse_resource(&res, qcgpio_get_nirq, sc);
329 		DPRINTF(1, "\n%s: npdcmap=%d\n", __func__, sc->sc_npdcmap);
330 		sc->sc_pdcmap = mallocarray(sc->sc_npdcmap,
331 		    sizeof(*sc->sc_pdcmap), M_DEVBUF, M_WAITOK | M_ZERO);
332 		aml_parse_resource(&res, qcgpio_get_irqs, sc);
333 		aml_freevalue(&res);
334 		qcgpio_fill_pdcmap(sc);
335 		sc->sc_npins = qcgpio_get_pin_count(sc->sc_acpi, sc->sc_node);
336 		DPRINTF(1, "%s: npins=%d\n", __func__, sc->sc_npins);
337 		sc->sc_pin_map = qcgpio_x1e80100_pin_map;
338 	}
339 	KASSERT(sc->sc_npins != 0);
340 
341 	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
342 	    M_DEVBUF, M_WAITOK | M_ZERO);
343 
344 	printf(" irq %d", aaa->aaa_irq[0]);
345 
346 	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0],
347 	    aaa->aaa_irq_flags[0], IPL_BIO, qcgpio_intr,
348 	    sc, sc->sc_dev.dv_xname);
349 	if (sc->sc_ih == NULL) {
350 		printf(": can't establish interrupt\n");
351 		goto unmap;
352 	}
353 
354 	sc->sc_gpio.cookie = sc;
355 	sc->sc_gpio.read_pin = qcgpio_read_pin;
356 	sc->sc_gpio.write_pin = qcgpio_write_pin;
357 	sc->sc_gpio.intr_establish = qcgpio_intr_establish;
358 	sc->sc_gpio.intr_enable = qcgpio_intr_enable;
359 	sc->sc_gpio.intr_disable = qcgpio_intr_disable;
360 	sc->sc_node->gpio = &sc->sc_gpio;
361 
362 	printf("\n");
363 
364 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
365 	return;
366 
367 unmap:
368 	if (sc->sc_ih)
369 		acpi_intr_disestablish(sc->sc_ih);
370 	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
371 	free(sc->sc_pdcmap, M_DEVBUF, sc->sc_npdcmap * sizeof(*sc->sc_pdcmap));
372 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, aaa->aaa_size[0]);
373 }
374 
375 int
376 qcgpio_sc7180_pin_map(struct qcgpio_softc *sc, int pin, bus_size_t *off)
377 {
378 	switch (pin) {
379 	case 30:
380 		*off = QCGPIO_SC7180_SOUTH;
381 		return 30;
382 #if 0
383 	/* XXX: Disable until we can fix the interrupt storm. */
384 	case 32:
385 	case 0x140:
386 		*off = QCGPIO_SC7180_NORTH;
387 		return 32;
388 #endif
389 	case 33:
390 	case 0x180:
391 		*off = QCGPIO_SC7180_NORTH;
392 		return 33;
393 	case 94:
394 	case 0x1c0:
395 		*off = QCGPIO_SC7180_SOUTH;
396 		return 94;
397 	default:
398 		return -1;
399 	}
400 }
401 
402 int
403 qcgpio_sc8280xp_pin_map(struct qcgpio_softc *sc, int pin, bus_size_t *off)
404 {
405 	switch (pin) {
406 	case 107:
407 	case 175:
408 		return pin;
409 	case 0x2c0:
410 		return 107;
411 	case 0x340:
412 		return 104;
413 	case 0x380:
414 		return 182;
415 	default:
416 		return -1;
417 	}
418 }
419 
420 int
421 qcgpio_x1e80100_pin_map(struct qcgpio_softc *sc, int pin, bus_size_t *off)
422 {
423 	int real_pin = -1;
424 
425 	if (pin < sc->sc_npins) {
426 		real_pin = pin;
427 	} else if (pin / 64 < sc->sc_npdcmap) {
428 		real_pin = sc->sc_pdcmap[pin / 64].pm_pin;
429 	}
430 
431 	DPRINTF(2, "%s: map pin %d to real_pin %d\n", __func__, pin, real_pin);
432 
433 	return real_pin;
434 }
435 
436 int
437 qcgpio_read_pin(void *cookie, int pin)
438 {
439 	struct qcgpio_softc *sc = cookie;
440 	bus_size_t off = 0;
441 	uint32_t reg;
442 
443 	pin = sc->sc_pin_map(sc, pin, &off);
444 	if (pin < 0 || pin >= sc->sc_npins)
445 		return 0;
446 
447 	reg = HREAD4(sc, off + TLMM_GPIO_IN_OUT(pin));
448 	return !!(reg & TLMM_GPIO_IN_OUT_GPIO_IN);
449 }
450 
451 void
452 qcgpio_write_pin(void *cookie, int pin, int val)
453 {
454 	struct qcgpio_softc *sc = cookie;
455 	bus_size_t off = 0;
456 
457 	pin = sc->sc_pin_map(sc, pin, &off);
458 	if (pin < 0 || pin >= sc->sc_npins)
459 		return;
460 
461 	if (val) {
462 		HSET4(sc, off + TLMM_GPIO_IN_OUT(pin),
463 		    TLMM_GPIO_IN_OUT_GPIO_OUT);
464 	} else {
465 		HCLR4(sc, off + TLMM_GPIO_IN_OUT(pin),
466 		    TLMM_GPIO_IN_OUT_GPIO_OUT);
467 	}
468 }
469 
470 void
471 qcgpio_intr_establish(void *cookie, int pin, int flags,
472     int (*func)(void *), void *arg)
473 {
474 	struct qcgpio_softc *sc = cookie;
475 	bus_size_t off = 0;
476 	uint32_t reg;
477 
478 	pin = sc->sc_pin_map(sc, pin, &off);
479 	if (pin < 0 || pin >= sc->sc_npins)
480 		return;
481 
482 	sc->sc_pin_ih[pin].ih_func = func;
483 	sc->sc_pin_ih[pin].ih_arg = arg;
484 
485 	reg = HREAD4(sc, off + TLMM_GPIO_INTR_CFG(pin));
486 	reg &= ~TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_MASK;
487 	reg &= ~TLMM_GPIO_INTR_CFG_INTR_POL_CTL;
488 	switch (flags & (LR_GPIO_MODE | LR_GPIO_POLARITY)) {
489 	case LR_GPIO_LEVEL | LR_GPIO_ACTLO:
490 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL;
491 		break;
492 	case LR_GPIO_LEVEL | LR_GPIO_ACTHI:
493 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL |
494 		    TLMM_GPIO_INTR_CFG_INTR_POL_CTL;
495 		break;
496 	case LR_GPIO_EDGE | LR_GPIO_ACTLO:
497 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_NEG |
498 		    TLMM_GPIO_INTR_CFG_INTR_POL_CTL;
499 		break;
500 	case LR_GPIO_EDGE | LR_GPIO_ACTHI:
501 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_POS |
502 		    TLMM_GPIO_INTR_CFG_INTR_POL_CTL;
503 		break;
504 	case LR_GPIO_EDGE | LR_GPIO_ACTBOTH:
505 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_BOTH;
506 		break;
507 	default:
508 		printf("%s: unsupported interrupt mode/polarity\n",
509 		    sc->sc_dev.dv_xname);
510 		break;
511 	}
512 	reg &= ~TLMM_GPIO_INTR_CFG_TARGET_PROC_MASK;
513 	reg |= TLMM_GPIO_INTR_CFG_TARGET_PROC_RPM;
514 	reg |= TLMM_GPIO_INTR_CFG_INTR_RAW_STATUS_EN;
515 	reg |= TLMM_GPIO_INTR_CFG_INTR_ENABLE;
516 	HWRITE4(sc, off + TLMM_GPIO_INTR_CFG(pin), reg);
517 }
518 
519 void
520 qcgpio_intr_enable(void *cookie, int pin)
521 {
522 	struct qcgpio_softc *sc = cookie;
523 	bus_size_t off = 0;
524 
525 	pin = sc->sc_pin_map(sc, pin, &off);
526 	if (pin < 0 || pin >= sc->sc_npins)
527 		return;
528 
529 	HSET4(sc, off + TLMM_GPIO_INTR_CFG(pin),
530 	    TLMM_GPIO_INTR_CFG_INTR_ENABLE);
531 }
532 
533 void
534 qcgpio_intr_disable(void *cookie, int pin)
535 {
536 	struct qcgpio_softc *sc = cookie;
537 	bus_size_t off = 0;
538 
539 	pin = sc->sc_pin_map(sc, pin, &off);
540 	if (pin < 0 || pin >= sc->sc_npins)
541 		return;
542 
543 	HCLR4(sc, off + TLMM_GPIO_INTR_CFG(pin),
544 	    TLMM_GPIO_INTR_CFG_INTR_ENABLE);
545 }
546 
547 int
548 qcgpio_intr(void *arg)
549 {
550 	struct qcgpio_softc *sc = arg;
551 	int pin, handled = 0;
552 	bus_size_t off = 0;
553 	uint32_t stat;
554 
555 	for (pin = 0; pin < sc->sc_npins; pin++) {
556 		if (sc->sc_pin_ih[pin].ih_func == NULL)
557 			continue;
558 
559 		sc->sc_pin_map(sc, pin, &off);
560 
561 		stat = HREAD4(sc, off + TLMM_GPIO_INTR_STATUS(pin));
562 		if (stat & TLMM_GPIO_INTR_STATUS_INTR_STATUS) {
563 			sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
564 			HWRITE4(sc, off + TLMM_GPIO_INTR_STATUS(pin),
565 			    stat & ~TLMM_GPIO_INTR_STATUS_INTR_STATUS);
566 			handled = 1;
567 		}
568 	}
569 
570 	return handled;
571 }
572