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