Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / i2c / algos / i2c-algo-pcf.c
index b53f65a..6e498df 100644 (file)
@@ -38,8 +38,6 @@
 #include "i2c-algo-pcf.h"
 
 
-/* ----- global defines ----------------------------------------------- */
-#define DEB(x) if (i2c_debug>=1) x
 #define DEB2(x) if (i2c_debug>=2) x
 #define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/
 #define DEBPROTO(x) if (i2c_debug>=9) x;
@@ -48,7 +46,7 @@
 
 /* module parameters:
  */
-static int i2c_debug=0;
+static int i2c_debug;
 
 /* --- setting states on the bus with the right timing: ---------------        */
 
@@ -80,7 +78,6 @@ static void i2c_stop(struct i2c_algo_pcf_data *adap)
        set_pcf(adap, 1, I2C_PCF_STOP);
 }
 
-
 static int wait_for_bb(struct i2c_algo_pcf_data *adap) {
 
        int timeout = DEF_TIMEOUT;
@@ -101,12 +98,6 @@ static int wait_for_bb(struct i2c_algo_pcf_data *adap) {
 }
 
 
-static inline void pcf_sleep(unsigned long timeout)
-{
-       schedule_timeout( timeout * HZ);
-}
-
-
 static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) {
 
        int timeout = DEF_TIMEOUT;
@@ -117,6 +108,26 @@ static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) {
                adap->waitforpin();
                *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)));
+               return(-EINTR);
+       }
 #endif
        if (timeout <= 0)
                return(-1);
@@ -196,16 +207,22 @@ static inline int try_address(struct i2c_algo_pcf_data *adap,
                       unsigned char addr, int retries)
 {
        int i, status, ret = -1;
+       int wfp;
        for (i=0;i<retries;i++) {
                i2c_outb(adap, addr);
                i2c_start(adap);
                status = get_pcf(adap, 1);
-               if (wait_for_pin(adap, &status) >= 0) {
+               if ((wfp = wait_for_pin(adap, &status)) >= 0) {
                        if ((status & I2C_PCF_LRB) == 0) { 
                                i2c_stop(adap);
                                break;  /* success! */
                        }
                }
+               if (wfp == -EINTR) {
+                       /* arbitration lost */
+                       udelay(adap->udelay);
+                       return -EINTR;
+               }
                i2c_stop(adap);
                udelay(adap->udelay);
        }
@@ -227,6 +244,10 @@ static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
                i2c_outb(adap, buf[wrcount]);
                timeout = wait_for_pin(adap, &status);
                if (timeout) {
+                       if (timeout == -EINTR) {
+                               /* arbitration lost */
+                               return -EINTR;
+                       }
                        i2c_stop(adap);
                        dev_err(&i2c_adap->dev, "i2c_write: error - timeout.\n");
                        return -EREMOTEIO; /* got a better one ?? */
@@ -255,11 +276,16 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
 {
        int i, status;
        struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+       int wfp;
 
        /* increment number of bytes to read by one -- read dummy byte */
        for (i = 0; i <= count; i++) {
 
-               if (wait_for_pin(adap, &status)) {
+               if ((wfp = wait_for_pin(adap, &status))) {
+                       if (wfp == -EINTR) {
+                               /* arbitration lost */
+                               return -EINTR;
+                       }
                        i2c_stop(adap);
                        dev_err(&i2c_adap->dev, "pcf_readbytes timed out.\n");
                        return (-1);
@@ -340,7 +366,7 @@ static inline int pcf_doAddress(struct i2c_algo_pcf_data *adap,
 }
 
 static int pcf_xfer(struct i2c_adapter *i2c_adap,
-                   struct i2c_msg msgs[]
+                   struct i2c_msg *msgs
                    int num)
 {
        struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
@@ -374,6 +400,10 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
                /* Wait for PIN (pending interrupt NOT) */
                timeout = wait_for_pin(adap, &status);
                if (timeout) {
+                       if (timeout == -EINTR) {
+                               /* arbitration lost */
+                               return (-EINTR);
+                       }
                        i2c_stop(adap);
                        DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting "
                                    "for PIN(1) in pcf_xfer\n");)
@@ -422,15 +452,13 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
 
 static u32 pcf_func(struct i2c_adapter *adap)
 {
-       return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | 
-              I2C_FUNC_PROTOCOL_MANGLING; 
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | 
+              I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; 
 }
 
 /* -----exported algorithm data: ------------------------------------- */
 
 static struct i2c_algorithm pcf_algo = {
-       .name           = "PCF8584 algorithm",
-       .id             = I2C_ALGO_PCF,
        .master_xfer    = pcf_xfer,
        .functionality  = pcf_func,
 };
@@ -446,8 +474,6 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap)
        DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
 
        /* register new adapter to i2c module... */
-
-       adap->id |= pcf_algo.id;
        adap->algo = &pcf_algo;
 
        adap->timeout = 100;            /* default values, should       */
@@ -472,6 +498,6 @@ MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
 MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(i2c_debug,"i");
+module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(i2c_debug,
         "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");