summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Yurchenko <grange@cvs.openbsd.org>2004-06-03 18:28:03 +0000
committerAlexander Yurchenko <grange@cvs.openbsd.org>2004-06-03 18:28:03 +0000
commit0c62644013fa42af4c90ca8da7e8e4c3e160e7c2 (patch)
tree2bd76c1ff038301c7f06496b7335d9c54ff593e1
parent559da32aab1ceb9534a2e3843d87bf17b9c8dd07 (diff)
Add support for the GPIO logical device.
ok deraadt@
-rw-r--r--sys/arch/i386/conf/GENERIC5
-rw-r--r--sys/dev/isa/files.isa4
-rw-r--r--sys/dev/isa/nsclpcsio_isa.c343
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