diff options
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 @@ | |||
54 | struct at24_data { | 54 | struct at24_data { |
55 | struct at24_platform_data chip; | 55 | struct at24_platform_data chip; |
56 | struct memory_accessor macc; | 56 | struct memory_accessor macc; |
57 | bool use_smbus; | 57 | int use_smbus; |
58 | 58 | ||
59 | /* | 59 | /* |
60 | * Lock protects against activities from other Linux tasks, | 60 | * Lock protects against activities from other Linux tasks, |
@@ -184,11 +184,19 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, | |||
184 | if (count > io_limit) | 184 | if (count > io_limit) |
185 | count = io_limit; | 185 | count = io_limit; |
186 | 186 | ||
187 | if (at24->use_smbus) { | 187 | switch (at24->use_smbus) { |
188 | case I2C_SMBUS_I2C_BLOCK_DATA: | ||
188 | /* Smaller eeproms can work given some SMBus extension calls */ | 189 | /* Smaller eeproms can work given some SMBus extension calls */ |
189 | if (count > I2C_SMBUS_BLOCK_MAX) | 190 | if (count > I2C_SMBUS_BLOCK_MAX) |
190 | count = I2C_SMBUS_BLOCK_MAX; | 191 | count = I2C_SMBUS_BLOCK_MAX; |
191 | } else { | 192 | break; |
193 | case I2C_SMBUS_WORD_DATA: | ||
194 | count = 2; | ||
195 | break; | ||
196 | case I2C_SMBUS_BYTE_DATA: | ||
197 | count = 1; | ||
198 | break; | ||
199 | default: | ||
192 | /* | 200 | /* |
193 | * When we have a better choice than SMBus calls, use a | 201 | * When we have a better choice than SMBus calls, use a |
194 | * combined I2C message. Write address; then read up to | 202 | * 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, | |||
219 | timeout = jiffies + msecs_to_jiffies(write_timeout); | 227 | timeout = jiffies + msecs_to_jiffies(write_timeout); |
220 | do { | 228 | do { |
221 | read_time = jiffies; | 229 | read_time = jiffies; |
222 | if (at24->use_smbus) { | 230 | switch (at24->use_smbus) { |
231 | case I2C_SMBUS_I2C_BLOCK_DATA: | ||
223 | status = i2c_smbus_read_i2c_block_data(client, offset, | 232 | status = i2c_smbus_read_i2c_block_data(client, offset, |
224 | count, buf); | 233 | count, buf); |
225 | } else { | 234 | break; |
235 | case I2C_SMBUS_WORD_DATA: | ||
236 | status = i2c_smbus_read_word_data(client, offset); | ||
237 | if (status >= 0) { | ||
238 | buf[0] = status & 0xff; | ||
239 | buf[1] = status >> 8; | ||
240 | status = count; | ||
241 | } | ||
242 | break; | ||
243 | case I2C_SMBUS_BYTE_DATA: | ||
244 | status = i2c_smbus_read_byte_data(client, offset); | ||
245 | if (status >= 0) { | ||
246 | buf[0] = status; | ||
247 | status = count; | ||
248 | } | ||
249 | break; | ||
250 | default: | ||
226 | status = i2c_transfer(client->adapter, msg, 2); | 251 | status = i2c_transfer(client->adapter, msg, 2); |
227 | if (status == 2) | 252 | if (status == 2) |
228 | status = count; | 253 | status = count; |
@@ -436,7 +461,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
436 | { | 461 | { |
437 | struct at24_platform_data chip; | 462 | struct at24_platform_data chip; |
438 | bool writable; | 463 | bool writable; |
439 | bool use_smbus = false; | 464 | int use_smbus = 0; |
440 | struct at24_data *at24; | 465 | struct at24_data *at24; |
441 | int err; | 466 | int err; |
442 | unsigned i, num_addresses; | 467 | unsigned i, num_addresses; |
@@ -477,12 +502,19 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
477 | err = -EPFNOSUPPORT; | 502 | err = -EPFNOSUPPORT; |
478 | goto err_out; | 503 | goto err_out; |
479 | } | 504 | } |
480 | if (!i2c_check_functionality(client->adapter, | 505 | if (i2c_check_functionality(client->adapter, |
481 | I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { | 506 | I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { |
507 | use_smbus = I2C_SMBUS_I2C_BLOCK_DATA; | ||
508 | } else if (i2c_check_functionality(client->adapter, | ||
509 | I2C_FUNC_SMBUS_READ_WORD_DATA)) { | ||
510 | use_smbus = I2C_SMBUS_WORD_DATA; | ||
511 | } else if (i2c_check_functionality(client->adapter, | ||
512 | I2C_FUNC_SMBUS_READ_BYTE_DATA)) { | ||
513 | use_smbus = I2C_SMBUS_BYTE_DATA; | ||
514 | } else { | ||
482 | err = -EPFNOSUPPORT; | 515 | err = -EPFNOSUPPORT; |
483 | goto err_out; | 516 | goto err_out; |
484 | } | 517 | } |
485 | use_smbus = true; | ||
486 | } | 518 | } |
487 | 519 | ||
488 | if (chip.flags & AT24_FLAG_TAKE8ADDR) | 520 | if (chip.flags & AT24_FLAG_TAKE8ADDR) |
@@ -568,11 +600,16 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
568 | dev_info(&client->dev, "%zu byte %s EEPROM %s\n", | 600 | dev_info(&client->dev, "%zu byte %s EEPROM %s\n", |
569 | at24->bin.size, client->name, | 601 | at24->bin.size, client->name, |
570 | writable ? "(writable)" : "(read-only)"); | 602 | writable ? "(writable)" : "(read-only)"); |
603 | if (use_smbus == I2C_SMBUS_WORD_DATA || | ||
604 | use_smbus == I2C_SMBUS_BYTE_DATA) { | ||
605 | dev_notice(&client->dev, "Falling back to %s reads, " | ||
606 | "performance will suffer\n", use_smbus == | ||
607 | I2C_SMBUS_WORD_DATA ? "word" : "byte"); | ||
608 | } | ||
571 | dev_dbg(&client->dev, | 609 | dev_dbg(&client->dev, |
572 | "page_size %d, num_addresses %d, write_max %d%s\n", | 610 | "page_size %d, num_addresses %d, write_max %d, use_smbus %d\n", |
573 | chip.page_size, num_addresses, | 611 | chip.page_size, num_addresses, |
574 | at24->write_max, | 612 | at24->write_max, use_smbus); |
575 | use_smbus ? ", use_smbus" : ""); | ||
576 | 613 | ||
577 | /* export data to kernel code */ | 614 | /* export data to kernel code */ |
578 | if (chip.setup) | 615 | if (chip.setup) |