Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Sep 2017 17:01:27 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r323446 - stable/11/sys/dev/iicbus
Message-ID:  <201709111701.v8BH1RKP030583@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ian
Date: Mon Sep 11 17:01:26 2017
New Revision: 323446
URL: https://svnweb.freebsd.org/changeset/base/323446

Log:
  MFC r321583, r321584:
  
  Add a pair of convenience routines for doing simple "register" read/writes
  on i2c devices, where the "register" can be any length.
  
  Add support for tracking nested calls to iicbus_request/release_bus().
  Usually it is sufficient to use iicbus_transfer_excl(), or one of the
  higher-level convenience functions that use it, to reserve the bus for the
  duration of each register access.  Occasionally it is important that a
  series of accesses or read-modify-write operations must be done without any
  other intervening access to the device, to prevent corrupting state.

Modified:
  stable/11/sys/dev/iicbus/iicbus.h
  stable/11/sys/dev/iicbus/iiconf.c
  stable/11/sys/dev/iicbus/iiconf.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/dev/iicbus/iicbus.h
==============================================================================
--- stable/11/sys/dev/iicbus/iicbus.h	Mon Sep 11 15:59:20 2017	(r323445)
+++ stable/11/sys/dev/iicbus/iicbus.h	Mon Sep 11 17:01:26 2017	(r323446)
@@ -39,6 +39,7 @@ struct iicbus_softc
 {
 	device_t dev;		/* Myself */
 	device_t owner;		/* iicbus owner device structure */
+	u_int owncount;		/* iicbus ownership nesting count */
 	u_char started;		/* address of the 'started' slave
 				 * 0 if no start condition succeeded */
 	u_char strict;		/* deny operations that violate the

Modified: stable/11/sys/dev/iicbus/iiconf.c
==============================================================================
--- stable/11/sys/dev/iicbus/iiconf.c	Mon Sep 11 15:59:20 2017	(r323445)
+++ stable/11/sys/dev/iicbus/iiconf.c	Mon Sep 11 17:01:26 2017	(r323446)
@@ -113,26 +113,30 @@ iicbus_request_bus(device_t bus, device_t dev, int how
 
 	IICBUS_LOCK(sc);
 
-	while ((error == 0) && (sc->owner != NULL))
+	while (error == 0 && sc->owner != NULL && sc->owner != dev)
 		error = iicbus_poll(sc, how);
 
 	if (error == 0) {
-		sc->owner = dev;
-		/* 
-		 * Drop the lock around the call to the bus driver. 
-		 * This call should be allowed to sleep in the IIC_WAIT case.
-		 * Drivers might also need to grab locks that would cause LOR
-		 * if our lock is held.
-		 */
-		IICBUS_UNLOCK(sc);
-		/* Ask the underlying layers if the request is ok */
-		error = IICBUS_CALLBACK(device_get_parent(bus),
-		    IIC_REQUEST_BUS, (caddr_t)&how);
-		IICBUS_LOCK(sc);
-
-		if (error != 0) {
-			sc->owner = NULL;
-			wakeup_one(sc);
+		++sc->owncount;
+		if (sc->owner == NULL) {
+			sc->owner = dev;
+			/* 
+			 * Drop the lock around the call to the bus driver, it
+			 * should be allowed to sleep in the IIC_WAIT case.
+			 * Drivers might also need to grab locks that would
+			 * cause a LOR if our lock is held.
+			 */
+			IICBUS_UNLOCK(sc);
+			/* Ask the underlying layers if the request is ok */
+			error = IICBUS_CALLBACK(device_get_parent(bus),
+			    IIC_REQUEST_BUS, (caddr_t)&how);
+			IICBUS_LOCK(sc);
+	
+			if (error != 0) {
+				sc->owner = NULL;
+				sc->owncount = 0;
+				wakeup_one(sc);
+			}
 		}
 	}
 
@@ -150,7 +154,6 @@ int
 iicbus_release_bus(device_t bus, device_t dev)
 {
 	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
-	int error;
 
 	IICBUS_LOCK(sc);
 
@@ -159,26 +162,16 @@ iicbus_release_bus(device_t bus, device_t dev)
 		return (IIC_EBUSBSY);
 	}
 
-	/* 
-	 * Drop the lock around the call to the bus driver. 
-	 * This call should be allowed to sleep in the IIC_WAIT case.
-	 * Drivers might also need to grab locks that would cause LOR
-	 * if our lock is held.
-	 */
-	IICBUS_UNLOCK(sc);
-	/* Ask the underlying layers if the release is ok */
-	error = IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL);
-
-	if (error == 0) {
+	if (--sc->owncount == 0) {
+		/* Drop the lock while informing the low-level driver. */
+		IICBUS_UNLOCK(sc);
+		IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL);
 		IICBUS_LOCK(sc);
 		sc->owner = NULL;
-
-		/* wakeup a waiting thread */
 		wakeup_one(sc);
-		IICBUS_UNLOCK(sc);
 	}
-
-	return (error);
+	IICBUS_UNLOCK(sc);
+	return (0);
 }
 
 /*
@@ -469,4 +462,56 @@ iicbus_transfer_gen(device_t dev, struct iic_msg *msgs
 	if (error != 0 && started)
 		iicbus_stop(bus);
 	return (error);
+}
+
+int
+iicdev_readfrom(device_t slavedev, uint8_t regaddr, void *buffer,
+    uint16_t buflen, int waithow)
+{
+	struct iic_msg msgs[2];
+	uint8_t slaveaddr;
+
+	/*
+	 * Two transfers back to back with a repeat-start between them; first we
+	 * write the address-within-device, then we read from the device.
+	 */
+	slaveaddr = iicbus_get_addr(slavedev);
+
+	msgs[0].slave = slaveaddr;
+	msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP;
+	msgs[0].len   = 1;
+	msgs[0].buf   = &regaddr;
+
+	msgs[1].slave = slaveaddr;
+	msgs[1].flags = IIC_M_RD;
+	msgs[1].len   = buflen;
+	msgs[1].buf   = buffer;
+
+	return (iicbus_transfer_excl(slavedev, msgs, nitems(msgs), waithow));
+}
+
+int iicdev_writeto(device_t slavedev, uint8_t regaddr, void *buffer,
+    uint16_t buflen, int waithow)
+{
+	struct iic_msg msgs[2];
+	uint8_t slaveaddr;
+
+	/*
+	 * Two transfers back to back with no stop or start between them; first
+	 * we write the address then we write the data to that address, all in a
+	 * single transfer from two scattered buffers.
+	 */
+	slaveaddr = iicbus_get_addr(slavedev);
+
+	msgs[0].slave = slaveaddr;
+	msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP;
+	msgs[0].len   = 1;
+	msgs[0].buf   = &regaddr;
+
+	msgs[1].slave = slaveaddr;
+	msgs[1].flags = IIC_M_WR | IIC_M_NOSTART;
+	msgs[1].len   = buflen;
+	msgs[1].buf   = buffer;
+
+	return (iicbus_transfer_excl(slavedev, msgs, nitems(msgs), waithow));
 }

Modified: stable/11/sys/dev/iicbus/iiconf.h
==============================================================================
--- stable/11/sys/dev/iicbus/iiconf.h	Mon Sep 11 15:59:20 2017	(r323445)
+++ stable/11/sys/dev/iicbus/iiconf.h	Mon Sep 11 17:01:26 2017	(r323446)
@@ -133,6 +133,16 @@ int iicbus_transfer_excl(device_t bus, struct iic_msg 
     int how);
 int iicbus_transfer_gen(device_t bus, struct iic_msg *msgs, uint32_t nmsgs);
 
+/*
+ * Simple register read/write routines, but the "register" can be any size.
+ * The transfers are done with iicbus_transfer_excl().  Reads use a repeat-start
+ * between sending the address and reading; writes use a single start/stop.
+ */
+int iicdev_readfrom(device_t _slavedev, uint8_t _regaddr, void *_buffer,
+    uint16_t _buflen, int _waithow);
+int iicdev_writeto(device_t _slavedev, uint8_t _regaddr, void *_buffer,
+    uint16_t _buflen, int _waithow);
+
 #define IICBUS_MODVER	1
 #define IICBUS_MINVER	1
 #define IICBUS_MAXVER	1



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201709111701.v8BH1RKP030583>