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) |
