eeprom: at24: split at24_eeprom_write() into specialized functions
authorBartosz Golaszewski <bgolaszewski@baylibre.com>
Mon, 6 Jun 2016 08:48:49 +0000 (10:48 +0200)
committerWolfram Sang <wsa@the-dreams.de>
Sun, 17 Jul 2016 17:41:54 +0000 (19:41 +0200)
Split at24_eeprom_write() into three smaller functions - one for the
i2c operations and two for the smbus extensions (separate routines for
block and byte transfers). Assign them in at24_probe() depending on
the bus capabilities.

Also: in order to avoid duplications move code adjusting the count
argument into a separate function and use it for i2c and smbus block
writes (no need for a roll-over for byte writes as we're always
writing one byte).

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
drivers/misc/eeprom/at24.c

index e7db137..6acf35a 100644 (file)
@@ -281,21 +281,15 @@ static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf,
  * chip is normally write protected. But there are plenty of product
  * variants here, including OTP fuses and partial chip protect.
  *
- * We only use page mode writes; the alternative is sloooow. This routine
- * writes at most one page.
+ * We only use page mode writes; the alternative is sloooow. These routines
+ * write at most one page.
  */
-static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
-                                unsigned int offset, size_t count)
+
+static size_t at24_adjust_write_count(struct at24_data *at24,
+                                     unsigned int offset, size_t count)
 {
-       struct i2c_client *client;
-       struct i2c_msg msg;
-       ssize_t status = 0;
-       unsigned long timeout, write_time;
        unsigned next_page;
 
-       /* Get corresponding I2C address and adjust offset */
-       client = at24_translate_offset(at24, &offset);
-
        /* write_max is at most a page */
        if (count > at24->write_max)
                count = at24->write_max;
@@ -305,43 +299,90 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
        if (offset + count > next_page)
                count = next_page - offset;
 
-       /* If we'll use I2C calls for I/O, set up the message */
-       if (!at24->use_smbus) {
-               int i = 0;
+       return count;
+}
+
+static ssize_t at24_eeprom_write_smbus_block(struct at24_data *at24,
+                                            const char *buf,
+                                            unsigned int offset, size_t count)
+{
+       unsigned long timeout, write_time;
+       struct i2c_client *client;
+       ssize_t status = 0;
+
+       client = at24_translate_offset(at24, &offset);
+       count = at24_adjust_write_count(at24, offset, count);
 
-               msg.addr = client->addr;
-               msg.flags = 0;
+       loop_until_timeout(timeout, write_time) {
+               status = i2c_smbus_write_i2c_block_data(client,
+                                                       offset, count, buf);
+               if (status == 0)
+                       status = count;
 
-               /* msg.buf is u8 and casts will mask the values */
-               msg.buf = at24->writebuf;
-               if (at24->chip.flags & AT24_FLAG_ADDR16)
-                       msg.buf[i++] = offset >> 8;
+               dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
+                               count, offset, status, jiffies);
 
-               msg.buf[i++] = offset;
-               memcpy(&msg.buf[i], buf, count);
-               msg.len = i + count;
+               if (status == count)
+                       return count;
        }
 
+       return -ETIMEDOUT;
+}
+
+static ssize_t at24_eeprom_write_smbus_byte(struct at24_data *at24,
+                                           const char *buf,
+                                           unsigned int offset, size_t count)
+{
+       unsigned long timeout, write_time;
+       struct i2c_client *client;
+       ssize_t status = 0;
+
+       client = at24_translate_offset(at24, &offset);
+
        loop_until_timeout(timeout, write_time) {
-               if (at24->use_smbus_write) {
-                       switch (at24->use_smbus_write) {
-                       case I2C_SMBUS_I2C_BLOCK_DATA:
-                               status = i2c_smbus_write_i2c_block_data(client,
-                                               offset, count, buf);
-                               break;
-                       case I2C_SMBUS_BYTE_DATA:
-                               status = i2c_smbus_write_byte_data(client,
-                                               offset, buf[0]);
-                               break;
-                       }
-
-                       if (status == 0)
-                               status = count;
-               } else {
-                       status = i2c_transfer(client->adapter, &msg, 1);
-                       if (status == 1)
-                               status = count;
-               }
+               status = i2c_smbus_write_byte_data(client, offset, buf[0]);
+               if (status == 0)
+                       status = count;
+
+               dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
+                               count, offset, status, jiffies);
+
+               if (status == count)
+                       return count;
+       }
+
+       return -ETIMEDOUT;
+}
+
+static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf,
+                                    unsigned int offset, size_t count)
+{
+       unsigned long timeout, write_time;
+       struct i2c_client *client;
+       struct i2c_msg msg;
+       ssize_t status = 0;
+       int i = 0;
+
+       client = at24_translate_offset(at24, &offset);
+       count = at24_adjust_write_count(at24, offset, count);
+
+       msg.addr = client->addr;
+       msg.flags = 0;
+
+       /* msg.buf is u8 and casts will mask the values */
+       msg.buf = at24->writebuf;
+       if (at24->chip.flags & AT24_FLAG_ADDR16)
+               msg.buf[i++] = offset >> 8;
+
+       msg.buf[i++] = offset;
+       memcpy(&msg.buf[i], buf, count);
+       msg.len = i + count;
+
+       loop_until_timeout(timeout, write_time) {
+               status = i2c_transfer(client->adapter, &msg, 1);
+               if (status == 1)
+                       status = count;
+
                dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
                                count, offset, status, jiffies);
 
@@ -538,7 +579,14 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
        at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus
                                          : at24_eeprom_read_i2c;
-       at24->write_func = at24_eeprom_write;
+       if (at24->use_smbus) {
+               if (at24->use_smbus_write == I2C_SMBUS_I2C_BLOCK_DATA)
+                       at24->write_func = at24_eeprom_write_smbus_block;
+               else
+                       at24->write_func = at24_eeprom_write_smbus_byte;
+       } else {
+               at24->write_func = at24_eeprom_write_i2c;
+       }
 
        writable = !(chip.flags & AT24_FLAG_READONLY);
        if (writable) {