aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/eeprom
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2010-05-21 12:40:57 -0400
committerJean Delvare <khali@linux-fr.org>2010-05-21 12:40:57 -0400
commit7aeb96642f70139a194d685b132605836f6f8dbb (patch)
tree16ff60fcd074e8b2efb052d883175b48f56b80bb /drivers/misc/eeprom
parentc5aa69285c573e42042530be86b7af6f5fe9e240 (diff)
at24: Fall back to byte or word reads if needed
Increase the portability of the at24 driver by letting it read from EEPROM chips connected to cheap SMBus controllers that support neither raw I2C messages nor even I2C block reads. All SMBus controllers should support either word reads or byte reads, so read support becomes universal, much like with the legacy "eeprom" driver. Obviously, this only works with EEPROM chips up to AT24C16, that use 8-bit offset addressing. 16-bit offset addressing is almost impossible to support on SMBus controllers. I did not add universal support for writes, as I had no immediate need for this, but it could be added later if needed (with the same performance issue as byte and word reads have, of course.) Signed-off-by: Jean Delvare <khali@linux-fr.org> Reviewed-by: Wolfram Sang <w.sang@pengutronix.de> Cc: Konstantin Lazarev <klazarev@sbcglobal.net>
Diffstat (limited to 'drivers/misc/eeprom')
-rw-r--r--drivers/misc/eeprom/at24.c59
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 @@
54struct at24_data { 54struct 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)