summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/sparc64/conf/GENERIC4
-rw-r--r--sys/arch/sparc64/conf/files.sparc646
-rw-r--r--sys/arch/sparc64/dev/pcfiic_ebus.c118
-rw-r--r--sys/conf/files6
-rw-r--r--sys/dev/ic/pcf8584.c312
-rw-r--r--sys/dev/ic/pcf8584var.h34
6 files changed, 477 insertions, 3 deletions
diff --git a/sys/arch/sparc64/conf/GENERIC b/sys/arch/sparc64/conf/GENERIC
index e9bc4ef58e0..06943343fbd 100644
--- a/sys/arch/sparc64/conf/GENERIC
+++ b/sys/arch/sparc64/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.139 2006/01/11 21:57:53 martin Exp $
+# $OpenBSD: GENERIC,v 1.140 2006/02/01 11:03:33 dlg Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -306,6 +306,8 @@ rgephy* at mii? # Realtek 8169S/8110S PHY
ukphy* at mii? # Unknown PHYs
# sensors
+pcfiic* at ebus?
+iic* at pcfiic?
alipm* at pci?
iic* at alipm?
diff --git a/sys/arch/sparc64/conf/files.sparc64 b/sys/arch/sparc64/conf/files.sparc64
index 9ac379993f3..9693d67d5de 100644
--- a/sys/arch/sparc64/conf/files.sparc64
+++ b/sys/arch/sparc64/conf/files.sparc64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.sparc64,v 1.63 2006/01/02 01:58:55 deraadt Exp $
+# $OpenBSD: files.sparc64,v 1.64 2006/02/01 11:03:33 dlg Exp $
# $NetBSD: files.sparc64,v 1.50 2001/08/10 20:53:50 eeh Exp $
# maxpartitions must be first item in files.${ARCH}
@@ -192,6 +192,10 @@ device fd: disk
attach fd at fdc
file arch/sparc64/dev/fd.c fdc | fd needs-flag
+# PCF8584 I2C Controller
+attach pcfiic at ebus with pcfiic_ebus
+file arch/sparc64/dev/pcfiic_ebus.c pcfiic_ebus
+
file arch/sparc64/dev/consinit.c
file arch/sparc64/fpu/fpu.c
diff --git a/sys/arch/sparc64/dev/pcfiic_ebus.c b/sys/arch/sparc64/dev/pcfiic_ebus.c
new file mode 100644
index 00000000000..cb9ee7ef170
--- /dev/null
+++ b/sys/arch/sparc64/dev/pcfiic_ebus.c
@@ -0,0 +1,118 @@
+/* $OpenBSD: pcfiic_ebus.c,v 1.1 2006/02/01 11:03:33 dlg Exp $ */
+
+/*
+ * Copyright (c) 2006 David Gwynne <dlg@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.
+ */
+
+/*
+ * Device specific driver for the EBus i2c devices found on some sun4u
+ * systems. On systems not having a boot-bus controller the i2c devices
+ * are PCF8584.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+
+#include <machine/bus.h>
+#include <machine/openfirm.h>
+
+#include <sparc64/dev/ebusreg.h>
+#include <sparc64/dev/ebusvar.h>
+
+#include <dev/i2c/i2cvar.h>
+#include <sparc64/dev/ofwi2cvar.h>
+
+#include <dev/ic/pcf8584var.h>
+
+int pcfiic_ebus_match(struct device *, void *, void *);
+void pcfiic_ebus_attach(struct device *, struct device *, void *);
+
+struct pcfiic_ebus_softc {
+ struct pcfiic_softc esc_sc;
+
+ int esc_node;
+ void *esc_ih;
+};
+
+struct cfattach pcfiic_ebus_ca = {
+ sizeof(struct pcfiic_ebus_softc), pcfiic_ebus_match, pcfiic_ebus_attach
+};
+
+int
+pcfiic_ebus_match(struct device *parent, void *match, void *aux)
+{
+ struct ebus_attach_args *ea = aux;
+ char compat[32];
+
+ if (strcmp(ea->ea_name, "i2c") != 0)
+ return (0);
+
+ if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) == -1)
+ return (0);
+
+ if (strcmp(compat, "i2cpcf,8584") != 0)
+ return (0);
+
+ return (1);
+}
+
+void
+pcfiic_ebus_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct pcfiic_ebus_softc *esc = (struct pcfiic_ebus_softc *)self;
+ struct pcfiic_softc *sc = &esc->esc_sc;
+ struct ebus_attach_args *ea = aux;
+ u_int64_t addr;
+
+ sc->sc_iot = ea->ea_memtag;
+
+ if (ea->ea_nregs != 1) {
+ printf(": expected 1 register, got %d\n", ea->ea_nregs);
+ return;
+ }
+
+ if (OF_getprop(ea->ea_node, "own-address", &addr, sizeof(addr)) == -1) {
+ printf(": unable to get own address\n");
+ return;
+ }
+ if (addr == 0x00 || addr > 0xff) {
+ printf(": invalid address on I2C bus\n");
+ return;
+ }
+
+ if (ebus_bus_map(sc->sc_iot, 0, EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
+ ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) != 0) {
+ printf(": can't map register space\n");
+ return;
+ }
+
+ if (ea->ea_nintrs >= 1)
+ esc->esc_ih = bus_intr_establish(sc->sc_iot, ea->ea_intrs[0],
+ IPL_BIO, 0, pcfiic_intr, sc, self->dv_xname);
+ else
+ esc->esc_ih = NULL;
+
+
+ if (esc->esc_ih == NULL)
+ sc->sc_poll = 1;
+
+#ifdef notyet
+ pcfiic_attach(sc, (i2c_addr_t)(addr >> 1), NULL, NULL);
+#endif
+ pcfiic_attach(sc, (i2c_addr_t)(addr >> 1), ofwi2c_scan, &ea->ea_node);
+ /* the rest of the attach line is printed by pcfiic_attach() */
+}
diff --git a/sys/conf/files b/sys/conf/files
index 9e3229ad325..1efe82f5165 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.364 2006/01/29 17:29:29 marco Exp $
+# $OpenBSD: files,v 1.365 2006/02/01 11:03:33 dlg Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -299,6 +299,10 @@ file dev/ic/pckbc.c pckbc needs-flag
# HPPA PS/2 input ports (forward definition)
device gsckbc {[slot = -1]}
+# PCF8584 I2C Controllers
+device pcfiic: i2cbus
+file dev/ic/pcf8584.c pcfiic
+
# OPL2/OPL3 FM synth driver
device opl: midibus, midisyn
file dev/ic/opl.c opl
diff --git a/sys/dev/ic/pcf8584.c b/sys/dev/ic/pcf8584.c
new file mode 100644
index 00000000000..8734d616023
--- /dev/null
+++ b/sys/dev/ic/pcf8584.c
@@ -0,0 +1,312 @@
+/* $OpenBSD: pcf8584.c,v 1.1 2006/02/01 11:03:34 dlg Exp $ */
+
+/*
+ * Copyright (c) 2006 David Gwynne <dlg@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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/proc.h>
+
+#include <machine/bus.h>
+
+#include <dev/i2c/i2cvar.h>
+
+#include <dev/ic/pcf8584var.h>
+
+#define PCF_S0 0x00
+#define PCF_S1 0x01
+#define PCF_S2 0x02
+#define PCF_S3 0x03
+
+#define PCF_CTRL_ACK (1<<0)
+#define PCF_CTRL_STO (1<<1)
+#define PCF_CTRL_STA (1<<2)
+#define PCF_CTRL_ENI (1<<3)
+#define PCF_CTRL_ES2 (1<<4)
+#define PCF_CTRL_ES1 (1<<5)
+#define PCF_CTRL_ESO (1<<6)
+#define PCF_CTRL_PIN (1<<7)
+
+#define PCF_CTRL_START (PCF_CTRL_PIN | PCF_CTRL_ESO | \
+ PCF_CTRL_STA | PCF_CTRL_ACK)
+#define PCF_CTRL_STOP (PCF_CTRL_PIN | PCF_CTRL_ESO | \
+ PCF_CTRL_STO | PCF_CTRL_ACK)
+#define PCF_CTRL_REPSTART (PCF_CTRL_ESO | PCF_CTRL_STA | PCF_CTRL_ACK)
+#define PCF_CTRL_IDLE (PCF_CTRL_PIN | PCF_CTRL_ESO | PCF_CTRL_ACK)
+
+#define PCF_STAT_nBB (1<<0)
+#define PCF_STAT_LAB (1<<1)
+#define PCF_STAT_AAS (1<<2)
+#define PCF_STAT_AD0 (1<<3)
+#define PCF_STAT_LRB (1<<3)
+#define PCF_STAT_BER (1<<4)
+#define PCF_STAT_STS (1<<5)
+#define PCF_STAT_PIN (1<<7)
+
+#define PCF_CLOCK_3 0x00 /* 3 MHz */
+#define PCF_CLOCK_4_43 0x10 /* 4.43 MHz */
+#define PCF_CLOCK_6 0x14 /* 6 MHz */
+#define PCF_CLOCK_8 0x18 /* 8 MHz */
+#define PCF_CLOCK_12 0x1c /* 12 MHz */
+
+#define PCF_FREQ_90 0x00 /* 90 kHz */
+#define PCF_FREQ_45 0x01 /* 45 kHz */
+#define PCF_FREQ_11 0x02 /* 11 kHz */
+#define PCF_FREQ_1_5 0x03 /* 1.5 kHz */
+
+struct cfdriver pcfiic_cd = {
+ NULL, "pcfiic", DV_DULL
+};
+
+int pcfiic_i2c_acquire_bus(void *, int);
+void pcfiic_i2c_release_bus(void *, int);
+int pcfiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
+ size_t, void *, size_t, int);
+
+int pcfiic_xmit(struct pcfiic_softc *, u_int8_t, const u_int8_t *,
+ size_t);
+int pcfiic_recv(struct pcfiic_softc *, u_int8_t, u_int8_t *,
+ size_t);
+
+u_int8_t pcfiic_read(struct pcfiic_softc *, bus_size_t);
+void pcfiic_write(struct pcfiic_softc *, bus_size_t, u_int8_t);
+int pcfiic_wait_nBB(struct pcfiic_softc *);
+int pcfiic_wait_pin(struct pcfiic_softc *, volatile u_int8_t *);
+
+#define pcfiic_ctrl_start(_sc) pcfiic_write((_sc), PCF_S1, \
+ PCF_CTRL_START)
+#define pcfiic_ctrl_repstart(_sc) pcf_write((_sc), PCF_S1, \
+ PCF_CTRL_REPSTART)
+#define pcfiic_ctrl_stop(_sc) pcfiic_write((_sc), PCF_S1, \
+ PCF_CTRL_STOP)
+
+void
+pcfiic_attach(struct pcfiic_softc *sc, i2c_addr_t addr,
+ void (*scan_func)(struct device *, struct i2cbus_attach_args *, void *),
+ void *scan_arg)
+{
+ struct i2cbus_attach_args iba;
+
+ /* init S1 */
+ pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN);
+ /* own address */
+ pcfiic_write(sc, PCF_S0, addr);
+
+ /* select clock reg */
+ pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN|PCF_CTRL_ES1);
+ pcfiic_write(sc, PCF_S0, PCF_CLOCK_12);
+
+ pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN | PCF_CTRL_ESO | PCF_CTRL_ENI |
+ PCF_CTRL_ACK);
+
+ printf(": PCF8584 I2C address 0x%02x%s\n", addr,
+ sc->sc_poll ? ", polled" : "");
+
+ lockinit(&sc->sc_lock, PRIBIO | PCATCH, "iiclk", 0, 0);
+ sc->sc_i2c.ic_cookie = sc;
+ sc->sc_i2c.ic_acquire_bus = pcfiic_i2c_acquire_bus;
+ sc->sc_i2c.ic_release_bus = pcfiic_i2c_release_bus;
+ sc->sc_i2c.ic_exec = pcfiic_i2c_exec;
+
+ bzero(&iba, sizeof(iba));
+ iba.iba_name = "iic";
+ iba.iba_tag = &sc->sc_i2c;
+ iba.iba_bus_scan = scan_func;
+ iba.iba_bus_scan_arg = scan_arg;
+ config_found(&sc->sc_dev, &iba, iicbus_print);
+}
+
+int
+pcfiic_intr(void *arg)
+{
+ return (0);
+}
+
+int
+pcfiic_i2c_acquire_bus(void *arg, int flags)
+{
+ struct pcfiic_softc *sc = arg;
+
+ if (cold || sc->sc_poll || (flags & I2C_F_POLL))
+ return (0);
+
+ return (lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL));
+}
+
+void
+pcfiic_i2c_release_bus(void *arg, int flags)
+{
+ struct pcfiic_softc *sc = arg;
+
+ if (cold || sc->sc_poll || (flags & I2C_F_POLL))
+ return;
+
+ lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
+}
+
+int
+pcfiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
+ const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
+{
+ struct pcfiic_softc *sc = arg;
+ int ret = 0;
+
+#if 0
+ printf("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n",
+ sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags);
+#endif
+
+ if (cold || sc->sc_poll)
+ flags |= I2C_F_POLL;
+
+ if (cmdlen > 0) {
+ if (pcfiic_xmit(sc, addr, cmdbuf, cmdlen) != 0)
+ return (1);
+ }
+
+ if (len > 0) {
+ if (I2C_OP_WRITE_P(op))
+ ret = pcfiic_xmit(sc, addr, buf, len);
+ else
+ ret = pcfiic_recv(sc, addr, buf, len);
+ }
+
+ return (ret);
+}
+
+int
+pcfiic_xmit(struct pcfiic_softc *sc, u_int8_t addr, const u_int8_t *buf,
+ size_t len)
+{
+ int i;
+ int err = 0;
+ volatile u_int8_t r;
+
+
+ while ((pcfiic_read(sc, PCF_S1) & PCF_STAT_nBB) == 0)
+ ;
+
+ pcfiic_write(sc, PCF_S0, addr << 1);
+
+ pcfiic_write(sc, PCF_S1, 0xc5);
+
+ for (i = 0; i <= len; i++) {
+ while ((r = pcfiic_read(sc, PCF_S1)) & PCF_STAT_PIN)
+ ;
+
+ if (r & PCF_STAT_LRB) {
+ err = 1;
+ break;
+ }
+
+ if (i < len)
+ pcfiic_write(sc, PCF_S0, buf[i]);
+ }
+
+ pcfiic_write(sc, PCF_S1, 0xc3);
+
+ return (err);
+}
+
+int
+pcfiic_recv(struct pcfiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len)
+{
+ int i;
+ int err = 0;
+ volatile u_int8_t r;
+
+ pcfiic_write(sc, PCF_S0, (addr << 1) | 0x01);
+
+ if (pcfiic_wait_nBB(sc) != 0)
+ return (1);
+
+ pcfiic_ctrl_start(sc);
+
+ i = 0;
+ for (i = 0; i <= len; i++) {
+ if (pcfiic_wait_pin(sc, &r) != 0) {
+ pcfiic_ctrl_stop(sc);
+ return (1);
+ }
+
+ if ((i != len) && (r & PCF_STAT_LRB)) {
+ pcfiic_ctrl_stop(sc);
+ return (1);
+ }
+
+ if (i == len - 1) {
+ pcfiic_write(sc, PCF_S1, PCF_CTRL_ESO);
+ } else if (i == len) {
+ pcfiic_ctrl_stop(sc);
+ }
+
+ r = pcfiic_read(sc, PCF_S0);
+ if (i > 0)
+ buf[i - 1] = r;
+ }
+
+ return (err);
+}
+
+
+u_int8_t
+pcfiic_read(struct pcfiic_softc *sc, bus_size_t r)
+{
+ bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 1,
+ BUS_SPACE_BARRIER_READ);
+ return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, r));
+}
+
+void
+pcfiic_write(struct pcfiic_softc *sc, bus_size_t r, u_int8_t v)
+{
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, r, v);
+ bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 1,
+ BUS_SPACE_BARRIER_WRITE);
+}
+
+int
+pcfiic_wait_nBB(struct pcfiic_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < 1000; i++) {
+ if (pcfiic_read(sc, PCF_S1) & PCF_STAT_nBB)
+ return (0);
+ delay(1000);
+ }
+
+ return (1);
+}
+
+int
+pcfiic_wait_pin(struct pcfiic_softc *sc, volatile u_int8_t *r)
+{
+ int i;
+
+ for (i = 0; i < 1000; i++) {
+ *r = pcfiic_read(sc, PCF_S1);
+ if ((*r & PCF_STAT_PIN) == 0)
+ return (0);
+ delay(1000);
+ }
+
+ return (1);
+}
diff --git a/sys/dev/ic/pcf8584var.h b/sys/dev/ic/pcf8584var.h
new file mode 100644
index 00000000000..7fbdac1d50a
--- /dev/null
+++ b/sys/dev/ic/pcf8584var.h
@@ -0,0 +1,34 @@
+/* $OpenBSD: pcf8584var.h,v 1.1 2006/02/01 11:03:34 dlg Exp $ */
+
+/*
+ * Copyright (c) 2006 David Gwynne <dlg@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.
+ */
+
+struct pcfiic_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ int sc_poll;
+
+ struct i2c_controller sc_i2c;
+ struct lock sc_lock;
+};
+
+void pcfiic_attach(struct pcfiic_softc *, i2c_addr_t,
+ void (*)(struct device *, struct i2cbus_attach_args *, void *),
+ void *);
+int pcfiic_intr(void *);