diff options
author | Alexander Yurchenko <grange@cvs.openbsd.org> | 2004-06-03 18:28:03 +0000 |
---|---|---|
committer | Alexander Yurchenko <grange@cvs.openbsd.org> | 2004-06-03 18:28:03 +0000 |
commit | 0c62644013fa42af4c90ca8da7e8e4c3e160e7c2 (patch) | |
tree | 2bd76c1ff038301c7f06496b7335d9c54ff593e1 | |
parent | 559da32aab1ceb9534a2e3843d87bf17b9c8dd07 (diff) |
Add support for the GPIO logical device.
ok deraadt@
-rw-r--r-- | sys/arch/i386/conf/GENERIC | 5 | ||||
-rw-r--r-- | sys/dev/isa/files.isa | 4 | ||||
-rw-r--r-- | sys/dev/isa/nsclpcsio_isa.c | 343 |
3 files changed, 279 insertions, 73 deletions
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index d0ac7b871df..d6b4fb0c24a 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.366 2004/06/03 18:22:21 grange Exp $ +# $OpenBSD: GENERIC,v 1.367 2004/06/03 18:28:02 grange Exp $ # # GENERIC -- everything that's currently supported # @@ -72,7 +72,8 @@ geodesc* at pci? dev ? function ? # Geode SC1100/SCx200 IAOC lm0 at isa? port 0x290 #lm1 at isa? port 0x280 #lm2 at isa? port 0x310 -nsclpcsio* at isa? # NS PC87366 hardware monitor +nsclpcsio* at isa? # NS PC87366 LPC Super I/O +gpio* at nsclpcsio? gscsio* at isa? # NS Geode SC1100 Super I/O iic0 at gscsio? # ACCESS.bus 1 iic1 at gscsio? # ACCESS.bus 2 diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa index 5858dca16c6..068afe59ee0 100644 --- a/sys/dev/isa/files.isa +++ b/sys/dev/isa/files.isa @@ -1,4 +1,4 @@ -# $OpenBSD: files.isa,v 1.87 2004/05/23 17:41:09 grange Exp $ +# $OpenBSD: files.isa,v 1.88 2004/06/03 18:28:02 grange Exp $ # $NetBSD: files.isa,v 1.21 1996/05/16 03:45:55 mycroft Exp $ # # Config file and device description for machine-independent ISA code. @@ -379,7 +379,7 @@ attach lm at isa with lm_isa file dev/isa/lm_isa.c lm_isa # NSC PC87366 Super IO / monitor chip -device nsclpcsio +device nsclpcsio: gpiobus attach nsclpcsio at isa with nsclpcsio_isa file dev/isa/nsclpcsio_isa.c nsclpcsio_isa diff --git a/sys/dev/isa/nsclpcsio_isa.c b/sys/dev/isa/nsclpcsio_isa.c index 43cd6a54ba0..0ecbb214fbb 100644 --- a/sys/dev/isa/nsclpcsio_isa.c +++ b/sys/dev/isa/nsclpcsio_isa.c @@ -1,9 +1,10 @@ -/* $OpenBSD: nsclpcsio_isa.c,v 1.2 2004/01/12 14:10:53 grange Exp $ */ +/* $OpenBSD: nsclpcsio_isa.c,v 1.3 2004/06/03 18:28:02 grange Exp $ */ /* $NetBSD: nsclpcsio_isa.c,v 1.5 2002/10/22 16:18:26 drochner Exp $ */ /* * Copyright (c) 2002 Matthias Drochner. All rights reserved. * Copyright (c) 2004 Markus Friedl. All rights reserved. + * Copyright (c) 2004 Alexander Yurchenko. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,25 +28,36 @@ * SUCH DAMAGE. */ +/* + * National Semiconductor PC87366 LPC Super I/O. + * Supported logical devices: GPIO, TMS, VLM. + */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/device.h> +#include <sys/gpio.h> #include <sys/kernel.h> #include <sys/sensors.h> #include <sys/timeout.h> + #include <machine/bus.h> #include <dev/isa/isareg.h> #include <dev/isa/isavar.h> +#include <dev/gpio/gpiovar.h> + +#include "gpio.h" + #if defined(NSC_LPC_SIO_DEBUG) #define DPRINTF(x) do { printf x; } while (0) #else #define DPRINTF(x) #endif -#define SIO_BADDR0 0x2e -#define SIO_BADDR1 0x4e +#define SIO_BADDR0 0x2e +#define SIO_BADDR1 0x4e #define SIO_REG_SID 0x20 /* Super I/O ID */ #define SIO_SID_PC87366 0xE9 /* PC87366 is identified by 0xE9.*/ @@ -70,9 +82,48 @@ #define SIO_LDN_TMS 0x0E /* Temperature Sensor (TMS) */ #define SIO_REG_ACTIVE 0x30 /* Logical Device Activate Register */ +#define SIO_ACTIVE_EN 0x01 /* enabled */ + #define SIO_REG_IO_MSB 0x60 /* I/O Port Base, bits 15-8 */ #define SIO_REG_IO_LSB 0x61 /* I/O Port Base, bits 7-0 */ +#define SIO_LDNUM 15 /* total number of logical devices */ + +/* Supported logical devices description */ +static const struct { + const char *ld_name; + int ld_num; + int ld_iosize; +} sio_ld[] = { + { "GPIO", SIO_LDN_GPIO, 16 }, + { "VLM", SIO_LDN_VLM, 16 }, + { "TMS", SIO_LDN_TMS, 16 }, +}; + +/* GPIO */ +#define SIO_GPIO_PINSEL 0xf0 +#define SIO_GPIO_PINCFG 0xf1 +#define SIO_GPIO_PINEV 0xf2 + +#define SIO_GPIO_CONF_OUTPUTEN (1 << 0) +#define SIO_GPIO_CONF_PUSHPULL (1 << 1) +#define SIO_GPIO_CONF_PULLUP (1 << 2) + +#define SIO_GPDO0 0x00 +#define SIO_GPDI0 0x01 +#define SIO_GPEVEN0 0x02 +#define SIO_GPEVST0 0x03 +#define SIO_GPDO1 0x04 +#define SIO_GPDI1 0x05 +#define SIO_GPEVEN1 0x06 +#define SIO_GPEVST1 0x07 +#define SIO_GPDO2 0x08 +#define SIO_GPDI2 0x09 +#define SIO_GPDO3 0x0a +#define SIO_GPDI3 0x0b + +#define SIO_GPIO_NPINS 29 + /* TMS */ #define SIO_TEVSTS 0x00 /* Temperature Event Status */ #define SIO_TEVSMI 0x02 /* Temperature Event to SMI */ @@ -119,21 +170,38 @@ struct nsclpcsio_softc { struct device sc_dev; - bus_space_tag_t sc_iot, sc_tms_iot, sc_vlm_iot; - bus_space_handle_t sc_ioh, sc_tms_ioh, sc_vlm_ioh; - int sc_tms, sc_vlm; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + bus_space_handle_t sc_ld_ioh[SIO_LDNUM]; + int sc_ld_en[SIO_LDNUM]; + + /* GPIO */ + struct gpio_chipset_tag sc_gpio_gc; + struct gpio_pin sc_gpio_pins[SIO_GPIO_NPINS]; + + /* TMS and VLM */ struct sensor sensors[SIO_NUM_SENSORS]; }; +#define GPIO_READ(sc, reg) \ + bus_space_read_1((sc)->sc_iot, \ + (sc)->sc_ld_ioh[SIO_LDN_GPIO], (reg)) +#define GPIO_WRITE(sc, reg, val) \ + bus_space_write_1((sc)->sc_iot, \ + (sc)->sc_ld_ioh[SIO_LDN_GPIO], (reg), (val)) #define TMS_WRITE(sc, reg, val) \ - bus_space_write_1((sc)->sc_tms_iot, (sc)->sc_tms_ioh, (reg), (val)) + bus_space_write_1((sc)->sc_iot, \ + (sc)->sc_ld_ioh[SIO_LDN_TMS], (reg), (val)) #define TMS_READ(sc, reg) \ - bus_space_read_1((sc)->sc_tms_iot, (sc)->sc_tms_ioh, (reg)) + bus_space_read_1((sc)->sc_iot, \ + (sc)->sc_ld_ioh[SIO_LDN_TMS], (reg)) #define VLM_WRITE(sc, reg, val) \ - bus_space_write_1((sc)->sc_vlm_iot, (sc)->sc_vlm_ioh, (reg), (val)) + bus_space_write_1((sc)->sc_iot, \ + (sc)->sc_ld_ioh[SIO_LDN_VLM], (reg), (val)) #define VLM_READ(sc, reg) \ - bus_space_read_1((sc)->sc_vlm_iot, (sc)->sc_vlm_ioh, (reg)) + bus_space_read_1((sc)->sc_iot, \ + (sc)->sc_ld_ioh[SIO_LDN_VLM], (reg)) int nsclpcsio_isa_match(struct device *, void *, void *); void nsclpcsio_isa_attach(struct device *, struct device *, void *); @@ -150,20 +218,24 @@ struct cfdriver nsclpcsio_cd = { struct timeout nsclpcsio_timeout; -static u_int8_t nsread(bus_space_tag_t, bus_space_handle_t, int); -static void nswrite(bus_space_tag_t, bus_space_handle_t, int, u_int8_t); -static int nscheck(bus_space_tag_t, int); +static u_int8_t nsread(bus_space_tag_t, bus_space_handle_t, int); +static void nswrite(bus_space_tag_t, bus_space_handle_t, int, u_int8_t); +static int nscheck(bus_space_tag_t, int); + +void nsclpcsio_gpio_init(struct nsclpcsio_softc *); +int nsclpcsio_gpio_pin_read(void *, int); +void nsclpcsio_gpio_pin_write(void *, int, int); +void nsclpcsio_gpio_pin_ctl(void *, int, int); -void nsclpcsio_tms_init(struct nsclpcsio_softc *); -void nsclpcsio_vlm_init(struct nsclpcsio_softc *); -void nsclpcsio_tms_update(struct nsclpcsio_softc *); -void nsclpcsio_vlm_update(struct nsclpcsio_softc *); -void nsclpcsio_refresh(void *); +void nsclpcsio_tms_init(struct nsclpcsio_softc *); +void nsclpcsio_vlm_init(struct nsclpcsio_softc *); +void nsclpcsio_tms_update(struct nsclpcsio_softc *); +void nsclpcsio_vlm_update(struct nsclpcsio_softc *); +void nsclpcsio_refresh(void *); static u_int8_t nsread(bus_space_tag_t iot, bus_space_handle_t ioh, int idx) { - bus_space_write_1(iot, ioh, 0, idx); return (bus_space_read_1(iot, ioh, 1)); } @@ -171,7 +243,6 @@ nsread(bus_space_tag_t iot, bus_space_handle_t ioh, int idx) static void nswrite(bus_space_tag_t iot, bus_space_handle_t ioh, int idx, u_int8_t data) { - bus_space_write_1(iot, ioh, 0, idx); bus_space_write_1(iot, ioh, 1, data); } @@ -216,15 +287,16 @@ found: } void -nsclpcsio_isa_attach(parent, self, aux) - struct device *parent, *self; - void *aux; +nsclpcsio_isa_attach(struct device *parent, struct device *self, void *aux) { struct nsclpcsio_softc *sc = (void *)self; struct isa_attach_args *ia = aux; bus_space_tag_t iot; int iobase; int i; +#if NGPIO > 0 + struct gpiobus_attach_args gba; +#endif iobase = ia->ipa_io[0].base; sc->sc_iot = iot = ia->ia_iot; @@ -232,27 +304,68 @@ nsclpcsio_isa_attach(parent, self, aux) printf(": can't map i/o space\n"); return; } - printf(": NSC PC87366 rev %d", + printf(": NSC PC87366 rev %d:", nsread(sc->sc_iot, sc->sc_ioh, SIO_REG_SRID)); - nsclpcsio_tms_init(sc); - nsclpcsio_vlm_init(sc); + /* Configure all supported logical devices */ + for (i = 0; i < sizeof(sio_ld) / sizeof(sio_ld[0]); i++) { + sc->sc_ld_en[sio_ld[i].ld_num] = 0; + + /* Select the device and check if it's activated */ + nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, sio_ld[i].ld_num); + if ((nsread(sc->sc_iot, sc->sc_ioh, + SIO_REG_ACTIVE) & SIO_ACTIVE_EN) == 0) + continue; + + /* Map I/O space if necessary */ + if (sio_ld[i].ld_iosize != 0) { + iobase = (nsread(sc->sc_iot, sc->sc_ioh, + SIO_REG_IO_MSB) << 8); + iobase |= nsread(sc->sc_iot, sc->sc_ioh, + SIO_REG_IO_LSB); + if (bus_space_map(sc->sc_iot, iobase, + sio_ld[i].ld_iosize, 0, + &sc->sc_ld_ioh[sio_ld[i].ld_num])) + continue; + } + + sc->sc_ld_en[sio_ld[i].ld_num] = 1; + printf(" %s", sio_ld[i].ld_name); + } printf("\n"); +#if NGPIO > 0 + nsclpcsio_gpio_init(sc); +#endif + nsclpcsio_tms_init(sc); + nsclpcsio_vlm_init(sc); + + /* Hook into hw.sensors sysctl */ for (i = 0; i < SIO_NUM_SENSORS; i++) { - if (i < SIO_VLM_OFF && !sc->sc_tms) + if (i < SIO_VLM_OFF && !sc->sc_ld_en[SIO_LDN_TMS]) continue; - if (i >= SIO_VLM_OFF && !sc->sc_vlm) + if (i >= SIO_VLM_OFF && !sc->sc_ld_en[SIO_LDN_VLM]) continue; strlcpy(sc->sensors[i].device, sc->sc_dev.dv_xname, sizeof(sc->sensors[i].device)); SENSOR_ADD(&sc->sensors[i]); } - if (sc->sc_tms || sc->sc_vlm) { + if (sc->sc_ld_en[SIO_LDN_TMS] || sc->sc_ld_en[SIO_LDN_VLM]) { timeout_set(&nsclpcsio_timeout, nsclpcsio_refresh, sc); timeout_add(&nsclpcsio_timeout, (20 * hz) / 10); } + +#if NGPIO > 0 + /* Attach GPIO framework */ + if (sc->sc_ld_en[SIO_LDN_GPIO]) { + gba.gba_name = "gpio"; + gba.gba_gc = &sc->sc_gpio_gc; + gba.gba_pins = sc->sc_gpio_pins; + gba.gba_npins = SIO_GPIO_NPINS; + config_found(&sc->sc_dev, &gba, NULL); + } +#endif } void @@ -260,9 +373,9 @@ nsclpcsio_refresh(void *arg) { struct nsclpcsio_softc *sc = (struct nsclpcsio_softc *)arg; - if (sc->sc_tms) + if (sc->sc_ld_en[SIO_LDN_TMS]) nsclpcsio_tms_update(sc); - if (sc->sc_vlm) + if (sc->sc_ld_en[SIO_LDN_VLM]) nsclpcsio_vlm_update(sc); timeout_add(&nsclpcsio_timeout, (20 * hz) / 10); } @@ -270,25 +383,7 @@ nsclpcsio_refresh(void *arg) void nsclpcsio_tms_init(struct nsclpcsio_softc *sc) { - u_int8_t val; - int iobase, i; - - sc->sc_tms = 0; - nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_TMS); - val = nsread(sc->sc_iot, sc->sc_ioh, SIO_REG_ACTIVE); - if (!(val & 1)) { - printf(", TMS disabled"); - return; - } - iobase = (nsread(sc->sc_iot, sc->sc_ioh, SIO_REG_IO_MSB) << 8); - iobase |= nsread(sc->sc_iot, sc->sc_ioh, SIO_REG_IO_LSB); - sc->sc_tms_iot = sc->sc_iot; - if (bus_space_map(sc->sc_tms_iot, iobase, 16, 0, &sc->sc_tms_ioh)) { - printf(", can't map TMS i/o space"); - return; - } - printf(", TMS at 0x%x", iobase); - sc->sc_tms = 1; + int i; /* Initialisation, PC87366.pdf, page 208 */ TMS_WRITE(sc, 0x08, 0x00); @@ -342,27 +437,9 @@ nsclpcsio_tms_update(struct nsclpcsio_softc *sc) void nsclpcsio_vlm_init(struct nsclpcsio_softc *sc) { - u_int8_t val; - int iobase, scale, i; + int scale, i; char *desc = NULL; - sc->sc_vlm = 0; - nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_VLM); - val = nsread(sc->sc_iot, sc->sc_ioh, SIO_REG_ACTIVE); - if (!(val & 1)) { - printf(", VLM disabled"); - return; - } - iobase = (nsread(sc->sc_iot, sc->sc_ioh, SIO_REG_IO_MSB) << 8); - iobase |= nsread(sc->sc_iot, sc->sc_ioh, SIO_REG_IO_LSB); - sc->sc_vlm_iot = sc->sc_iot; - if (bus_space_map(sc->sc_vlm_iot, iobase, 16, 0, &sc->sc_vlm_ioh)) { - printf(", can't map VLM i/o space"); - return; - } - printf(", VLM at 0x%x", iobase); - sc->sc_vlm = 1; - VLM_WRITE(sc, SIO_VLMCFG, 0x00); /* Enable the sensors */ @@ -436,3 +513,131 @@ nsclpcsio_vlm_update(struct nsclpcsio_softc *sc) data * sc->sensors[SIO_VLM_OFF + i].rfact; } } + +#if NGPIO > 0 +static __inline void +nsclpcsio_gpio_pin_select(struct nsclpcsio_softc *sc, int pin) +{ + int port, shift; + u_int8_t data; + + port = pin / 8; + shift = pin % 8; + data = (port << 4) | shift; + + nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_GPIO); + nswrite(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINSEL, data); +} + +void +nsclpcsio_gpio_init(struct nsclpcsio_softc *sc) +{ + int i; + + for (i = 0; i < SIO_GPIO_NPINS; i++) { + sc->sc_gpio_pins[i].pin_num = i; + sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | + GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | + GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE | + GPIO_PIN_PULLUP; + + /* safe defaults */ + sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_TRISTATE; + sc->sc_gpio_pins[i].pin_state = GPIO_PIN_LOW; + nsclpcsio_gpio_pin_ctl(sc, i, sc->sc_gpio_pins[i].pin_flags); + nsclpcsio_gpio_pin_write(sc, i, sc->sc_gpio_pins[i].pin_state); + } + + /* Create controller tag */ + sc->sc_gpio_gc.gp_cookie = sc; + sc->sc_gpio_gc.gp_pin_read = nsclpcsio_gpio_pin_read; + sc->sc_gpio_gc.gp_pin_write = nsclpcsio_gpio_pin_write; + sc->sc_gpio_gc.gp_pin_ctl = nsclpcsio_gpio_pin_ctl; +} + +int +nsclpcsio_gpio_pin_read(void *arg, int pin) +{ + struct nsclpcsio_softc *sc = arg; + int port, shift, reg; + u_int8_t data; + + port = pin / 8; + shift = pin % 8; + + switch (port) { + case 0: + reg = SIO_GPDI0; + break; + case 1: + reg = SIO_GPDI1; + break; + case 2: + reg = SIO_GPDI2; + break; + case 3: + reg = SIO_GPDI3; + break; + } + + data = GPIO_READ(sc, reg); + + return ((data >> shift) & 0x1); +} + +void +nsclpcsio_gpio_pin_write(void *arg, int pin, int value) +{ + struct nsclpcsio_softc *sc = arg; + int port, shift, reg; + u_int8_t data; + + port = pin / 8; + shift = pin % 8; + + switch (port) { + case 0: + reg = SIO_GPDO0; + break; + case 1: + reg = SIO_GPDO1; + break; + case 2: + reg = SIO_GPDO2; + break; + case 3: + reg = SIO_GPDO3; + break; + } + + data = GPIO_READ(sc, reg); + if (value == 0) + data &= ~(1 << shift); + else if (value == 1) + data |= (1 << shift); + + GPIO_WRITE(sc, reg, data); +} + +void +nsclpcsio_gpio_pin_ctl(void *arg, int pin, int flags) +{ + struct nsclpcsio_softc *sc = arg; + u_int8_t conf = 1; + + nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_GPIO); + nsclpcsio_gpio_pin_select(sc, pin); + conf = nsread(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINCFG); + + conf &= ~(SIO_GPIO_CONF_OUTPUTEN | SIO_GPIO_CONF_PUSHPULL | + SIO_GPIO_CONF_PULLUP); + if ((flags & GPIO_PIN_TRISTATE) == 0) + conf |= SIO_GPIO_CONF_OUTPUTEN; + if (flags & GPIO_PIN_PUSHPULL) + conf |= SIO_GPIO_CONF_PUSHPULL; + if (flags & GPIO_PIN_PULLUP) + conf |= SIO_GPIO_CONF_PULLUP; + + nswrite(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINCFG, conf); +} +#endif |