[i2c] [PATCH 1/2] Add polling transfer for i2c-pxa

Mike Rapoport mike at compulab.co.il
Thu Dec 6 10:10:26 CET 2007


Hi Jean,

This patchset adds ability to make i2c transfers in interrupts-off contexts and
implements polling transfers for i2c-pxa.
The i2c-core patch includes fixes for the issues you raised. The only problem
left is the mutex nesting, since, as you pointed there's no mutex_trylock_nested...

> I'm curious how many drivers will need this; I'm not sure I see the
> value. This could be implemented at the driver-level as well, and I
> think I'd prefer it that way, unless you have reasons to believe that
> many drivers will want this.

I think that most PMIC drivers will need this. There are cases when you need to
access the PMIC in interrupts-off context, for example during late suspend and
early resume.


Signed-off-by: Mike Rapoport <mike at compulab.co.il>

 drivers/i2c/i2c-core.c |   50 +++++++++++++++++++++++++++++++++++------------
 include/linux/i2c.h    |    5 ++++
 2 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index b5e13e4..059c6bd 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -33,6 +33,8 @@
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
 #include <linux/completion.h>
+#include <linux/hardirq.h>
+#include <linux/irqflags.h>
 #include <asm/uaccess.h>

 #include "i2c-core.h"
@@ -868,26 +870,48 @@ module_exit(i2c_exit);
 int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
 {
 	int ret;
+	int (*xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);

-	if (adap->algo->master_xfer) {
-#ifdef DEBUG
-		for (ret = 0; ret < num; ret++) {
-			dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
-				"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
-				? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
-				(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
+	if (in_atomic() || irqs_disabled()) {
+		if (adap->algo->master_nosleep_xfer == NULL) {
+			dev_dbg(&adap->dev, "algo has no nosleep xfer");
+			return -EINVAL;
 		}
-#endif
-
-		mutex_lock_nested(&adap->bus_lock, adap->level);
-		ret = adap->algo->master_xfer(adap,msgs,num);
-		mutex_unlock(&adap->bus_lock);
+		ret = mutex_trylock(&adap->bus_lock);
+		if (ret) {
+			/* We get bus_lock, no ongoing I2C activity on
+			   the Linux side */
+			ret = adap->algo->master_nosleep_xfer(adap, msgs, num);
+			mutex_unlock(&adap->bus_lock);
+			return ret;
+		} else {
+			/* I2C activity is ongoing. */
+			return -EAGAIN;
+		}
+	}

-		return ret;
+	if (adap->use_nosleep_xfer && adap->algo->master_nosleep_xfer) {
+		xfer = adap->algo->master_nosleep_xfer;
+	} else if (adap->algo->master_xfer) {
+		xfer = adap->algo->master_xfer;
 	} else {
 		dev_dbg(&adap->dev, "I2C level transfers not supported\n");
 		return -ENOSYS;
 	}
+
+#ifdef DEBUG
+	for (ret = 0; ret < num; ret++)
+		dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
+			"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
+			? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
+			(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
+#endif
+
+	mutex_lock_nested(&adap->bus_lock, adap->level);
+	ret = xfer(adap, msgs, num);
+	mutex_unlock(&adap->bus_lock);
+
+	return ret;
 }
 EXPORT_SYMBOL(i2c_transfer);

diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index a100c9f..bf4dca3 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -290,6 +290,10 @@ struct i2c_algorithm {
 	                   unsigned short flags, char read_write,
 	                   u8 command, int size, union i2c_smbus_data * data);

+	/* PIO xfer can be used in no-interrupts context */
+	int (*master_nosleep_xfer)(struct i2c_adapter *adap,
+				   struct i2c_msg *msgs, int num);
+
 	/* To determine what the adapter supports */
 	u32 (*functionality) (struct i2c_adapter *);
 };
@@ -304,6 +308,7 @@ struct i2c_adapter {
 	unsigned int class;
 	const struct i2c_algorithm *algo; /* the algorithm to access the bus */
 	void *algo_data;
+	int use_nosleep_xfer;

 	/* --- administration stuff. */
 	int (*client_register)(struct i2c_client *);

-- 
Sincerely yours,
Mike.





More information about the i2c mailing list