1 /* $OpenBSD: blambert $ */ 2 /* $NetBSD: nsclpcsio_isa.c,v 1.5 2002/10/22 16:18:26 drochner Exp $ */ 3 4 /* 5 * Copyright (c) 2002 Matthias Drochner. All rights reserved. 6 * Copyright (c) 2004 Markus Friedl. All rights reserved. 7 * Copyright (c) 2004 Alexander Yurchenko. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions, and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* 32 * National Semiconductor PC87366 LPC Super I/O. 33 * Supported logical devices: GPIO, TMS, VLM. 34 */ 35 36 #include "use_gpio.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 #include <sys/kernel.h> 42 #include <sys/sensors.h> 43 #include <sys/module.h> 44 #include <sys/rman.h> 45 #include <sys/systm.h> 46 47 #include <sys/bus.h> 48 49 #include <bus/isa/isareg.h> 50 #include <bus/isa/isavar.h> 51 52 #include <dev/misc/gpio/gpio.h> 53 54 #if defined(NSC_LPC_SIO_DEBUG) 55 #define DPRINTF(x) do { kprintf x; } while (0) 56 #else 57 #define DPRINTF(x) 58 #endif 59 60 #define SIO_REG_SID 0x20 /* Super I/O ID */ 61 #define SIO_SID_PC87366 0xE9 /* PC87366 is identified by 0xE9.*/ 62 63 #define SIO_REG_SRID 0x27 /* Super I/O Revision */ 64 65 #define SIO_REG_LDN 0x07 /* Logical Device Number */ 66 #define SIO_LDN_FDC 0x00 /* Floppy Disk Controller (FDC) */ 67 #define SIO_LDN_PP 0x01 /* Parallel Port (PP) */ 68 #define SIO_LDN_SP2 0x02 /* Serial Port 2 with IR (SP2) */ 69 #define SIO_LDN_SP1 0x03 /* Serial Port 1 (SP1) */ 70 #define SIO_LDN_SWC 0x04 /* System Wake-Up Control (SWC) */ 71 #define SIO_LDN_KBCM 0x05 /* Mouse Controller (KBC) */ 72 #define SIO_LDN_KBCK 0x06 /* Keyboard Controller (KBC) */ 73 #define SIO_LDN_GPIO 0x07 /* General-Purpose I/O (GPIO) Ports */ 74 #define SIO_LDN_ACB 0x08 /* ACCESS.bus Interface (ACB) */ 75 #define SIO_LDN_FSCM 0x09 /* Fan Speed Control and Monitor (FSCM) */ 76 #define SIO_LDN_WDT 0x0A /* WATCHDOG Timer (WDT) */ 77 #define SIO_LDN_GMP 0x0B /* Game Port (GMP) */ 78 #define SIO_LDN_MIDI 0x0C /* Musical Instrument Digital Interface */ 79 #define SIO_LDN_VLM 0x0D /* Voltage Level Monitor (VLM) */ 80 #define SIO_LDN_TMS 0x0E /* Temperature Sensor (TMS) */ 81 82 #define SIO_REG_ACTIVE 0x30 /* Logical Device Activate Register */ 83 #define SIO_ACTIVE_EN 0x01 /* enabled */ 84 85 #define SIO_REG_IO_MSB 0x60 /* I/O Port Base, bits 15-8 */ 86 #define SIO_REG_IO_LSB 0x61 /* I/O Port Base, bits 7-0 */ 87 88 #define SIO_LDNUM 15 /* total number of logical devices */ 89 90 /* Supported logical devices description */ 91 static const struct { 92 const char *ld_name; 93 int ld_num; 94 int ld_iosize; 95 } sio_ld[] = { 96 { "GPIO", SIO_LDN_GPIO, 16 }, 97 { "VLM", SIO_LDN_VLM, 16 }, 98 { "TMS", SIO_LDN_TMS, 16 }, 99 }; 100 101 /* GPIO */ 102 #define SIO_GPIO_PINSEL 0xf0 103 #define SIO_GPIO_PINCFG 0xf1 104 #define SIO_GPIO_PINEV 0xf2 105 106 #define SIO_GPIO_CONF_OUTPUTEN (1 << 0) 107 #define SIO_GPIO_CONF_PUSHPULL (1 << 1) 108 #define SIO_GPIO_CONF_PULLUP (1 << 2) 109 110 #define SIO_GPDO0 0x00 111 #define SIO_GPDI0 0x01 112 #define SIO_GPEVEN0 0x02 113 #define SIO_GPEVST0 0x03 114 #define SIO_GPDO1 0x04 115 #define SIO_GPDI1 0x05 116 #define SIO_GPEVEN1 0x06 117 #define SIO_GPEVST1 0x07 118 #define SIO_GPDO2 0x08 119 #define SIO_GPDI2 0x09 120 #define SIO_GPDO3 0x0a 121 #define SIO_GPDI3 0x0b 122 123 #define SIO_GPIO_NPINS 29 124 125 /* TMS */ 126 #define SIO_TEVSTS 0x00 /* Temperature Event Status */ 127 #define SIO_TEVSMI 0x02 /* Temperature Event to SMI */ 128 #define SIO_TEVIRQ 0x04 /* Temperature Event to IRQ */ 129 #define SIO_TMSCFG 0x08 /* TMS Configuration */ 130 #define SIO_TMSBS 0x09 /* TMS Bank Select */ 131 #define SIO_TCHCFST 0x0A /* Temperature Channel Config and Status */ 132 #define SIO_RDCHT 0x0B /* Read Channel Temperature */ 133 #define SIO_CHTH 0x0C /* Channel Temperature High Limit */ 134 #define SIO_CHTL 0x0D /* Channel Temperature Low Limit */ 135 #define SIO_CHOTL 0x0E /* Channel Overtemperature Limit */ 136 137 /* VLM */ 138 #define SIO_VEVSTS0 0x00 /* Voltage Event Status 0 */ 139 #define SIO_VEVSTS1 0x01 /* Voltage Event Status 1 */ 140 #define SIO_VEVSMI0 0x02 /* Voltage Event to SMI 0 */ 141 #define SIO_VEVSMI1 0x03 /* Voltage Event to SMI 1 */ 142 #define SIO_VEVIRQ0 0x04 /* Voltage Event to IRQ 0 */ 143 #define SIO_VEVIRQ1 0x05 /* Voltage Event to IRQ 1 */ 144 #define SIO_VID 0x06 /* Voltage ID */ 145 #define SIO_VCNVR 0x07 /* Voltage Conversion Rate */ 146 #define SIO_VLMCFG 0x08 /* VLM Configuration */ 147 #define SIO_VLMBS 0x09 /* VLM Bank Select */ 148 #define SIO_VCHCFST 0x0A /* Voltage Channel Config and Status */ 149 #define SIO_RDCHV 0x0B /* Read Channel Voltage */ 150 #define SIO_CHVH 0x0C /* Channel Voltage High Limit */ 151 #define SIO_CHVL 0x0D /* Channel Voltage Low Limit */ 152 #define SIO_OTSL 0x0E /* Overtemperature Shutdown Limit */ 153 154 #define SIO_REG_SIOCF1 0x21 155 #define SIO_REG_SIOCF2 0x22 156 #define SIO_REG_SIOCF3 0x23 157 #define SIO_REG_SIOCF4 0x24 158 #define SIO_REG_SIOCF5 0x25 159 #define SIO_REG_SIOCF8 0x28 160 #define SIO_REG_SIOCFA 0x2A 161 #define SIO_REG_SIOCFB 0x2B 162 #define SIO_REG_SIOCFC 0x2C 163 #define SIO_REG_SIOCFD 0x2D 164 165 #define SIO_NUM_SENSORS (3+14) 166 #define SIO_VLM_OFF 3 167 #define SIO_VREF 1235 /* 1000.0 * VREF */ 168 169 struct nsclpcsio_softc { 170 struct device* sc_dev; 171 struct resource *sc_iores; 172 int sc_iorid; 173 bus_space_tag_t sc_iot; 174 bus_space_handle_t sc_ioh; 175 176 bus_space_handle_t sc_ld_ioh[SIO_LDNUM]; 177 int sc_ld_en[SIO_LDNUM]; 178 #if NGPIO > 0 179 /* GPIO */ 180 struct gpio sc_gpio_gc; 181 struct gpio_pin sc_gpio_pins[SIO_GPIO_NPINS]; 182 #endif 183 184 /* TMS and VLM */ 185 struct ksensor sensors[SIO_NUM_SENSORS]; 186 struct ksensordev sensordev; 187 }; 188 189 #define GPIO_READ(sc, reg) \ 190 bus_space_read_1((sc)->sc_iot, \ 191 (sc)->sc_ld_ioh[SIO_LDN_GPIO], (reg)) 192 #define GPIO_WRITE(sc, reg, val) \ 193 bus_space_write_1((sc)->sc_iot, \ 194 (sc)->sc_ld_ioh[SIO_LDN_GPIO], (reg), (val)) 195 #define TMS_WRITE(sc, reg, val) \ 196 bus_space_write_1((sc)->sc_iot, \ 197 (sc)->sc_ld_ioh[SIO_LDN_TMS], (reg), (val)) 198 #define TMS_READ(sc, reg) \ 199 bus_space_read_1((sc)->sc_iot, \ 200 (sc)->sc_ld_ioh[SIO_LDN_TMS], (reg)) 201 #define VLM_WRITE(sc, reg, val) \ 202 bus_space_write_1((sc)->sc_iot, \ 203 (sc)->sc_ld_ioh[SIO_LDN_VLM], (reg), (val)) 204 #define VLM_READ(sc, reg) \ 205 bus_space_read_1((sc)->sc_iot, \ 206 (sc)->sc_ld_ioh[SIO_LDN_VLM], (reg)) 207 208 int nsclpcsio_isa_probe(struct device *); 209 int nsclpcsio_isa_attach(struct device *); 210 211 212 static device_method_t nsclpcsio_isa_methods[] = { 213 DEVMETHOD(device_probe, nsclpcsio_isa_probe), 214 DEVMETHOD(device_attach, nsclpcsio_isa_attach), 215 { 0, 0 } 216 }; 217 218 static driver_t nsclpcsio_isa_driver = { 219 "nsclpcsio", 220 nsclpcsio_isa_methods, 221 sizeof (struct nsclpcsio_softc) 222 }; 223 224 static devclass_t nsclpcsio_devclass; 225 226 DRIVER_MODULE(nsclpcsio_isa, isa, nsclpcsio_isa_driver, nsclpcsio_devclass, NULL, NULL); 227 228 229 230 static u_int8_t nsread(bus_space_tag_t, bus_space_handle_t, int); 231 static void nswrite(bus_space_tag_t, bus_space_handle_t, int, u_int8_t); 232 233 #if NGPIO > 0 234 void nsclpcsio_gpio_init(struct nsclpcsio_softc *); 235 int nsclpcsio_gpio_pin_read(void *, int); 236 void nsclpcsio_gpio_pin_write(void *, int, int); 237 void nsclpcsio_gpio_pin_ctl(void *, int, int); 238 #endif 239 240 void nsclpcsio_tms_init(struct nsclpcsio_softc *); 241 void nsclpcsio_vlm_init(struct nsclpcsio_softc *); 242 void nsclpcsio_tms_update(struct nsclpcsio_softc *); 243 void nsclpcsio_vlm_update(struct nsclpcsio_softc *); 244 void nsclpcsio_refresh(void *); 245 246 static u_int8_t 247 nsread(bus_space_tag_t iot, bus_space_handle_t ioh, int idx) 248 { 249 bus_space_write_1(iot, ioh, 0, idx); 250 return (bus_space_read_1(iot, ioh, 1)); 251 } 252 253 static void 254 nswrite(bus_space_tag_t iot, bus_space_handle_t ioh, int idx, u_int8_t data) 255 { 256 bus_space_write_1(iot, ioh, 0, idx); 257 bus_space_write_1(iot, ioh, 1, data); 258 } 259 260 int 261 nsclpcsio_isa_probe(struct device *dev) 262 { 263 struct resource *iores; 264 int iorid = 0; 265 bus_space_tag_t iot; 266 bus_space_handle_t ioh; 267 int rv = 0; 268 269 iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid, 0ul, ~0ul, 8, RF_ACTIVE); 270 if (iores == NULL) { 271 return 1; 272 } 273 iot = rman_get_bustag(iores); 274 ioh = rman_get_bushandle(iores); 275 276 if (nsread(iot, ioh, SIO_REG_SID) == SIO_SID_PC87366) 277 rv = 1; 278 279 bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores); 280 if (rv) { 281 return 0; 282 } 283 284 return 1; 285 } 286 287 int 288 nsclpcsio_isa_attach(struct device *dev) 289 { 290 int iobase; 291 struct nsclpcsio_softc *sc = device_get_softc(dev); 292 int i; 293 294 sc->sc_dev = dev; 295 sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid, 0ul, ~0ul, 8, RF_ACTIVE); 296 if (sc->sc_iores == NULL) { 297 return 1; 298 } 299 sc->sc_iot = rman_get_bustag(sc->sc_iores); 300 sc->sc_ioh = rman_get_bushandle(sc->sc_iores); 301 302 kprintf("%s: NSC PC87366 rev %d:", device_get_nameunit(sc->sc_dev), 303 nsread(sc->sc_iot, sc->sc_ioh, SIO_REG_SRID)); 304 305 /* Configure all supported logical devices */ 306 for (i = 0; i < NELEM(sio_ld); i++) { 307 sc->sc_ld_en[sio_ld[i].ld_num] = 0; 308 309 /* Select the device and check if it's activated */ 310 nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, sio_ld[i].ld_num); 311 if ((nsread(sc->sc_iot, sc->sc_ioh, 312 SIO_REG_ACTIVE) & SIO_ACTIVE_EN) == 0) 313 continue; 314 315 /* Map I/O space if necessary */ 316 if (sio_ld[i].ld_iosize != 0) { 317 318 iobase = (nsread(sc->sc_iot, sc->sc_ioh, 319 SIO_REG_IO_MSB) << 8); 320 321 iobase |= nsread(sc->sc_iot, sc->sc_ioh, 322 SIO_REG_IO_LSB); 323 #if 0 324 /* XXX: Not elegant without alloc_resource, but works */ 325 kprintf("debugging: iobase = %x\n", iobase); 326 iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid, 327 iobase, sio_ld[i].ld_iosize, sio_ld[i].ld_iosize, RF_ACTIVE); 328 if (iores == NULL) { 329 kprintf("messed up alloc3\n"); 330 continue; 331 } 332 /* XXX: if implemented, also use the rman get handle stuff */ 333 #endif 334 sc->sc_ld_ioh[sio_ld[i].ld_num] = iobase; 335 } 336 337 sc->sc_ld_en[sio_ld[i].ld_num] = 1; 338 kprintf(" %s", sio_ld[i].ld_name); 339 } 340 341 kprintf("\n"); 342 #if NGPIO > 0 343 nsclpcsio_gpio_init(sc); 344 #endif 345 nsclpcsio_tms_init(sc); 346 nsclpcsio_vlm_init(sc); 347 348 /* Hook into hw.sensors sysctl */ 349 strlcpy(sc->sensordev.xname, device_get_nameunit(sc->sc_dev), 350 sizeof(sc->sensordev.xname)); 351 for (i = 0; i < SIO_NUM_SENSORS; i++) { 352 if (i < SIO_VLM_OFF && !sc->sc_ld_en[SIO_LDN_TMS]) 353 continue; 354 if (i >= SIO_VLM_OFF && !sc->sc_ld_en[SIO_LDN_VLM]) 355 continue; 356 sensor_attach(&sc->sensordev, &sc->sensors[i]); 357 } 358 sensordev_install(&sc->sensordev); 359 if (sc->sc_ld_en[SIO_LDN_TMS] || sc->sc_ld_en[SIO_LDN_VLM]) { 360 sensor_task_register(sc, nsclpcsio_refresh, 2); 361 } 362 363 #if NGPIO > 0 364 /* Attach GPIO framework */ 365 if (sc->sc_ld_en[SIO_LDN_GPIO]) { 366 sc->sc_gpio_gc.driver_name = "pc83766"; 367 sc->sc_gpio_gc.arg = sc; 368 sc->sc_gpio_gc.pin_read = nsclpcsio_gpio_pin_read; 369 sc->sc_gpio_gc.pin_write = nsclpcsio_gpio_pin_write; 370 sc->sc_gpio_gc.pin_ctl = nsclpcsio_gpio_pin_ctl; 371 sc->sc_gpio_gc.pins = sc->sc_gpio_pins; 372 sc->sc_gpio_gc.npins = SIO_GPIO_NPINS; 373 gpio_register(&sc->sc_gpio_gc); 374 } 375 #endif 376 377 return 0; 378 } 379 380 void 381 nsclpcsio_refresh(void *arg) 382 { 383 struct nsclpcsio_softc *sc = (struct nsclpcsio_softc *)arg; 384 385 if (sc->sc_ld_en[SIO_LDN_TMS]) 386 nsclpcsio_tms_update(sc); 387 if (sc->sc_ld_en[SIO_LDN_VLM]) 388 nsclpcsio_vlm_update(sc); 389 } 390 391 void 392 nsclpcsio_tms_init(struct nsclpcsio_softc *sc) 393 { 394 int i; 395 396 /* Initialisation, PC87366.pdf, page 208 */ 397 TMS_WRITE(sc, 0x08, 0x00); 398 TMS_WRITE(sc, 0x09, 0x0f); 399 TMS_WRITE(sc, 0x0a, 0x08); 400 TMS_WRITE(sc, 0x0b, 0x04); 401 TMS_WRITE(sc, 0x0c, 0x35); 402 TMS_WRITE(sc, 0x0d, 0x05); 403 TMS_WRITE(sc, 0x0e, 0x05); 404 405 TMS_WRITE(sc, SIO_TMSCFG, 0x00); 406 407 /* Enable the sensors */ 408 for (i = 0; i < 3; i++) { 409 TMS_WRITE(sc, SIO_TMSBS, i); 410 TMS_WRITE(sc, SIO_TCHCFST, 0x01); 411 412 sc->sensors[i].type = SENSOR_TEMP; 413 } 414 415 strlcpy(sc->sensors[0].desc, "Remote", sizeof(sc->sensors[0].desc)); 416 strlcpy(sc->sensors[1].desc, "Remote", sizeof(sc->sensors[1].desc)); 417 strlcpy(sc->sensors[2].desc, "Local", sizeof(sc->sensors[2].desc)); 418 419 nsclpcsio_tms_update(sc); 420 } 421 422 void 423 nsclpcsio_tms_update(struct nsclpcsio_softc *sc) 424 { 425 u_int8_t status; 426 int8_t sdata; 427 int i; 428 429 for (i = 0; i < 3; i++) { 430 TMS_WRITE(sc, SIO_TMSBS, i); 431 status = TMS_READ(sc, SIO_TCHCFST); 432 if (!(status & 0x01)) { 433 DPRINTF(("%s: status %d: disabled\n", 434 sc->sensors[i].desc, status)); 435 sc->sensors[i].value = 0; 436 continue; 437 } 438 sdata = TMS_READ(sc, SIO_RDCHT); 439 DPRINTF(("%s: status %d C %d\n", sc->sensors[i].desc, 440 status, sdata)); 441 sc->sensors[i].value = sdata * 1000000 + 273150000; 442 } 443 } 444 445 void 446 nsclpcsio_vlm_init(struct nsclpcsio_softc *sc) 447 { 448 int i; 449 char *desc = NULL; 450 451 VLM_WRITE(sc, SIO_VLMCFG, 0x00); 452 453 /* Enable the sensors */ 454 for (i = 0; i < 14; i++) { 455 VLM_WRITE(sc, SIO_VLMBS, i); 456 VLM_WRITE(sc, SIO_VCHCFST, 0x01); 457 458 desc = NULL; 459 switch (i) { 460 case 7: 461 desc = "VSB"; 462 break; 463 case 8: 464 desc = "VDD"; 465 break; 466 case 9: 467 desc = "VBAT"; 468 break; 469 case 10: 470 desc = "AVDD"; 471 break; 472 case 11: 473 desc = "TS1"; 474 break; 475 case 12: 476 desc = "TS2"; 477 break; 478 case 13: 479 desc = "TS3"; 480 break; 481 } 482 /* only init .desc if we have something meaningful to say */ 483 if (desc != NULL) 484 strlcpy(sc->sensors[SIO_VLM_OFF + i].desc, desc, 485 sizeof(sc->sensors[SIO_VLM_OFF + i].desc)); 486 sc->sensors[SIO_VLM_OFF + i].type = SENSOR_VOLTS_DC; 487 488 } 489 nsclpcsio_vlm_update(sc); 490 } 491 492 void 493 nsclpcsio_vlm_update(struct nsclpcsio_softc *sc) 494 { 495 u_int8_t status; 496 u_int8_t data; 497 int scale, rfact, i; 498 499 for (i = 0; i < 14; i++) { 500 VLM_WRITE(sc, SIO_VLMBS, i); 501 status = VLM_READ(sc, SIO_VCHCFST); 502 if (!(status & 0x01)) { 503 DPRINTF(("%s: status %d: disabled\n", 504 sc->sensors[SIO_VLM_OFF + i].desc, status)); 505 sc->sensors[SIO_VLM_OFF + i].value = 0; 506 continue; 507 } 508 data = VLM_READ(sc, SIO_RDCHV); 509 DPRINTF(("%s: status %d V %d\n", 510 sc->sensors[SIO_VLM_OFF + i].desc, status, data)); 511 512 scale = 1; 513 switch (i) { 514 case 7: 515 case 8: 516 case 10: 517 scale = 2; 518 } 519 520 /* Vi = (2.45�0.05)*VREF *RDCHVi / 256 */ 521 rfact = 10 * scale * ((245 * SIO_VREF) >> 8); 522 sc->sensors[SIO_VLM_OFF + i].value = data * rfact; 523 } 524 } 525 526 #if NGPIO > 0 527 static __inline void 528 nsclpcsio_gpio_pin_select(struct nsclpcsio_softc *sc, int pin) 529 { 530 int port, shift; 531 u_int8_t data; 532 533 port = pin / 8; 534 shift = pin % 8; 535 data = (port << 4) | shift; 536 537 nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_GPIO); 538 nswrite(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINSEL, data); 539 } 540 541 void 542 nsclpcsio_gpio_init(struct nsclpcsio_softc *sc) 543 { 544 int i; 545 546 for (i = 0; i < SIO_GPIO_NPINS; i++) { 547 sc->sc_gpio_pins[i].pin_num = i; 548 sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | 549 GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | 550 GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE | 551 GPIO_PIN_PULLUP; 552 553 /* Read initial state */ 554 sc->sc_gpio_pins[i].pin_state = nsclpcsio_gpio_pin_read(sc, 555 i) ? GPIO_PIN_HIGH : GPIO_PIN_LOW; 556 } 557 } 558 559 int 560 nsclpcsio_gpio_pin_read(void *arg, int pin) 561 { 562 struct nsclpcsio_softc *sc = arg; 563 int port, shift, reg; 564 u_int8_t data; 565 566 port = pin / 8; 567 shift = pin % 8; 568 569 switch (port) { 570 case 0: 571 reg = SIO_GPDI0; 572 break; 573 case 1: 574 reg = SIO_GPDI1; 575 break; 576 case 2: 577 reg = SIO_GPDI2; 578 break; 579 case 3: 580 reg = SIO_GPDI3; 581 break; 582 default: 583 return 0; 584 } 585 586 data = GPIO_READ(sc, reg); 587 588 return ((data >> shift) & 0x1); 589 } 590 591 void 592 nsclpcsio_gpio_pin_write(void *arg, int pin, int value) 593 { 594 struct nsclpcsio_softc *sc = arg; 595 int port, shift, reg; 596 u_int8_t data; 597 598 port = pin / 8; 599 shift = pin % 8; 600 601 switch (port) { 602 case 0: 603 reg = SIO_GPDO0; 604 break; 605 case 1: 606 reg = SIO_GPDO1; 607 break; 608 case 2: 609 reg = SIO_GPDO2; 610 break; 611 case 3: 612 reg = SIO_GPDO3; 613 break; 614 default: 615 return; 616 } 617 618 data = GPIO_READ(sc, reg); 619 if (value == 0) 620 data &= ~(1 << shift); 621 else if (value == 1) 622 data |= (1 << shift); 623 624 GPIO_WRITE(sc, reg, data); 625 } 626 627 void 628 nsclpcsio_gpio_pin_ctl(void *arg, int pin, int flags) 629 { 630 struct nsclpcsio_softc *sc = arg; 631 u_int8_t conf = 1; 632 633 nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_GPIO); 634 nsclpcsio_gpio_pin_select(sc, pin); 635 conf = nsread(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINCFG); 636 637 conf &= ~(SIO_GPIO_CONF_OUTPUTEN | SIO_GPIO_CONF_PUSHPULL | 638 SIO_GPIO_CONF_PULLUP); 639 if ((flags & GPIO_PIN_TRISTATE) == 0) 640 conf |= SIO_GPIO_CONF_OUTPUTEN; 641 if (flags & GPIO_PIN_PUSHPULL) 642 conf |= SIO_GPIO_CONF_PUSHPULL; 643 if (flags & GPIO_PIN_PULLUP) 644 conf |= SIO_GPIO_CONF_PULLUP; 645 646 nswrite(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINCFG, conf); 647 } 648 #endif /* NGPIO */ 649