summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/sparc64/dev/pcfiic_ebus.c36
-rw-r--r--sys/dev/ic/pcf8584.c74
-rw-r--r--sys/dev/ic/pcf8584var.h14
3 files changed, 79 insertions, 45 deletions
diff --git a/sys/arch/sparc64/dev/pcfiic_ebus.c b/sys/arch/sparc64/dev/pcfiic_ebus.c
index 6084b6dec9e..750ccb0f481 100644
--- a/sys/arch/sparc64/dev/pcfiic_ebus.c
+++ b/sys/arch/sparc64/dev/pcfiic_ebus.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pcfiic_ebus.c,v 1.4 2006/06/14 01:15:19 deraadt Exp $ */
+/* $OpenBSD: pcfiic_ebus.c,v 1.5 2006/06/22 08:33:45 deraadt Exp $ */
/*
* Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
@@ -29,6 +29,7 @@
#include <machine/bus.h>
#include <machine/openfirm.h>
+#include <machine/autoconf.h>
#include <sparc64/dev/ebusreg.h>
#include <sparc64/dev/ebusvar.h>
@@ -76,8 +77,11 @@ 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;
+ struct ebus_attach_args *ea = aux;
+ char compat[32];
u_int64_t addr;
+ u_int8_t clock = PCF_CLOCK_12;
+ int swapregs = 0;
sc->sc_iot = ea->ea_memtag;
@@ -86,6 +90,24 @@ pcfiic_ebus_attach(struct device *parent, struct device *self, void *aux)
return;
}
+ if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) == -1)
+ return;
+
+ if (strcmp(compat, "SUNW,bbc-i2c") == 0) {
+ /*
+ * On BBC-based machines, Sun swapped the order of
+ * the registers on their clone pcf, plus they feed
+ * it a non-standard clock.
+ */
+ int clk = getpropint(findroot(), "clock-frequency", 0);
+
+ if (clk < 105000000)
+ clock = PCF_CLOCK_3;
+ else if (clk < 160000000)
+ clock = PCF_CLOCK_4_43;
+ swapregs = 1;
+ }
+
if (OF_getprop(ea->ea_node, "own-address", &addr, sizeof(addr)) == -1) {
addr = 0xaa;
} else if (addr == 0x00 || addr > 0xff) {
@@ -95,9 +117,9 @@ pcfiic_ebus_attach(struct device *parent, struct device *self, void *aux)
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;
- }
+ printf(": can't map register space\n");
+ return;
+ }
if (ea->ea_nregs == 2) {
if (ebus_bus_map(sc->sc_iot, 0, EBUS_PADDR_FROM_REG(&ea->ea_regs[1]),
@@ -118,6 +140,6 @@ pcfiic_ebus_attach(struct device *parent, struct device *self, void *aux)
if (esc->esc_ih == NULL)
sc->sc_poll = 1;
- pcfiic_attach(sc, (i2c_addr_t)(addr >> 1), ofwiic_scan, &ea->ea_node);
- /* the rest of the attach line is printed by pcfiic_attach() */
+ pcfiic_attach(sc, (i2c_addr_t)(addr >> 1), clock, swapregs,
+ ofwiic_scan, &ea->ea_node);
}
diff --git a/sys/dev/ic/pcf8584.c b/sys/dev/ic/pcf8584.c
index 7c99ebfe154..8a425df832e 100644
--- a/sys/dev/ic/pcf8584.c
+++ b/sys/dev/ic/pcf8584.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pcf8584.c,v 1.6 2006/06/21 15:58:19 deraadt Exp $ */
+/* $OpenBSD: pcf8584.c,v 1.7 2006/06/22 08:33:43 deraadt Exp $ */
/*
* Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
@@ -60,12 +60,6 @@
#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 */
@@ -75,6 +69,7 @@ struct cfdriver pcfiic_cd = {
NULL, "pcfiic", DV_DULL
};
+void pcfiic_init(struct pcfiic_softc *);
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 *,
@@ -92,26 +87,41 @@ int pcfiic_wait_nBB(struct pcfiic_softc *);
int pcfiic_wait_pin(struct pcfiic_softc *, volatile u_int8_t *);
void
-pcfiic_attach(struct pcfiic_softc *sc, i2c_addr_t addr,
- void (*scan_func)(struct device *, struct i2cbus_attach_args *, void *),
- void *scan_arg)
+pcfiic_init(struct pcfiic_softc *sc)
{
- struct i2cbus_attach_args iba;
-
/* init S1 */
pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN);
/* own address */
- pcfiic_write(sc, PCF_S0, addr);
+ pcfiic_write(sc, PCF_S0, sc->sc_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_S0, sc->sc_clock);
pcfiic_write(sc, PCF_S1, PCF_CTRL_IDLE);
-#if 0
- pcfiic_read(sc, PCF_S0); /* dummy read maybe? */
-#endif
+ delay(200000); /* Multi-Master mode, wait for longest i2c message */
+}
+
+void
+pcfiic_attach(struct pcfiic_softc *sc, i2c_addr_t addr, u_int8_t clock,
+ int swapregs,
+ void (*scan_func)(struct device *, struct i2cbus_attach_args *, void *),
+ void *scan_arg)
+{
+ struct i2cbus_attach_args iba;
+
+ if (swapregs) {
+ sc->sc_regmap[PCF_S1] = PCF_S0;
+ sc->sc_regmap[PCF_S0] = PCF_S1;
+ } else {
+ sc->sc_regmap[PCF_S0] = PCF_S0;
+ sc->sc_regmap[PCF_S1] = PCF_S1;
+ }
+ sc->sc_clock = clock;
+ sc->sc_addr = addr;
+
+ pcfiic_init(sc);
printf("\n");
@@ -195,25 +205,19 @@ int
pcfiic_xmit(struct pcfiic_softc *sc, u_int8_t addr, const u_int8_t *buf,
size_t len)
{
- int i, err = 0, tries = 100;
+ int i, err = 0;
volatile u_int8_t r;
- while ((pcfiic_read(sc, PCF_S1) & PCF_STAT_nBB) == 0) {
- if (--tries == 0)
- return (1);
- DELAY(1);
- }
+ if (pcfiic_wait_nBB(sc) != 0)
+ return (1);
pcfiic_write(sc, PCF_S0, addr << 1);
pcfiic_write(sc, PCF_S1, PCF_CTRL_START);
for (i = 0; i <= len; i++) {
- while ((r = pcfiic_read(sc, PCF_S1)) & PCF_STAT_PIN) {
- if (--tries == 0) {
- err = 1;
- goto fail;
- }
- DELAY(1);
+ if (pcfiic_wait_pin(sc, &r) != 0) {
+ pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
+ return (1);
}
if (r & PCF_STAT_LRB) {
@@ -224,7 +228,6 @@ pcfiic_xmit(struct pcfiic_softc *sc, u_int8_t addr, const u_int8_t *buf,
if (i < len)
pcfiic_write(sc, PCF_S0, buf[i]);
}
-fail:
pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
return (err);
}
@@ -235,11 +238,10 @@ pcfiic_recv(struct pcfiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len)
int i = 0, err = 0;
volatile u_int8_t r;
- pcfiic_write(sc, PCF_S0, (addr << 1) | 0x01);
-
if (pcfiic_wait_nBB(sc) != 0)
return (1);
+ pcfiic_write(sc, PCF_S0, (addr << 1) | 0x01);
pcfiic_write(sc, PCF_S1, PCF_CTRL_START);
for (i = 0; i <= len; i++) {
@@ -269,16 +271,16 @@ pcfiic_recv(struct pcfiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len)
volatile 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(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], 1,
BUS_SPACE_BARRIER_READ);
- return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, r));
+ return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r]));
}
volatile 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_write_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], v);
+ bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], 1,
BUS_SPACE_BARRIER_WRITE);
}
diff --git a/sys/dev/ic/pcf8584var.h b/sys/dev/ic/pcf8584var.h
index c3a0ed576bc..cd8947f4b91 100644
--- a/sys/dev/ic/pcf8584var.h
+++ b/sys/dev/ic/pcf8584var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pcf8584var.h,v 1.2 2006/06/14 01:15:17 deraadt Exp $ */
+/* $OpenBSD: pcf8584var.h,v 1.3 2006/06/22 08:33:43 deraadt Exp $ */
/*
* Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
@@ -23,6 +23,9 @@ struct pcfiic_softc {
bus_space_handle_t sc_ioh;
bus_space_handle_t sc_ioh2;
int sc_master;
+ u_int8_t sc_addr;
+ u_int8_t sc_clock;
+ u_int8_t sc_regmap[2];
int sc_poll;
@@ -30,7 +33,14 @@ struct pcfiic_softc {
struct lock sc_lock;
};
-void pcfiic_attach(struct pcfiic_softc *, i2c_addr_t,
+/* clock divisor settings */
+#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 */
+
+void pcfiic_attach(struct pcfiic_softc *, i2c_addr_t, u_int8_t, int,
void (*)(struct device *, struct i2cbus_attach_args *, void *),
void *);
int pcfiic_intr(void *);