Support reads of more than 32 bytes in a single xfer.
This commit is contained in:
parent
8b42e4de60
commit
03b6843e43
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: rk_i2c.c,v 1.5 2019/09/18 12:49:34 tnn Exp $ */
|
||||
/* $NetBSD: rk_i2c.c,v 1.6 2019/11/08 00:35:16 jmcneill Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca>
|
||||
|
@ -28,7 +28,7 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__KERNEL_RCSID(0, "$NetBSD: rk_i2c.c,v 1.5 2019/09/18 12:49:34 tnn Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: rk_i2c.c,v 1.6 2019/11/08 00:35:16 jmcneill Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
|
@ -284,7 +284,7 @@ rk_i2c_write(struct rk_i2c_softc *sc, i2c_addr_t addr, const uint8_t *cmd,
|
|||
static int
|
||||
rk_i2c_read(struct rk_i2c_softc *sc, i2c_addr_t addr,
|
||||
const uint8_t *cmd, size_t cmdlen, uint8_t *buf,
|
||||
size_t buflen, int flags, bool send_start)
|
||||
size_t buflen, int flags, bool send_start, bool last_ack)
|
||||
{
|
||||
uint32_t rxdata[8];
|
||||
uint32_t con, mrxaddr, mrxraddr;
|
||||
|
@ -296,24 +296,27 @@ rk_i2c_read(struct rk_i2c_softc *sc, i2c_addr_t addr,
|
|||
if (cmdlen > 3)
|
||||
return EINVAL;
|
||||
|
||||
mode = RKI2C_CON_I2C_MODE_RTX;
|
||||
con = RKI2C_CON_I2C_EN | RKI2C_CON_ACK | __SHIFTIN(mode, RKI2C_CON_I2C_MODE);
|
||||
mode = send_start ? RKI2C_CON_I2C_MODE_RTX : RKI2C_CON_I2C_MODE_RX;
|
||||
con = RKI2C_CON_I2C_EN | __SHIFTIN(mode, RKI2C_CON_I2C_MODE);
|
||||
WR4(sc, RKI2C_CON, con);
|
||||
|
||||
if (send_start && (error = rk_i2c_start(sc)) != 0)
|
||||
return error;
|
||||
|
||||
mrxaddr = __SHIFTIN((addr << 1) | 1, RKI2C_MRXADDR_SADDR) |
|
||||
RKI2C_MRXADDR_ADDLVLD;
|
||||
WR4(sc, RKI2C_MRXADDR, mrxaddr);
|
||||
for (n = 0, mrxraddr = 0; n < cmdlen; n++) {
|
||||
mrxraddr |= cmd[n] << (n * 8);
|
||||
mrxraddr |= (RKI2C_MRXRADDR_ADDLVLD << n);
|
||||
if (send_start) {
|
||||
mrxaddr = __SHIFTIN((addr << 1) | 1, RKI2C_MRXADDR_SADDR) |
|
||||
RKI2C_MRXADDR_ADDLVLD;
|
||||
WR4(sc, RKI2C_MRXADDR, mrxaddr);
|
||||
for (n = 0, mrxraddr = 0; n < cmdlen; n++) {
|
||||
mrxraddr |= cmd[n] << (n * 8);
|
||||
mrxraddr |= (RKI2C_MRXRADDR_ADDLVLD << n);
|
||||
}
|
||||
WR4(sc, RKI2C_MRXRADDR, mrxraddr);
|
||||
}
|
||||
WR4(sc, RKI2C_MRXRADDR, mrxraddr);
|
||||
|
||||
/* Acknowledge last byte read */
|
||||
con |= RKI2C_CON_ACK;
|
||||
if (last_ack) {
|
||||
con |= RKI2C_CON_ACK;
|
||||
}
|
||||
WR4(sc, RKI2C_CON, con);
|
||||
|
||||
/* Receive data. Slave address goes in the lower 8 bits of MRXADDR */
|
||||
|
@ -321,8 +324,14 @@ rk_i2c_read(struct rk_i2c_softc *sc, i2c_addr_t addr,
|
|||
if ((error = rk_i2c_wait(sc, RKI2C_IPD_MBRFIPD)) != 0)
|
||||
return error;
|
||||
|
||||
#if 0
|
||||
bus_space_read_region_4(sc->sc_bst, sc->sc_bsh, RKI2C_RXDATA(0),
|
||||
rxdata, howmany(buflen, 4));
|
||||
#else
|
||||
for (n = 0; n < roundup(buflen, 4); n += 4)
|
||||
rxdata[n/4] = RD4(sc, RKI2C_RXDATA(n/4));
|
||||
#endif
|
||||
|
||||
memcpy(buf, rxdata, buflen);
|
||||
|
||||
return 0;
|
||||
|
@ -339,7 +348,19 @@ rk_i2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
|
|||
KASSERT(mutex_owned(&sc->sc_lock));
|
||||
|
||||
if (I2C_OP_READ_P(op)) {
|
||||
error = rk_i2c_read(sc, addr, cmdbuf, cmdlen, buf, buflen, flags, send_start);
|
||||
uint8_t *databuf = buf;
|
||||
while (buflen > 0) {
|
||||
const size_t datalen = uimin(buflen, 32);
|
||||
const bool last_ack = datalen == buflen;
|
||||
error = rk_i2c_read(sc, addr, cmdbuf, cmdlen, databuf, datalen, flags, send_start, last_ack);
|
||||
if (error != 0)
|
||||
break;
|
||||
databuf += datalen;
|
||||
buflen -= datalen;
|
||||
send_start = false;
|
||||
cmdbuf = NULL;
|
||||
cmdlen = 0;
|
||||
}
|
||||
} else {
|
||||
error = rk_i2c_write(sc, addr, cmdbuf, cmdlen, buf, buflen, flags, send_start);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue