1 /* $NetBSD: nsclpcsio_isa.c,v 1.28 2008/11/12 12:36:12 ad Exp $ */ 2 3 /* 4 * Copyright (c) 2002 5 * Matthias Drochner. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions, and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * National Semiconductor PC87366 LPC Super I/O driver. 31 * Supported logical devices: GPIO, TMS, VLM. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: nsclpcsio_isa.c,v 1.28 2008/11/12 12:36:12 ad Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 #include <sys/mutex.h> 41 #include <sys/gpio.h> 42 #include <sys/bus.h> 43 44 /* Don't use gpio for now in the module */ 45 #ifdef _MODULE 46 #undef NGPIO 47 #endif 48 49 #include <dev/isa/isareg.h> 50 #include <dev/isa/isavar.h> 51 52 #ifndef _MODULE 53 #include "gpio.h" 54 #endif 55 #if NGPIO > 0 56 #include <dev/gpio/gpiovar.h> 57 #endif 58 #include <dev/sysmon/sysmonvar.h> 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_VLM_OFF 3 166 #define SIO_NUM_SENSORS (SIO_VLM_OFF + 14) 167 #define SIO_VREF 1235 /* 1000.0 * VREF */ 168 169 struct nsclpcsio_softc { 170 device_t sc_dev; 171 172 bus_space_tag_t sc_iot; 173 bus_space_handle_t sc_ioh; 174 175 bus_space_handle_t sc_ld_ioh[SIO_LDNUM]; 176 int sc_ld_en[SIO_LDNUM]; 177 178 /* TMS and VLM */ 179 struct sysmon_envsys *sc_sme; 180 envsys_data_t sc_sensor[SIO_NUM_SENSORS]; 181 182 kmutex_t sc_lock; 183 #if NGPIO > 0 184 /* GPIO */ 185 struct gpio_chipset_tag sc_gpio_gc; 186 struct gpio_pin sc_gpio_pins[SIO_GPIO_NPINS]; 187 #endif 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 static int nsclpcsio_isa_match(device_t, cfdata_t, void *); 210 static void nsclpcsio_isa_attach(device_t, device_t, void *); 211 static int nsclpcsio_isa_detach(device_t, int); 212 213 CFATTACH_DECL_NEW(nsclpcsio_isa, sizeof(struct nsclpcsio_softc), 214 nsclpcsio_isa_match, nsclpcsio_isa_attach, nsclpcsio_isa_detach, NULL); 215 216 static uint8_t nsread(bus_space_tag_t, bus_space_handle_t, int); 217 static void nswrite(bus_space_tag_t, bus_space_handle_t, int, uint8_t); 218 static int nscheck(bus_space_tag_t, int); 219 220 static void nsclpcsio_tms_init(struct nsclpcsio_softc *); 221 static void nsclpcsio_vlm_init(struct nsclpcsio_softc *); 222 static void nsclpcsio_refresh(struct sysmon_envsys *, envsys_data_t *); 223 224 #if NGPIO > 0 225 static void nsclpcsio_gpio_init(struct nsclpcsio_softc *); 226 static void nsclpcsio_gpio_pin_select(struct nsclpcsio_softc *, int); 227 static void nsclpcsio_gpio_pin_write(void *, int, int); 228 static int nsclpcsio_gpio_pin_read(void *, int); 229 static void nsclpcsio_gpio_pin_ctl(void *, int, int); 230 #endif 231 232 static uint8_t 233 nsread(bus_space_tag_t iot, bus_space_handle_t ioh, int idx) 234 { 235 bus_space_write_1(iot, ioh, 0, idx); 236 return bus_space_read_1(iot, ioh, 1); 237 } 238 239 static void 240 nswrite(bus_space_tag_t iot, bus_space_handle_t ioh, int idx, uint8_t data) 241 { 242 bus_space_write_1(iot, ioh, 0, idx); 243 bus_space_write_1(iot, ioh, 1, data); 244 } 245 246 static int 247 nscheck(bus_space_tag_t iot, int base) 248 { 249 bus_space_handle_t ioh; 250 int rv = 0; 251 252 if (bus_space_map(iot, base, 2, 0, &ioh)) 253 return 0; 254 255 /* XXX this is for PC87366 only for now */ 256 if (nsread(iot, ioh, SIO_REG_SID) == SIO_SID_PC87366) 257 rv = 1; 258 259 bus_space_unmap(iot, ioh, 2); 260 return rv; 261 } 262 263 static int 264 nsclpcsio_isa_match(device_t parent, cfdata_t match, void *aux) 265 { 266 struct isa_attach_args *ia = aux; 267 int iobase; 268 269 if (ISA_DIRECT_CONFIG(ia)) 270 return 0; 271 272 if (ia->ia_nio > 0 && ia->ia_io[0].ir_addr != ISA_UNKNOWN_PORT) { 273 /* XXX check for legal iobase ??? */ 274 if (nscheck(ia->ia_iot, ia->ia_io[0].ir_addr)) { 275 iobase = ia->ia_io[0].ir_addr; 276 goto found; 277 } 278 return 0; 279 } 280 281 /* PC87366 has two possible locations depending on wiring */ 282 if (nscheck(ia->ia_iot, 0x2e)) { 283 iobase = 0x2e; 284 goto found; 285 } 286 if (nscheck(ia->ia_iot, 0x4e)) { 287 iobase = 0x4e; 288 goto found; 289 } 290 291 return 0; 292 293 found: 294 ia->ia_nio = 1; 295 ia->ia_io[0].ir_addr = iobase; 296 ia->ia_io[0].ir_size = 2; 297 ia->ia_niomem = 0; 298 ia->ia_nirq = 0; 299 ia->ia_ndrq = 0; 300 301 return 1; 302 } 303 304 static struct sysmon_envsys * 305 nsclpcsio_envsys_init(struct nsclpcsio_softc *sc) 306 { 307 int i; 308 struct sysmon_envsys *sme; 309 310 sme = sysmon_envsys_create(); 311 for (i = 0; i < SIO_NUM_SENSORS; i++) { 312 if (sysmon_envsys_sensor_attach(sme, &sc->sc_sensor[i]) != 0) { 313 aprint_error_dev(sc->sc_dev, 314 "could not attach sensor %d", i); 315 goto err; 316 } 317 } 318 319 /* 320 * Hook into the System Monitor. 321 */ 322 sme->sme_name = device_xname(sc->sc_dev); 323 sme->sme_cookie = sc; 324 sme->sme_refresh = nsclpcsio_refresh; 325 326 if ((i = sysmon_envsys_register(sme)) != 0) { 327 aprint_error_dev(sc->sc_dev, 328 "unable to register with sysmon (%d)\n", i); 329 goto err; 330 } 331 return sme; 332 err: 333 sysmon_envsys_destroy(sme); 334 return NULL; 335 } 336 337 static void 338 nsclpcsio_isa_attach(device_t parent, device_t self, void *aux) 339 { 340 struct nsclpcsio_softc *sc = device_private(self); 341 struct isa_attach_args *ia = aux; 342 #if NGPIO > 0 343 struct gpiobus_attach_args gba; 344 #endif 345 int i, iobase; 346 347 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 348 349 sc->sc_dev = self; 350 sc->sc_iot = ia->ia_iot; 351 iobase = ia->ia_io[0].ir_addr; 352 353 if (bus_space_map(ia->ia_iot, iobase, 2, 0, &sc->sc_ioh)) { 354 aprint_error(": can't map i/o space\n"); 355 return; 356 } 357 358 aprint_normal(": NSC PC87366 rev. 0x%d ", 359 nsread(sc->sc_iot, sc->sc_ioh, SIO_REG_SRID)); 360 361 /* Configure all supported logical devices */ 362 for (i = 0; i < __arraycount(sio_ld); i++) { 363 sc->sc_ld_en[sio_ld[i].ld_num] = 0; 364 365 /* Select the device and check if it's activated */ 366 nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, sio_ld[i].ld_num); 367 if ((nsread(sc->sc_iot, sc->sc_ioh, 368 SIO_REG_ACTIVE) & SIO_ACTIVE_EN) == 0) 369 continue; 370 371 /* Map I/O space if necessary */ 372 if (sio_ld[i].ld_iosize != 0) { 373 iobase = (nsread(sc->sc_iot, sc->sc_ioh, 374 SIO_REG_IO_MSB) << 8); 375 iobase |= nsread(sc->sc_iot, sc->sc_ioh, 376 SIO_REG_IO_LSB); 377 if (bus_space_map(sc->sc_iot, iobase, 378 sio_ld[i].ld_iosize, 0, 379 &sc->sc_ld_ioh[sio_ld[i].ld_num])) 380 continue; 381 } 382 383 sc->sc_ld_en[sio_ld[i].ld_num] = 1; 384 aprint_normal("%s ", sio_ld[i].ld_name); 385 } 386 387 aprint_normal("\n"); 388 389 #if NGPIO > 0 390 nsclpcsio_gpio_init(sc); 391 #endif 392 nsclpcsio_tms_init(sc); 393 nsclpcsio_vlm_init(sc); 394 sc->sc_sme = nsclpcsio_envsys_init(sc); 395 396 #if NGPIO > 0 397 /* attach GPIO framework */ 398 if (sc->sc_ld_en[SIO_LDN_GPIO]) { 399 gba.gba_gc = &sc->sc_gpio_gc; 400 gba.gba_pins = sc->sc_gpio_pins; 401 gba.gba_npins = SIO_GPIO_NPINS; 402 config_found_ia(self, "gpiobus", &gba, NULL); 403 } 404 #endif 405 } 406 407 static int 408 nsclpcsio_isa_detach(device_t self, int flags) 409 { 410 int i, rc; 411 struct nsclpcsio_softc *sc = device_private(self); 412 413 if ((rc = config_detach_children(self, flags)) != 0) 414 return rc; 415 416 if (sc->sc_sme != NULL) 417 sysmon_envsys_unregister(sc->sc_sme); 418 mutex_destroy(&sc->sc_lock); 419 420 for (i = 0; i < __arraycount(sio_ld); i++) { 421 if (sc->sc_ld_en[sio_ld[i].ld_num] && 422 sio_ld[i].ld_iosize != 0) { 423 bus_space_unmap(sc->sc_iot, 424 sc->sc_ld_ioh[sio_ld[i].ld_num], 425 sio_ld[i].ld_iosize); 426 } 427 } 428 429 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2); 430 431 return 0; 432 } 433 434 static void 435 nsclpcsio_tms_init(struct nsclpcsio_softc *sc) 436 { 437 int i; 438 439 /* Initialisation, PC87366.pdf, page 208 */ 440 TMS_WRITE(sc, 0x08, 0x00); 441 TMS_WRITE(sc, 0x09, 0x0f); 442 TMS_WRITE(sc, 0x0a, 0x08); 443 TMS_WRITE(sc, 0x0b, 0x04); 444 TMS_WRITE(sc, 0x0c, 0x35); 445 TMS_WRITE(sc, 0x0d, 0x05); 446 TMS_WRITE(sc, 0x0e, 0x05); 447 448 TMS_WRITE(sc, SIO_TMSCFG, 0x00); 449 450 for (i = 0; i < SIO_VLM_OFF; i++) { 451 TMS_WRITE(sc, SIO_TMSBS, i); 452 TMS_WRITE(sc, SIO_TCHCFST, 0x01); 453 sc->sc_sensor[i].units = ENVSYS_STEMP; 454 } 455 456 #define COPYDESCR(x, y) \ 457 do { \ 458 (void)strlcpy((x), (y), sizeof(x)); \ 459 } while (/* CONSTCOND */ 0) 460 461 COPYDESCR(sc->sc_sensor[0].desc, "TSENS1"); 462 COPYDESCR(sc->sc_sensor[1].desc, "TSENS2"); 463 COPYDESCR(sc->sc_sensor[2].desc, "TNSC"); 464 } 465 466 static void 467 nsclpcsio_vlm_init(struct nsclpcsio_softc *sc) 468 { 469 int i; 470 char tmp[16]; 471 envsys_data_t *sensor = &sc->sc_sensor[SIO_VLM_OFF]; 472 473 for (i = 0; i < SIO_NUM_SENSORS - SIO_VLM_OFF; i++) { 474 VLM_WRITE(sc, SIO_VLMBS, i); 475 VLM_WRITE(sc, SIO_VCHCFST, 0x01); 476 sensor[i].units = ENVSYS_SVOLTS_DC; 477 } 478 479 for (i = 0; i < 7; i++) { 480 (void)snprintf(tmp, sizeof(tmp), "VSENS%d", i); 481 COPYDESCR(sensor[i].desc, tmp); 482 } 483 484 COPYDESCR(sensor[7 ].desc, "VSB"); 485 COPYDESCR(sensor[8 ].desc, "VDD"); 486 COPYDESCR(sensor[9 ].desc, "VBAT"); 487 COPYDESCR(sensor[10].desc, "AVDD"); 488 COPYDESCR(sensor[11].desc, "TS1"); 489 COPYDESCR(sensor[12].desc, "TS2"); 490 COPYDESCR(sensor[13].desc, "TS3"); 491 } 492 493 494 static void 495 nsclpcsio_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 496 { 497 struct nsclpcsio_softc *sc = sme->sme_cookie; 498 uint8_t status, data; 499 int8_t sdata = 0; 500 int scale, rfact; 501 502 scale = rfact = 0; 503 status = data = 0; 504 505 mutex_enter(&sc->sc_lock); 506 /* TMS */ 507 if (edata->sensor < SIO_VLM_OFF && sc->sc_ld_en[SIO_LDN_TMS]) { 508 TMS_WRITE(sc, SIO_TMSBS, edata->sensor); 509 status = TMS_READ(sc, SIO_TCHCFST); 510 if (!(status & 0x01)) 511 edata->state = ENVSYS_SINVALID; 512 513 sdata = TMS_READ(sc, SIO_RDCHT); 514 edata->value_cur = sdata * 1000000 + 273150000; 515 edata->state = ENVSYS_SVALID; 516 /* VLM */ 517 } else if (edata->sensor >= SIO_VLM_OFF && 518 edata->sensor < SIO_NUM_SENSORS && 519 sc->sc_ld_en[SIO_LDN_VLM]) { 520 VLM_WRITE(sc, SIO_VLMBS, edata->sensor - SIO_VLM_OFF); 521 status = VLM_READ(sc, SIO_VCHCFST); 522 if (!(status & 0x01)) { 523 edata->state = ENVSYS_SINVALID; 524 } else { 525 data = VLM_READ(sc, SIO_RDCHV); 526 scale = 1; 527 switch (edata->sensor - SIO_VLM_OFF) { 528 case 7: 529 case 8: 530 case 10: 531 scale = 2; 532 break; 533 } 534 /* Vi = (2.45�0.05)*VREF *RDCHVi / 256 */ 535 rfact = 10 * scale * ((245 * SIO_VREF) >> 8); 536 edata->value_cur = data * rfact; 537 edata->state = ENVSYS_SVALID; 538 } 539 } 540 mutex_exit(&sc->sc_lock); 541 } 542 543 #if NGPIO > 0 544 static void 545 nsclpcsio_gpio_pin_select(struct nsclpcsio_softc *sc, int pin) 546 { 547 uint8_t v; 548 549 v = ((pin / 8) << 4) | (pin % 8); 550 551 nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_GPIO); 552 nswrite(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINSEL, v); 553 } 554 555 static void 556 nsclpcsio_gpio_init(struct nsclpcsio_softc *sc) 557 { 558 int i; 559 560 for (i = 0; i < SIO_GPIO_NPINS; i++) { 561 sc->sc_gpio_pins[i].pin_num = i; 562 sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | 563 GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | 564 GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE | 565 GPIO_PIN_PULLUP; 566 /* safe defaults */ 567 sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_TRISTATE; 568 sc->sc_gpio_pins[i].pin_state = GPIO_PIN_LOW; 569 nsclpcsio_gpio_pin_ctl(sc, i, sc->sc_gpio_pins[i].pin_flags); 570 nsclpcsio_gpio_pin_write(sc, i, sc->sc_gpio_pins[i].pin_state); 571 } 572 573 /* create controller tag */ 574 sc->sc_gpio_gc.gp_cookie = sc; 575 sc->sc_gpio_gc.gp_pin_read = nsclpcsio_gpio_pin_read; 576 sc->sc_gpio_gc.gp_pin_write = nsclpcsio_gpio_pin_write; 577 sc->sc_gpio_gc.gp_pin_ctl = nsclpcsio_gpio_pin_ctl; 578 } 579 580 static int 581 nsclpcsio_gpio_pin_read(void *aux, int pin) 582 { 583 struct nsclpcsio_softc *sc = (struct nsclpcsio_softc *)aux; 584 int port, shift, reg; 585 uint8_t v; 586 587 port = pin / 8; 588 shift = pin % 8; 589 590 switch (port) { 591 case 0: 592 reg = SIO_GPDI0; 593 break; 594 case 1: 595 reg = SIO_GPDI1; 596 break; 597 case 2: 598 reg = SIO_GPDI2; 599 break; 600 case 3: 601 reg = SIO_GPDI3; 602 break; 603 default: 604 reg = SIO_GPDI0; 605 break; 606 } 607 608 v = GPIO_READ(sc, reg); 609 610 return ((v >> shift) & 0x1); 611 } 612 613 static void 614 nsclpcsio_gpio_pin_write(void *aux, int pin, int v) 615 { 616 struct nsclpcsio_softc *sc = (struct nsclpcsio_softc *)aux; 617 int port, shift, reg; 618 uint8_t d; 619 620 port = pin / 8; 621 shift = pin % 8; 622 623 switch (port) { 624 case 0: 625 reg = SIO_GPDO0; 626 break; 627 case 1: 628 reg = SIO_GPDO1; 629 break; 630 case 2: 631 reg = SIO_GPDO2; 632 break; 633 case 3: 634 reg = SIO_GPDO3; 635 break; 636 default: 637 reg = SIO_GPDO0; 638 break; /* shouldn't happen */ 639 } 640 641 d = GPIO_READ(sc, reg); 642 if (v == 0) 643 d &= ~(1 << shift); 644 else if (v == 1) 645 d |= (1 << shift); 646 GPIO_WRITE(sc, reg, d); 647 } 648 649 void 650 nsclpcsio_gpio_pin_ctl(void *aux, int pin, int flags) 651 { 652 struct nsclpcsio_softc *sc = (struct nsclpcsio_softc *)aux; 653 uint8_t conf; 654 655 mutex_enter(&sc->sc_lock); 656 657 nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_GPIO); 658 nsclpcsio_gpio_pin_select(sc, pin); 659 conf = nsread(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINCFG); 660 661 conf &= ~(SIO_GPIO_CONF_OUTPUTEN | SIO_GPIO_CONF_PUSHPULL | 662 SIO_GPIO_CONF_PULLUP); 663 if ((flags & GPIO_PIN_TRISTATE) == 0) 664 conf |= SIO_GPIO_CONF_OUTPUTEN; 665 if (flags & GPIO_PIN_PUSHPULL) 666 conf |= SIO_GPIO_CONF_PUSHPULL; 667 if (flags & GPIO_PIN_PULLUP) 668 conf |= SIO_GPIO_CONF_PULLUP; 669 670 nswrite(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINCFG, conf); 671 672 mutex_exit(&sc->sc_lock); 673 } 674 #endif /* NGPIO */ 675