summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Yurchenko <grange@cvs.openbsd.org>2004-05-23 17:41:10 +0000
committerAlexander Yurchenko <grange@cvs.openbsd.org>2004-05-23 17:41:10 +0000
commitc3af576a7b133b4c2046eef9ddf14925c38ba25c (patch)
tree0cb54c1fdc2a67598086c8c20ba6195912df6a4b
parent71a75fdbc0855c8da85afd759f3d28e3e6a3c160 (diff)
gscsio(4) -- National Semiconductor Geode SC1100 Super I/O driver.
For now it only supports I2C-compatible ACCESS.bus interface, so we use it as an i2c master controller. ACCESS.bus interface is enabled and used on the PC Engines WRAP.1C board.
-rw-r--r--sys/arch/i386/conf/GENERIC5
-rw-r--r--sys/dev/isa/files.isa7
-rw-r--r--sys/dev/isa/gscsio.c448
-rw-r--r--sys/dev/isa/gscsioreg.h89
4 files changed, 547 insertions, 2 deletions
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index fefeaa95437..0a644f1d9c8 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.361 2004/05/23 03:23:00 deraadt Exp $
+# $OpenBSD: GENERIC,v 1.362 2004/05/23 17:41:08 grange Exp $
#
# GENERIC -- everything that's currently supported
#
@@ -70,6 +70,9 @@ lm0 at isa? port 0x290
#lm1 at isa? port 0x280
#lm2 at isa? port 0x310
nsclpcsio* at isa? # NS PC87366 hardware monitor
+gscsio* at isa? # NS Geode SC1100 Super I/O
+iic0 at gscsio? # ACCESS.bus 1
+iic1 at gscsio? # ACCESS.bus 2
it0 at isa? port 0x290 # IT8705F, IT8712F and SiS970 hardware
# monitors
diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa
index 8c8e3ef8a1e..5858dca16c6 100644
--- a/sys/dev/isa/files.isa
+++ b/sys/dev/isa/files.isa
@@ -1,4 +1,4 @@
-# $OpenBSD: files.isa,v 1.86 2004/01/05 17:27:30 markus Exp $
+# $OpenBSD: files.isa,v 1.87 2004/05/23 17:41:09 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.
@@ -383,6 +383,11 @@ device nsclpcsio
attach nsclpcsio at isa with nsclpcsio_isa
file dev/isa/nsclpcsio_isa.c nsclpcsio_isa
+# National Semiconductor Geode SC1100 Super I/O
+device gscsio: i2cbus
+attach gscsio at isa
+file dev/isa/gscsio.c gscsio
+
# IT8705F, IT8712F and SiS970 hardware monitors
device it
attach it at isa
diff --git a/sys/dev/isa/gscsio.c b/sys/dev/isa/gscsio.c
new file mode 100644
index 00000000000..1a448892af6
--- /dev/null
+++ b/sys/dev/isa/gscsio.c
@@ -0,0 +1,448 @@
+/* $OpenBSD: gscsio.c,v 1.1 2004/05/23 17:41:09 grange Exp $ */
+/*
+ * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * National Semiconductor Geode SC1100 Super I/O.
+ * Only ACCESS.bus logical device is supported.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/proc.h>
+
+#include <machine/bus.h>
+
+#include <dev/i2c/i2cvar.h>
+
+#include <dev/isa/isareg.h>
+#include <dev/isa/isavar.h>
+
+#include <dev/isa/gscsioreg.h>
+
+struct gscsio_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ int sc_ld_en[GSCSIO_LDNUM];
+ bus_space_handle_t sc_ld_ioh0[GSCSIO_LDNUM];
+ bus_space_handle_t sc_ld_ioh1[GSCSIO_LDNUM];
+
+ /* ACCESS.bus */
+ struct gscsio_acb {
+ void *sc;
+ bus_space_handle_t ioh;
+ struct lock buslock;
+ } sc_acb[2];
+ struct i2c_controller sc_acb1_tag;
+ struct i2c_controller sc_acb2_tag;
+};
+
+/* Supported logical devices description */
+static const struct {
+ const char *ld_name;
+ int ld_num;
+ int ld_iosize0;
+ int ld_iosize1;
+} gscsio_ld[] = {
+ { "ACB1", GSCSIO_LDN_ACB1, 6, 0 },
+ { "ACB2", GSCSIO_LDN_ACB2, 6, 0 },
+};
+
+int gscsio_probe(struct device *, void *, void *);
+void gscsio_attach(struct device *, struct device *, void *);
+
+void gscsio_acb_init(struct gscsio_acb *, i2c_tag_t);
+int gscsio_acb_wait(struct gscsio_acb *, int, int);
+void gscsio_acb_reset(struct gscsio_acb *acb);
+
+int gscsio_acb_acquire_bus(void *, int);
+void gscsio_acb_release_bus(void *, int);
+int gscsio_acb_send_start(void *, int);
+int gscsio_acb_send_stop(void *, int);
+int gscsio_acb_initiate_xfer(void *, uint16_t, int);
+int gscsio_acb_read_byte(void *, uint8_t *, int);
+int gscsio_acb_write_byte(void *, uint8_t, int);
+
+struct cfattach gscsio_ca = {
+ sizeof(struct gscsio_softc),
+ gscsio_probe,
+ gscsio_attach
+};
+
+struct cfdriver gscsio_cd = {
+ NULL, "gscsio", DV_DULL
+};
+
+#define ACB_READ(reg) \
+ bus_space_read_1(sc->sc_iot, acb->ioh, (reg))
+#define ACB_WRITE(reg, val) \
+ bus_space_write_1(sc->sc_iot, acb->ioh, (reg), (val))
+
+static __inline u_int8_t
+idxread(bus_space_tag_t iot, bus_space_handle_t ioh, int idx)
+{
+ bus_space_write_1(iot, ioh, GSCSIO_IDX, idx);
+
+ return (bus_space_read_1(iot, ioh, GSCSIO_DAT));
+}
+
+static __inline void
+idxwrite(bus_space_tag_t iot, bus_space_handle_t ioh, int idx, u_int8_t data)
+{
+ bus_space_write_1(iot, ioh, GSCSIO_IDX, idx);
+ bus_space_write_1(iot, ioh, GSCSIO_DAT, data);
+}
+
+static int
+ioprobe(bus_space_tag_t iot, int base)
+{
+ bus_space_handle_t ioh;
+ int rv = 0;
+
+ if (bus_space_map(iot, base, GSCSIO_IOSIZE, 0, &ioh))
+ return (0);
+ if (idxread(iot, ioh, GSCSIO_ID) == GSCSIO_ID_SC1100)
+ rv = 1;
+ bus_space_unmap(iot, ioh, GSCSIO_IOSIZE);
+
+ return (rv);
+}
+
+int
+gscsio_probe(struct device *parent, void *match, void *aux)
+{
+ struct isa_attach_args *ia = aux;
+ int iobase;
+
+ iobase = GSCSIO_IOBASE1;
+ if (ioprobe(ia->ia_iot, iobase))
+ goto found;
+ iobase = GSCSIO_IOBASE2;
+ if (ioprobe(ia->ia_iot, iobase))
+ goto found;
+
+ return (0);
+
+found:
+ ia->ipa_nio = 1;
+ ia->ipa_io[0].base = iobase;
+ ia->ipa_io[0].length = GSCSIO_IOSIZE;
+ ia->ipa_nmem = 0;
+ ia->ipa_nirq = 0;
+ ia->ipa_ndrq = 0;
+
+ return (1);
+}
+
+void
+gscsio_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct gscsio_softc *sc = (void *)self;
+ struct isa_attach_args *ia = aux;
+ int i;
+ int iobase;
+
+ sc->sc_iot = ia->ia_iot;
+ if (bus_space_map(sc->sc_iot, ia->ipa_io[0].base, GSCSIO_IOSIZE,
+ 0, &sc->sc_ioh)) {
+ printf(": can't map I/O space\n");
+ return;
+ }
+ printf(": SC1100 SIO rev %d:",
+ idxread(sc->sc_iot, sc->sc_ioh, GSCSIO_REV));
+
+ /* Configure all supported logical devices */
+ for (i = 0; i < sizeof (gscsio_ld) / sizeof(gscsio_ld[0]); i++) {
+ sc->sc_ld_en[gscsio_ld[i].ld_num] = 0;
+
+ /* Select the device and check if it's activated */
+ idxwrite(sc->sc_iot, sc->sc_ioh, GSCSIO_LDN,
+ gscsio_ld[i].ld_num);
+ if ((idxread(sc->sc_iot, sc->sc_ioh, GSCSIO_ACT) &
+ GSCSIO_ACT_EN) == 0)
+ continue;
+
+ /* Map I/O space 0 if necessary */
+ if (gscsio_ld[i].ld_iosize0 != 0) {
+ iobase = idxread(sc->sc_iot, sc->sc_ioh,
+ GSCSIO_IO0_MSB);
+ iobase <<= 8;
+ iobase |= idxread(sc->sc_iot, sc->sc_ioh,
+ GSCSIO_IO0_LSB);
+ if (bus_space_map(sc->sc_iot, iobase,
+ gscsio_ld[i].ld_iosize0, 0,
+ &sc->sc_ld_ioh0[gscsio_ld[i].ld_num]))
+ continue;
+ }
+
+ /* Map I/O space 1 if necessary */
+ if (gscsio_ld[i].ld_iosize1 != 0) {
+ iobase = idxread(sc->sc_iot, sc->sc_ioh,
+ GSCSIO_IO1_MSB);
+ iobase <<= 8;
+ iobase |= idxread(sc->sc_iot, sc->sc_ioh,
+ GSCSIO_IO1_LSB);
+ if (bus_space_map(sc->sc_iot, iobase,
+ gscsio_ld[i].ld_iosize1, 0,
+ &sc->sc_ld_ioh0[gscsio_ld[i].ld_num])) {
+ bus_space_unmap(sc->sc_iot,
+ sc->sc_ld_ioh0[gscsio_ld[i].ld_num],
+ gscsio_ld[i].ld_iosize0);
+ continue;
+ }
+ }
+
+ sc->sc_ld_en[gscsio_ld[i].ld_num] = 1;
+ printf(" %s", gscsio_ld[i].ld_name);
+ }
+ printf("\n");
+
+ /* Initialize ACCESS.bus 1 */
+ if (sc->sc_ld_en[GSCSIO_LDN_ACB1]) {
+ sc->sc_acb[0].sc = sc;
+ sc->sc_acb[0].ioh = sc->sc_ld_ioh0[GSCSIO_LDN_ACB1];
+ gscsio_acb_init(&sc->sc_acb[0], &sc->sc_acb1_tag);
+ }
+
+ /* Initialize ACCESS.bus 2 */
+ if (sc->sc_ld_en[GSCSIO_LDN_ACB2]) {
+ sc->sc_acb[1].sc = sc;
+ sc->sc_acb[1].ioh = sc->sc_ld_ioh0[GSCSIO_LDN_ACB2];
+ gscsio_acb_init(&sc->sc_acb[1], &sc->sc_acb2_tag);
+ }
+}
+
+void
+gscsio_acb_init(struct gscsio_acb *acb, i2c_tag_t tag)
+{
+ struct gscsio_softc *sc = acb->sc;
+ struct i2cbus_attach_args iba;
+
+ /* Enable ACB and configure clock frequency */
+ ACB_WRITE(GSCSIO_ACB_CTL2, GSCSIO_ACB_CTL2_EN |
+ (GSCSIO_ACB_FREQ << GSCSIO_ACB_CTL2_FREQ_SHIFT));
+
+ /* Select polling mode */
+ ACB_WRITE(GSCSIO_ACB_CTL1, ACB_READ(GSCSIO_ACB_CTL1) &
+ ~GSCSIO_ACB_CTL1_INTEN);
+
+ /* Disable slave address */
+ ACB_WRITE(GSCSIO_ACB_ADDR, ACB_READ(GSCSIO_ACB_ADDR) &
+ ~GSCSIO_ACB_ADDR_SAEN);
+
+ /* Attach I2C framework */
+ tag->ic_cookie = acb;
+ tag->ic_acquire_bus = gscsio_acb_acquire_bus;
+ tag->ic_release_bus = gscsio_acb_release_bus;
+ tag->ic_send_start = gscsio_acb_send_start;
+ tag->ic_send_stop = gscsio_acb_send_stop;
+ tag->ic_initiate_xfer = gscsio_acb_initiate_xfer;
+ tag->ic_read_byte = gscsio_acb_read_byte;
+ tag->ic_write_byte = gscsio_acb_write_byte;
+
+ iba.iba_name = "iic";
+ iba.iba_tag = tag;
+ config_found(&sc->sc_dev, &iba, iicbus_print);
+}
+
+int
+gscsio_acb_wait(struct gscsio_acb *acb, int bits, int flags)
+{
+ struct gscsio_softc *sc = acb->sc;
+ u_int8_t st;
+ int i;
+
+ for (i = 0; i < 100; i++) {
+ st = ACB_READ(GSCSIO_ACB_ST);
+ if (st & GSCSIO_ACB_ST_BER) {
+ printf("%s: bus error, flags=0x%x\n",
+ sc->sc_dev.dv_xname, flags);
+ gscsio_acb_reset(acb);
+ return (EIO);
+ }
+ if (st & GSCSIO_ACB_ST_NEGACK) {
+ printf("%s: negative ack, flags=0x%x\n",
+ sc->sc_dev.dv_xname, flags);
+ gscsio_acb_reset(acb);
+ return (EIO);
+ }
+ if ((st & bits) == bits)
+ break;
+ delay(10);
+ }
+ if ((st & bits) != bits) {
+ printf("%s: timeout, flags=0x%x\n",
+ sc->sc_dev.dv_xname, flags);
+ gscsio_acb_reset(acb);
+ return (ETIMEDOUT);
+ }
+
+ return (0);
+}
+
+void
+gscsio_acb_reset(struct gscsio_acb *acb)
+{
+ struct gscsio_softc *sc = acb->sc;
+ u_int8_t st, ctl;
+
+ /* Clear MASTER, NEGACK and BER */
+ st = ACB_READ(GSCSIO_ACB_ST);
+ st |= GSCSIO_ACB_ST_MASTER | GSCSIO_ACB_ST_NEGACK | GSCSIO_ACB_ST_BER;
+ ACB_WRITE(GSCSIO_ACB_ST, st);
+
+ /* Disable and re-enable ACB */
+ ACB_WRITE(GSCSIO_ACB_CTL2, 0);
+ ACB_WRITE(GSCSIO_ACB_CTL2, GSCSIO_ACB_CTL2_EN |
+ (GSCSIO_ACB_FREQ << GSCSIO_ACB_CTL2_FREQ_SHIFT));
+
+ /* Send stop */
+ ctl = ACB_READ(GSCSIO_ACB_CTL1);
+ ctl |= GSCSIO_ACB_CTL1_STOP;
+ ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
+}
+
+int
+gscsio_acb_acquire_bus(void *cookie, int flags)
+{
+ struct gscsio_acb *acb = cookie;
+
+ if (flags & I2C_F_POLL)
+ return (0);
+
+ return (lockmgr(&acb->buslock, LK_EXCLUSIVE, NULL, curproc));
+}
+
+void
+gscsio_acb_release_bus(void *cookie, int flags)
+{
+ struct gscsio_acb *acb = cookie;
+
+ if (flags & I2C_F_POLL)
+ return;
+
+ lockmgr(&acb->buslock, LK_RELEASE, NULL, curproc);
+}
+
+int
+gscsio_acb_send_start(void *cookie, int flags)
+{
+ struct gscsio_acb *acb = cookie;
+ struct gscsio_softc *sc = acb->sc;
+ u_int8_t ctl;
+
+ ctl = ACB_READ(GSCSIO_ACB_CTL1);
+ ctl |= GSCSIO_ACB_CTL1_START;
+ ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
+
+ return (0);
+}
+
+int
+gscsio_acb_send_stop(void *cookie, int flags)
+{
+ struct gscsio_acb *acb = cookie;
+ struct gscsio_softc *sc = acb->sc;
+ u_int8_t ctl;
+
+ ctl = ACB_READ(GSCSIO_ACB_CTL1);
+ ctl |= GSCSIO_ACB_CTL1_STOP;
+ ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
+
+ return (0);
+}
+
+int
+gscsio_acb_initiate_xfer(void *cookie, uint16_t addr, int flags)
+{
+ struct gscsio_acb *acb = cookie;
+ struct gscsio_softc *sc = acb->sc;
+ u_int8_t ctl;
+ int dir;
+ int error;
+
+ /* Issue start condition */
+ ctl = ACB_READ(GSCSIO_ACB_CTL1);
+ ctl |= GSCSIO_ACB_CTL1_START;
+ ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
+
+ /* Wait for bus mastership */
+ if ((error = gscsio_acb_wait(acb,
+ GSCSIO_ACB_ST_MASTER | GSCSIO_ACB_ST_SDAST, flags)))
+ return (error);
+
+ /* Send address byte */
+ dir = (flags & I2C_F_READ ? 1 : 0);
+ ACB_WRITE(GSCSIO_ACB_SDA, (addr << 1) | dir);
+
+ return (0);
+}
+
+int
+gscsio_acb_read_byte(void *cookie, uint8_t *bytep, int flags)
+{
+ struct gscsio_acb *acb = cookie;
+ struct gscsio_softc *sc = acb->sc;
+ u_int8_t ctl;
+ int error;
+
+ /* Wait for the bus to be ready */
+ if ((error = gscsio_acb_wait(acb, GSCSIO_ACB_ST_SDAST, flags)))
+ return (error);
+
+ /* Acknowledge the last byte */
+ if (flags & I2C_F_LAST) {
+ ctl = ACB_READ(GSCSIO_ACB_CTL1);
+ ctl |= GSCSIO_ACB_CTL1_ACK;
+ ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
+ }
+
+ /* Read data byte */
+ *bytep = ACB_READ(GSCSIO_ACB_SDA);
+
+ return (0);
+}
+
+int
+gscsio_acb_write_byte(void *cookie, uint8_t byte, int flags)
+{
+ struct gscsio_acb *acb = cookie;
+ struct gscsio_softc *sc = acb->sc;
+ u_int8_t ctl;
+ int error;
+
+ /* Wait for the bus to be ready */
+ if ((error = gscsio_acb_wait(acb, GSCSIO_ACB_ST_SDAST, flags)))
+ return (error);
+
+ /* Send stop after the last byte */
+ if (flags & I2C_F_STOP) {
+ ctl = ACB_READ(GSCSIO_ACB_CTL1);
+ ctl |= GSCSIO_ACB_CTL1_STOP;
+ ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
+ }
+
+ /* Write data byte */
+ ACB_WRITE(GSCSIO_ACB_SDA, byte);
+
+ return (0);
+}
diff --git a/sys/dev/isa/gscsioreg.h b/sys/dev/isa/gscsioreg.h
new file mode 100644
index 00000000000..dc8793b0bc4
--- /dev/null
+++ b/sys/dev/isa/gscsioreg.h
@@ -0,0 +1,89 @@
+/* $OpenBSD: gscsioreg.h,v 1.1 2004/05/23 17:41:09 grange Exp $ */
+/*
+ * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * National Semiconductor Geode SC1100 Super I/O register definitions.
+ */
+
+/* Possible index-data register pair base addresses */
+#define GSCSIO_IOBASE1 0x2e
+#define GSCSIO_IOBASE2 0x15c
+#define GSCSIO_IOSIZE 2 /* I/O space size */
+
+/* Index-data register pair */
+#define GSCSIO_IDX 0x0 /* index register */
+#define GSCSIO_DAT 0x1 /* data register */
+
+/* SIO control and configuration registers */
+#define GSCSIO_LDN 0x07 /* logical device number */
+#define GSCSIO_LDN_ACB1 0x05 /* ACCESS.bus 1 */
+#define GSCSIO_LDN_ACB2 0x06 /* ACCESS.bus 2 */
+#define GSCSIO_ID 0x20 /* SIO ID */
+#define GSCSIO_ID_SC1100 0xf5 /* Geode SC1100 ID */
+#define GSCSIO_CFG1 0x21 /* configuration 1 */
+#define GSCSIO_CFG2 0x22 /* configuration 2 */
+#define GSCSIO_REV 0x27 /* revision ID */
+
+/* Logical device control and configuration registers */
+#define GSCSIO_ACT 0x30 /* logical device activation control */
+#define GSCSIO_ACT_EN 0x01 /* enabled */
+#define GSCSIO_IO0_MSB 0x60 /* I/O space 0 base bits [15:8] */
+#define GSCSIO_IO0_LSB 0x61 /* I/O space 0 base bits [7:0] */
+#define GSCSIO_IO1_MSB 0x62 /* I/O space 1 base bits [15:8] */
+#define GSCSIO_IO1_LSB 0x63 /* I/O space 1 base bits [7:0] */
+#define GSCSIO_INUM 0x70 /* interrupt number */
+#define GSCSIO_ITYPE 0x71 /* interrupt type */
+#define GSCSIO_DMA0 0x74 /* DMA channel 0 */
+#define GSCSIO_DMA1 0x75 /* DMA channel 1 */
+
+#define GSCSIO_LDNUM 6 /* total number of logical devices */
+
+/* ACB (ACCESS.bus) logical device registers */
+#define GSCSIO_ACB_SDA 0x00 /* serial data */
+#define GSCSIO_ACB_ST 0x01 /* status */
+#define GSCSIO_ACB_ST_XMIT (1 << 0) /* transmit mode active */
+#define GSCSIO_ACB_ST_MASTER (1 << 1) /* master mode active */
+#define GSCSIO_ACB_ST_NMATCH (1 << 2) /* new match */
+#define GSCSIO_ACB_ST_STASTR (1 << 3) /* stall after start */
+#define GSCSIO_ACB_ST_NEGACK (1 << 4) /* negative ack */
+#define GSCSIO_ACB_ST_BER (1 << 5) /* bus error */
+#define GSCSIO_ACB_ST_SDAST (1 << 6) /* wait or hold data */
+#define GSCSIO_ACB_ST_SLVSTP (1 << 7) /* slave stop */
+#define GSCSIO_ACB_CST 0x02 /* control status */
+#define GSCSIO_ACB_CST_BUSY (1 << 0) /* busy */
+#define GSCSIO_ACB_CST_BB (1 << 1) /* bus busy */
+#define GSCSIO_ACB_CST_MATCH (1 << 2) /* match address */
+#define GSCSIO_ACB_CST_GCMTCH (1 << 3) /* global call match */
+#define GSCSIO_ACB_CST_TSDA (1 << 4) /* test ABD line */
+#define GSCSIO_ACB_CST_TGABC (1 << 5) /* toggle ABC line */
+#define GSCSIO_ACB_CTL1 0x03 /* control 1 */
+#define GSCSIO_ACB_CTL1_START (1 << 0) /* start condition */
+#define GSCSIO_ACB_CTL1_STOP (1 << 1) /* stop condition */
+#define GSCSIO_ACB_CTL1_INTEN (1 << 2) /* interrupt enabled */
+#define GSCSIO_ACB_CTL1_ACK (1 << 4) /* acknowledge */
+#define GSCSIO_ACB_CTL1_GCMEN (1 << 5) /* global call match enable */
+#define GSCSIO_ACB_CTL1_NMINTE (1 << 6) /* new match intr enable */
+#define GSCSIO_ACB_CTL1_STASTRE (1 << 7) /* stall after start enable */
+#define GSCSIO_ACB_ADDR 0x04 /* own address */
+#define GSCSIO_ACB_ADDR_MASK 0x7f /* address mask */
+#define GSCSIO_ACB_ADDR_SAEN (1 << 7) /* slave address enable */
+#define GSCSIO_ACB_CTL2 0x05 /* control 2 */
+#define GSCSIO_ACB_CTL2_EN (1 << 0) /* ACB enabled */
+#define GSCSIO_ACB_CTL2_FREQ_SHIFT 1 /* ACB frequency shift */
+#define GSCSIO_ACB_CTL2_FREQ_MASK 0x7f /* ACB frequency mask */
+
+#define GSCSIO_ACB_FREQ 0x3c /* standard I2C frequency 100kHz */