diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2005-12-13 19:21:46 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2005-12-13 19:21:46 +0000 |
commit | 686708f227fab1dd0666f0fcce4dc651f4479d04 (patch) | |
tree | 05c0702208a4f90b15c30258f1388526e061a51f /sys | |
parent | 58e72beb4fe8203520b4d7b7c081d9b1acdca444 (diff) |
Deal with ki2c(4) controllers with multiple i2c busses.
tested by xsa@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/macppc/dev/ki2c.c | 63 | ||||
-rw-r--r-- | sys/arch/macppc/dev/ki2cvar.h | 10 |
2 files changed, 55 insertions, 18 deletions
diff --git a/sys/arch/macppc/dev/ki2c.c b/sys/arch/macppc/dev/ki2c.c index fbd4f656744..a8a7e118b55 100644 --- a/sys/arch/macppc/dev/ki2c.c +++ b/sys/arch/macppc/dev/ki2c.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ki2c.c,v 1.10 2005/11/19 21:46:41 brad Exp $ */ +/* $OpenBSD: ki2c.c,v 1.11 2005/12/13 19:21:45 kettenis Exp $ */ /* $NetBSD: ki2c.c,v 1.1 2003/12/27 02:19:34 grant Exp $ */ /*- @@ -40,6 +40,7 @@ int ki2c_match(struct device *, void *, void *); void ki2c_attach(struct device *, struct device *, void *); +void ki2c_attach_bus(struct ki2c_softc *, struct ki2c_bus *, int); inline u_int ki2c_readreg(struct ki2c_softc *, int); inline void ki2c_writereg(struct ki2c_softc *, int, u_int); u_int ki2c_getmode(struct ki2c_softc *); @@ -85,9 +86,9 @@ ki2c_attach(struct device *parent, struct device *self, void *aux) { struct ki2c_softc *sc = (struct ki2c_softc *)self; struct confargs *ca = aux; - struct maci2cbus_attach_args iba; int node = ca->ca_node; - int rate; + int rate, count = 0; + char name[32]; ca->ca_reg[0] += ca->ca_baseaddr; @@ -117,13 +118,43 @@ ki2c_attach(struct device *parent, struct device *self, void *aux) lockinit(&sc->sc_buslock, PZERO, sc->sc_dev.dv_xname, 0, 0); ki2c_writereg(sc, IER,I2C_INT_DATA|I2C_INT_ADDR|I2C_INT_STOP); - sc->sc_i2c_tag.ic_cookie = sc; - sc->sc_i2c_tag.ic_acquire_bus = ki2c_i2c_acquire_bus; - sc->sc_i2c_tag.ic_release_bus = ki2c_i2c_release_bus; - sc->sc_i2c_tag.ic_exec = ki2c_i2c_exec; + for (node = OF_child(ca->ca_node); node; node = OF_peer(node)) { + if (OF_getprop(node, "name", &name, sizeof name) > 0) { + if (strcmp(name, "i2c-bus") == 0) { + ki2c_attach_bus(sc, &sc->sc_bus[count], node); + if (++count >= KI2C_MAX_BUSSES) + break; + } + } + } + + /* + * If we didn't find any i2c-bus nodes, there is only a single + * i2c bus. + */ + + if (count == 0) + ki2c_attach_bus(sc, &sc->sc_bus[0], ca->ca_node); +} + +void +ki2c_attach_bus(struct ki2c_softc *sc, struct ki2c_bus *bus, int node) +{ + struct maci2cbus_attach_args iba; + u_int32_t reg; + + if (OF_getprop(node, "reg", ®, sizeof reg) != sizeof reg) + return; + + bus->sc = sc; + bus->i2c_tag.ic_cookie = bus; + bus->i2c_tag.ic_acquire_bus = ki2c_i2c_acquire_bus; + bus->i2c_tag.ic_release_bus = ki2c_i2c_release_bus; + bus->i2c_tag.ic_exec = ki2c_i2c_exec; + bus->reg = reg; iba.iba_node = node; - iba.iba_tag = &sc->sc_i2c_tag; + iba.iba_tag = &bus->i2c_tag; config_found(&sc->sc_dev, &iba, NULL); } @@ -317,24 +348,24 @@ ki2c_write(struct ki2c_softc *sc, int addr, int subaddr, const void *data, int l int ki2c_i2c_acquire_bus(void *cookie, int flags) { - struct ki2c_softc *sc = cookie; + struct ki2c_bus *bus = cookie; - return (lockmgr(&sc->sc_buslock, LK_EXCLUSIVE, NULL)); + return (lockmgr(&bus->sc->sc_buslock, LK_EXCLUSIVE, NULL)); } void ki2c_i2c_release_bus(void *cookie, int flags) { - struct ki2c_softc *sc = cookie; + struct ki2c_bus *bus = cookie; - (void) lockmgr(&sc->sc_buslock, LK_RELEASE, NULL); + (void) lockmgr(&bus->sc->sc_buslock, LK_RELEASE, NULL); } int ki2c_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) { - struct ki2c_softc *sc = cookie; + struct ki2c_bus *bus = cookie; u_int mode = I2C_STDSUBMODE; u_int8_t cmd = 0; @@ -349,14 +380,14 @@ ki2c_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, if (cmdlen > 0) cmd = *(u_int8_t *)cmdbuf; - ki2c_setmode(sc, mode, addr & 0x80); + ki2c_setmode(bus->sc, mode, bus->reg || addr & 0x80); addr &= 0x7f; if (I2C_OP_READ_P(op)) { - if (ki2c_read(sc, (addr << 1), cmd, buf, len) != 0) + if (ki2c_read(bus->sc, (addr << 1), cmd, buf, len) != 0) return (EIO); } else { - if (ki2c_write(sc, (addr << 1), cmd, buf, len) != 0) + if (ki2c_write(bus->sc, (addr << 1), cmd, buf, len) != 0) return (EIO); } return (0); diff --git a/sys/arch/macppc/dev/ki2cvar.h b/sys/arch/macppc/dev/ki2cvar.h index 378bac8cc91..4a8c39b559d 100644 --- a/sys/arch/macppc/dev/ki2cvar.h +++ b/sys/arch/macppc/dev/ki2cvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ki2cvar.h,v 1.3 2005/11/14 22:29:35 deraadt Exp $ */ +/* $OpenBSD: ki2cvar.h,v 1.4 2005/12/13 19:21:45 kettenis Exp $ */ /*- * Copyright (c) 2001 Tsubai Masanari. All rights reserved. @@ -82,14 +82,20 @@ #define I2C_READING 0x02 #define I2C_ERROR 0x04 +#define KI2C_MAX_BUSSES 2 + struct ki2c_softc { struct device sc_dev; paddr_t sc_paddr; u_char *sc_reg; int sc_regstep; - struct i2c_controller sc_i2c_tag; struct lock sc_buslock; + struct ki2c_bus { + struct ki2c_softc *sc; + struct i2c_controller i2c_tag; + u_int32_t reg; + } sc_bus[KI2C_MAX_BUSSES]; int sc_flags; u_char *sc_data; |