Date: Mon, 15 Jul 2019 21:40:58 +0000 (UTC) From: Ian Lepore <ian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r350015 - head/sys/dev/iicbus Message-ID: <201907152140.x6FLewnE063649@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: ian Date: Mon Jul 15 21:40:58 2019 New Revision: 350015 URL: https://svnweb.freebsd.org/changeset/base/350015 Log: 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. Modified: head/sys/dev/iicbus/nxprtc.c Modified: head/sys/dev/iicbus/nxprtc.c ============================================================================== --- head/sys/dev/iicbus/nxprtc.c Mon Jul 15 21:26:55 2019 (r350014) +++ head/sys/dev/iicbus/nxprtc.c Mon Jul 15 21:40:58 2019 (r350015) @@ -236,10 +236,43 @@ static nxprtc_compat_data compat_data[] = { }; 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_reg 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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201907152140.x6FLewnE063649>