i2c-algo-pcf: Multi-master lost-arbitration improvement
authorEric Brower <ebrower@gmail.com>
Mon, 14 Jul 2008 20:38:31 +0000 (22:38 +0200)
committerJean Delvare <khali@mahadeva.delvare>
Mon, 14 Jul 2008 20:38:31 +0000 (22:38 +0200)
Improve lost-arbitration handling of PCF8584.  This is necessary for
support of a currently out-of-kernel driver for Sun Microsystems E250
environmental management; perhaps others.

Signed-off-by: Eric Brower <ebrower@gmail.com>
Acked-by: Dan Smolik <marvin@mydatex.cz>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
drivers/i2c/algos/i2c-algo-pcf.c
include/linux/i2c-algo-pcf.h

index 8907b01..1e328d1 100644 (file)
@@ -78,6 +78,36 @@ static void i2c_stop(struct i2c_algo_pcf_data *adap)
        set_pcf(adap, 1, I2C_PCF_STOP);
 }
 
+static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status)
+{
+       DEB2(printk(KERN_INFO
+               "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
+                *status));
+
+       /* Cleanup from LAB -- reset and enable ESO.
+        * This resets the PCF8584; since we've lost the bus, no
+        * further attempts should be made by callers to clean up
+        * (no i2c_stop() etc.)
+        */
+       set_pcf(adap, 1, I2C_PCF_PIN);
+       set_pcf(adap, 1, I2C_PCF_ESO);
+
+       /* We pause for a time period sufficient for any running
+        * I2C transaction to complete -- the arbitration logic won't
+        * work properly until the next START is seen.
+        * It is assumed the bus driver or client has set a proper value.
+        *
+        * REVISIT: should probably use msleep instead of mdelay if we
+        * know we can sleep.
+        */
+       if (adap->lab_mdelay)
+               mdelay(adap->lab_mdelay);
+
+       DEB2(printk(KERN_INFO
+               "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
+               get_pcf(adap, 1)));
+}
+
 static int wait_for_bb(struct i2c_algo_pcf_data *adap) {
 
        int timeout = DEF_TIMEOUT;
@@ -109,23 +139,7 @@ static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) {
                *status = get_pcf(adap, 1);
        }
        if (*status & I2C_PCF_LAB) {
-               DEB2(printk(KERN_INFO 
-                       "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
-                        *status));
-               /* Cleanup from LAB-- reset and enable ESO.
-                * This resets the PCF8584; since we've lost the bus, no
-                * further attempts should be made by callers to clean up 
-                * (no i2c_stop() etc.)
-                */
-               set_pcf(adap, 1, I2C_PCF_PIN);
-               set_pcf(adap, 1, I2C_PCF_ESO);
-               /* TODO: we should pause for a time period sufficient for any
-                * running I2C transaction to complete-- the arbitration
-                * logic won't work properly until the next START is seen.
-                */
-               DEB2(printk(KERN_INFO 
-                       "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n", 
-                       get_pcf(adap,1)));
+               handle_lab(adap, status);
                return(-EINTR);
        }
 #endif
index 77afbb6..74fb6f8 100644 (file)
@@ -36,6 +36,12 @@ struct i2c_algo_pcf_data {
        /* local settings */
        int udelay;
        int timeout;
+
+       /* Multi-master lost arbitration back-off delay (msecs)
+        * This should be set by the bus adapter or knowledgable client
+        * if bus is multi-mastered, else zero
+        */
+       unsigned long lab_mdelay;
 };
 
 int i2c_pcf_add_bus(struct i2c_adapter *);