Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 53252
b: refs/heads/master
c: 12b5053
h: refs/heads/master
v: v3
  • Loading branch information
Jean Delvare authored and Jean Delvare committed May 1, 2007
1 parent b412fed commit b223553
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0f3b48385213355a2d4408bec1b481ffcf0e8638
refs/heads/master: 12b5053ac58709c7d475888bc18d1f61958afc4e
63 changes: 63 additions & 0 deletions trunk/drivers/i2c/i2c-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions trunk/include/linux/i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit b223553

Please sign in to comment.