Re: [PATCH] make the registers of the stv0297 visible for other applications (e.g. i2cdump)

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

 



On Sat, 19 May 2007, e9hack wrote:
> Trent Piepho wrote:
> > On Fri, 18 May 2007, Johannes Stezenbach wrote:
> >> Or you could propose a change to i2c-core to add
> >> a I2C_M_STOP flag (analogous to I2C_M_NOSTART), which
> >> then would have to be implemented by all i2c bus drivers.
> >
> > It seems like this is the only way to send multiple stops in a single
> > atomic transaction.  All drivers wouldn't have to implement it, just the
> > ones where someone actually wants this ability.  Few drivers actually
> > implement all of the existing i2c features.
> >
>
> It is a big difference between the I2C_M_STOP and the I2C_M_NOSTART flag. I2C_M_NOSTART is a nice feature, which a
> master may implement. If I look through the different implementations, it isn't defined exactly, what it means.
> I2C_M_STOP is a must have for the master, if a slave is connected to the bus like the stv0297.

It doesn't seem any different than I2C_M_TEN, I2C_M_NO_RD_ACK, etc. in that a
slave that needs one of these features won't work with a master (i2c_adapter
in Linux I2C terms) that doesn't implement them.  There are plenty of i2c
adapters that don't even support messages longer than two bytes or
transactions with more than one or two parts.

> It isn't necessary, that I2C_M_STOP is implemented by the master itself. It is possible to implement it in i2ctransfer.
> If the flag is set, each entry of the message array is send as a single request to the underlaying transfer function of

That's a good point, i2c_tranfer() is basically:

  mutex_lock(i2c_adapter->mutex);
  i2c_adapter->master_xfer(...);
  mutex_unlock(i2c_adapter->mutex);

The problem with stv0297 is that one wants multiple calls to master_xfer()
inside the mutex protected region.  It would be easy to have this code break a
series of i2c messages into multiple calls to master_xfer() with a I2C_M_STOP
flag.  Then all i2c_adapters could support I2C_M_STOP without needing to be
changed.  One could also support the flag inside an i2c_adapter driver, but
there doesn't seem to be much point.

I've written a patch that implements I2C_M_STOP.  It would be used like this:

char buf1[2] = {0x0b,0x3c}, buf2[1];
struct i2c_msg msgs[2] = {
	{ .addr = 0x61, .buf = buf1, .len = 2, .flags = I2C_M_STOP },
	{ .addr = 0x61, .buf = buf2, .len = 1, .flags = I2C_M_RD } };
i2c_transfer(adap, msgs, 2);

_Without_ the I2C_M_STOP flag, one would see a transfer like this:
i2c-adapter i2c-0: emitting start condition
i2c-adapter i2c-0: i2c_outb: 0xc2 A
i2c-adapter i2c-0: i2c_outb: 0x0b A
i2c-adapter i2c-0: i2c_outb: 0x3c A
i2c-adapter i2c-0: wrote 2 bytes
i2c-adapter i2c-0: emitting repeated start condition
i2c-adapter i2c-0: i2c_outb: 0xc3 A
i2c-adapter i2c-0: i2c_inb: 0x74 NA
i2c-adapter i2c-0: read 1 byte
i2c-adapter i2c-0: emitting stop condition

_With_ the I2C_M_STOP flag, one sees this:
i2c-adapter i2c-0: emitting start condition
i2c-adapter i2c-0: i2c_outb: 0xc2 A
i2c-adapter i2c-0: i2c_outb: 0x0b A
i2c-adapter i2c-0: i2c_outb: 0x3c A
i2c-adapter i2c-0: wrote 2 bytes
i2c-adapter i2c-0: emitting stop condition
i2c-adapter i2c-0: emitting start condition
i2c-adapter i2c-0: i2c_outb: 0xc3 A
i2c-adapter i2c-0: i2c_inb: 0x74 NA
i2c-adapter i2c-0: read 1 byte
i2c-adapter i2c-0: emitting stop condition

This would work for stv0297, wouldn't it?

--------------------------------------------------------------------
diff -r 56b4c3e8f350 drivers/i2c/i2c-core.c
--- a/drivers/i2c/i2c-core.c	Sat May 19 05:00:32 2007 +0000
+++ b/drivers/i2c/i2c-core.c	Sat May 19 17:35:19 2007 -0700
@@ -862,6 +862,7 @@ int i2c_transfer(struct i2c_adapter * ad
 	int ret;

 	if (adap->algo->master_xfer) {
+		int n, total = 0;
 #ifdef DEBUG
 		for (ret = 0; ret < num; ret++) {
 			dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
@@ -872,10 +873,28 @@ int i2c_transfer(struct i2c_adapter * ad
 #endif

 		mutex_lock_nested(&adap->bus_lock, adap->level);
-		ret = adap->algo->master_xfer(adap,msgs,num);
+		for (n=1; n<=num; n++) {
+			/* xfer the message(s) if we want a stop or if
+			   it's the last message. */
+			if (n == num || (msgs[n-1].flags & I2C_M_STOP)) {
+				ret = adap->algo->master_xfer(adap,msgs,n);
+
+				total += ret;
+				if (ret < n) {
+					/* Return error code, if any */
+					if (ret < 0)
+						total = ret;
+					break;
+				}
+
+				/* Process any remaining messages */
+				msgs += n;
+				num -= n;
+				n = 0;
+			}
+		}
 		mutex_unlock(&adap->bus_lock);
-
-		return ret;
+		return total;
 	} else {
 		dev_dbg(&adap->dev, "I2C level transfers not supported\n");
 		return -ENOSYS;
diff -r 56b4c3e8f350 include/linux/i2c.h
--- a/include/linux/i2c.h	Sat May 19 05:00:32 2007 +0000
+++ b/include/linux/i2c.h	Sat May 19 17:35:03 2007 -0700
@@ -448,6 +448,7 @@ struct i2c_msg {
 #define I2C_M_IGNORE_NAK	0x1000
 #define I2C_M_NO_RD_ACK		0x0800
 #define I2C_M_RECV_LEN		0x0400 /* length will be first received byte */
+#define I2C_M_STOP		0x0200 /* send STOP condition after this msg */
 	__u16 len;		/* msg length				*/
 	__u8 *buf;		/* pointer to msg data			*/
 };

_______________________________________________
linux-dvb mailing list
linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux