diff options
-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 db7d0f21b65d..0c11e411d8ec 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; |
@@ -434,7 +459,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
434 | { | 459 | { |
435 | struct at24_platform_data chip; | 460 | struct at24_platform_data chip; |
436 | bool writable; | 461 | bool writable; |
437 | bool use_smbus = false; | 462 | int use_smbus = 0; |
438 | struct at24_data *at24; | 463 | struct at24_data *at24; |
439 | int err; | 464 | int err; |
440 | unsigned i, num_addresses; | 465 | unsigned i, num_addresses; |
@@ -475,12 +500,19 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
475 | err = -EPFNOSUPPORT; | 500 | err = -EPFNOSUPPORT; |
476 | goto err_out; | 501 | goto err_out; |
477 | } | 502 | } |
478 | if (!i2c_check_functionality(client->adapter, | 503 | if (i2c_check_functionality(client->adapter, |
479 | I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { | 504 | I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { |
505 | use_smbus = I2C_SMBUS_I2C_BLOCK_DATA; | ||
506 | } else if (i2c_check_functionality(client->adapter, | ||
507 | I2C_FUNC_SMBUS_READ_WORD_DATA)) { | ||
508 | use_smbus = I2C_SMBUS_WORD_DATA; | ||
509 | } else if (i2c_check_functionality(client->adapter, | ||
510 | I2C_FUNC_SMBUS_READ_BYTE_DATA)) { | ||
511 | use_smbus = I2C_SMBUS_BYTE_DATA; | ||
512 | } else { | ||
480 | err = -EPFNOSUPPORT; | 513 | err = -EPFNOSUPPORT; |
481 | goto err_out; | 514 | goto err_out; |
482 | } | 515 | } |
483 | use_smbus = true; | ||
484 | } | 516 | } |
485 | 517 | ||
486 | if (chip.flags & AT24_FLAG_TAKE8ADDR) | 518 | if (chip.flags & AT24_FLAG_TAKE8ADDR) |
@@ -566,11 +598,16 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
566 | dev_info(&client->dev, "%zu byte %s EEPROM %s\n", | 598 | dev_info(&client->dev, "%zu byte %s EEPROM %s\n", |
567 | at24->bin.size, client->name, | 599 | at24->bin.size, client->name, |
568 | writable ? "(writable)" : "(read-only)"); | 600 | writable ? "(writable)" : "(read-only)"); |
601 | if (use_smbus == I2C_SMBUS_WORD_DATA || | ||
602 | use_smbus == I2C_SMBUS_BYTE_DATA) { | ||
603 | dev_notice(&client->dev, "Falling back to %s reads, " | ||
604 | "performance will suffer\n", use_smbus == | ||
605 | I2C_SMBUS_WORD_DATA ? "word" : "byte"); | ||
606 | } | ||
569 | dev_dbg(&client->dev, | 607 | dev_dbg(&client->dev, |
570 | "page_size %d, num_addresses %d, write_max %d%s\n", | 608 | "page_size %d, num_addresses %d, write_max %d, use_smbus %d\n", |
571 | chip.page_size, num_addresses, | 609 | chip.page_size, num_addresses, |
572 | at24->write_max, | 610 | at24->write_max, use_smbus); |
573 | use_smbus ? ", use_smbus" : ""); | ||
574 | 611 | ||
575 | /* export data to kernel code */ | 612 | /* export data to kernel code */ |
576 | if (chip.setup) | 613 | if (chip.setup) |