static void kiic_intr(void *xsc) { struct kiic_softc *sc = xsc; u_int isr; uint32_t x; mtx_lock(&sc->sc_mutex); isr = kiic_readreg(sc, ISR); if (isr & I2C_INT_ADDR) { sc->sc_flags |= I2C_SELECTED; if (sc->sc_flags & I2C_READING) { if (sc->sc_resid > 1) { x = kiic_readreg(sc, CONTROL); x |= I2C_CT_AAK; kiic_writereg(sc, CONTROL, x); } } else { kiic_writereg(sc, DATA, *sc->sc_data++); sc->sc_resid--; } } if (isr & I2C_INT_DATA) { if (sc->sc_flags & I2C_READING) { if (sc->sc_resid > 0) { *sc->sc_data++ = kiic_readreg(sc, DATA); sc->sc_resid--; } if (sc->sc_resid == 0) /* done */ kiic_writereg(sc, CONTROL, 0); } else { if (sc->sc_resid == 0) { x = kiic_readreg(sc, CONTROL); x |= I2C_CT_STOP; kiic_writereg(sc, CONTROL, x); } else { kiic_writereg(sc, DATA, *sc->sc_data++); sc->sc_resid--; } } } if (isr & I2C_INT_STOP) { kiic_writereg(sc, CONTROL, 0); sc->sc_flags &= ~I2C_SELECTED; wakeup(sc->sc_dev); } kiic_writereg(sc, ISR, isr); mtx_unlock(&sc->sc_mutex); }
int kiic_start(struct kiic_softc *sc, int addr, int subaddr, void *data, int len) { int rw = (sc->sc_flags & I2C_READING) ? 1 : 0; int timo, x; KASSERT((addr & 1) == 0); sc->sc_data = data; sc->sc_resid = len; sc->sc_flags |= I2C_BUSY; timo = 1000 + len * 200; /* XXX TAS3001 sometimes takes 50ms to finish writing registers. */ /* if (addr == 0x68) */ timo += 100000; kiic_writereg(sc, ADDR, addr | rw); kiic_writereg(sc, SUBADDR, subaddr); x = kiic_readreg(sc, CONTROL) | I2C_CT_ADDR; kiic_writereg(sc, CONTROL, x); if (kiic_poll(sc, timo)) return (-1); if (sc->sc_flags & I2C_ERROR) { printf("I2C_ERROR\n"); return (-1); } if (sc->sc_resid != 0) return (-1); return (0); }
static void kiic_setspeed(struct kiic_softc *sc, u_int speed) { u_int x; KASSERT((speed & ~I2C_SPEED) == 0, ("bad speed")); x = kiic_readreg(sc, MODE); x &= ~I2C_SPEED; x |= speed; kiic_writereg(sc, MODE, x); }
static void kiic_setport(struct kiic_softc *sc, u_int port) { u_int x; KASSERT(port == 1 || port == 0, ("bad port")); x = kiic_readreg(sc, MODE); x &= ~I2C_PORT; x |= (port << 4); kiic_writereg(sc, MODE, x); }
static void kiic_setmode(struct kiic_softc *sc, u_int mode) { u_int x; KASSERT((mode & ~I2C_MODE) == 0, ("bad mode")); x = kiic_readreg(sc, MODE); x &= ~I2C_MODE; x |= mode; kiic_writereg(sc, MODE, x); }
int kiic_poll(struct kiic_softc *sc, int timo) { while (sc->sc_flags & I2C_BUSY) { if (kiic_readreg(sc, ISR)) kiic_intr(sc); timo -= 100; if (timo < 0) { printf("i2c_poll: timeout\n"); return (-1); } delay(100); } return (0); }
void kiic_setmode(struct kiic_softc *sc, u_int mode, u_int bus) { u_int x; KASSERT((mode & ~I2C_MODE) == 0); x = kiic_readreg(sc, MODE); x &= ~(I2C_MODE); if (bus) x |= I2C_BUS1; else x &= ~I2C_BUS1; x |= mode; kiic_writereg(sc, MODE, x); }
static int kiic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) { struct kiic_softc *sc; int i, x, timo, err; uint16_t addr; uint8_t subaddr; sc = device_get_softc(dev); timo = 100; subaddr = 0; mtx_lock(&sc->sc_mutex); if (sc->sc_flags & I2C_BUSY) mtx_sleep(dev, &sc->sc_mutex, 0, "kiic", timo); if (sc->sc_flags & I2C_BUSY) { mtx_unlock(&sc->sc_mutex); return (ETIMEDOUT); } sc->sc_flags = I2C_BUSY; /* Clear pending interrupts, and reset controller */ kiic_writereg(sc, ISR, kiic_readreg(sc, ISR)); kiic_writereg(sc, STATUS, 0); for (i = 0; i < nmsgs; i++) { if (msgs[i].flags & IIC_M_NOSTOP) { if (msgs[i+1].flags & IIC_M_RD) kiic_setmode(sc, I2C_COMBMODE); else kiic_setmode(sc, I2C_STDSUBMODE); KASSERT(msgs[i].len == 1, ("oversize I2C message")); subaddr = msgs[i].buf[0]; i++; } else { kiic_setmode(sc, I2C_STDMODE); } sc->sc_data = msgs[i].buf; sc->sc_resid = msgs[i].len; sc->sc_flags = I2C_BUSY; addr = msgs[i].slave; timo = 1000 + sc->sc_resid * 200; timo += 100000; if (msgs[i].flags & IIC_M_RD) { sc->sc_flags |= I2C_READING; addr |= 1; } addr |= sc->sc_i2c_base; kiic_setport(sc, (addr & 0x100) >> 8); kiic_writereg(sc, ADDR, addr & 0xff); kiic_writereg(sc, SUBADDR, subaddr); x = kiic_readreg(sc, CONTROL) | I2C_CT_ADDR; kiic_writereg(sc, CONTROL, x); err = mtx_sleep(dev, &sc->sc_mutex, 0, "kiic", timo); msgs[i].len -= sc->sc_resid; if ((sc->sc_flags & I2C_ERROR) || err == EWOULDBLOCK) { device_printf(sc->sc_dev, "I2C error\n"); sc->sc_flags = 0; mtx_unlock(&sc->sc_mutex); return (EIO); } } sc->sc_flags = 0; mtx_unlock(&sc->sc_mutex); return (0); }
static int kiic_attach(device_t self) { struct kiic_softc *sc = device_get_softc(self); int rid, rate; phandle_t node; char name[64]; bzero(sc, sizeof(*sc)); sc->sc_dev = self; node = ofw_bus_get_node(self); if (node == 0 || node == -1) { return (EINVAL); } rid = 0; sc->sc_reg = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->sc_reg == NULL) { return (ENOMEM); } if (OF_getencprop(node, "AAPL,i2c-rate", &rate, 4) != 4) { device_printf(self, "cannot get i2c-rate\n"); return (ENXIO); } if (OF_getencprop(node, "AAPL,address-step", &sc->sc_regstep, 4) != 4) { device_printf(self, "unable to find i2c address step\n"); return (ENXIO); } /* * Some Keywest I2C devices have their children attached directly * underneath them. Some have a single 'iicbus' child with the * devices underneath that. Sort this out, and make sure that the * OFW I2C layer has the correct node. * * Note: the I2C children of the Uninorth bridges have two ports. * In general, the port is designated in the 9th bit of the I2C * address. However, for kiic devices with children attached below * an i2c-bus node, the port is indicated in the 'reg' property * of the i2c-bus node. */ sc->sc_node = node; node = OF_child(node); if (OF_getprop(node, "name", name, sizeof(name)) > 0) { if (strcmp(name,"i2c-bus") == 0) { phandle_t reg; if (OF_getprop(node, "reg", ®, sizeof(reg)) > 0) sc->sc_i2c_base = reg << 8; sc->sc_node = node; } } mtx_init(&sc->sc_mutex, "kiic", NULL, MTX_DEF); sc->sc_irq = bus_alloc_resource_any(self, SYS_RES_IRQ, &sc->sc_irqrid, RF_ACTIVE); bus_setup_intr(self, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE, NULL, kiic_intr, sc, &sc->sc_ih); kiic_writereg(sc, ISR, kiic_readreg(sc, ISR)); kiic_writereg(sc, STATUS, 0); kiic_writereg(sc, IER, 0); kiic_setmode(sc, I2C_STDMODE); kiic_setspeed(sc, I2C_100kHz); /* XXX rate */ kiic_writereg(sc, IER, I2C_INT_DATA | I2C_INT_ADDR | I2C_INT_STOP); if (bootverbose) device_printf(self, "Revision: %02X\n", kiic_readreg(sc, REV)); /* Add the IIC bus layer */ sc->sc_iicbus = device_add_child(self, "iicbus", -1); return (bus_generic_attach(self)); }
int kiic_intr(struct kiic_softc *sc) { u_int isr, x; isr = kiic_readreg(sc, ISR); if (isr & I2C_INT_ADDR) { #if 0 if ((kiic_readreg(sc, STATUS) & I2C_ST_LASTAAK) == 0) { /* No slave responded. */ sc->sc_flags |= I2C_ERROR; goto out; } #endif if (sc->sc_flags & I2C_READING) { if (sc->sc_resid > 1) { x = kiic_readreg(sc, CONTROL); x |= I2C_CT_AAK; kiic_writereg(sc, CONTROL, x); } } else { kiic_writereg(sc, DATA, *sc->sc_data++); sc->sc_resid--; } } if (isr & I2C_INT_DATA) { if (sc->sc_flags & I2C_READING) { *sc->sc_data++ = kiic_readreg(sc, DATA); sc->sc_resid--; if (sc->sc_resid == 0) { /* Completed */ kiic_writereg(sc, CONTROL, 0); goto out; } } else { #if 0 if ((kiic_readreg(sc, STATUS) & I2C_ST_LASTAAK) == 0) { /* No slave responded. */ sc->sc_flags |= I2C_ERROR; goto out; } #endif if (sc->sc_resid == 0) { x = kiic_readreg(sc, CONTROL) | I2C_CT_STOP; kiic_writereg(sc, CONTROL, x); } else { kiic_writereg(sc, DATA, *sc->sc_data++); sc->sc_resid--; } } } out: if (isr & I2C_INT_STOP) { kiic_writereg(sc, CONTROL, 0); sc->sc_flags &= ~I2C_BUSY; } kiic_writereg(sc, ISR, isr); return (1); }
u_int kiic_getspeed(struct kiic_softc *sc) { return kiic_readreg(sc, MODE) & I2C_SPEED; }
u_int kiic_getmode(struct kiic_softc *sc) { return kiic_readreg(sc, MODE) & I2C_MODE; }