at24: Fall back to byte or word reads if needed
Subsystems (2)
PATCH 1/1 at24: Fall back to byte or word reads if needed
From: Jean Delvare <[email protected]>
Subject: 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.)
---
Konstantin, please test and report.
drivers/misc/eeprom/at24.c | 47 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-)
drivers/misc/eeprom/at24.c +38 -9
@@ -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,10 +184,14 @@ static ssize_t at24_eeprom_read(struct aif (count > io_limit) count = io_limit; -if (at24->use_smbus) { +if (at24->use_smbus ==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 if (at24->use_smbus ==I2C_SMBUS_WORD_DATA ) { + count =2 ; + }else if (at24->use_smbus ==I2C_SMBUS_BYTE_DATA ) { + count =1 ; }else {/* * When we have a better choice than SMBus calls, use a
@@ -219,9 +223,22 @@ static ssize_t at24_eeprom_read(struct a timeout = jiffies +msecs_to_jiffies (write_timeout); do { read_time = jiffies; - if (at24->use_smbus) { + if (at24->use_smbus == I2C_SMBUS_I2C_BLOCK_DATA) { status = i2c_smbus_read_i2c_block_data(client, offset, count, buf); + } else if (at24->use_smbus == 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; + } + } else if (at24->use_smbus == I2C_SMBUS_BYTE_DATA) { + status = i2c_smbus_read_byte_data(client, offset); + if (status >= 0) { + buf[0] = status; + status = count; + } } else { status = i2c_transfer(client->adapter, msg, 2); if (status == 2)
@@ -434,7 +451,7 @@ static int at24_probe(struct i2c_client {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;
@@ -475,12 +492,19 @@ static int at24_probe(struct i2c_client 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 )
@@ -565,11 +589,16 @@ static int at24_probe(struct i2c_clientdev_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)
Signature · 1 line
Jean Delvare
A message that is not in the archive (sent off-list or not yet received): [email protected]
Wolfram Sang
Reviewed-byQuoted 13 lines · Jean Delvare
From: Jean Delvare <[email protected]>
Subject: at24: Fall back to byte or word reads if neededIncrease 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.
Quoted 7 lines
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 <[email protected]>Cc Wolfram Sang <[email protected]>Cc Konstantin Lazarev <[email protected]>
I wondered a bit if switch-case would make the code more readable instead of if-elseif-elseif-else. But definately no show-stopper.
I don't have hardware to actually test the new functionality, other than that it appears good to me. Thanks!
Signature · 2 lines
Pengutronix e.K. | Wolfram Sang | Industrial Linux Solutions | http://www.pengutronix.de/ |
A message that is not in the archive (sent off-list or not yet received): [email protected]
Hi Wolfram,
Quoted 18 lines · Wolfram Sang
Quoted 17 lines · Jean Delvare
From: Jean Delvare <[email protected]>
Subject: at24: Fall back to byte or word reads if neededIncrease 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.)
Quoted 6 lines
Quoted 3 lines
Signed-off-by Jean Delvare <[email protected]>Cc Wolfram Sang <[email protected]>Cc Konstantin Lazarev <[email protected]>I wondered a bit if switch-case would make the code more readable instead of if-elseif-elseif-else. But definately no show-stopper.
Good point, I'll post an updated version soon.
Quoted 4 lines
I don't have hardware to actually test the new functionality, other than that it appears good to me. Thanks!
Reviewed-by Wolfram Sang <[email protected]>
Thanks for the review.
Signature · 1 line
Jean Delvare
Quoted 9 lines · Jean Delvare
From: Jean Delvare <[email protected]>
Subject: at24: Fall back to byte or word reads if neededIncrease 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.
Quoted 7 lines
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.)
It would be worth sorting out which i2c busses are exporting the correct functionality, I think for example the i2c-s3c2410.c driver is missing the I2C block functionality.
Signature · 3 lines
Ben ([email protected], http://www.fluff.org/) 'a smiley only costs 4 bytes'