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