svn commit: r350015 - head/sys/dev/iicbus

Ian Lepore ian at FreeBSD.org
Mon Jul 15 21:40:58 UTC 2019


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);


More information about the svn-src-all mailing list