i2c: Retry automatically on arbitration loss
[safe/jmp/linux-2.6] / drivers / i2c / i2c-core.c
index dfd7bc8..635c488 100644 (file)
@@ -1022,7 +1022,8 @@ module_exit(i2c_exit);
  */
 int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 {
-       int ret;
+       unsigned long orig_jiffies;
+       int ret, try;
 
        /* REVISIT the fault reporting model here is weak:
         *
@@ -1060,7 +1061,15 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                        mutex_lock_nested(&adap->bus_lock, adap->level);
                }
 
-               ret = adap->algo->master_xfer(adap,msgs,num);
+               /* Retry automatically on arbitration loss */
+               orig_jiffies = jiffies;
+               for (ret = 0, try = 0; try <= adap->retries; try++) {
+                       ret = adap->algo->master_xfer(adap, msgs, num);
+                       if (ret != -EAGAIN)
+                               break;
+                       if (time_after(jiffies, orig_jiffies + adap->timeout))
+                               break;
+               }
                mutex_unlock(&adap->bus_lock);
 
                return ret;
@@ -1995,14 +2004,27 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
                   char read_write, u8 command, int protocol,
                   union i2c_smbus_data *data)
 {
+       unsigned long orig_jiffies;
+       int try;
        s32 res;
 
        flags &= I2C_M_TEN | I2C_CLIENT_PEC;
 
        if (adapter->algo->smbus_xfer) {
                mutex_lock(&adapter->bus_lock);
-               res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
-                                               command, protocol, data);
+
+               /* Retry automatically on arbitration loss */
+               orig_jiffies = jiffies;
+               for (res = 0, try = 0; try <= adapter->retries; try++) {
+                       res = adapter->algo->smbus_xfer(adapter, addr, flags,
+                                                       read_write, command,
+                                                       protocol, data);
+                       if (res != -EAGAIN)
+                               break;
+                       if (time_after(jiffies,
+                                      orig_jiffies + adapter->timeout))
+                               break;
+               }
                mutex_unlock(&adapter->bus_lock);
        } else
                res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,