1 /* $NetBSD: vrc4172gpio.c,v 1.12 2007/12/15 00:39:18 perry Exp $ */ 2 /*- 3 * Copyright (c) 2001 TAKEMRUA Shin. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the project nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: vrc4172gpio.c,v 1.12 2007/12/15 00:39:18 perry Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/device.h> 37 #include <sys/malloc.h> 38 #include <sys/queue.h> 39 #include <sys/reboot.h> 40 #include <machine/bus.h> 41 #include <machine/platid.h> 42 #include <machine/platid_mask.h> 43 44 #include <dev/hpc/hpciovar.h> 45 46 #include <hpcmips/vr/vripif.h> 47 #include <hpcmips/vr/vripvar.h> 48 #include <hpcmips/vr/vrc4172gpioreg.h> 49 50 #include "locators.h" 51 52 #define VRC2GPIODEBUG 53 #ifdef VRC2GPIODEBUG 54 #define DBG_IO (1<<0) 55 #define DBG_INTR (1<<1) 56 #define DBG_INFO (1<<2) 57 #ifndef VRC2GPIODEBUG_CONF 58 #define VRC2GPIODEBUG_CONF 0 59 #endif /* VRC2GPIODEBUG_CONF */ 60 int vrc4172gpio_debug = VRC2GPIODEBUG_CONF; 61 #define DBG(flag) (vrc4172gpio_debug & (flag)) 62 #define DPRINTF(flag, arg...) do { \ 63 if (DBG(flag)) \ 64 printf(arg); \ 65 } while (0) 66 #else 67 #define DBG(flag) (0) 68 #define DPRINTF(flag, arg...) do {} while(0) 69 #endif 70 #define VPRINTF(arg...) do { \ 71 if (bootverbose) \ 72 printf(##arg); \ 73 } while (0) 74 75 #define CHECK_PORT(x) (0 <= (x) && (x) < VRC2_EXGP_NPORTS) 76 77 struct vrc4172gpio_intr_entry { 78 int ih_port; 79 int (*ih_fun)(void*); 80 void *ih_arg; 81 TAILQ_ENTRY(vrc4172gpio_intr_entry) ih_link; 82 }; 83 84 struct vrc4172gpio_softc { 85 struct device sc_dev; 86 bus_space_tag_t sc_iot; 87 bus_space_handle_t sc_ioh; 88 struct hpcio_attach_args sc_args; 89 struct hpcio_chip *sc_hc; 90 91 void *sc_intr_handle; 92 u_int32_t sc_intr_mask; 93 u_int32_t sc_data; 94 u_int32_t sc_intr_mode[VRC2_EXGP_NPORTS]; 95 TAILQ_HEAD(, vrc4172gpio_intr_entry) sc_intr_head[VRC2_EXGP_NPORTS]; 96 struct hpcio_chip sc_iochip; 97 struct hpcio_attach_args sc_haa; 98 }; 99 100 int vrc4172gpio_match(struct device*, struct cfdata*, void*); 101 void vrc4172gpio_attach(struct device*, struct device*, void*); 102 void vrc4172gpio_callback(struct device *self); 103 int vrc4172gpio_intr(void*); 104 int vrc4172gpio_print(void*, const char*); 105 106 int vrc4172gpio_port_read(hpcio_chip_t, int); 107 void vrc4172gpio_port_write(hpcio_chip_t, int, int); 108 void *vrc4172gpio_intr_establish(hpcio_chip_t, int, int, int (*)(void *), void*); 109 void vrc4172gpio_intr_disestablish(hpcio_chip_t, void*); 110 void vrc4172gpio_intr_clear(hpcio_chip_t, void*); 111 void vrc4172gpio_register_iochip(hpcio_chip_t, hpcio_chip_t); 112 void vrc4172gpio_update(hpcio_chip_t); 113 void vrc4172gpio_dump(hpcio_chip_t); 114 void vrc4172gpio_intr_dump(struct vrc4172gpio_softc *, int); 115 hpcio_chip_t vrc4172gpio_getchip(void*, int); 116 static void vrc4172gpio_diffport(struct vrc4172gpio_softc *sc); 117 118 static u_int16_t read_2(struct vrc4172gpio_softc *, bus_addr_t); 119 static void write_2(struct vrc4172gpio_softc *, bus_addr_t, u_int16_t); 120 static u_int32_t read_4(struct vrc4172gpio_softc *, bus_addr_t); 121 static void write_4(struct vrc4172gpio_softc *, bus_addr_t, u_int32_t); 122 static void dumpbits(u_int32_t*, int, int, int, const char[2]); 123 124 static struct hpcio_chip vrc4172gpio_iochip = { 125 .hc_portread = vrc4172gpio_port_read, 126 .hc_portwrite = vrc4172gpio_port_write, 127 .hc_intr_establish = vrc4172gpio_intr_establish, 128 .hc_intr_disestablish = vrc4172gpio_intr_disestablish, 129 .hc_intr_clear = vrc4172gpio_intr_clear, 130 .hc_register_iochip = vrc4172gpio_register_iochip, 131 .hc_update = vrc4172gpio_update, 132 .hc_dump = vrc4172gpio_dump, 133 }; 134 135 static int intlv_regs[] = { 136 VRC2_EXGPINTLV0L, 137 VRC2_EXGPINTLV0H, 138 VRC2_EXGPINTLV1L 139 }; 140 141 CFATTACH_DECL(vrc4172gpio, sizeof(struct vrc4172gpio_softc), 142 vrc4172gpio_match, vrc4172gpio_attach, NULL, NULL); 143 144 /* 145 * regster access method 146 */ 147 static inline u_int16_t 148 read_2(struct vrc4172gpio_softc *sc, bus_addr_t off) 149 { 150 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, off); 151 } 152 153 static inline void 154 write_2(struct vrc4172gpio_softc *sc, bus_addr_t off, u_int16_t data) 155 { 156 bus_space_write_2(sc->sc_iot, sc->sc_ioh, off, data); 157 } 158 159 static u_int32_t 160 read_4(struct vrc4172gpio_softc *sc, bus_addr_t off) 161 { 162 u_int16_t reg0, reg1; 163 164 reg0 = read_2(sc, off); 165 reg1 = read_2(sc, off + VRC2_EXGP_OFFSET); 166 167 return (reg0|(reg1<<16)); 168 } 169 170 static void 171 write_4(struct vrc4172gpio_softc *sc, bus_addr_t off, u_int32_t data) 172 { 173 write_2(sc, off, data & 0xffff); 174 write_2(sc, off + VRC2_EXGP_OFFSET, (data>>16)&0xffff); 175 } 176 177 int 178 vrc4172gpio_match(struct device *parent, struct cfdata *cf, void *aux) 179 { 180 struct hpcio_attach_args *haa = aux; 181 platid_mask_t mask; 182 183 if (strcmp(haa->haa_busname, HPCIO_BUSNAME)) 184 return (0); 185 if (cf->cf_loc[HPCIOIFCF_PLATFORM] == 0) 186 return (0); 187 mask = PLATID_DEREF(cf->cf_loc[HPCIOIFCF_PLATFORM]); 188 189 return platid_match(&platid, &mask); 190 } 191 192 void 193 vrc4172gpio_attach(struct device *parent, struct device *self, void *aux) 194 { 195 struct hpcio_attach_args *args = aux; 196 struct vrc4172gpio_softc *sc = (void*)self; 197 int i, *loc, port, mode; 198 u_int32_t regs[6], t0, t1, t2; 199 200 printf("\n"); 201 loc = device_cfdata(&sc->sc_dev)->cf_loc; 202 203 /* 204 * map bus space 205 */ 206 sc->sc_iot = args->haa_iot; 207 sc->sc_hc = (*args->haa_getchip)(args->haa_sc, loc[HPCIOIFCF_IOCHIP]); 208 sc->sc_args = *args; /* structure copy */ 209 bus_space_map(sc->sc_iot, loc[HPCIOIFCF_ADDR], loc[HPCIOIFCF_SIZE], 210 0 /* no cache */, &sc->sc_ioh); 211 if (sc->sc_ioh == 0) { 212 printf("%s: can't map bus space\n", sc->sc_dev.dv_xname); 213 return; 214 } 215 216 /* 217 * dump Windows CE register setting 218 */ 219 regs[0] = read_4(sc, VRC2_EXGPDATA); 220 regs[1] = read_4(sc, VRC2_EXGPDIR); 221 regs[2] = read_4(sc, VRC2_EXGPINTEN); 222 regs[3] = read_4(sc, VRC2_EXGPINTTYP); 223 t0 = read_2(sc, VRC2_EXGPINTLV0L); 224 t1 = read_2(sc, VRC2_EXGPINTLV0H); 225 t2 = read_2(sc, VRC2_EXGPINTLV1L); 226 regs[4] = ((t2&0xff00)<<8) | (t1&0xff00) | ((t0&0xff00)>>8); 227 regs[5] = ((t2&0xff)<<16) | ((t1&0xff)<<8) | (t0&0xff); 228 229 if (bootverbose || DBG(DBG_INFO)) { 230 /* 231 * o: output 232 * i: input (no interrupt) 233 * H: level sense interrupt (active high) 234 * L: level sense interrupt (active low) 235 * B: both edge trigger interrupt 236 * P: positive edge trigger interrupt 237 * N: negative edge trigger interrupt 238 */ 239 printf(" port#:321098765432109876543210\n"); 240 printf(" EXGPDATA :"); 241 dumpbits(®s[0], 1, 23, 0, "10\n"); 242 printf("WIN setting:"); 243 dumpbits(®s[1], 5, 23, 0, 244 "oooo" /* dir=1 en=1 typ=1 */ 245 "oooo" /* dir=1 en=1 typ=0 */ 246 "oooo" /* dir=1 en=0 typ=1 */ 247 "oooo" /* dir=1 en=0 typ=0 */ 248 "BBPN" /* dir=0 en=1 typ=1 */ 249 "HLHL" /* dir=0 en=1 typ=0 */ 250 "iiii" /* dir=0 en=0 typ=1 */ 251 "iiii" /* dir=0 en=0 typ=0 */ 252 ); 253 printf("\n"); 254 } 255 #ifdef VRC2GPIODEBUG 256 if (DBG(DBG_INFO)) { 257 printf(" EXGPDIR :"); 258 dumpbits(®s[1], 1, 23, 0, "oi\n"); 259 260 printf(" EXGPINTEN :"); 261 dumpbits(®s[2], 1, 23, 0, "I-\n"); 262 263 printf(" EXGPINTTYP:"); 264 dumpbits(®s[3], 1, 23, 0, "EL\n"); 265 266 printf(" EXPIB :"); 267 dumpbits(®s[4], 1, 23, 0, "10\n"); 268 269 printf(" EXPIL :"); 270 dumpbits(®s[5], 1, 23, 0, "10\n"); 271 272 printf(" EXGPINTLV :%04x %04x %04x\n", t2, t1, t0); 273 } 274 #endif /* VRC2GPIODEBUG */ 275 276 /* 277 * initialize register and internal data 278 */ 279 sc->sc_intr_mask = 0; 280 write_2(sc, VRC2_EXGPINTEN, sc->sc_intr_mask); 281 for (i = 0; i < VRC2_EXGP_NPORTS; i++) 282 TAILQ_INIT(&sc->sc_intr_head[i]); 283 sc->sc_data = read_4(sc, VRC2_EXGPDATA); 284 if (bootverbose || DBG(DBG_INFO)) { 285 u_int32_t data; 286 287 sc->sc_intr_mask = (~read_4(sc, VRC2_EXGPDIR) & 0xffffff); 288 write_4(sc, VRC2_EXGPINTTYP, 0); /* level sence interrupt */ 289 data = ~read_4(sc, VRC2_EXGPDATA); 290 write_2(sc, VRC2_EXGPINTLV0L, (data >> 0) & 0xff); 291 write_2(sc, VRC2_EXGPINTLV0H, (data >> 8) & 0xff); 292 write_2(sc, VRC2_EXGPINTLV1L, (data >> 16) & 0xff); 293 } 294 295 /* 296 * install interrupt handler 297 */ 298 port = loc[HPCIOIFCF_PORT]; 299 mode = HPCIO_INTR_LEVEL | HPCIO_INTR_HIGH; 300 sc->sc_intr_handle = 301 hpcio_intr_establish(sc->sc_hc, port, mode, vrc4172gpio_intr, sc); 302 if (sc->sc_intr_handle == NULL) { 303 printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname); 304 return; 305 } 306 307 /* 308 * fill hpcio_chip structure 309 */ 310 sc->sc_iochip = vrc4172gpio_iochip; /* structure copy */ 311 sc->sc_iochip.hc_chipid = VRIP_IOCHIP_VRC4172GPIO; 312 sc->sc_iochip.hc_name = sc->sc_dev.dv_xname; 313 sc->sc_iochip.hc_sc = sc; 314 /* Register functions to upper interface */ 315 hpcio_register_iochip(sc->sc_hc, &sc->sc_iochip); 316 317 /* 318 * hpcio I/F 319 */ 320 sc->sc_haa.haa_busname = HPCIO_BUSNAME; 321 sc->sc_haa.haa_sc = sc; 322 sc->sc_haa.haa_getchip = vrc4172gpio_getchip; 323 sc->sc_haa.haa_iot = sc->sc_iot; 324 while (config_found(self, &sc->sc_haa, vrc4172gpio_print)) ; 325 /* 326 * GIU-ISA bridge 327 */ 328 #if 1 /* XXX Sometimes mounting root device failed. Why? XXX*/ 329 config_defer(self, vrc4172gpio_callback); 330 #else 331 vrc4172gpio_callback(self); 332 #endif 333 } 334 335 void 336 vrc4172gpio_callback(struct device *self) 337 { 338 struct vrc4172gpio_softc *sc = (void*)self; 339 340 sc->sc_haa.haa_busname = "vrisab"; 341 config_found(self, &sc->sc_haa, vrc4172gpio_print); 342 } 343 344 int 345 vrc4172gpio_print(void *aux, const char *pnp) 346 { 347 if (pnp) 348 return (QUIET); 349 return (UNCONF); 350 } 351 352 /* 353 * PORT 354 */ 355 int 356 vrc4172gpio_port_read(hpcio_chip_t hc, int port) 357 { 358 struct vrc4172gpio_softc *sc = hc->hc_sc; 359 int on; 360 361 if (!CHECK_PORT(port)) 362 panic("%s: illegal gpio port", __func__); 363 364 on = (read_4(sc, VRC2_EXGPDATA) & (1 << port)); 365 366 return (on ? 1 : 0); 367 } 368 369 void 370 vrc4172gpio_port_write(hpcio_chip_t hc, int port, int onoff) 371 { 372 struct vrc4172gpio_softc *sc = hc->hc_sc; 373 u_int32_t data; 374 375 if (!CHECK_PORT(port)) 376 panic("%s: illegal gpio port", __func__); 377 data = read_4(sc, VRC2_EXGPDATA); 378 if (onoff) 379 data |= (1<<port); 380 else 381 data &= ~(1<<port); 382 write_4(sc, VRC2_EXGPDATA, data); 383 } 384 385 void 386 vrc4172gpio_update(hpcio_chip_t hc) 387 { 388 } 389 390 void 391 vrc4172gpio_intr_dump(struct vrc4172gpio_softc *sc, int port) 392 { 393 u_int32_t mask, mask2; 394 int intlv_reg; 395 396 mask = (1 << port); 397 mask2 = (1 << (port % 8)); 398 intlv_reg = intlv_regs[port/8]; 399 400 if (read_4(sc, VRC2_EXGPDIR) & mask) { 401 printf(" output"); 402 return; 403 } 404 printf(" input"); 405 406 if (read_4(sc, VRC2_EXGPINTTYP) & mask) { 407 if (read_4(sc, intlv_reg) & (mask2 << 8)) { 408 printf(", both edge"); 409 } else { 410 if (read_4(sc, intlv_reg) & mask2) 411 printf(", positive edge"); 412 else 413 printf(", negative edge"); 414 } 415 } else { 416 if (read_4(sc, intlv_reg) & mask2) 417 printf(", high level"); 418 else 419 printf(", low level"); 420 } 421 } 422 423 static void 424 vrc4172gpio_diffport(struct vrc4172gpio_softc *sc) 425 { 426 u_int32_t data; 427 data = read_4(sc, VRC2_EXGPDATA); 428 if (sc->sc_data != data) { 429 printf(" port# 321098765432109876543210\n"); 430 printf("vrc4172data:"); 431 dumpbits(&data, 1, 23, 0, "10\n"); 432 /* bits which changed */ 433 data = (data & ~sc->sc_data)|(~data & sc->sc_data); 434 printf(" "); 435 dumpbits(&data, 1, 23, 0, "^ \n"); 436 sc->sc_data = data; 437 } 438 } 439 440 static void 441 dumpbits(u_int32_t *data, int ndata, int start, int end, const char *sym) 442 { 443 int i, j; 444 445 if (start <= end) 446 panic("%s(%d): %s", __FILE__, __LINE__, __func__); 447 448 for (i = start; end <= i; i--) { 449 int d = 0; 450 for (j = 0; j < ndata; j++) 451 d = (d << 1) | ((data[j] & (1 << i)) ? 1 : 0); 452 printf("%c", sym[(1 << ndata) - d - 1]); 453 454 } 455 if (sym[1<<ndata]) 456 printf("%c", sym[1<<ndata]); 457 } 458 459 void 460 vrc4172gpio_dump(hpcio_chip_t hc) 461 { 462 } 463 464 hpcio_chip_t 465 vrc4172gpio_getchip(void* scx, int chipid) 466 { 467 struct vrc4172gpio_softc *sc = scx; 468 469 return (&sc->sc_iochip); 470 } 471 472 /* 473 * Interrupt staff 474 */ 475 void * 476 vrc4172gpio_intr_establish( 477 hpcio_chip_t hc, 478 int port, /* GPIO pin # */ 479 int mode, /* GIU trigger setting */ 480 int (*ih_fun)(void*), 481 void *ih_arg) 482 { 483 struct vrc4172gpio_softc *sc = hc->hc_sc; 484 int s; 485 u_int32_t reg, mask, mask2; 486 struct vrc4172gpio_intr_entry *ih; 487 int intlv_reg; 488 489 s = splhigh(); 490 491 if (!CHECK_PORT(port)) 492 panic ("%s: bogus interrupt line", __func__); 493 if (sc->sc_intr_mode[port] && mode != sc->sc_intr_mode[port]) 494 panic ("%s: bogus interrupt type", __func__); 495 else 496 sc->sc_intr_mode[port] = mode; 497 498 mask = (1 << port); 499 mask2 = (1 << (port % 8)); 500 intlv_reg = intlv_regs[port/8]; 501 502 ih = malloc(sizeof(struct vrc4172gpio_intr_entry), M_DEVBUF, M_NOWAIT); 503 if (ih == NULL) 504 panic("%s: no memory", __func__); 505 506 ih->ih_port = port; 507 ih->ih_fun = ih_fun; 508 ih->ih_arg = ih_arg; 509 TAILQ_INSERT_TAIL(&sc->sc_intr_head[port], ih, ih_link); 510 511 #ifdef VRC2GPIODEBUG 512 if (DBG(DBG_INFO)) { 513 printf("port %2d:", port); 514 vrc4172gpio_intr_dump(sc, port); 515 printf("->"); 516 } 517 #endif 518 519 /* 520 * Setup registers 521 */ 522 /* I/O direction */ 523 reg = read_4(sc, VRC2_EXGPDIR); 524 reg &= ~mask; 525 write_4(sc, VRC2_EXGPDIR, reg); 526 527 /* interrupt triger (level/edge) */ 528 reg = read_4(sc, VRC2_EXGPINTTYP); 529 if (mode & HPCIO_INTR_EDGE) 530 reg |= mask; /* edge */ 531 else 532 reg &= ~mask; /* level */ 533 write_4(sc, VRC2_EXGPINTTYP, reg); 534 535 /* interrupt trigger option */ 536 reg = read_4(sc, intlv_reg); 537 if (mode & HPCIO_INTR_EDGE) { 538 switch (mode & (HPCIO_INTR_POSEDGE | HPCIO_INTR_NEGEDGE)) { 539 case HPCIO_INTR_POSEDGE: 540 reg &= ~(mask2 << 8); 541 reg |= mask2; 542 break; 543 case HPCIO_INTR_NEGEDGE: 544 reg &= ~(mask2 << 8); 545 reg &= ~mask2; 546 break; 547 case HPCIO_INTR_POSEDGE | HPCIO_INTR_NEGEDGE: 548 default: 549 reg |= (mask2 << 8); 550 break; 551 } 552 } else { 553 if (mode & HPCIO_INTR_HIGH) 554 reg |= mask2; /* high */ 555 else 556 reg &= ~mask2; /* low */ 557 } 558 write_4(sc, intlv_reg, reg); 559 560 #ifdef VRC2GPIODEBUG 561 if (DBG(DBG_INFO)) { 562 vrc4172gpio_intr_dump(sc, port); 563 printf("\n"); 564 } 565 #endif 566 567 /* XXX, Vrc4172 doesn't have register to set hold or through */ 568 569 /* 570 * clear interrupt status and enable interrupt 571 */ 572 vrc4172gpio_intr_clear(&sc->sc_iochip, ih); 573 sc->sc_intr_mask |= mask; 574 write_4(sc, VRC2_EXGPINTEN, sc->sc_intr_mask); 575 576 splx(s); 577 578 DPRINTF(DBG_INFO, "\n"); 579 580 return (ih); 581 } 582 583 void 584 vrc4172gpio_intr_disestablish(hpcio_chip_t hc, void *arg) 585 { 586 struct vrc4172gpio_intr_entry *ihe = arg; 587 struct vrc4172gpio_softc *sc = hc->hc_sc; 588 int port = ihe->ih_port; 589 struct vrc4172gpio_intr_entry *ih; 590 int s; 591 592 s = splhigh(); 593 TAILQ_FOREACH(ih, &sc->sc_intr_head[port], ih_link) { 594 if (ih == ihe) { 595 TAILQ_REMOVE(&sc->sc_intr_head[port], ih, ih_link); 596 free(ih, M_DEVBUF); 597 if (TAILQ_EMPTY(&sc->sc_intr_head[port])) { 598 /* disable interrupt */ 599 sc->sc_intr_mask &= ~(1<<port); 600 write_4(sc, VRC2_EXGPINTEN, 601 sc->sc_intr_mask); 602 } 603 splx(s); 604 return; 605 } 606 } 607 panic("%s: no such a handle.", __func__); 608 /* NOTREACHED */ 609 } 610 611 /* Clear interrupt */ 612 void 613 vrc4172gpio_intr_clear(hpcio_chip_t hc, void *arg) 614 { 615 struct vrc4172gpio_softc *sc = hc->hc_sc; 616 struct vrc4172gpio_intr_entry *ihe = arg; 617 618 write_4(sc, VRC2_EXGPINTST, 1 << ihe->ih_port); 619 write_4(sc, VRC2_EXGPINTST, 0); 620 } 621 622 void 623 vrc4172gpio_register_iochip(hpcio_chip_t hc, hpcio_chip_t iochip) 624 { 625 struct vrc4172gpio_softc *sc = hc->hc_sc; 626 627 hpcio_register_iochip(sc->sc_hc, iochip); 628 } 629 630 /* interrupt handler */ 631 int 632 vrc4172gpio_intr(void *arg) 633 { 634 struct vrc4172gpio_softc *sc = arg; 635 int i; 636 u_int32_t reg; 637 638 /* dispatch handler */ 639 reg = read_4(sc, VRC2_EXGPINTST); 640 DPRINTF(DBG_INTR, "%s: EXGPINTST=%06x\n", __func__, reg); 641 for (i = 0; i < VRC2_EXGP_NPORTS; i++) { 642 if (reg & (1 << i)) { 643 register struct vrc4172gpio_intr_entry *ih; 644 645 /* 646 * call interrupt handler 647 */ 648 TAILQ_FOREACH(ih, &sc->sc_intr_head[i], ih_link) { 649 ih->ih_fun(ih->ih_arg); 650 } 651 652 /* 653 * disable interrupt if no handler is installed 654 */ 655 if (TAILQ_EMPTY(&sc->sc_intr_head[i])) { 656 sc->sc_intr_mask &= ~(1 << i); 657 write_2(sc, VRC2_EXGPINTEN, sc->sc_intr_mask); 658 659 /* dump EXGPDATA bits which changed */ 660 if (bootverbose || DBG(DBG_INFO)) 661 vrc4172gpio_diffport(sc); 662 } 663 } 664 } 665 666 return (0); 667 } 668