Fix nxprtc(4) on systems that support i2c repeat-start correctly.
An obscure footnote in the datasheets for the PCx2127, PCx2129, and PCF8523 rtc chips states that the chips do not support i2c repeat-start operations. When the driver was originally written and tested, the i2c bus on that system also didn't support repeat-start and just quietly turned repeat-start operations into a stop-then-start, making it appear that the nxprtc driver was working properly. The repeat-start situation only comes up on reads, so instead of using the standard iicdev_readfrom(), use a local nxprtc_readfrom(), which is just a cut-and-pasted copy of iicdev_readfrom(), modified to send two separate start-data-stop sequences instead of using repeat-start.
This commit is contained in:
parent
64ee41ff55
commit
264fbd07fe
@ -235,11 +235,44 @@ static nxprtc_compat_data compat_data[] = {
|
||||
{NULL, TYPE_NONE},
|
||||
};
|
||||
|
||||
static int
|
||||
nxprtc_readfrom(device_t slavedev, uint8_t regaddr, void *buffer,
|
||||
uint16_t buflen, int waithow)
|
||||
{
|
||||
struct iic_msg msg;
|
||||
int err;
|
||||
uint8_t slaveaddr;
|
||||
|
||||
/*
|
||||
* Two transfers back to back with a stop and start between them; first we
|
||||
* write the address-within-device, then we read from the device. This
|
||||
* is used instead of the standard iicdev_readfrom() because some of the
|
||||
* chips we service don't support i2c repeat-start operations (grrrrr)
|
||||
* so we do two completely separate transfers with a full stop between.
|
||||
*/
|
||||
slaveaddr = iicbus_get_addr(slavedev);
|
||||
|
||||
msg.slave = slaveaddr;
|
||||
msg.flags = IIC_M_WR;
|
||||
msg.len = 1;
|
||||
msg.buf = ®addr;
|
||||
|
||||
if ((err = iicbus_transfer_excl(slavedev, &msg, 1, waithow)) != 0)
|
||||
return (err);
|
||||
|
||||
msg.slave = slaveaddr;
|
||||
msg.flags = IIC_M_RD;
|
||||
msg.len = buflen;
|
||||
msg.buf = buffer;
|
||||
|
||||
return (iicbus_transfer_excl(slavedev, &msg, 1, waithow));
|
||||
}
|
||||
|
||||
static int
|
||||
read_reg(struct nxprtc_softc *sc, uint8_t reg, uint8_t *val)
|
||||
{
|
||||
|
||||
return (iicdev_readfrom(sc->dev, reg, val, sizeof(*val), WAITFLAGS));
|
||||
return (nxprtc_readfrom(sc->dev, reg, val, sizeof(*val), WAITFLAGS));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -272,7 +305,7 @@ read_timeregs(struct nxprtc_softc *sc, struct time_regs *tregs, uint8_t *tmr)
|
||||
if (tmr1 != tmr2)
|
||||
continue;
|
||||
}
|
||||
if ((err = iicdev_readfrom(sc->dev, sc->secaddr, tregs,
|
||||
if ((err = nxprtc_readfrom(sc->dev, sc->secaddr, tregs,
|
||||
sizeof(*tregs), WAITFLAGS)) != 0)
|
||||
break;
|
||||
} while (sc->use_timer && tregs->sec != sec);
|
||||
|
Loading…
Reference in New Issue
Block a user