svn commit: r287820 - head/usr.sbin/i2c

Zbigniew Bodek zbb at FreeBSD.org
Tue Sep 15 11:21:17 UTC 2015


Author: zbb
Date: Tue Sep 15 11:21:16 2015
New Revision: 287820
URL: https://svnweb.freebsd.org/changeset/base/287820

Log:
  Perform I2C transmission in a single burst when mode is "none" or not set
  
  Some more automated I2C controllers cannot explicitly create
  START/STOP/etc. conditions on the bus.
  Instead, the correct condition is set automatically according
  to the pending transfer status.
  This particular behavior can cause trouble if some I2C slave
  requires sending address offset within the chip followed by
  the actual data or command. In that case we cannot assume that
  the driver will not STOP immediately after sending
  offset.
  
  To avoid that, do not split offset transfer from data transfer
  for default transmission modes and do exactly that if requested
  in command line (stop-start and repeated-start modes).
  This more generic approach should cover special cases like
  the one described.
  
  Reviewed by:   imp
  Submitted by:  Marcin Mazurek <mma at semihalf.com>
  Obtained from: Semihalf

Modified:
  head/usr.sbin/i2c/i2c.c

Modified: head/usr.sbin/i2c/i2c.c
==============================================================================
--- head/usr.sbin/i2c/i2c.c	Tue Sep 15 10:57:16 2015	(r287819)
+++ head/usr.sbin/i2c/i2c.c	Tue Sep 15 11:21:16 2015	(r287820)
@@ -280,9 +280,6 @@ i2c_write(char *dev, struct options i2c_
 		err(1, "open failed");
 	}
 
-	/*
-	 * Write offset where the data will go
-	 */
 	cmd.slave = i2c_opt.addr;
 	error = ioctl(fd, I2CSTART, &cmd);
 	if (error == -1) {
@@ -297,20 +294,24 @@ i2c_write(char *dev, struct options i2c_
 			err_msg = "error: offset malloc";
 			goto err1;
 		}
+	}
 
-		cmd.count = bufsize;
-		cmd.buf = buf;
-		error = ioctl(fd, I2CWRITE, &cmd);
-		free(buf);
-		if (error == -1) {
-			err_msg = "ioctl: error when write offset";
-			goto err1;
+	switch(i2c_opt.mode) {
+	case I2C_MODE_STOP_START:
+		/*
+		 * Write offset where the data will go
+		 */
+		if (i2c_opt.width) {
+			cmd.count = bufsize;
+			cmd.buf = buf;
+			error = ioctl(fd, I2CWRITE, &cmd);
+			free(buf);
+			if (error == -1) {
+				err_msg = "ioctl: error when write offset";
+				goto err1;
+			}
 		}
-	}
 
-	/* Mode - stop start */
-	if (i2c_opt.mode == I2C_MODE_STOP_START) {
-		cmd.slave = i2c_opt.addr;
 		error = ioctl(fd, I2CSTOP, &cmd);
 		if (error == -1) {
 			err_msg = "ioctl: error sending stop condition";
@@ -322,9 +323,35 @@ i2c_write(char *dev, struct options i2c_
 			err_msg = "ioctl: error sending start condition";
 			goto err1;
 		}
-	}
-	/* Mode - repeated start */
-	if (i2c_opt.mode == I2C_MODE_REPEATED_START) {
+
+		/*
+		 * Write the data
+		 */
+		cmd.count = i2c_opt.count;
+		cmd.buf = i2c_buf;
+		cmd.last = 0;
+		error = ioctl(fd, I2CWRITE, &cmd);
+		if (error == -1) {
+			err_msg = "ioctl: error when write";
+			goto err1;
+		}
+		break;
+
+	case I2C_MODE_REPEATED_START:
+		/*
+		 * Write offset where the data will go
+		 */
+		if (i2c_opt.width) {
+			cmd.count = bufsize;
+			cmd.buf = buf;
+			error = ioctl(fd, I2CWRITE, &cmd);
+			free(buf);
+			if (error == -1) {
+				err_msg = "ioctl: error when write offset";
+				goto err1;
+			}
+		}
+
 		cmd.slave = i2c_opt.addr;
 		error = ioctl(fd, I2CRPTSTART, &cmd);
 		if (error == -1) {
@@ -332,18 +359,42 @@ i2c_write(char *dev, struct options i2c_
 			    "condition";
 			goto err1;
 		}
-	}
 
-	/*
-	 * Write the data
-	 */
-	cmd.count = i2c_opt.count;
-	cmd.buf = i2c_buf;
-	cmd.last = 0;
-	error = ioctl(fd, I2CWRITE, &cmd);
-	if (error == -1) {
-		err_msg = "ioctl: error when write";
-		goto err1;
+		/*
+		 * Write the data
+		 */
+		cmd.count = i2c_opt.count;
+		cmd.buf = i2c_buf;
+		cmd.last = 0;
+		error = ioctl(fd, I2CWRITE, &cmd);
+		if (error == -1) {
+			err_msg = "ioctl: error when write";
+			goto err1;
+		}
+		break;
+
+	case I2C_MODE_NONE: /* fall through */
+	default:		
+		buf = realloc(buf, bufsize + i2c_opt.count);
+		if (buf == NULL) {
+			err_msg = "error: data malloc";
+			goto err1;
+		}
+
+		memcpy(buf + bufsize, i2c_buf, i2c_opt.count);
+		/*
+		 * Write offset and data
+		 */
+		cmd.count = bufsize + i2c_opt.count;
+		cmd.buf = buf;
+		cmd.last = 0;
+		error = ioctl(fd, I2CWRITE, &cmd);
+		free(buf);
+		if (error == -1) {
+			err_msg = "ioctl: error when write";
+			goto err1;
+		}
+		break;
 	}
 	cmd.slave = i2c_opt.addr;
 	error = ioctl(fd, I2CSTOP, &cmd);


More information about the svn-src-head mailing list