All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] - i2c virtual adapter driver for multiplexed busses
@ 2005-05-19  6:24 Brian Kuschak
  2005-05-19  6:24 ` Brian Kuschak
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Brian Kuschak @ 2005-05-19  6:24 UTC (permalink / raw)
  To: lm-sensors

Hi Greg, Mark,

As described in a previous email to this list, this is
a patch for simplified access to multiplexed i2c
busses.  A documentation file is included, as well as
an example (i2c-virtual_cb.c) of how to implement the
mux-control callbacks.

Tested on a heavily patched 2.4.19 kernel on embedded
PowerPC.  However, this patch is against a clean
kernel.org 2.4.19 tree.  I don't have the bandwidth to
port this to 2.6.0 right now, but I wanted to make it
available in case someone else finds it useful. 

Comments/feedback welcome.

Thanks,
Brian Kuschak



__________________________________
Do you Yahoo!?
Protect your identity with Yahoo! Mail AddressGuard
http://antispam.yahoo.com/whatsnewfree
-------------- next part --------------
diff -urN linux-2.4.19/Documentation/Configure.help linux-2.4.19.new/Documentation/Configure.help
--- linux-2.4.19/Documentation/Configure.help	Fri Aug  2 17:39:42 2002
+++ linux-2.4.19.new/Documentation/Configure.help	Tue Nov 11 09:54:38 2003
@@ -16905,6 +16905,15 @@
   it as a module, say M here and read <file:Documentation/modules.txt>.
   The module will be called i2c-proc.o.
 
+I2C virtual bus
+CONFIG_I2C_VIRTUAL
+  This driver allows you to handle multiplexed or bus-switched I2C
+  bus topologies by registering 'virtual' i2c busses for each multiplexed
+  bus segment.  It requires some hardware-specific code to be written to 
+  perform the multiplexor control.
+
+  See Documentation/i2c/virtual_i2c for details.
+
 Bus Mouse Support
 CONFIG_BUSMOUSE
   Say Y here if your machine has a bus mouse as opposed to a serial
diff -urN linux-2.4.19/Documentation/i2c/virtual_i2c linux-2.4.19.new/Documentation/i2c/virtual_i2c
--- linux-2.4.19/Documentation/i2c/virtual_i2c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19.new/Documentation/i2c/virtual_i2c	Tue Nov 11 09:54:38 2003
@@ -0,0 +1,102 @@
+Virtual i2c bus
+Brian Kuschak  <bkuschak@yahoo.com>
+
+
+I2C devices must have a unique 7 bit address on the bus to which they 
+are attached.  Many I2C chips have one or more input lines which can be
+used to configure one or more of their address bits.  This allows the
+hardware designer to include multiple chips on a single bus by selecting
+different addresses for each one.  However, some chips have fixed addresses
+which present a problem if more than one of them are required on a board.
+Also, sometimes there are more devices than there are selectable addresses.
+
+A common solution is to break the i2c bus into disjoint segments, by using
+a multiplexor or i2c bus switch.  This electrically isolates the individual
+bus segments.  Then the devices with duplicate addresses are placed on 
+separate bus segments, to prevent address conflicts.
+
+This seems to be a very common approach in certain types of applications,
+such as bladed chassis, where many identical 'blades' or cards are inserted
+into a common backplane.  The I2C bus on each blade is then located behind
+a mux or i2c bus switch.  This solution works great from the hardware 
+perspective, but presents some complexities for software.
+
+The 'virtual i2c adapter' driver is an attempt to provide a flexible software
+abstraction to simiplify these issues, while minimizing the impact on 
+existing code and fitting nicely into the i2c driver framework.
+
+
+What is a 'virtual i2c adapter'
+===============+
+Think of this adapter as a layer above the existing algorithm and adapter
+drivers.  The virtual i2c adapter is the handle by which you access a 
+specific multiplexed bus segment.  Each disjoint bus segment becomes a new
+virtual bus.  The virtual adapter is associated with a 'real' adapter and a 
+set of multiplexor control variables.
+
+For example: you have an i2c-0 bus with one multiplexor or i2c bus switch,
+and the mux has four outputs which can be electrically connected to the
+i2c-0 bus.  You would register four virtual i2c busses, one for each position
+of the mux.  As part of the registration, you provide callback functions to
+select and deselect the mux as well as the selector values to be passed to
+these functions.
+
+                     ---------  <-------->  i2c-1  virtual
+                    | i2c mux | <-------->  i2c-2  virtual
+   i2c-0 <------->  |         | <-------->  i2c-3  virtual
+  ibm_ocp           |  0x74   | <-------->  i2c-4  virtual
+                     ---------
+                        ^ 
+                        |
+                        +---  (or externally controlled)
+
+The mux may be i2c-controlled, in which case the mux_addr is set to the 
+slave address (0x74) and the mux_val would be the port number to select (0-3).  
+Alternatively, the mux could be controlled by some fixed memory-mapped register
+in which case only the mux_val would be needed.  The callback functions
+are hardware specific and written by the user.  
+
+Once the virtual busses are registered, you may talk to any devices behind
+the mux simply the using the i2c-1, i2c-2, i2c-3, etc. adapters instead of
+the i2c-0 adapter.  This makes the mux essentially transparent to the 
+i2c_client. 
+
+The great advantage of course is that all the existing sensor drivers and
+other i2c client drivers automatically work, and the mux becomes transparent
+to them.
+
+
+Additional capabilities
+===========+
+This driver also supports multiple levels of muxing, by allowing the
+user to register a virtual bus which has a different virtual bus as its
+'real' adapter.  In addition, each virtual bus may have different kinds of 
+multiplexors, with each bus having its own set of callback functions.
+This allows you to easily support some very complex topologies.
+
+In addition to multiplexing, some systems require that you obtain hardware 
+access to the bus behind the mux before talking on it.  (Again, bladed chassis
+typically 'fence' other blades off the bus to prevent a crashed blade from 
+bringing down the whole backplane.)  Before talking on this bus, you have to
+arbitrate with the other blades to acquire exclusive access to the bus.  This
+requirement is met by the addition of two new function pointers to the 
+algorithm drivers, acquire_exclusive() and release_exclusive().  Traditional
+adapters will not use these and they can safely be left NULL.  If they are
+non-null, the virtual bus driver will call the acquire_exclusive() function 
+before attempting any operations on that virtual bus.  This function may block,
+and this is done before acquiring the lock on the underlying 'real' bus to
+allow transactions on the real bus to continue unimpeded while waiting for
+arbitrartion.  In addition the ownership is only held for as long as it takes
+to complete the transfer.  
+
+
+Files
+==+
+drivers/i2c/i2c-virtual.c: 	The 'algorithm' and 'adapter' driver
+include/linux/i2c-virtual.h:	Header file with the mux control structure
+                                and callback prototypes.
+
+
diff -urN linux-2.4.19/drivers/i2c/Config.in linux-2.4.19.new/drivers/i2c/Config.in
--- linux-2.4.19/drivers/i2c/Config.in	Mon Feb 25 11:37:57 2002
+++ linux-2.4.19.new/drivers/i2c/Config.in	Tue Nov 11 10:01:51 2003
@@ -48,6 +48,7 @@
 
    dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C
    dep_tristate 'I2C /proc interface (required for hardware sensors)' CONFIG_I2C_PROC $CONFIG_I2C
+   dep_tristate 'Virtualized I2C adapter' CONFIG_I2C_VIRTUAL $CONFIG_I2C
 
 fi
 endmenu
diff -urN linux-2.4.19/drivers/i2c/Makefile linux-2.4.19.new/drivers/i2c/Makefile
--- linux-2.4.19/drivers/i2c/Makefile	Mon Feb 25 11:37:57 2002
+++ linux-2.4.19.new/drivers/i2c/Makefile	Tue Nov 11 10:02:48 2003
@@ -5,7 +5,7 @@
 O_TARGET := i2c.o
 
 export-objs	:= i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \
-		   i2c-algo-ite.o i2c-proc.o
+		   i2c-algo-ite.o i2c-proc.o i2c-virtual.o
 
 obj-$(CONFIG_I2C)		+= i2c-core.o
 obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
@@ -19,9 +19,12 @@
 obj-$(CONFIG_ITE_I2C_ADAP)	+= i2c-adap-ite.o
 obj-$(CONFIG_I2C_PROC)		+= i2c-proc.o
 obj-$(CONFIG_I2C_KEYWEST)	+= i2c-keywest.o
+obj-$(CONFIG_I2C_VIRTUAL)	+= i2c-virtual.o
 
 # This is needed for automatic patch generation: sensors code starts here
 # This is needed for automatic patch generation: sensors code ends here
+
+ 
 
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.4.19/drivers/i2c/i2c-core.c linux-2.4.19.new/drivers/i2c/i2c-core.c
--- linux-2.4.19/drivers/i2c/i2c-core.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.19.new/drivers/i2c/i2c-core.c	Tue Nov 11 10:00:32 2003
@@ -30,6 +30,7 @@
 #include <linux/config.h>
 
 #include <linux/i2c.h>
+#include <linux/i2c-virtual.h>
 
 /* ----- compatibility stuff ----------------------------------------------- */
 
@@ -120,6 +121,19 @@
  * --------------------------------------------------- 
  */
 
+struct i2c_adapter* i2c_get_adapter(int index)
+{
+	struct i2c_adapter *ret;
+
+	if(index > I2C_ADAP_MAX) 
+		return NULL;
+
+	ADAP_LOCK();
+	ret = adapters[index];
+	ADAP_UNLOCK();
+	return ret;
+}
+
 /* -----
  * i2c_add_adapter is called from within the algorithm layer,
  * when a new hw adapter registers. A new device is register to be
@@ -410,6 +424,16 @@
 	for (i = 0; i < I2C_CLIENT_MAX ; i++) 
 		if (adapter->clients[i] && (adapter->clients[i]->addr = addr))
 			return -EBUSY;
+
+#ifdef CONFIG_I2C_VIRTUAL
+	/* Also check for aliasing on multiplexed busses (even if they are nested) */
+	while((adapter = i2c_get_real_adap(adapter)) != NULL) {
+
+		for (i = 0; i < I2C_CLIENT_MAX ; i++)
+			if (adapter->clients[i] && (adapter->clients[i]->addr = addr))
+				return -EBUSY;
+	}
+#endif
 	return 0;
 }
 
@@ -760,16 +784,27 @@
 
 int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num)
 {
-	int ret;
+	int ret, ret2;
 
 	if (adap->algo->master_xfer) {
  	 	DEB2(printk("i2c-core.o: master_xfer: %s with %d msgs.\n",
 		            adap->name,num));
 
+ 		/* Acquire exclusive access to a shared I2C bus _before_ taking the local I2C lock
+ 		 * to prevent stalling local I2C transactions while waiting for exclusive access.
+ 		 */
+ 		if(adap->algo->acquire_exclusive) 
+ 			if ((ret = adap->algo->acquire_exclusive(adap)) < 0)
+ 				return ret;
+
 		I2C_LOCK(adap);
 		ret = adap->algo->master_xfer(adap,msgs,num);
 		I2C_UNLOCK(adap);
 
+ 		if(adap->algo->release_exclusive) 
+ 			if ((ret2 = adap->algo->release_exclusive(adap)) < 0)
+ 				return ret2;
+
 		return ret;
 	} else {
 		printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
@@ -780,7 +815,7 @@
 
 int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
 {
-	int ret;
+	int ret, ret2;
 	struct i2c_adapter *adap=client->adapter;
 	struct i2c_msg msg;
 
@@ -793,10 +828,20 @@
 		DEB2(printk("i2c-core.o: master_send: writing %d bytes on %s.\n",
 			count,client->adapter->name));
 	
+		/* Acquire exclusive access to a shared I2C bus _before_ taking the local I2C lock
+		 * to prevent stalling local I2C transactions while waiting for exclusive access.
+		 */
+		if(adap->algo->acquire_exclusive) 
+			if ((ret = adap->algo->acquire_exclusive(adap)) < 0)
+				return ret;
 		I2C_LOCK(adap);
 		ret = adap->algo->master_xfer(adap,&msg,1);
 		I2C_UNLOCK(adap);
 
+		if(adap->algo->release_exclusive) 
+			if ((ret2 = adap->algo->release_exclusive(adap)) < 0)
+				return ret2;
+
 		/* if everything went ok (i.e. 1 msg transmitted), return #bytes
 		 * transmitted, else error code.
 		 */
@@ -812,7 +857,7 @@
 {
 	struct i2c_adapter *adap=client->adapter;
 	struct i2c_msg msg;
-	int ret;
+	int ret, ret2;
 	if (client->adapter->algo->master_xfer) {
 		msg.addr   = client->addr;
 		msg.flags = client->flags & I2C_M_TEN;
@@ -823,10 +868,21 @@
 		DEB2(printk("i2c-core.o: master_recv: reading %d bytes on %s.\n",
 			count,client->adapter->name));
 	
+ 		/* Acquire exclusive access to a shared I2C bus _before_ taking the local I2C lock
+ 		 * to prevent stalling local I2C transactions while waiting for exclusive access.
+ 		 */
+ 		if(adap->algo->acquire_exclusive) 
+ 			if ((ret = adap->algo->acquire_exclusive(adap)) < 0)
+ 				return ret;
+
 		I2C_LOCK(adap);
 		ret = adap->algo->master_xfer(adap,&msg,1);
 		I2C_UNLOCK(adap);
 	
+ 		if(adap->algo->release_exclusive) 
+ 			if ((ret2 = adap->algo->release_exclusive(adap)) < 0)
+ 				return ret2;
+ 
 		DEB2(printk("i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n",
 			ret, count, client->addr));
 	
@@ -872,7 +928,7 @@
                    struct i2c_client_address_data *address_data,
                    i2c_client_found_addr_proc *found_proc)
 {
-	int addr,i,found,err;
+	int addr,i,found,err,ret;
 	int adap_id = i2c_adapter_id(adapter);
 
 	/* Forget it if we can't probe using SMBUS_QUICK */
@@ -982,7 +1038,12 @@
 
 		/* OK, so we really should examine this address. First check
 		   whether there is some client here at all! */
-		if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
+		ret = i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL);
+			
+		DEB2(printk("i2c_probe: bus=%d addr=%02hx, ret=%d\n", 
+			i2c_adapter_id(adapter), addr, ret));
+
+		if (ret >= 0)
 			if ((err = found_proc(adapter,addr,0,-1)))
 				return err;
 	}
@@ -1142,7 +1203,7 @@
 	struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, 
 	                          { addr, flags | I2C_M_RD, 0, msgbuf1 }
 	                        };
-	int i;
+	int i, ret;
 
 	msgbuf0[0] = command;
 	switch(size) {
@@ -1205,9 +1266,9 @@
 		       size);
 		return -1;
 	}
-
-	if (i2c_transfer(adapter, msg, num) < 0)
-		return -1;
+	
+	if ((ret = i2c_transfer(adapter, msg, num)) < 0)
+		return ret;
 
 	if (read_write = I2C_SMBUS_READ)
 		switch(size) {
@@ -1230,13 +1291,24 @@
                    char read_write, u8 command, int size, 
                    union i2c_smbus_data * data)
 {
-	s32 res;
+	s32 res, res2;
 	flags = flags & I2C_M_TEN;
 	if (adapter->algo->smbus_xfer) {
+
+		/* Acquire exclusive access to a shared I2C bus _before_ taking the local I2C lock
+		 * to prevent stalling local I2C transactions while waiting for exclusive access.
+		 */
+		if(adapter->algo->acquire_exclusive) 
+			if ((res = adapter->algo->acquire_exclusive(adapter)) < 0)
+				return res;
 		I2C_LOCK(adapter);
 		res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
 		                                command,size,data);
 		I2C_UNLOCK(adapter);
+
+		if(adapter->algo->release_exclusive) 
+			if ((res2 = adapter->algo->release_exclusive(adapter)) < 0)
+				return res2;
 	} else
 		res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
 	                                      command,size,data);
@@ -1389,6 +1461,7 @@
 EXPORT_SYMBOL(i2c_transfer);
 EXPORT_SYMBOL(i2c_adapter_id);
 EXPORT_SYMBOL(i2c_probe);
+EXPORT_SYMBOL(i2c_get_adapter);
 
 EXPORT_SYMBOL(i2c_smbus_xfer);
 EXPORT_SYMBOL(i2c_smbus_write_quick);
diff -urN linux-2.4.19/drivers/i2c/i2c-virtual.c linux-2.4.19.new/drivers/i2c/i2c-virtual.c
--- linux-2.4.19/drivers/i2c/i2c-virtual.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19.new/drivers/i2c/i2c-virtual.c	Tue Nov 11 09:54:38 2003
@@ -0,0 +1,275 @@
+/*
+ * Virtual I2C bus driver.
+ * Simplifies access to complex multiplexed I2C bus topologies, by presenting
+ * each multiplexed bus segment as a virtual I2C adapter.  Supports multi-level
+ * mux'ing (mux behind a mux), as well as arbitration for exclusive bus access
+ * for those systems which require it (some bladed chassis for example).
+ *
+ * Brian Kuschak <bkuschak@yahoo.com>
+ *
+ * Adapted from i2c-adap-ibm_ocp.c 
+ * Original file Copyright 2000-2002 MontaVista Software Inc.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-virtual.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+
+
+//#define		DBG(x)		x
+#define	DBG(x)		{}
+
+#define VIRT_TIMEOUT		(HZ/2)		/* 500msec */
+#define VIRT_RETRIES		3		
+
+/* exclusive access to the bus */
+#define I2C_LOCK(adap) down(&adap->lock)
+#define I2C_UNLOCK(adap) up(&adap->lock)
+
+static int i2c_scan = 1;
+
+/* First the I2C 'algorithm' driver code: */
+
+/*
+ * Description: acquire exclusive access (if needed), select the mux,
+ * perform the transfer on the real i2c adapter, deselect mux and drop
+ * exclusive access.
+ */
+static int
+virt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct i2c_virt_priv 	*priv = (void*)adap->data;
+	struct i2c_adapter 	*real = priv->real_adap;
+	int ret, ret2;
+
+
+	/* Acquire exclusive access to a shared I2C bus _before_ taking the local I2C lock
+	 * to prevent stalling local I2C transactions while waiting for exclusive access.
+	 */
+	if(real->algo->acquire_exclusive) 
+		if ((ret = real->algo->acquire_exclusive(real)) < 0)
+			return ret;
+
+	/* Grab the lock for the _real_ adapter.  We already hold the lock for the
+	 * virtual adapter.  Then select the right mux port and perform the transfer.
+	 */
+	I2C_LOCK(real);
+	priv->mux.select(real, &priv->mux);
+	ret = real->algo->master_xfer(real, msgs, num);
+	priv->mux.deselect(real, &priv->mux);
+	I2C_UNLOCK(real);
+
+	/* Release exclusive bus access */
+	if(real->algo->release_exclusive) 
+		if ((ret2 = real->algo->release_exclusive(real)) < 0)
+			return ret2;
+
+	return ret;
+}
+
+/*
+ * Description: Implements device specific ioctls.  
+ * We don't support any yet.
+ */
+static int
+virt_algo_control(struct i2c_adapter *adap, unsigned int cmd, unsigned long arg)
+{
+	int ret = 0;
+	return ret;
+}
+
+static u32
+virt_i2c_func(struct i2c_adapter *adap)
+{
+	/* FIXME : we should probably return the functionality of the 
+	 * real adapter...
+	 */
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
+	    I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+static struct i2c_algorithm virt_i2c_algo = {
+	"Virtual I2C algorithm driver",
+	I2C_ALGO_MPC8XX,
+	virt_i2c_xfer,		/* master_xfer		*/
+	NULL,
+	NULL,			/* slave_xmit           */
+	NULL,			/* slave_recv           */
+	virt_algo_control,	/* ioctl                */
+	virt_i2c_func,		/* functionality        */
+};
+
+/*
+ * Description: Register bus structure
+ */
+static int
+i2c_virt_add_bus(struct i2c_adapter *adap)
+{
+	adap->id |= virt_i2c_algo.id;
+	adap->algo = &virt_i2c_algo;
+	adap->timeout = VIRT_TIMEOUT;
+	adap->retries = VIRT_RETRIES;
+
+	i2c_add_adapter(adap);
+
+	/* scan the I2C bus for valid 7 bit addresses
+	 * (ie things that ACK on 1byte read)
+	 * TODO: check for 10-bit mode and never run as a slave.
+	 */
+
+	if (i2c_scan) {
+
+		int found = 0;
+		int i;
+		printk(KERN_INFO "i2c%d: scanning bus. Found ",
+		       i2c_adapter_id(adap));
+		for (i = 0; i < 0x7f; i++) {
+			int ret;
+			struct i2c_msg msg;
+			char data[1];
+			msg.addr = i;
+			msg.buf = data;
+			msg.len = 1;
+			msg.flags = I2C_M_RD;
+			if ((ret = virt_i2c_xfer(adap, &msg, 1)) = 1) {
+				printk("0x%02x ", i);
+				found++;
+			}
+		}
+		
+		if (found)
+			printk("\n");
+		else
+			printk("Nothing\n");
+
+	}
+	return 0;
+}
+
+static int
+i2c_virt_del_bus(struct i2c_adapter *adap)
+{
+	int ret;
+	if ((ret = i2c_del_adapter(adap)) < 0)
+		return ret;
+	return 0;
+}
+
+/* The 'adapter' driver code: */
+
+static int
+i2c_virt_reg(struct i2c_client *client)
+{
+	return 0;
+}
+static int
+i2c_virt_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+static void
+i2c_virt_inc_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+}
+static void
+i2c_virt_dec_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+}
+
+/*
+ * Called to create a 'virtual' i2c bus which represents a multiplexed bus
+ * segment.  Mux_addr and mux_val are passed to the select and deselect
+ * callback functions to perform hardware-specific mux control.
+ */
+struct i2c_adapter *register_virtual_i2c_adap(struct i2c_adapter *real_adap, 
+					unsigned long mux_addr, 
+					unsigned long mux_val, 
+					void *select_cb,
+					void *deselect_cb)
+{
+	struct i2c_adapter *adap;
+	struct i2c_virt_priv *priv;
+
+	if (!(adap = kmalloc(sizeof (struct i2c_adapter) + sizeof(struct i2c_virt_priv), 
+			GFP_KERNEL))) {
+		printk("register_virtual_i2c_adap: Failed allocation\n");
+		return NULL;
+	}
+
+	memset(adap, 0, sizeof(struct i2c_adapter) + sizeof(struct i2c_virt_priv));
+
+	snprintf(adap->name, sizeof(adap->name)-1,
+		"Virtual I2C (i2c%d, mux %02lx:%02lx)",
+		i2c_adapter_id(real_adap), mux_addr, mux_val);
+	adap->name[sizeof(adap->name)-1] = 0;
+
+	adap->data = priv = (void*) (adap+1);	/* point to first byte of i2c_virt_priv */
+	adap->id = I2C_HW_VIRT;
+	adap->algo = NULL;
+	adap->inc_use = i2c_virt_inc_use;
+	adap->dec_use = i2c_virt_dec_use;
+	adap->client_register = i2c_virt_reg;
+	adap->client_unregister = i2c_virt_unreg;
+
+	priv->real_adap = real_adap;
+	priv->mux.addr = mux_addr;
+	priv->mux.value = mux_val;
+	priv->mux.select = select_cb;
+	priv->mux.deselect = deselect_cb;
+
+	if (i2c_virt_add_bus(adap) < 0)
+		return NULL;
+
+	printk(KERN_NOTICE "i2c%d: Virtual I2C bus "
+		"(Physical bus i2c%d, multiplexor %02lx port %ld)\n",
+		i2c_adapter_id(adap), i2c_adapter_id(real_adap), 
+		mux_addr, mux_val);
+
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+	return adap;
+}
+
+int unregister_virtual_i2c_adap(struct i2c_adapter *adap)
+{
+	int ret;
+	if((ret = i2c_virt_del_bus(adap)) != 0) 
+		return ret;
+
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	return 0;
+}
+
+EXPORT_SYMBOL(register_virtual_i2c_adap);
+EXPORT_SYMBOL(unregister_virtual_i2c_adap);
+
+MODULE_AUTHOR("B Kuschak <www.yahoo.com>");
+MODULE_DESCRIPTION("Virual I2C driver for multiplexed I2C busses");
+MODULE_LICENSE("GPL");
+
+
diff -urN linux-2.4.19/drivers/i2c/i2c-virtual_cb.c linux-2.4.19.new/drivers/i2c/i2c-virtual_cb.c
--- linux-2.4.19/drivers/i2c/i2c-virtual_cb.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19.new/drivers/i2c/i2c-virtual_cb.c	Tue Nov 11 09:54:38 2003
@@ -0,0 +1,335 @@
+/*
+ *    Description:
+ *	This file implements the mux control callback functions fr the
+ *	virtual i2c adapter.
+ *	See Documentation/i2c/virtual_i2c for details.
+ *	Brian Kuschak <bkuschak@yahoo.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/i2c-adap-virt.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/proc_fs.h>
+#include <asm/delay.h>
+#include <asm/io.h>
+
+//#define		DBG(x)		x
+#define		DBG(x)		{}
+
+#ifndef elemof
+#define elemof(a)	(sizeof(a) / sizeof((a)[0]))
+#endif
+
+#define	REQUIRE_ARBITRATION		/* some bladed systems need this */
+
+/* pointer to the list of i2c_bus_mappings */
+static LIST_HEAD(i2c_map_list);
+struct i2c_bus_mapping {
+	struct i2c_adapter	*real;	
+	struct i2c_adapter	*virt;
+	unsigned long		mux_addr;	
+	unsigned long		mux_val;
+	struct list_head	list; 
+};
+
+static struct i2c_adapter *add_virt_bus(struct i2c_adapter *real, 
+                                        unsigned long mux_addr,
+                                        unsigned long mux_val,
+                                        void *select_cb,
+                                        void *deselect_cb);
+
+/********************************************************************************************
+ * These functions are allowed to block.  At this point we have acquired the local I2C_LOCK
+ * semaphore.  Select the proper mux values.                                
+ * 
+ ********************************************************************************************/
+
+/* PCA9544 and PCA9548 I2C-controlled bus switches are similar.  Try to 
+ * share code for these two different parts.  '44 is four port mux, '48 is eight port.
+ */
+static void pca954x_select_mux(struct i2c_adapter *adap, struct i2c_mux_ctrl *mux,
+				unsigned long value)
+{
+	struct i2c_msg msg;
+	int i2c_switch_addr = mux->addr;
+	char buf[1];
+	int ret;
+
+	/* send I2C commands to the bus switch(es) to select the right path */
+	if (adap->algo->master_xfer) {
+		msg.addr	= i2c_switch_addr;
+		msg.flags	= 0;
+		msg.len		= 1;
+		buf[0] 		= value;
+		msg.buf 	= buf;
+		
+		if((ret = adap->algo->master_xfer(adap,&msg,1)) < 0)
+			printk(KERN_ERR "%s: Failed to select the I2C multiplexor "
+					"(addr=%02hx, val=%02hx, err=%d)!\n", 
+					__FUNCTION__,
+					i2c_switch_addr, value, ret);
+		else 
+			DBG(printk("I2C mux selected [i2c addr: %hX, port: %d]!\n", 
+				i2c_switch_addr, value));
+	}
+	else {
+		printk(KERN_ERR "%s: no master_xfer??\n", __FUNCTION__);
+	}
+}
+
+static void pca954x_deselect(struct i2c_adapter *adap, struct i2c_mux_ctrl *mux,
+				unsigned long value) 
+{
+	struct i2c_msg msg;
+	int i2c_switch_addr = mux->addr; 
+	char buf[1];
+	int ret;
+
+	/* send I2C commands to the bus switch(es) to select the right path */
+	if (adap->algo->master_xfer) {
+		msg.addr	= i2c_switch_addr;
+		msg.flags	= 0;
+		msg.len		= 1;
+		buf[0] 		= 0;	/* select nothing */
+		msg.buf 	= buf;
+
+		if((ret = adap->algo->master_xfer(adap,&msg,1)) < 0)
+			printk(KERN_ERR "Failed to deselect the I2C multiplexor "
+					"(addr=%02hx, val=%02hx, err=%d)!\n", 
+					i2c_switch_addr, 0, ret);
+		else
+			DBG(printk("I2C mux deselected [i2c addr: %hX]!\n", 
+				i2c_switch_addr));
+	}
+	else {
+		printk(KERN_ERR "%s: no master_xfer??\n", __FUNCTION__);
+	}
+}
+
+/* The 9544 and 9548 use different register definitions, hence these two functions */
+static void pca9544_select_mux(struct i2c_adapter *adap, struct i2c_mux_ctrl *mux)
+{
+	int i2c_mux_sel     = mux->value;
+	return(pca954x_select_mux(adap, mux, ((i2c_mux_sel & 0x3) + 4)));
+}
+
+static void pca9548_select_mux(struct i2c_adapter *adap, struct i2c_mux_ctrl *mux)
+{
+	int i2c_mux_sel     = mux->value;
+	return(pca954x_select_mux(adap, mux, 1<<(i2c_mux_sel & 0x7)));	
+}
+
+/* Disabling the mux is the same for both 9544 and 9548 */
+static void pca954x_deselect_mux(struct i2c_adapter *adap, struct i2c_mux_ctrl *mux)
+{
+	return(pca954x_deselect_mux(adap, mux, 0));
+}
+
+static void pca954x_deselect_mux(struct i2c_adapter *adap, struct i2c_mux_ctrl *mux)
+{
+	return(pulsar_deselect_mux(adap, mux, 0));
+}
+
+#if 0
+/* Multiplexors controlled by a memory-mapped register
+ */
+static void mmreg_select_mux(struct i2c_adapter *adap, struct i2c_mux_ctrl *mux)
+{
+	char data;
+
+	data = (mux->value & MUX_SELECT_MASK);
+	cpld_write_register(I2C_SELECT_REG, data);
+
+	DBG(printk("I2C mux selected [port: %d]!\n", mux->value));
+}
+
+static void mmreg_deselect_mux(struct i2c_adapter *adap, struct i2c_mux_ctrl *mux)
+{
+	char data;
+
+	/* Last position is reserved as 'disconnected' */
+	data = MUX_SELECT_MASK;
+	cpld_write_register(I2C_SELECT_REG, data);
+
+	DBG(printk("I2C mux deselected!\n"));
+}
+#endif
+
+/********************************************************************************************
+ * Here we have the arbitration functions for bladed systems, where multiple blades
+ * access a shared I2C bus.  Arbitrate for and acquire exclusive access to the bus.
+ * This code is called from the i2c-core driver _without_ the I2C_LOCK held.
+ * 
+ ********************************************************************************************/
+
+static int acquire_shared_bus(struct i2c_adapter *adap)
+{
+	/* Only bus 1 (global I2C bus) requires arbitrating with the other CP */
+	if(i2c_adapter_id(adap) != 1)
+		return 0;
+
+	/* FIXME: Do hardware-specific arbitration here (may block) */
+
+	return 0;
+}
+
+static int release_shared_bus(struct i2c_adapter *adap)
+{
+	/* Only bus 1 (global I2C bus) requires arbitrating with the other CP */
+	if(i2c_adapter_id(adap) != 1)
+		return 0;
+
+	/* FIXME: Do hardware-specific arbitration here (may block) */
+
+	return 0;
+}
+
+/* This fn is called once for each adapter. We use this to add our platform-specific
+ * callback functions.
+ */
+static int attach_adapter(struct i2c_adapter *adap)
+{
+	int i;
+	struct i2c_adapter *virt;
+	int index = i2c_adapter_id(adap);
+	
+#ifdef REQURE_ARBITRATION
+	adap->algo->acquire_exclusive = &acquire_shared_bus;
+	adap->algo->release_exclusive = &release_shared_bus;
+#endif
+
+	/* The first level mux has 4 outputs.  It uses 0x76 slave address.
+	 * Register a virtual bus for each output.
+	 */
+	virt = add_virt_bus(adap, 0x76, 0, &pca9544_select_mux, &pca9544_deselect_mux);
+	add_virt_bus(adap, 0x76, 1, &pca9544_select_mux, &pca9544_deselect_mux);
+	add_virt_bus(adap, 0x76, 2, &pca9544_select_mux, &pca9544_deselect_mux);
+	add_virt_bus(adap, 0x76, 3, &pca9544_select_mux, &pca9544_deselect_mux);
+	
+	/* There are 2nd level virtual buses at slave addresses 0x70, 0x71, 0x72 */
+	if(!virt) 
+		break;
+
+	/* first 2nd level mux */
+	sfpidx = 0;
+	for(i=0; i<7; i++) 
+		add_virt_bus(virt, 0x70, i, &pca9548_select_mux, &pca9548_deselect_mux);
+
+	/* second 2nd level mux */
+	for(i=0; i<7; i++) 
+		add_virt_bus(virt, 0x71, i, &pca9548_select_mux, &pca9548_deselect_mux);
+
+	/* third 2nd level mux */
+	for(i=0; i<7; i++) 
+		add_virt_bus(virt, 0x72, i, &pca9548_select_mux, &pca9548_deselect_mux);
+	
+	printk("iic%d: Registered I2C mux callbacks\n", index);
+	return 0;
+}
+
+/* Register a virtual bus and also store some information about this bus that will be useful to
+ * clients.
+ */
+static struct i2c_adapter *add_virt_bus(struct i2c_adapter *real, 
+                                        unsigned long mux_addr,
+                                        unsigned long mux_val,
+                                        void *select_cb,
+                                        void *deselect_cb)
+{
+	struct i2c_bus_mapping *pmap;
+	struct i2c_adapter *virt;
+
+	if((virt = register_virtual_i2c_adap(real, mux_addr, mux_val, select_cb, deselect_cb)) = NULL)
+		return virt;
+
+	if((pmap = kmalloc(sizeof(struct i2c_bus_mapping), GFP_KERNEL)) = NULL) {
+		printk(KERN_ERR "%s: Failed to allocate bus mapping\n", __FUNCTION__);
+		return -1;
+	}
+	pmap->real = real;
+	pmap->mux_addr = mux_addr;
+	pmap->mux_val = mux_val;
+	pmap->virt = virt;
+	list_add_tail(&pmap->list, &i2c_map_list);
+	return virt;
+}
+
+/* Called to find out which i2c bus to use to get to a specific bus segment.
+ */
+struct i2c_adapter *i2c_lookup_adapter(struct i2c_adapter *base, unsigned long mux_addr, 
+					unsigned long mux_val)
+{	
+	struct list_head *l;
+	struct i2c_bus_mapping *pmap;
+
+	list_for_each(l, &i2c_map_list) {
+		pmap = list_entry(l, struct i2c_bus_mapping, list);
+		if(pmap->real = base && pmap->mux_addr = mux_addr && pmap->mux_val = mux_val)
+			return pmap->virt;
+	}
+	return NULL;	/* none found */
+}
+
+static int i2c_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data)
+{
+	int len;
+	char *buf = page;
+	struct list_head *l;
+	struct i2c_bus_mapping *pmap;
+
+        buf += sprintf(buf, "i2c bus_mapping\n");
+
+	list_for_each(l, &i2c_map_list) {
+		pmap = list_entry(l, struct i2c_bus_mapping, list);
+
+		if(pmap)
+        		buf += sprintf(buf, "base=iic%d  mux_addr=%02hx, mux_val=%02hx  =>  iic%d\n", 
+				i2c_adapter_id(pmap->real), pmap->mux_addr, pmap->mux_val, 
+				i2c_adapter_id(pmap->virt));
+	}
+
+        len = buf - page;
+        if (len <= off+count) *eof = 1;
+        *start = page + off;
+        len -= off;
+        if (len>count) len = count;
+        if (len<0) len = 0;
+        return len;
+}
+
+static int __init i2c_mux_init(void)
+{
+	int status, i;
+	struct i2c_adapter *adap;
+
+	/* Iterate through the _real_ adapters */
+	for(i=0; i<I2C_ADAP_MAX; i++) {
+
+		if((adap = i2c_get_adapter(i)) != NULL && 
+		   (adap->id & 0xff) = I2C_HW_OCP) {	/* we have ibm_ocp adapters */
+			attach_adapter(adap);
+		}
+	}
+
+	create_proc_read_entry("driver/i2c/virtual_i2c_map", 0, NULL, &i2c_read_proc, NULL);
+	return (status);
+}
+
+static void __exit i2c_mux_exit(void)
+{
+}
+
+module_init(i2c_mux_init);
+module_exit(i2c_mux_exit);
+
+EXPORT_SYMBOL(i2c_lookup_adapter);
+
+MODULE_DESCRIPTION("I2C multiplexor callbacks");
+
diff -urN linux-2.4.19/include/linux/i2c-virtual.h linux-2.4.19.new/include/linux/i2c-virtual.h
--- linux-2.4.19/include/linux/i2c-virtual.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19.new/include/linux/i2c-virtual.h	Tue Nov 11 09:54:39 2003
@@ -0,0 +1,38 @@
+/* This is the header files for the 'virtual i2c' adapter driver.
+ * See Documentation/i2c/virtual_i2c for usage information.
+ */
+#ifndef __I2C_VIRTUAL_H
+#define __I2C_VIRTUAL_H
+
+#include <linux/i2c.h>
+
+struct i2c_mux_ctrl {
+	unsigned long	addr;		
+	unsigned long	value;
+
+	/* fn which enables the mux */
+	void (*select)(struct i2c_adapter *adap, struct i2c_mux_ctrl *mux);	
+
+	/* fn which disables the mux */
+	void (*deselect)(struct i2c_adapter *adap, struct i2c_mux_ctrl *mux);	
+};
+
+/* This has to be exposed, since the code which assigns the callbacks must use it. */
+struct i2c_virt_priv {
+	struct i2c_adapter	*real_adap;		/* pointer to our 'real' adapter */
+	struct i2c_mux_ctrl	mux;			/* MUX settings for this adapter */
+};
+
+
+static inline struct i2c_adapter *i2c_get_real_adap(struct i2c_adapter *adap)
+{
+	struct i2c_virt_priv *priv;
+
+	if((adap->id & 0xff) != I2C_HW_VIRT)
+		return NULL;
+	
+	priv = (void*) adap->data;
+	return(priv->real_adap);
+}
+
+#endif /* __I2C_VIRTUAL_H */
diff -urN linux-2.4.19/include/linux/i2c.h linux-2.4.19.new/include/linux/i2c.h
--- linux-2.4.19/include/linux/i2c.h	Thu Oct 11 08:05:47 2001
+++ linux-2.4.19.new/include/linux/i2c.h	Tue Nov 11 09:54:39 2003
@@ -58,7 +58,7 @@
 /* --- General options ------------------------------------------------	*/
 
 #define I2C_ALGO_MAX	4		/* control memory consumption	*/
-#define I2C_ADAP_MAX	16
+#define I2C_ADAP_MAX	48
 #define I2C_DRIVER_MAX	16
 #define I2C_CLIENT_MAX	32
 #define I2C_DUMMY_MAX 4
@@ -184,6 +184,7 @@
 	unsigned int addr;		/* chip address - NOTE: 7bit 	*/
 					/* addresses are stored in the	*/
 					/* _LOWER_ 7 bits of this char	*/
+
 	/* addr: unsigned int to make lm_sensors i2c-isa adapter work
 	  more cleanly. It does not take any more memory space, due to
 	  alignment considerations */
@@ -224,6 +225,12 @@
 
 	/* To determine what the adapter supports */
 	u32 (*functionality) (struct i2c_adapter *);
+
+	/* Some chassis/bladed systems must arbitrate with another CPU to
+	 * get exclusive access to the I2C bus.  Set NULL if not used.
+	 */
+	int (*acquire_exclusive)(struct i2c_adapter *adap);
+	int (*release_exclusive)(struct i2c_adapter *adap);
 };
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)
@@ -367,7 +374,8 @@
  */
 extern int i2c_adapter_id(struct i2c_adapter *adap);
 
-
+/* Return a pointer to the i2c_adapter */
+extern struct i2c_adapter* i2c_get_adapter(int index);
 
 /* Return the functionality mask */
 extern u32 i2c_get_functionality (struct i2c_adapter *adap);
diff -urN linux-2.4.19/include/linux/i2c-id.h linux-2.4.19.new/include/linux/i2c-id.h
--- linux-2.4.19/include/linux/i2c-id.h	Thu Oct 11 08:05:47 2001
+++ linux-2.4.19.new/include/linux/i2c-id.h	Tue Nov 11 10:30:51 2003
@@ -189,6 +189,8 @@
 /* --- MPC8xx PowerPC adapters						*/
 #define I2C_HW_MPC8XX_EPON 0x00	/* Eponymous MPC8xx I2C adapter 	*/
 
+#define I2C_HW_VIRT	0x01 	/* Virtualized adapter                  */
+
 /* --- SMBus only adapters						*/
 #define I2C_HW_SMBUS_PIIX4	0x00
 #define I2C_HW_SMBUS_ALI15X3	0x01

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH] - i2c virtual adapter driver for multiplexed busses
  2005-05-19  6:24 [PATCH] - i2c virtual adapter driver for multiplexed busses Brian Kuschak
  2005-05-19  6:24 ` Brian Kuschak
@ 2005-05-19  6:24 ` Mark Studebaker
  2005-05-19  6:24 ` Mark Studebaker
  2 siblings, 0 replies; 4+ messages in thread
From: Mark Studebaker @ 2005-05-19  6:24 UTC (permalink / raw)
  To: lm-sensors

excellent. here's some first comments.
Thanks for doing some good documentation.

- I think i2c-virtual is really the algorithm driver
(i2c-algo-virtual?).
  It contains a common algorithm for virtual drivers.

- Therefore i2c-virtual_cb is the adapter driver, specific to the
  PCA954x chips (ic2-pca954x?).
  The algo/adapter boundary in the 405 driver you copied may be a little
muddy.
  See i2c-algo-bit and its many adapter drivers in sensors for examples.

- I'd rather not add entries to struct i2c_algorithm, we just went
through that
  hell and are finishing a patch to go to Marcelo. Rather than
xxx_exclusive,
  we could use the (essentially unused) algo_control. i2c-core could
recognize
  that a driver is virtual by adding a functionality entry to identify
that
  it is virtual. If you really want it the way it is we need to put
#ifdefs everywhere
  so we can stay compatible, at least for now...

- If i2c-pca954x also registered as a chip driver (sensors-style)
  (that is, be an i2c client as well) at addresses 0x70-77 then it will
  get called whenever a device is found at that location, it can do
detection
  (if possible -doesn't look like it) and then register the new busses,
and
  everything gets bootstrapped. You'll get called anytime a bus
  is registered. That's better than simply scanning the
  adapters already present at module_init time.

- It's much easier for us if you give us a patch against CVS, or else
patch
  your kernel with our kernel patches first (see home page) and then
give us a patch
  against that kernel. At least for i2c-core.

Brian Kuschak wrote:
> 
> Hi Greg, Mark,
> 
> As described in a previous email to this list, this is
> a patch for simplified access to multiplexed i2c
> busses.  A documentation file is included, as well as
> an example (i2c-virtual_cb.c) of how to implement the
> mux-control callbacks.
> 
> Tested on a heavily patched 2.4.19 kernel on embedded
> PowerPC.  However, this patch is against a clean
> kernel.org 2.4.19 tree.  I don't have the bandwidth to
> port this to 2.6.0 right now, but I wanted to make it
> available in case someone else finds it useful.
> 
> Comments/feedback welcome.
> 
> Thanks,
> Brian Kuschak
> 
> __________________________________
> Do you Yahoo!?
> Protect your identity with Yahoo! Mail AddressGuard
> http://antispam.yahoo.com/whatsnewfree
> 
> 
>                                   Name: i2c_virtual.2_4_19.patch
>    i2c_virtual.2_4_19.patch       Type: Plain Text (text/plain)
>                            Description: i2c_virtual.2_4_19.patch

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH] - i2c virtual adapter driver for multiplexed busses
  2005-05-19  6:24 [PATCH] - i2c virtual adapter driver for multiplexed busses Brian Kuschak
@ 2005-05-19  6:24 ` Brian Kuschak
  2005-05-19  6:24 ` Mark Studebaker
  2005-05-19  6:24 ` Mark Studebaker
  2 siblings, 0 replies; 4+ messages in thread
From: Brian Kuschak @ 2005-05-19  6:24 UTC (permalink / raw)
  To: lm-sensors

Hi Mark, 
See my comments below.
Regards, Brian

> 
> - I think i2c-virtual is really the algorithm driver
> (i2c-algo-virtual?).
>   It contains a common algorithm for virtual
> drivers.
> 
> - Therefore i2c-virtual_cb is the adapter driver,
> specific to the
>   PCA954x chips (ic2-pca954x?).
>   The algo/adapter boundary in the 405 driver you
> copied may be a little
> muddy.
>   See i2c-algo-bit and its many adapter drivers in
> sensors for examples.
> 

It's quite possible I muddied the boundaries here. 
The reason for keeping the main functionality out of
i2c-virtual_cb.c is that this file is where the
user-specific and platform-specific code resides.  The
makefiles in the patch don't actually use
i2c-virtual_cb.c - it was included more as an example
of usage.  In my case, at least, the callbacks are
where some of our proprietary code resides and I
wanted to keep that isolated.

> - I'd rather not add entries to struct
> i2c_algorithm, we just went
> through that
>   hell and are finishing a patch to go to Marcelo.
> Rather than
> xxx_exclusive,
>   we could use the (essentially unused)
> algo_control. i2c-core could
> recognize
>   that a driver is virtual by adding a functionality
> entry to identify
> that
>   it is virtual. If you really want it the way it is
> we need to put
> #ifdefs everywhere
>   so we can stay compatible, at least for now...
> 

Point well taken.  This sounds like a reasonable
change.

One comment is that the bus exclusivity and
multiplexing are two separate things.  Even a regular
non-multiplexed bus may require 'arbitration' with
other blades before being allowed to use it.  Likewise
some multiplexed busses may not require arbitration. 

> - If i2c-pca954x also registered as a chip driver
> (sensors-style)
>   (that is, be an i2c client as well) at addresses
> 0x70-77 then it will
>   get called whenever a device is found at that
> location, it can do
> detection
>   (if possible -doesn't look like it) and then
> register the new busses,
> and
>   everything gets bootstrapped. You'll get called
> anytime a bus
>   is registered. That's better than simply scanning
> the
>   adapters already present at module_init time.
> 

Yes, I originally thought about doing exactly that. 
In our application due to the variety of different HW
platforms it made more sense to register these busses
manually based on a priori knowledge of the HW.

I'll try to put together a little pcf954x client
driver to do the runtime registration of the virtual
busses, since that will likely be more useful for the
larger audience.

> - It's much easier for us if you give us a patch
> against CVS, or else
> patch
>   your kernel with our kernel patches first (see
> home page) and then
> give us a patch
>   against that kernel. At least for i2c-core.
> 

Understood.  Is your CVS based on 2.4 or 2.6?

> Brian Kuschak wrote:
> > 
> > Hi Greg, Mark,
> > 
> > As described in a previous email to this list,
> this is
> > a patch for simplified access to multiplexed i2c
> > busses.  A documentation file is included, as well
> as
> > an example (i2c-virtual_cb.c) of how to implement
> the
> > mux-control callbacks.
> > 
> > Tested on a heavily patched 2.4.19 kernel on
> embedded
> > PowerPC.  However, this patch is against a clean
> > kernel.org 2.4.19 tree.  I don't have the
> bandwidth to
> > port this to 2.6.0 right now, but I wanted to make
> it
> > available in case someone else finds it useful.
> > 
> > Comments/feedback welcome.
> > 
> > Thanks,
> > Brian Kuschak
> > 
> > __________________________________
> > Do you Yahoo!?
> > Protect your identity with Yahoo! Mail
> AddressGuard
> > http://antispam.yahoo.com/whatsnewfree
> > 
> > 
> >                                   Name:
> i2c_virtual.2_4_19.patch
> >    i2c_virtual.2_4_19.patch       Type: Plain Text
> (text/plain)
> >                            Description:
i2c_virtual.2_4_19.patch


__________________________________
Do you Yahoo!?
Protect your identity with Yahoo! Mail AddressGuard
http://antispam.yahoo.com/whatsnewfree

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH] - i2c virtual adapter driver for multiplexed busses
  2005-05-19  6:24 [PATCH] - i2c virtual adapter driver for multiplexed busses Brian Kuschak
  2005-05-19  6:24 ` Brian Kuschak
  2005-05-19  6:24 ` Mark Studebaker
@ 2005-05-19  6:24 ` Mark Studebaker
  2 siblings, 0 replies; 4+ messages in thread
From: Mark Studebaker @ 2005-05-19  6:24 UTC (permalink / raw)
  To: lm-sensors

inline

Brian Kuschak wrote:
> 
> Hi Mark,
> See my comments below.
> Regards, Brian
> 
> >
> > - I think i2c-virtual is really the algorithm driver
> > (i2c-algo-virtual?).
> >   It contains a common algorithm for virtual
> > drivers.
> >
> > - Therefore i2c-virtual_cb is the adapter driver,
> > specific to the
> >   PCA954x chips (ic2-pca954x?).
> >   The algo/adapter boundary in the 405 driver you
> > copied may be a little
> > muddy.
> >   See i2c-algo-bit and its many adapter drivers in
> > sensors for examples.
> >
> 
> It's quite possible I muddied the boundaries here.
> The reason for keeping the main functionality out of
> i2c-virtual_cb.c is that this file is where the
> user-specific and platform-specific code resides.  The
> makefiles in the patch don't actually use
> i2c-virtual_cb.c - it was included more as an example
> of usage.  In my case, at least, the callbacks are
> where some of our proprietary code resides and I
> wanted to keep that isolated.
> 

we're in agreement. You did it right, I'm just conceptually mapping what
you did
onto our naming conventions. i2c-virtual is a generic 'algorithm" and
i2c-virtual-cb is one of many possible hardware-specific "adapters"
using that algorithm.


> > - I'd rather not add entries to struct
> > i2c_algorithm, we just went
> > through that
> >   hell and are finishing a patch to go to Marcelo.
> > Rather than
> > xxx_exclusive,
> >   we could use the (essentially unused)
> > algo_control. i2c-core could
> > recognize
> >   that a driver is virtual by adding a functionality
> > entry to identify
> > that
> >   it is virtual. If you really want it the way it is
> > we need to put
> > #ifdefs everywhere
> >   so we can stay compatible, at least for now...
> >
> 
> Point well taken.  This sounds like a reasonable
> change.
> 
> One comment is that the bus exclusivity and
> multiplexing are two separate things.  Even a regular
> non-multiplexed bus may require 'arbitration' with
> other blades before being allowed to use it.  Likewise
> some multiplexed busses may not require arbitration.
> 

ok. if they are two separate things let's keep them separate...


> > - If i2c-pca954x also registered as a chip driver
> > (sensors-style)
> >   (that is, be an i2c client as well) at addresses
> > 0x70-77 then it will
> >   get called whenever a device is found at that
> > location, it can do
> > detection
> >   (if possible -doesn't look like it) and then
> > register the new busses,
> > and
> >   everything gets bootstrapped. You'll get called
> > anytime a bus
> >   is registered. That's better than simply scanning
> > the
> >   adapters already present at module_init time.
> >
> 
> Yes, I originally thought about doing exactly that.
> In our application due to the variety of different HW
> platforms it made more sense to register these busses
> manually based on a priori knowledge of the HW.
> 
> I'll try to put together a little pcf954x client
> driver to do the runtime registration of the virtual
> busses, since that will likely be more useful for the
> larger audience.
> 

do that and you don't need the bus scan in i2c-virtual I don't think
(i2c-core scans for you).
also you can greatly simplify i2c-virtual-cb by using the
i2c_smbus_write_byte function from i2c-core rather than calling
master_xfer directly.

> > - It's much easier for us if you give us a patch
> > against CVS, or else
> > patch
> >   your kernel with our kernel patches first (see
> > home page) and then
> > give us a patch
> >   against that kernel. At least for i2c-core.
> >
> 
> Understood.  Is your CVS based on 2.4 or 2.6?
> 

2.4


> > Brian Kuschak wrote:
> > >
> > > Hi Greg, Mark,
> > >
> > > As described in a previous email to this list,
> > this is
> > > a patch for simplified access to multiplexed i2c
> > > busses.  A documentation file is included, as well
> > as
> > > an example (i2c-virtual_cb.c) of how to implement
> > the
> > > mux-control callbacks.
> > >
> > > Tested on a heavily patched 2.4.19 kernel on
> > embedded
> > > PowerPC.  However, this patch is against a clean
> > > kernel.org 2.4.19 tree.  I don't have the
> > bandwidth to
> > > port this to 2.6.0 right now, but I wanted to make
> > it
> > > available in case someone else finds it useful.
> > >
> > > Comments/feedback welcome.
> > >
> > > Thanks,
> > > Brian Kuschak
> > >
> > > __________________________________
> > > Do you Yahoo!?
> > > Protect your identity with Yahoo! Mail
> > AddressGuard
> > > http://antispam.yahoo.com/whatsnewfree
> > >
> > >
> > >                                   Name:
> > i2c_virtual.2_4_19.patch
> > >    i2c_virtual.2_4_19.patch       Type: Plain Text
> > (text/plain)
> > >                            Description:
> i2c_virtual.2_4_19.patch
> 
> __________________________________
> Do you Yahoo!?
> Protect your identity with Yahoo! Mail AddressGuard
> http://antispam.yahoo.com/whatsnewfree

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2005-05-19  6:24 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-05-19  6:24 [PATCH] - i2c virtual adapter driver for multiplexed busses Brian Kuschak
2005-05-19  6:24 ` Brian Kuschak
2005-05-19  6:24 ` Mark Studebaker
2005-05-19  6:24 ` Mark Studebaker

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.