/** * twl_scan - scans the i2c bus for sub modules * @dev: the twl device * * TWL devices don't just have one i2c slave address, rather they have up to * 5 other addresses, each is for separate modules within the device. This * function scans the bus for 4 possible sub-devices and stores the info * internally. * */ static void twl_scan(void *dev) { struct twl_softc *sc; unsigned i; uint8_t devs[TWL_MAX_SUBADDRS]; uint8_t base = TWL_CHIP_ID0; sc = device_get_softc((device_t)dev); memset(devs, TWL_INVALID_CHIP_ID, TWL_MAX_SUBADDRS); /* Try each of the addresses (0x48, 0x49, 0x4a & 0x4b) to determine which * sub modules we have. */ for (i = 0; i < TWL_MAX_SUBADDRS; i++) { if (twl_test_present(sc, (base + i)) == 0) { devs[i] = (base + i); device_printf(sc->sc_dev, "Found (sub)device at 0x%02x\n", (base + i)); } } TWL_LOCK(sc); memcpy(sc->sc_subaddr_map, devs, TWL_MAX_SUBADDRS); TWL_UNLOCK(sc); /* Finished with the interrupt hook */ config_intrhook_disestablish(&sc->sc_scan_hook); }
/** * twl_write - writes one or more registers to the TWL device * @sc: device soft context * @nsub: the sub-module to read from * @reg: the register offset within the module to read * @buf: data to write * @cnt: the number of bytes to write * * Writes one or more registers. * * LOCKING: * Expects the TWL lock to be held. * * RETURNS: * Zero on success or a negative error code on failure. */ int twl_write(device_t dev, uint8_t nsub, uint8_t reg, uint8_t *buf, uint16_t cnt) { struct twl_softc *sc; struct iic_msg msg; uint8_t addr; uint8_t tmp_buf[TWL_MAX_IIC_DATA_SIZE + 1]; int rc; if (cnt > TWL_MAX_IIC_DATA_SIZE) return (ENOMEM); /* Set the register address as the first byte */ tmp_buf[0] = reg; memcpy(&tmp_buf[1], buf, cnt); sc = device_get_softc(dev); TWL_LOCK(sc); addr = sc->sc_subaddr_map[nsub]; if (addr == TWL_INVALID_CHIP_ID) { TWL_UNLOCK(sc); return (EIO); } /* Setup the transfer and execute it */ msg.slave = addr; msg.flags = IIC_M_WR; msg.len = cnt + 1; msg.buf = tmp_buf; TWL_UNLOCK(sc); rc = iicbus_transfer(dev, &msg, 1); if (rc != 0) { device_printf(sc->sc_dev, "iicbus write failed (adr:0x%02x, reg:0x%02x)\n", addr, reg); return (EIO); } return (0); }
/** * twl_read - read one or more registers from the TWL device * @sc: device soft context * @nsub: the sub-module to read from * @reg: the register offset within the module to read * @buf: buffer to store the bytes in * @cnt: the number of bytes to read * * Reads one or registers and stores the result in the suppled buffer. * * LOCKING: * Expects the TWL lock to be held. * * RETURNS: * Zero on success or a negative error code on failure. */ int twl_read(device_t dev, uint8_t nsub, uint8_t reg, uint8_t *buf, uint16_t cnt) { struct twl_softc *sc; struct iic_msg msg[2]; uint8_t addr; int rc; sc = device_get_softc(dev); TWL_LOCK(sc); addr = sc->sc_subaddr_map[nsub]; if (addr == TWL_INVALID_CHIP_ID) { TWL_UNLOCK(sc); return (EIO); } /* Set the address to read from */ msg[0].slave = addr; msg[0].flags = IIC_M_WR | IIC_M_NOSTOP; msg[0].len = 1; msg[0].buf = ® /* Read the data back */ msg[1].slave = addr; msg[1].flags = IIC_M_RD; msg[1].len = cnt; msg[1].buf = buf; TWL_UNLOCK(sc); rc = iicbus_transfer(dev, msg, 2); if (rc != 0) { device_printf(dev, "iicbus read failed (adr:0x%02x, reg:0x%02x)\n", addr, reg); return (EIO); } return (0); }