Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=12b5053ac58709c7d475888bc18d1f61958afc4e
Commit:     12b5053ac58709c7d475888bc18d1f61958afc4e
Parent:     0f3b48385213355a2d4408bec1b481ffcf0e8638
Author:     Jean Delvare <[EMAIL PROTECTED]>
AuthorDate: Tue May 1 23:26:31 2007 +0200
Committer:  Jean Delvare <[EMAIL PROTECTED]>
CommitDate: Tue May 1 23:26:31 2007 +0200

    i2c: Add i2c_new_probed_device()
    
    Add a new helper function to instantiate an i2c device. It is meant as a
    replacement for i2c_new_device() when you don't know for sure at which
    address your I2C/SMBus device lives. This happens frequently on TV
    adapters for example, you know there is a tuner chip on the bus, but
    depending on the exact board model and revision, it can live at different
    addresses. So, the new i2c_new_probed_device() function will probe the bus
    according to a list of addresses, and as soon as one of these addresses
    responds, it will call i2c_new_device() on that one address.
    
    This function will make it possible to port the old i2c drivers to the
    new model quickly.
    
    Signed-off-by: Jean Delvare <[EMAIL PROTECTED]>
---
 drivers/i2c/i2c-core.c |   63 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/i2c.h    |    9 +++++++
 2 files changed, 72 insertions(+), 0 deletions(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 1812439..0fd4acb 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -1092,6 +1092,69 @@ int i2c_probe(struct i2c_adapter *adapter,
 }
 EXPORT_SYMBOL(i2c_probe);
 
+struct i2c_client *
+i2c_new_probed_device(struct i2c_adapter *adap,
+                     struct i2c_board_info *info,
+                     unsigned short const *addr_list)
+{
+       int i;
+
+       /* Stop here if the bus doesn't support probing */
+       if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE)) {
+               dev_err(&adap->dev, "Probing not supported\n");
+               return NULL;
+       }
+
+       mutex_lock(&adap->clist_lock);
+       for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
+               /* Check address validity */
+               if (addr_list[i] < 0x03 || addr_list[i] > 0x77) {
+                       dev_warn(&adap->dev, "Invalid 7-bit address "
+                                "0x%02x\n", addr_list[i]);
+                       continue;
+               }
+
+               /* Check address availability */
+               if (__i2c_check_addr(adap, addr_list[i])) {
+                       dev_dbg(&adap->dev, "Address 0x%02x already in "
+                               "use, not probing\n", addr_list[i]);
+                       continue;
+               }
+
+               /* Test address responsiveness
+                  The default probe method is a quick write, but it is known
+                  to corrupt the 24RF08 EEPROMs due to a state machine bug,
+                  and could also irreversibly write-protect some EEPROMs, so
+                  for address ranges 0x30-0x37 and 0x50-0x5f, we use a byte
+                  read instead. Also, some bus drivers don't implement
+                  quick write, so we fallback to a byte read it that case
+                  too. */
+               if ((addr_list[i] & ~0x07) == 0x30
+                || (addr_list[i] & ~0x0f) == 0x50
+                || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) {
+                       if (i2c_smbus_xfer(adap, addr_list[i], 0,
+                                          I2C_SMBUS_READ, 0,
+                                          I2C_SMBUS_BYTE, NULL) >= 0)
+                               break;
+               } else {
+                       if (i2c_smbus_xfer(adap, addr_list[i], 0,
+                                          I2C_SMBUS_WRITE, 0,
+                                          I2C_SMBUS_QUICK, NULL) >= 0)
+                               break;
+               }
+       }
+       mutex_unlock(&adap->clist_lock);
+
+       if (addr_list[i] == I2C_CLIENT_END) {
+               dev_dbg(&adap->dev, "Probing failed, no device found\n");
+               return NULL;
+       }
+
+       info->addr = addr_list[i];
+       return i2c_new_device(adap, info);
+}
+EXPORT_SYMBOL_GPL(i2c_new_probed_device);
+
 struct i2c_adapter* i2c_get_adapter(int id)
 {
        struct i2c_adapter *adapter;
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 36d6814..da95ce7 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -245,6 +245,15 @@ struct i2c_board_info {
 extern struct i2c_client *
 i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
 
+/* If you don't know the exact address of an I2C device, use this variant
+ * instead, which can probe for device presence in a list of possible
+ * addresses.
+ */
+extern struct i2c_client *
+i2c_new_probed_device(struct i2c_adapter *adap,
+                     struct i2c_board_info *info,
+                     unsigned short const *addr_list);
+
 extern void i2c_unregister_device(struct i2c_client *);
 
 /* Mainboard arch_initcall() code should register all its I2C devices.
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to