1/* $NetBSD: nsclpcsio_isa.c,v 1.34 2021/08/07 16:19:12 thorpej 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.34 2021/08/07 16:19:12 thorpej 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#include <sys/module.h> 44 45/* Don't use gpio for now in the module */ 46#ifdef _MODULE 47#undef NGPIO 48#endif 49 50#include <dev/isa/isareg.h> 51#include <dev/isa/isavar.h> 52 53#ifndef _MODULE 54#include "gpio.h" 55#endif 56#if NGPIO > 0 57#include <dev/gpio/gpiovar.h> 58#endif 59#include <dev/sysmon/sysmonvar.h> 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 */ 92static 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_VLM_OFF 3 167#define SIO_NUM_SENSORS (SIO_VLM_OFF + 14) 168#define SIO_VREF 1235 /* 1000.0 * VREF */ 169 170struct nsclpcsio_softc { 171 device_t sc_dev; 172 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 179 /* TMS and VLM */ 180 struct sysmon_envsys *sc_sme; 181 envsys_data_t sc_sensor[SIO_NUM_SENSORS]; 182 183 kmutex_t sc_lock; 184#if NGPIO > 0 185 /* GPIO */ 186 struct gpio_chipset_tag sc_gpio_gc; 187 struct gpio_pin sc_gpio_pins[SIO_GPIO_NPINS]; 188#endif 189}; 190 191#define GPIO_READ(sc, reg) \ 192 bus_space_read_1((sc)->sc_iot, \ 193 (sc)->sc_ld_ioh[SIO_LDN_GPIO], (reg)) 194#define GPIO_WRITE(sc, reg, val) \ 195 bus_space_write_1((sc)->sc_iot, \ 196 (sc)->sc_ld_ioh[SIO_LDN_GPIO], (reg), (val)) 197#define TMS_WRITE(sc, reg, val) \ 198 bus_space_write_1((sc)->sc_iot, \ 199 (sc)->sc_ld_ioh[SIO_LDN_TMS], (reg), (val)) 200#define TMS_READ(sc, reg) \ 201 bus_space_read_1((sc)->sc_iot, \ 202 (sc)->sc_ld_ioh[SIO_LDN_TMS], (reg)) 203#define VLM_WRITE(sc, reg, val) \ 204 bus_space_write_1((sc)->sc_iot, \ 205 (sc)->sc_ld_ioh[SIO_LDN_VLM], (reg), (val)) 206#define VLM_READ(sc, reg) \ 207 bus_space_read_1((sc)->sc_iot, \ 208 (sc)->sc_ld_ioh[SIO_LDN_VLM], (reg)) 209 210static int nsclpcsio_isa_match(device_t, cfdata_t, void *); 211static void nsclpcsio_isa_attach(device_t, device_t, void *); 212static int nsclpcsio_isa_detach(device_t, int); 213 214CFATTACH_DECL_NEW(nsclpcsio_isa, sizeof(struct nsclpcsio_softc), 215 nsclpcsio_isa_match, nsclpcsio_isa_attach, nsclpcsio_isa_detach, NULL); 216 217static uint8_t nsread(bus_space_tag_t, bus_space_handle_t, int); 218static void nswrite(bus_space_tag_t, bus_space_handle_t, int, uint8_t); 219static int nscheck(bus_space_tag_t, int); 220 221static void nsclpcsio_tms_init(struct nsclpcsio_softc *); 222static void nsclpcsio_vlm_init(struct nsclpcsio_softc *); 223static void nsclpcsio_refresh(struct sysmon_envsys *, envsys_data_t *); 224 225#if NGPIO > 0 226static void nsclpcsio_gpio_init(struct nsclpcsio_softc *); 227static void nsclpcsio_gpio_pin_select(struct nsclpcsio_softc *, int); 228static void nsclpcsio_gpio_pin_write(void *, int, int); 229static int nsclpcsio_gpio_pin_read(void *, int); 230static void nsclpcsio_gpio_pin_ctl(void *, int, int); 231#endif 232 233static uint8_t 234nsread(bus_space_tag_t iot, bus_space_handle_t ioh, int idx) 235{ 236 bus_space_write_1(iot, ioh, 0, idx); 237 return bus_space_read_1(iot, ioh, 1); 238} 239 240static void 241nswrite(bus_space_tag_t iot, bus_space_handle_t ioh, int idx, uint8_t data) 242{ 243 bus_space_write_1(iot, ioh, 0, idx); 244 bus_space_write_1(iot, ioh, 1, data); 245} 246 247static int 248nscheck(bus_space_tag_t iot, int base) 249{ 250 bus_space_handle_t ioh; 251 int rv = 0; 252 253 if (bus_space_map(iot, base, 2, 0, &ioh)) 254 return 0; 255 256 /* XXX this is for PC87366 only for now */ 257 if (nsread(iot, ioh, SIO_REG_SID) == SIO_SID_PC87366) 258 rv = 1; 259 260 bus_space_unmap(iot, ioh, 2); 261 return rv; 262} 263 264static int 265nsclpcsio_isa_match(device_t parent, cfdata_t match, void *aux) 266{ 267 struct isa_attach_args *ia = aux; 268 int iobase; 269 270 if (ISA_DIRECT_CONFIG(ia)) 271 return 0; 272 273 if (ia->ia_nio > 0 && ia->ia_io[0].ir_addr != ISA_UNKNOWN_PORT) { 274 /* XXX check for legal iobase ??? */ 275 if (nscheck(ia->ia_iot, ia->ia_io[0].ir_addr)) { 276 iobase = ia->ia_io[0].ir_addr; 277 goto found; 278 } 279 return 0; 280 } 281 282 /* PC87366 has two possible locations depending on wiring */ 283 if (nscheck(ia->ia_iot, 0x2e)) { 284 iobase = 0x2e; 285 goto found; 286 } 287 if (nscheck(ia->ia_iot, 0x4e)) { 288 iobase = 0x4e; 289 goto found; 290 } 291 292 return 0; 293 294found: 295 ia->ia_nio = 1; 296 ia->ia_io[0].ir_addr = iobase; 297 ia->ia_io[0].ir_size = 2; 298 ia->ia_niomem = 0; 299 ia->ia_nirq = 0; 300 ia->ia_ndrq = 0; 301 302 return 1; 303} 304 305static struct sysmon_envsys * 306nsclpcsio_envsys_init(struct nsclpcsio_softc *sc) 307{ 308 int i; 309 struct sysmon_envsys *sme; 310 311 sme = sysmon_envsys_create(); 312 for (i = 0; i < SIO_NUM_SENSORS; i++) { 313 sc->sc_sensor[i].state = ENVSYS_SINVALID; 314 if (sysmon_envsys_sensor_attach(sme, &sc->sc_sensor[i]) != 0) { 315 aprint_error_dev(sc->sc_dev, 316 "could not attach sensor %d", i); 317 goto err; 318 } 319 } 320 321 /* 322 * Hook into the System Monitor. 323 */ 324 sme->sme_name = device_xname(sc->sc_dev); 325 sme->sme_cookie = sc; 326 sme->sme_refresh = nsclpcsio_refresh; 327 328 if ((i = sysmon_envsys_register(sme)) != 0) { 329 aprint_error_dev(sc->sc_dev, 330 "unable to register with sysmon (%d)\n", i); 331 goto err; 332 } 333 return sme; 334err: 335 sysmon_envsys_destroy(sme); 336 return NULL; 337} 338 339static void 340nsclpcsio_isa_attach(device_t parent, device_t self, void *aux) 341{ 342 struct nsclpcsio_softc *sc = device_private(self); 343 struct isa_attach_args *ia = aux; 344#if NGPIO > 0 345 struct gpiobus_attach_args gba; 346#endif 347 int i, iobase; 348 349 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 350 351 sc->sc_dev = self; 352 sc->sc_iot = ia->ia_iot; 353 iobase = ia->ia_io[0].ir_addr; 354 355 if (bus_space_map(ia->ia_iot, iobase, 2, 0, &sc->sc_ioh)) { 356 aprint_error(": can't map i/o space\n"); 357 return; 358 } 359 360 aprint_normal(": NSC PC87366 rev. %d ", 361 nsread(sc->sc_iot, sc->sc_ioh, SIO_REG_SRID)); 362 363 /* Configure all supported logical devices */ 364 for (i = 0; i < __arraycount(sio_ld); i++) { 365 sc->sc_ld_en[sio_ld[i].ld_num] = 0; 366 367 /* Select the device and check if it's activated */ 368 nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, sio_ld[i].ld_num); 369 if ((nsread(sc->sc_iot, sc->sc_ioh, 370 SIO_REG_ACTIVE) & SIO_ACTIVE_EN) == 0) 371 continue; 372 373 /* Map I/O space if necessary */ 374 if (sio_ld[i].ld_iosize != 0) { 375 iobase = (nsread(sc->sc_iot, sc->sc_ioh, 376 SIO_REG_IO_MSB) << 8); 377 iobase |= nsread(sc->sc_iot, sc->sc_ioh, 378 SIO_REG_IO_LSB); 379 if (bus_space_map(sc->sc_iot, iobase, 380 sio_ld[i].ld_iosize, 0, 381 &sc->sc_ld_ioh[sio_ld[i].ld_num])) 382 continue; 383 } 384 385 sc->sc_ld_en[sio_ld[i].ld_num] = 1; 386 aprint_normal("%s ", sio_ld[i].ld_name); 387 } 388 389 aprint_normal("\n"); 390 391#if NGPIO > 0 392 nsclpcsio_gpio_init(sc); 393#endif 394 nsclpcsio_tms_init(sc); 395 nsclpcsio_vlm_init(sc); 396 sc->sc_sme = nsclpcsio_envsys_init(sc); 397 398#if NGPIO > 0 399 /* attach GPIO framework */ 400 if (sc->sc_ld_en[SIO_LDN_GPIO]) { 401 gba.gba_gc = &sc->sc_gpio_gc; 402 gba.gba_pins = sc->sc_gpio_pins; 403 gba.gba_npins = SIO_GPIO_NPINS; 404 config_found(self, &gba, NULL, CFARGS_NONE); 405 } 406#endif 407} 408 409static int 410nsclpcsio_isa_detach(device_t self, int flags) 411{ 412 int i, rc; 413 struct nsclpcsio_softc *sc = device_private(self); 414 415 if ((rc = config_detach_children(self, flags)) != 0) 416 return rc; 417 418 if (sc->sc_sme != NULL) 419 sysmon_envsys_unregister(sc->sc_sme); 420 mutex_destroy(&sc->sc_lock); 421 422 for (i = 0; i < __arraycount(sio_ld); i++) { 423 if (sc->sc_ld_en[sio_ld[i].ld_num] && 424 sio_ld[i].ld_iosize != 0) { 425 bus_space_unmap(sc->sc_iot, 426 sc->sc_ld_ioh[sio_ld[i].ld_num], 427 sio_ld[i].ld_iosize); 428 } 429 } 430 431 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2); 432 433 return 0; 434} 435 436static void 437nsclpcsio_tms_init(struct nsclpcsio_softc *sc) 438{ 439 int i; 440 441 /* Initialisation, PC87366.pdf, page 208 */ 442 TMS_WRITE(sc, 0x08, 0x00); 443 TMS_WRITE(sc, 0x09, 0x0f); 444 TMS_WRITE(sc, 0x0a, 0x08); 445 TMS_WRITE(sc, 0x0b, 0x04); 446 TMS_WRITE(sc, 0x0c, 0x35); 447 TMS_WRITE(sc, 0x0d, 0x05); 448 TMS_WRITE(sc, 0x0e, 0x05); 449 450 TMS_WRITE(sc, SIO_TMSCFG, 0x00); 451 452 for (i = 0; i < SIO_VLM_OFF; i++) { 453 TMS_WRITE(sc, SIO_TMSBS, i); 454 TMS_WRITE(sc, SIO_TCHCFST, 0x01); 455 sc->sc_sensor[i].units = ENVSYS_STEMP; 456 } 457 458#define COPYDESCR(x, y) \ 459 do { \ 460 (void)strlcpy((x), (y), sizeof(x)); \ 461 } while (/* CONSTCOND */ 0) 462 463 COPYDESCR(sc->sc_sensor[0].desc, "TSENS1"); 464 COPYDESCR(sc->sc_sensor[1].desc, "TSENS2"); 465 COPYDESCR(sc->sc_sensor[2].desc, "TNSC"); 466} 467 468static void 469nsclpcsio_vlm_init(struct nsclpcsio_softc *sc) 470{ 471 int i; 472 char tmp[16]; 473 envsys_data_t *sensor = &sc->sc_sensor[SIO_VLM_OFF]; 474 475 for (i = 0; i < SIO_NUM_SENSORS - SIO_VLM_OFF; i++) { 476 VLM_WRITE(sc, SIO_VLMBS, i); 477 VLM_WRITE(sc, SIO_VCHCFST, 0x01); 478 sensor[i].units = ENVSYS_SVOLTS_DC; 479 } 480 481 for (i = 0; i < 7; i++) { 482 (void)snprintf(tmp, sizeof(tmp), "VSENS%d", i); 483 COPYDESCR(sensor[i].desc, tmp); 484 } 485 486 COPYDESCR(sensor[7 ].desc, "VSB"); 487 COPYDESCR(sensor[8 ].desc, "VDD"); 488 COPYDESCR(sensor[9 ].desc, "VBAT"); 489 COPYDESCR(sensor[10].desc, "AVDD"); 490 COPYDESCR(sensor[11].desc, "TS1"); 491 COPYDESCR(sensor[12].desc, "TS2"); 492 COPYDESCR(sensor[13].desc, "TS3"); 493} 494 495 496static void 497nsclpcsio_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 498{ 499 struct nsclpcsio_softc *sc = sme->sme_cookie; 500 uint8_t status, data; 501 int8_t sdata = 0; 502 int scale, rfact; 503 504 scale = rfact = 0; 505 status = data = 0; 506 507 mutex_enter(&sc->sc_lock); 508 /* TMS */ 509 if (edata->sensor < SIO_VLM_OFF && sc->sc_ld_en[SIO_LDN_TMS]) { 510 TMS_WRITE(sc, SIO_TMSBS, edata->sensor); 511 status = TMS_READ(sc, SIO_TCHCFST); 512 if (!(status & 0x01)) 513 edata->state = ENVSYS_SINVALID; 514 515 sdata = TMS_READ(sc, SIO_RDCHT); 516 edata->value_cur = sdata * 1000000 + 273150000; 517 edata->state = ENVSYS_SVALID; 518 /* VLM */ 519 } else if (edata->sensor >= SIO_VLM_OFF && 520 edata->sensor < SIO_NUM_SENSORS && 521 sc->sc_ld_en[SIO_LDN_VLM]) { 522 VLM_WRITE(sc, SIO_VLMBS, edata->sensor - SIO_VLM_OFF); 523 status = VLM_READ(sc, SIO_VCHCFST); 524 if (!(status & 0x01)) { 525 edata->state = ENVSYS_SINVALID; 526 } else { 527 data = VLM_READ(sc, SIO_RDCHV); 528 scale = 1; 529 switch (edata->sensor - SIO_VLM_OFF) { 530 case 7: 531 case 8: 532 case 10: 533 scale = 2; 534 break; 535 } 536 /* Vi = (2.45�0.05)*VREF *RDCHVi / 256 */ 537 rfact = 10 * scale * ((245 * SIO_VREF) >> 8); 538 edata->value_cur = data * rfact; 539 edata->state = ENVSYS_SVALID; 540 } 541 } 542 mutex_exit(&sc->sc_lock); 543} 544 545#if NGPIO > 0 546static void 547nsclpcsio_gpio_pin_select(struct nsclpcsio_softc *sc, int pin) 548{ 549 uint8_t v; 550 551 v = ((pin / 8) << 4) | (pin % 8); 552 553 nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_GPIO); 554 nswrite(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINSEL, v); 555} 556 557static void 558nsclpcsio_gpio_init(struct nsclpcsio_softc *sc) 559{ 560 int i; 561 562 for (i = 0; i < SIO_GPIO_NPINS; i++) { 563 sc->sc_gpio_pins[i].pin_num = i; 564 sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | 565 GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | 566 GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE | 567 GPIO_PIN_PULLUP; 568 /* safe defaults */ 569 sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_TRISTATE; 570 sc->sc_gpio_pins[i].pin_state = GPIO_PIN_LOW; 571 nsclpcsio_gpio_pin_ctl(sc, i, sc->sc_gpio_pins[i].pin_flags); 572 nsclpcsio_gpio_pin_write(sc, i, sc->sc_gpio_pins[i].pin_state); 573 } 574 575 /* create controller tag */ 576 sc->sc_gpio_gc.gp_cookie = sc; 577 sc->sc_gpio_gc.gp_pin_read = nsclpcsio_gpio_pin_read; 578 sc->sc_gpio_gc.gp_pin_write = nsclpcsio_gpio_pin_write; 579 sc->sc_gpio_gc.gp_pin_ctl = nsclpcsio_gpio_pin_ctl; 580} 581 582static int 583nsclpcsio_gpio_pin_read(void *aux, int pin) 584{ 585 struct nsclpcsio_softc *sc = (struct nsclpcsio_softc *)aux; 586 int port, shift, reg; 587 uint8_t v; 588 589 port = pin / 8; 590 shift = pin % 8; 591 592 switch (port) { 593 case 0: 594 reg = SIO_GPDI0; 595 break; 596 case 1: 597 reg = SIO_GPDI1; 598 break; 599 case 2: 600 reg = SIO_GPDI2; 601 break; 602 case 3: 603 reg = SIO_GPDI3; 604 break; 605 default: 606 reg = SIO_GPDI0; 607 break; 608 } 609 610 v = GPIO_READ(sc, reg); 611 612 return ((v >> shift) & 0x1); 613} 614 615static void 616nsclpcsio_gpio_pin_write(void *aux, int pin, int v) 617{ 618 struct nsclpcsio_softc *sc = (struct nsclpcsio_softc *)aux; 619 int port, shift, reg; 620 uint8_t d; 621 622 port = pin / 8; 623 shift = pin % 8; 624 625 switch (port) { 626 case 0: 627 reg = SIO_GPDO0; 628 break; 629 case 1: 630 reg = SIO_GPDO1; 631 break; 632 case 2: 633 reg = SIO_GPDO2; 634 break; 635 case 3: 636 reg = SIO_GPDO3; 637 break; 638 default: 639 reg = SIO_GPDO0; 640 break; /* shouldn't happen */ 641 } 642 643 d = GPIO_READ(sc, reg); 644 if (v == 0) 645 d &= ~(1 << shift); 646 else if (v == 1) 647 d |= (1 << shift); 648 GPIO_WRITE(sc, reg, d); 649} 650 651void 652nsclpcsio_gpio_pin_ctl(void *aux, int pin, int flags) 653{ 654 struct nsclpcsio_softc *sc = (struct nsclpcsio_softc *)aux; 655 uint8_t conf; 656 657 mutex_enter(&sc->sc_lock); 658 659 nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_GPIO); 660 nsclpcsio_gpio_pin_select(sc, pin); 661 conf = nsread(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINCFG); 662 663 conf &= ~(SIO_GPIO_CONF_OUTPUTEN | SIO_GPIO_CONF_PUSHPULL | 664 SIO_GPIO_CONF_PULLUP); 665 if ((flags & GPIO_PIN_TRISTATE) == 0) 666 conf |= SIO_GPIO_CONF_OUTPUTEN; 667 if (flags & GPIO_PIN_PUSHPULL) 668 conf |= SIO_GPIO_CONF_PUSHPULL; 669 if (flags & GPIO_PIN_PULLUP) 670 conf |= SIO_GPIO_CONF_PULLUP; 671 672 nswrite(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINCFG, conf); 673 674 mutex_exit(&sc->sc_lock); 675} 676#endif /* NGPIO */ 677 678MODULE(MODULE_CLASS_DRIVER, nsclpcsio, "sysmon_envsys"); 679 680#ifdef _MODULE 681#include "ioconf.c" 682#endif 683 684static int 685nsclpcsio_modcmd(modcmd_t cmd, void *opaque) 686{ 687 switch (cmd) { 688 case MODULE_CMD_INIT: 689#ifdef _MODULE 690 return config_init_component(cfdriver_ioconf_nsclpcsio, 691 cfattach_ioconf_nsclpcsio, cfdata_ioconf_nsclpcsio); 692#else 693 return 0; 694#endif 695 case MODULE_CMD_FINI: 696#ifdef _MODULE 697 return config_fini_component(cfdriver_ioconf_nsclpcsio, 698 cfattach_ioconf_nsclpcsio, cfdata_ioconf_nsclpcsio); 699#else 700 return 0; 701#endif 702 default: 703 return ENOTTY; 704 } 705} 706