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
qcgpio_get_nirq(int crsidx,union acpi_resource * crs,void * arg)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
qcgpio_get_irqs(int crsidx,union acpi_resource * crs,void * arg)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
qcgpio_fill_pdcmap(struct qcgpio_softc * sc)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
qcgpio_get_pin_count(struct acpi_softc * sc,struct aml_node * node)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
qcgpio_acpi_match(struct device * parent,void * match,void * aux)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
qcgpio_acpi_attach(struct device * parent,struct device * self,void * aux)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
qcgpio_sc7180_pin_map(struct qcgpio_softc * sc,int pin,bus_size_t * off)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
qcgpio_sc8280xp_pin_map(struct qcgpio_softc * sc,int pin,bus_size_t * off)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
qcgpio_x1e80100_pin_map(struct qcgpio_softc * sc,int pin,bus_size_t * off)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
qcgpio_read_pin(void * cookie,int pin)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
qcgpio_write_pin(void * cookie,int pin,int val)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
qcgpio_intr_establish(void * cookie,int pin,int flags,int (* func)(void *),void * arg)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
qcgpio_intr_enable(void * cookie,int pin)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
qcgpio_intr_disable(void * cookie,int pin)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
qcgpio_intr(void * arg)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