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