diff options
-rw-r--r-- | sys/arch/sparc64/dev/pcfiic_ebus.c | 36 | ||||
-rw-r--r-- | sys/dev/ic/pcf8584.c | 74 | ||||
-rw-r--r-- | sys/dev/ic/pcf8584var.h | 14 |
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 *); |