diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 10:49:43 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 10:49:43 -0700 |
commit | e0bc5d4a54938eedcde14005210e6c08aa9727e4 (patch) | |
tree | bcbabc1651c6bc9c138363b617714cd2349cecb3 /drivers/misc | |
parent | 7f02ab3ce3c7e093c414fcbd93bdc591cc4419d0 (diff) | |
parent | 7c4fda1aa15fdbbd2563e7e652cd3745f92a16da (diff) |
Merge branch 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging
* 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
i2c-nforce2: Remove redundant error messages on ACPI conflict
i2c: Use <linux/io.h> instead of <asm/io.h>
i2c-algo-pca: Fix coding style issues
i2c-dev: Fix all coding style issues
i2c-core: Fix some coding style issues
i2c-gpio: Move initialization code to subsys_initcall()
i2c-parport: Make template structure const
i2c-dev: Remove unnecessary casts
at24: Fall back to byte or word reads if needed
i2c-stub: Expose the default functionality flags
i2c/scx200_acb: Make PCI device ids constant
i2c-i801: Fix all checkpatch warnings
i2c-i801: All newer devices have all the optional features
i2c-i801: Let the user disable selected driver features
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/eeprom/at24.c | 59 |
1 files changed, 48 insertions, 11 deletions
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index a79a62f75481..f7ca3a42b490 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -54,7 +54,7 @@ struct at24_data { struct at24_platform_data chip; struct memory_accessor macc; - bool use_smbus; + int use_smbus; /* * Lock protects against activities from other Linux tasks, @@ -184,11 +184,19 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, if (count > io_limit) count = io_limit; - if (at24->use_smbus) { + switch (at24->use_smbus) { + case I2C_SMBUS_I2C_BLOCK_DATA: /* Smaller eeproms can work given some SMBus extension calls */ if (count > I2C_SMBUS_BLOCK_MAX) count = I2C_SMBUS_BLOCK_MAX; - } else { + break; + case I2C_SMBUS_WORD_DATA: + count = 2; + break; + case I2C_SMBUS_BYTE_DATA: + count = 1; + break; + default: /* * When we have a better choice than SMBus calls, use a * combined I2C message. Write address; then read up to @@ -219,10 +227,27 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, timeout = jiffies + msecs_to_jiffies(write_timeout); do { read_time = jiffies; - if (at24->use_smbus) { + switch (at24->use_smbus) { + case I2C_SMBUS_I2C_BLOCK_DATA: status = i2c_smbus_read_i2c_block_data(client, offset, count, buf); - } else { + break; + case I2C_SMBUS_WORD_DATA: + status = i2c_smbus_read_word_data(client, offset); + if (status >= 0) { + buf[0] = status & 0xff; + buf[1] = status >> 8; + status = count; + } + break; + case I2C_SMBUS_BYTE_DATA: + status = i2c_smbus_read_byte_data(client, offset); + if (status >= 0) { + buf[0] = status; + status = count; + } + break; + default: status = i2c_transfer(client->adapter, msg, 2); if (status == 2) status = count; @@ -436,7 +461,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct at24_platform_data chip; bool writable; - bool use_smbus = false; + int use_smbus = 0; struct at24_data *at24; int err; unsigned i, num_addresses; @@ -477,12 +502,19 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) err = -EPFNOSUPPORT; goto err_out; } - if (!i2c_check_functionality(client->adapter, + if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + use_smbus = I2C_SMBUS_I2C_BLOCK_DATA; + } else if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_WORD_DATA)) { + use_smbus = I2C_SMBUS_WORD_DATA; + } else if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA)) { + use_smbus = I2C_SMBUS_BYTE_DATA; + } else { err = -EPFNOSUPPORT; goto err_out; } - use_smbus = true; } if (chip.flags & AT24_FLAG_TAKE8ADDR) @@ -568,11 +600,16 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) dev_info(&client->dev, "%zu byte %s EEPROM %s\n", at24->bin.size, client->name, writable ? "(writable)" : "(read-only)"); + if (use_smbus == I2C_SMBUS_WORD_DATA || + use_smbus == I2C_SMBUS_BYTE_DATA) { + dev_notice(&client->dev, "Falling back to %s reads, " + "performance will suffer\n", use_smbus == + I2C_SMBUS_WORD_DATA ? "word" : "byte"); + } dev_dbg(&client->dev, - "page_size %d, num_addresses %d, write_max %d%s\n", + "page_size %d, num_addresses %d, write_max %d, use_smbus %d\n", chip.page_size, num_addresses, - at24->write_max, - use_smbus ? ", use_smbus" : ""); + at24->write_max, use_smbus); /* export data to kernel code */ if (chip.setup) |