Merge branch 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvar...
[pandora-kernel.git] / drivers / misc / eeprom / at24.c
index a79a62f..f7ca3a4 100644 (file)
@@ -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;
@@ -436,7 +461,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;
@@ -477,12 +502,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)
@@ -568,11 +600,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)