i2c: Retry automatically on arbitration loss
[safe/jmp/linux-2.6] / drivers / i2c / i2c-core.c
index 5a485c2..635c488 100644 (file)
@@ -152,7 +152,7 @@ static void i2c_device_shutdown(struct device *dev)
                driver->shutdown(to_i2c_client(dev));
 }
 
-static int i2c_device_suspend(struct device * dev, pm_message_t mesg)
+static int i2c_device_suspend(struct device *dev, pm_message_t mesg)
 {
        struct i2c_driver *driver;
 
@@ -164,7 +164,7 @@ static int i2c_device_suspend(struct device * dev, pm_message_t mesg)
        return driver->suspend(to_i2c_client(dev), mesg);
 }
 
-static int i2c_device_resume(struct device * dev)
+static int i2c_device_resume(struct device *dev)
 {
        struct i2c_driver *driver;
 
@@ -187,13 +187,15 @@ static void i2c_client_dev_release(struct device *dev)
        kfree(to_i2c_client(dev));
 }
 
-static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t
+show_client_name(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct i2c_client *client = to_i2c_client(dev);
        return sprintf(buf, "%s\n", client->name);
 }
 
-static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t
+show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct i2c_client *client = to_i2c_client(dev);
        return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
@@ -365,8 +367,7 @@ static struct i2c_driver dummy_driver = {
  * This returns the new i2c client, which should be saved for later use with
  * i2c_unregister_device(); or NULL to indicate an error.
  */
-struct i2c_client *
-i2c_new_dummy(struct i2c_adapter *adapter, u16 address)
+struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address)
 {
        struct i2c_board_info info = {
                I2C_BOARD_INFO("dummy", address),
@@ -413,8 +414,8 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
                if (devinfo->busnum == adapter->nr
                                && !i2c_new_device(adapter,
                                                &devinfo->board_info))
-                       printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n",
-                               i2c_adapter_id(adapter),
+                       dev_err(&adapter->dev,
+                               "Can't create device at 0x%02x\n",
                                devinfo->board_info.addr);
        }
        mutex_unlock(&__i2c_board_lock);
@@ -459,7 +460,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
                pr_debug("I2C adapter driver [%s] forgot to specify "
                         "physical device\n", adap->name);
        }
-       sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
+
+       /* Set default timeout to 1 second if not already set */
+       if (adap->timeout == 0)
+               adap->timeout = HZ;
+
+       dev_set_name(&adap->dev, "i2c-%d", adap->nr);
        adap->dev.release = &i2c_adapter_dev_release;
        adap->dev.class = &i2c_adapter_class;
        res = device_register(&adap->dev);
@@ -581,7 +587,8 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data)
        struct i2c_client *client, *_n;
        int res;
 
-       /* Remove the devices we created ourselves */
+       /* Remove the devices we created ourselves as the result of hardware
+        * probing (using a driver's detect method) */
        list_for_each_entry_safe(client, _n, &driver->clients, detected) {
                if (client->adapter == adapter) {
                        dev_dbg(&adapter->dev, "Removing %s at 0x%x\n",
@@ -631,7 +638,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
 
        /* detach any active clients. This must be done first, because
         * it can fail; in which case we give up. */
-       list_for_each_entry_safe(client, _n, &adap->clients, list) {
+       list_for_each_entry_safe_reverse(client, _n, &adap->clients, list) {
                struct i2c_driver       *driver;
 
                driver = client->driver;
@@ -709,8 +716,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
 
        /* new style driver methods can't mix with legacy ones */
        if (is_newstyle_driver(driver)) {
-               if (driver->attach_adapter || driver->detach_adapter
-                               || driver->detach_client) {
+               if (driver->detach_adapter || driver->detach_client) {
                        printk(KERN_WARNING
                                        "i2c-core: driver [%s] is confused\n",
                                        driver->driver.name);
@@ -749,6 +755,8 @@ static int __detach_adapter(struct device *dev, void *data)
        struct i2c_driver *driver = data;
        struct i2c_client *client, *_n;
 
+       /* Remove the devices we created ourselves as the result of hardware
+        * probing (using a driver's detect method) */
        list_for_each_entry_safe(client, _n, &driver->clients, detected) {
                dev_dbg(&adapter->dev, "Removing %s at 0x%x\n",
                        client->name, client->addr);
@@ -841,12 +849,12 @@ int i2c_attach_client(struct i2c_client *client)
 
        if (client->driver && !is_newstyle_driver(client->driver)) {
                client->dev.release = i2c_client_release;
-               client->dev.uevent_suppress = 1;
+               dev_set_uevent_suppress(&client->dev, 1);
        } else
                client->dev.release = i2c_client_dev_release;
 
-       snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
-               "%d-%04x", i2c_adapter_id(adapter), client->addr);
+       dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adapter),
+                    client->addr);
        res = device_register(&client->dev);
        if (res)
                goto out_err;
@@ -856,7 +864,7 @@ int i2c_attach_client(struct i2c_client *client)
        mutex_unlock(&adapter->clist_lock);
 
        dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
-               client->name, client->dev.bus_id);
+               client->name, dev_name(&client->dev));
 
        if (adapter->client_register)  {
                if (adapter->client_register(client)) {
@@ -1012,9 +1020,10 @@ module_exit(i2c_exit);
  * Note that there is no requirement that each message be sent to
  * the same slave address, although that is the most common model.
  */
-int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
+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:
         *
@@ -1052,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;
@@ -1501,7 +1518,7 @@ struct i2c_adapter* i2c_get_adapter(int id)
        struct i2c_adapter *adapter;
 
        mutex_lock(&core_lock);
-       adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
+       adapter = idr_find(&i2c_adapter_idr, id);
        if (adapter && !try_module_get(adapter->owner))
                adapter = NULL;
 
@@ -1519,8 +1536,7 @@ EXPORT_SYMBOL(i2c_put_adapter);
 /* The SMBus parts */
 
 #define POLY    (0x1070U << 3)
-static u8
-crc8(u16 data)
+static u8 crc8(u16 data)
 {
        int i;
 
@@ -1831,7 +1847,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
        case I2C_SMBUS_QUICK:
                msg[0].len = 0;
                /* Special case: The read/write field is used as data */
-               msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0;
+               msg[0].flags = flags | (read_write == I2C_SMBUS_READ ?
+                                       I2C_M_RD : 0);
                num = 1;
                break;
        case I2C_SMBUS_BYTE:
@@ -1983,18 +2000,31 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
  * This executes an SMBus protocol operation, and returns a negative
  * errno code else zero on success.
  */
-s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
+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)
+                  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,