- i2c-add-support-for-virtual-i2c-adapters.patch removed from -mm tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The patch titled

     i2c: Add support for virtual I2C adapters

has been removed from the -mm tree.  Its filename is

     i2c-add-support-for-virtual-i2c-adapters.patch

This patch was probably dropped from -mm because
it has now been merged into a subsystem tree or
into Linus's tree, or because it was folded into
its parent patch in the -mm tree.

------------------------------------------------------
Subject: i2c: Add support for virtual I2C adapters
From: Kumar Gala <galak@xxxxxxxxxxxxxxxxxxx>


Virtual adapters are useful to handle multiplexed I2C bus topologies, by
presenting each multiplexed segment as a I2C adapter.  Typically, either a
mux (or switch) exists which is an I2C device on the parent bus.  One
selects a given child bus via programming the mux and then all the devices
on that bus become present on the parent bus.  The intent is to allow
multiple devices of the same type to exist in a system which would normally
have address conflicts.

Since virtual adapters will get registered in an I2C client's detect
function we have to expose versions of i2c_{add,del}_adapter for
i2c_{add,del}_virt_adapter to call that don't lock.

Additionally, i2c_virt_master_xfer (and i2c_virt_smbus_xfer) acquire the
parent->bus_lock and call the parent's master_xfer directly.  This is
because on a i2c_virt_master_xfer we have issue an i2c write on the parent
bus to select the given virtual adapter, then do the i2c operation on the
parent bus, followed by another i2c write on the parent to deslect the
virtual adapter.

Signed-off-by: Kumar Gala <galak@xxxxxxxxxxxxxxxxxxx>
Cc: Jean Delvare <khali@xxxxxxxxxxxx>
Cc: Greg KH <greg@xxxxxxxxx>
Signed-off-by: Andrew Morton <akpm@xxxxxxxx>
---

 drivers/i2c/Kconfig    |    9 ++
 drivers/i2c/Makefile   |    1 
 drivers/i2c/i2c-core.c |   45 ++++++----
 drivers/i2c/i2c-virt.c |  174 +++++++++++++++++++++++++++++++++++++++
 include/linux/i2c-id.h |    2 
 include/linux/i2c.h    |   20 ++++
 6 files changed, 237 insertions(+), 14 deletions(-)

diff -puN drivers/i2c/i2c-core.c~i2c-add-support-for-virtual-i2c-adapters drivers/i2c/i2c-core.c
--- devel/drivers/i2c/i2c-core.c~i2c-add-support-for-virtual-i2c-adapters	2006-04-22 01:39:11.000000000 -0700
+++ devel-akpm/drivers/i2c/i2c-core.c	2006-04-22 01:39:11.000000000 -0700
@@ -150,22 +150,31 @@ static struct device_attribute dev_attr_
  */
 int i2c_add_adapter(struct i2c_adapter *adap)
 {
+	int res;
+
+	mutex_lock(&core_lists);
+	res = i2c_add_adapter_nolock(adap);
+	mutex_unlock(&core_lists);
+
+	return res;
+}
+
+int i2c_add_adapter_nolock(struct i2c_adapter *adap)
+{
 	int id, res = 0;
 	struct list_head   *item;
 	struct i2c_driver  *driver;
 
-	mutex_lock(&core_lists);
-
 	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) {
 		res = -ENOMEM;
-		goto out_unlock;
+		goto out;
 	}
 
 	res = idr_get_new(&i2c_adapter_idr, adap, &id);
 	if (res < 0) {
 		if (res == -EAGAIN)
 			res = -ENOMEM;
-		goto out_unlock;
+		goto out;
 	}
 
 	adap->nr =  id & MAX_ID_MASK;
@@ -203,21 +212,30 @@ int i2c_add_adapter(struct i2c_adapter *
 			driver->attach_adapter(adap);
 	}
 
-out_unlock:
-	mutex_unlock(&core_lists);
+out:
 	return res;
 }
-
+EXPORT_SYMBOL_GPL(i2c_add_adapter_nolock);
 
 int i2c_del_adapter(struct i2c_adapter *adap)
 {
+	int res;
+
+	mutex_lock(&core_lists);
+	res = i2c_del_adapter_nolock(adap);
+	mutex_unlock(&core_lists);
+
+	return res;
+}
+
+int i2c_del_adapter_nolock(struct i2c_adapter *adap)
+{
 	struct list_head  *item, *_n;
 	struct i2c_adapter *adap_from_list;
 	struct i2c_driver *driver;
 	struct i2c_client *client;
 	int res = 0;
 
-	mutex_lock(&core_lists);
 
 	/* First make sure that this adapter was ever added */
 	list_for_each_entry(adap_from_list, &adapters, list) {
@@ -228,7 +246,7 @@ int i2c_del_adapter(struct i2c_adapter *
 		pr_debug("i2c-core: attempting to delete unregistered "
 			 "adapter [%s]\n", adap->name);
 		res = -EINVAL;
-		goto out_unlock;
+		goto out;
 	}
 
 	list_for_each(item,&drivers) {
@@ -238,7 +256,7 @@ int i2c_del_adapter(struct i2c_adapter *
 				dev_err(&adap->dev, "detach_adapter failed "
 					"for driver [%s]\n",
 					driver->driver.name);
-				goto out_unlock;
+				goto out;
 			}
 	}
 
@@ -251,7 +269,7 @@ int i2c_del_adapter(struct i2c_adapter *
 			dev_err(&adap->dev, "detach_client failed for client "
 				"[%s] at address 0x%02x\n", client->name,
 				client->addr);
-			goto out_unlock;
+			goto out;
 		}
 	}
 
@@ -272,11 +290,10 @@ int i2c_del_adapter(struct i2c_adapter *
 
 	dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
 
- out_unlock:
-	mutex_unlock(&core_lists);
+out:
 	return res;
 }
-
+EXPORT_SYMBOL_GPL(i2c_del_adapter_nolock);
 
 /* -----
  * What follows is the "upwards" interface: commands for talking to clients,
diff -puN /dev/null drivers/i2c/i2c-virt.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/i2c/i2c-virt.c	2006-04-22 01:39:11.000000000 -0700
@@ -0,0 +1,174 @@
+/*
+ * i2c-virtual.c - 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).
+ *
+ * Based on:
+ *    i2c-virtual.c from Copyright (c) 2004 Google, Inc. (Ken Harrenstien)
+ *    i2c-virtual.c from Brian Kuschak <bkuschak@xxxxxxxxx>
+ * which was:
+ *    Adapted from i2c-adap-ibm_ocp.c
+ *    Original file Copyright 2000-2002 MontaVista Software Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+
+struct i2c_virt_priv {
+	struct i2c_adapter *parent_adap;
+	struct i2c_client *client;	/* The mux chip/device */
+
+	u32 id;				/* the mux id */
+
+	/* fn which enables the mux */
+	int (*select) (struct i2c_adapter *, struct i2c_client *, u32);
+
+	/* fn which disables the mux */
+	int (*deselect) (struct i2c_adapter *, struct i2c_client *, u32);
+};
+
+#define VIRT_TIMEOUT		(HZ/2)
+#define VIRT_RETRIES		3
+
+static int
+i2c_virt_master_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct i2c_virt_priv *priv = adap->algo_data;
+	struct i2c_adapter *parent = priv->parent_adap;
+	int ret;
+
+	/* Grab the lock for the parent adapter.  We already hold the lock for
+	   the virtual adapter.  Then select the right mux port and perform
+	   the transfer.
+	 */
+
+	mutex_lock(&parent->bus_lock);
+	ret = priv->select(parent, priv->client, priv->id);
+	if (ret >= 0)
+		ret = parent->algo->master_xfer(parent, msgs, num);
+	priv->deselect(parent, priv->client, priv->id);
+	mutex_unlock(&parent->bus_lock);
+
+	return ret;
+}
+
+static int
+i2c_virt_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+		    unsigned short flags, char read_write,
+		    u8 command, int size, union i2c_smbus_data *data)
+{
+	struct i2c_virt_priv *priv = adap->algo_data;
+	struct i2c_adapter *parent = priv->parent_adap;
+	int ret;
+
+	/* Grab the lock for the parent adapter.  We already hold the lock for
+	   the virtual adapter.  Then select the right mux port and perform
+	   the transfer.
+	 */
+
+	mutex_lock(&parent->bus_lock);
+	ret = priv->select(parent, priv->client, priv->id);
+	if (ret == 0)
+		ret = parent->algo->smbus_xfer(parent, addr, flags,
+					       read_write, command, size, data);
+	priv->deselect(parent, priv->client, priv->id);
+	mutex_unlock(&parent->bus_lock);
+
+	return ret;
+}
+
+/* return the parent's functionality for the virtual adapter */
+static u32 i2c_virt_functionality(struct i2c_adapter *adap)
+{
+	struct i2c_virt_priv *priv = adap->algo_data;
+	struct i2c_adapter *parent = priv->parent_adap;
+
+	return parent->algo->functionality(parent);
+}
+
+struct i2c_adapter *
+i2c_add_virt_adapter(struct i2c_adapter *parent, struct i2c_client *client,
+		     u32 mux_val,
+		     int (*select_cb) (struct i2c_adapter *,
+				       struct i2c_client *, u32),
+		     int (*deselect_cb) (struct i2c_adapter *,
+					 struct i2c_client *, u32))
+{
+	struct i2c_adapter *adap;
+	struct i2c_virt_priv *priv;
+	struct i2c_algorithm *algo;
+
+	adap = kzalloc(sizeof(struct i2c_adapter) + sizeof(struct i2c_virt_priv)
+			     + sizeof(struct i2c_algorithm), GFP_KERNEL);
+	if (!adap)
+		return NULL;
+
+	priv = (struct i2c_virt_priv *)(adap + 1);
+	algo = (struct i2c_algorithm *)(priv + 1);
+
+	/* Set up private adapter data */
+	priv->parent_adap = parent;
+	priv->client = client;
+	priv->id = mux_val;
+	priv->select = select_cb;
+	priv->deselect = deselect_cb;
+
+	/* Need to do algo dynamically because we don't know ahead
+	   of time what sort of physical adapter we'll be dealing with.
+	 */
+	algo->master_xfer = (parent->algo->master_xfer
+			     ? i2c_virt_master_xfer : NULL);
+	algo->smbus_xfer = (parent->algo->smbus_xfer
+			    ? i2c_virt_smbus_xfer : NULL);
+	algo->functionality = i2c_virt_functionality;
+
+	/* Now fill out new adapter structure */
+	snprintf(adap->name, sizeof(adap->name),
+		 "Virtual I2C (i2c-%d, mux %02x:%02x)",
+		 i2c_adapter_id(parent), client->addr, mux_val);
+	adap->id = I2C_HW_VIRT | i2c_adapter_id(parent);
+	adap->algo = algo;
+	adap->algo_data = priv;
+	adap->timeout = VIRT_TIMEOUT;
+	adap->retries = VIRT_RETRIES;
+	adap->dev.parent = &parent->dev;
+
+	if (i2c_add_adapter_nolock(adap) < 0) {
+		kfree(adap);
+		return NULL;
+	}
+
+	printk(KERN_NOTICE "i2c-%d: Virtual I2C bus "
+	       "(Physical bus i2c-%d, multiplexer 0x%02x port %d)\n",
+	       i2c_adapter_id(adap), i2c_adapter_id(parent),
+	       client->addr, mux_val);
+
+	return adap;
+}
+
+int i2c_del_virt_adapter(struct i2c_adapter *adap)
+{
+	int ret;
+
+	ret = i2c_del_adapter_nolock(adap);
+	if (ret < 0)
+		return ret;
+	kfree(adap);
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(i2c_add_virt_adapter);
+EXPORT_SYMBOL_GPL(i2c_del_virt_adapter);
+
+MODULE_AUTHOR("Kumar Gala <galak@xxxxxxxxxxxxxxxxxxx>");
+MODULE_DESCRIPTION("Virtual I2C driver for multiplexed I2C busses");
+MODULE_LICENSE("GPL");
diff -puN drivers/i2c/Kconfig~i2c-add-support-for-virtual-i2c-adapters drivers/i2c/Kconfig
--- devel/drivers/i2c/Kconfig~i2c-add-support-for-virtual-i2c-adapters	2006-04-22 01:39:11.000000000 -0700
+++ devel-akpm/drivers/i2c/Kconfig	2006-04-22 01:39:11.000000000 -0700
@@ -34,6 +34,15 @@ config I2C_CHARDEV
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-dev.
 
+config I2C_VIRT
+	tristate "I2C virtual adapter support"
+	depends on I2C
+	help
+	  Say Y here if you want the I2C core to support the ability to have
+	  virtual adapters. Virtual adapters are useful to handle multiplexed
+	  I2C bus topologies, by presenting each multiplexed segment as a
+	  I2C adapter.
+
 source drivers/i2c/algos/Kconfig
 source drivers/i2c/busses/Kconfig
 source drivers/i2c/chips/Kconfig
diff -puN drivers/i2c/Makefile~i2c-add-support-for-virtual-i2c-adapters drivers/i2c/Makefile
--- devel/drivers/i2c/Makefile~i2c-add-support-for-virtual-i2c-adapters	2006-04-22 01:39:11.000000000 -0700
+++ devel-akpm/drivers/i2c/Makefile	2006-04-22 01:39:11.000000000 -0700
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_I2C)		+= i2c-core.o
+obj-$(CONFIG_I2C_VIRT)		+= i2c-virt.o
 obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
 obj-y				+= busses/ chips/ algos/
 
diff -puN include/linux/i2c.h~i2c-add-support-for-virtual-i2c-adapters include/linux/i2c.h
--- devel/include/linux/i2c.h~i2c-add-support-for-virtual-i2c-adapters	2006-04-22 01:39:11.000000000 -0700
+++ devel-akpm/include/linux/i2c.h	2006-04-22 01:39:11.000000000 -0700
@@ -294,6 +294,10 @@ struct i2c_client_address_data {
 extern int i2c_add_adapter(struct i2c_adapter *);
 extern int i2c_del_adapter(struct i2c_adapter *);
 
+/* Assume the caller has the core_list lock already */
+extern int i2c_add_adapter_nolock(struct i2c_adapter *);
+extern int i2c_del_adapter_nolock(struct i2c_adapter *);
+
 extern int i2c_register_driver(struct module *, struct i2c_driver *);
 extern int i2c_del_driver(struct i2c_driver *);
 
@@ -440,6 +444,22 @@ union i2c_smbus_data {
 #define I2C_SMBUS_I2C_BLOCK_DATA    6
 #define I2C_SMBUS_BLOCK_PROC_CALL   7		/* SMBus 2.0 */
 
+/*
+ * Called to create a 'virtual' i2c bus which represents a multiplexed bus
+ * segment.  The client and mux_val are passed to the select and deselect
+ * callback functions to perform hardware-specific mux control.
+ *
+ * The caller is expected to have the core_lists lock
+ */
+struct i2c_adapter *
+i2c_add_virt_adapter(struct i2c_adapter *parent, struct i2c_client *client,
+		     u32 mux_val,
+		     int (*select_cb) (struct i2c_adapter *,
+				       struct i2c_client *, u32),
+		     int (*deselect_cb) (struct i2c_adapter *,
+					 struct i2c_client *, u32));
+
+int i2c_del_virt_adapter(struct i2c_adapter *adap);
 
 /* ----- commands for the ioctl like i2c_command call:
  * note that additional calls are defined in the algorithm and hw 
diff -puN include/linux/i2c-id.h~i2c-add-support-for-virtual-i2c-adapters include/linux/i2c-id.h
--- devel/include/linux/i2c-id.h~i2c-add-support-for-virtual-i2c-adapters	2006-04-22 01:39:11.000000000 -0700
+++ devel-akpm/include/linux/i2c-id.h	2006-04-22 01:39:11.000000000 -0700
@@ -267,4 +267,6 @@
 #define I2C_HW_SAA7146		0x060000 /* SAA7146 video decoder bus */
 #define I2C_HW_SAA7134		0x090000 /* SAA7134 video decoder bus */
 
+#define I2C_HW_VIRT		0x80000000 /* a virtual adapter */
+
 #endif /* LINUX_I2C_ID_H */
_

Patches currently in -mm which might be from galak@xxxxxxxxxxxxxxxxxxx are

i2c-pca954x-i2c-mux-driver.patch
i2c-mpc-fix-up-error-handling.patch
i2c-pca954x-fix-initial-access-to-first-mux-switch-port.patch
git-powerpc.patch

-
To unsubscribe from this list: send the line "unsubscribe mm-commits" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Kernel Newbies FAQ]     [Kernel Archive]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Photo]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux