|
@@ -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,11 +184,19 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
|
|
|
if (count > io_limit)
|
|
|
count = io_limit;
|
|
|
|
|
|
- if (at24->use_smbus) {
|
|
|
+ switch (at24->use_smbus) {
|
|
|
+ case 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 {
|
|
|
+ break;
|
|
|
+ case I2C_SMBUS_WORD_DATA:
|
|
|
+ count = 2;
|
|
|
+ break;
|
|
|
+ case I2C_SMBUS_BYTE_DATA:
|
|
|
+ count = 1;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
/*
|
|
|
* When we have a better choice than SMBus calls, use a
|
|
|
* 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,
|
|
|
timeout = jiffies + msecs_to_jiffies(write_timeout);
|
|
|
do {
|
|
|
read_time = jiffies;
|
|
|
- if (at24->use_smbus) {
|
|
|
+ switch (at24->use_smbus) {
|
|
|
+ case I2C_SMBUS_I2C_BLOCK_DATA:
|
|
|
status = i2c_smbus_read_i2c_block_data(client, offset,
|
|
|
count, buf);
|
|
|
- } else {
|
|
|
+ break;
|
|
|
+ case 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;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case I2C_SMBUS_BYTE_DATA:
|
|
|
+ status = i2c_smbus_read_byte_data(client, offset);
|
|
|
+ if (status >= 0) {
|
|
|
+ buf[0] = status;
|
|
|
+ status = count;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
status = i2c_transfer(client->adapter, msg, 2);
|
|
|
if (status == 2)
|
|
|
status = count;
|
|
@@ -434,7 +459,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|
|
{
|
|
|
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 +500,19 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|
|
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)
|
|
@@ -566,11 +598,16 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|
|
dev_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)
|