summaryrefslogtreecommitdiff
path: root/drivers/misc/eeprom/at24.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/eeprom/at24.c')
-rw-r--r--drivers/misc/eeprom/at24.c109
1 files changed, 78 insertions, 31 deletions
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 59dcd97ee3de..f8cfcd063649 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -113,22 +113,6 @@ MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
((1 << AT24_SIZE_FLAGS | (_flags)) \
<< AT24_SIZE_BYTELEN | ilog2(_len))
-/*
- * Both reads and writes fail if the previous write didn't complete yet. This
- * macro loops a few times waiting at least long enough for one entire page
- * write to work while making sure that at least one iteration is run before
- * checking the break condition.
- *
- * It takes two parameters: a variable in which the future timeout in jiffies
- * will be stored and a temporary variable holding the time of the last
- * iteration of processing the request. Both should be unsigned integers
- * holding at least 32 bits.
- */
-#define loop_until_timeout(tout, op_time) \
- for (tout = jiffies + msecs_to_jiffies(write_timeout), op_time = 0; \
- op_time ? time_before(op_time, tout) : true; \
- usleep_range(1000, 1500), op_time = jiffies)
-
static const struct i2c_device_id at24_ids[] = {
/* needs 8 addresses as A0-A2 are ignored */
{ "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) },
@@ -234,7 +218,14 @@ static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf,
if (count > I2C_SMBUS_BLOCK_MAX)
count = I2C_SMBUS_BLOCK_MAX;
- loop_until_timeout(timeout, read_time) {
+ timeout = jiffies + msecs_to_jiffies(write_timeout);
+ do {
+ /*
+ * The timestamp shall be taken before the actual operation
+ * to avoid a premature timeout in case of high CPU load.
+ */
+ read_time = jiffies;
+
status = i2c_smbus_read_i2c_block_data_or_emulated(client,
offset,
count, buf);
@@ -244,7 +235,9 @@ static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf,
if (status == count)
return count;
- }
+
+ usleep_range(1000, 1500);
+ } while (time_before(read_time, timeout));
return -ETIMEDOUT;
}
@@ -284,7 +277,14 @@ static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf,
msg[1].buf = buf;
msg[1].len = count;
- loop_until_timeout(timeout, read_time) {
+ timeout = jiffies + msecs_to_jiffies(write_timeout);
+ do {
+ /*
+ * The timestamp shall be taken before the actual operation
+ * to avoid a premature timeout in case of high CPU load.
+ */
+ read_time = jiffies;
+
status = i2c_transfer(client->adapter, msg, 2);
if (status == 2)
status = count;
@@ -294,7 +294,9 @@ static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf,
if (status == count)
return count;
- }
+
+ usleep_range(1000, 1500);
+ } while (time_before(read_time, timeout));
return -ETIMEDOUT;
}
@@ -343,11 +345,20 @@ static ssize_t at24_eeprom_read_serial(struct at24_data *at24, char *buf,
msg[1].buf = buf;
msg[1].len = count;
- loop_until_timeout(timeout, read_time) {
+ timeout = jiffies + msecs_to_jiffies(write_timeout);
+ do {
+ /*
+ * The timestamp shall be taken before the actual operation
+ * to avoid a premature timeout in case of high CPU load.
+ */
+ read_time = jiffies;
+
status = i2c_transfer(client->adapter, msg, 2);
if (status == 2)
return count;
- }
+
+ usleep_range(1000, 1500);
+ } while (time_before(read_time, timeout));
return -ETIMEDOUT;
}
@@ -374,11 +385,20 @@ static ssize_t at24_eeprom_read_mac(struct at24_data *at24, char *buf,
msg[1].buf = buf;
msg[1].len = count;
- loop_until_timeout(timeout, read_time) {
+ timeout = jiffies + msecs_to_jiffies(write_timeout);
+ do {
+ /*
+ * The timestamp shall be taken before the actual operation
+ * to avoid a premature timeout in case of high CPU load.
+ */
+ read_time = jiffies;
+
status = i2c_transfer(client->adapter, msg, 2);
if (status == 2)
return count;
- }
+
+ usleep_range(1000, 1500);
+ } while (time_before(read_time, timeout));
return -ETIMEDOUT;
}
@@ -420,7 +440,14 @@ static ssize_t at24_eeprom_write_smbus_block(struct at24_data *at24,
client = at24_translate_offset(at24, &offset);
count = at24_adjust_write_count(at24, offset, count);
- loop_until_timeout(timeout, write_time) {
+ timeout = jiffies + msecs_to_jiffies(write_timeout);
+ do {
+ /*
+ * The timestamp shall be taken before the actual operation
+ * to avoid a premature timeout in case of high CPU load.
+ */
+ write_time = jiffies;
+
status = i2c_smbus_write_i2c_block_data(client,
offset, count, buf);
if (status == 0)
@@ -431,7 +458,9 @@ static ssize_t at24_eeprom_write_smbus_block(struct at24_data *at24,
if (status == count)
return count;
- }
+
+ usleep_range(1000, 1500);
+ } while (time_before(write_time, timeout));
return -ETIMEDOUT;
}
@@ -446,7 +475,14 @@ static ssize_t at24_eeprom_write_smbus_byte(struct at24_data *at24,
client = at24_translate_offset(at24, &offset);
- loop_until_timeout(timeout, write_time) {
+ timeout = jiffies + msecs_to_jiffies(write_timeout);
+ do {
+ /*
+ * The timestamp shall be taken before the actual operation
+ * to avoid a premature timeout in case of high CPU load.
+ */
+ write_time = jiffies;
+
status = i2c_smbus_write_byte_data(client, offset, buf[0]);
if (status == 0)
status = count;
@@ -456,7 +492,9 @@ static ssize_t at24_eeprom_write_smbus_byte(struct at24_data *at24,
if (status == count)
return count;
- }
+
+ usleep_range(1000, 1500);
+ } while (time_before(write_time, timeout));
return -ETIMEDOUT;
}
@@ -485,7 +523,14 @@ static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf,
memcpy(&msg.buf[i], buf, count);
msg.len = i + count;
- loop_until_timeout(timeout, write_time) {
+ timeout = jiffies + msecs_to_jiffies(write_timeout);
+ do {
+ /*
+ * The timestamp shall be taken before the actual operation
+ * to avoid a premature timeout in case of high CPU load.
+ */
+ write_time = jiffies;
+
status = i2c_transfer(client->adapter, &msg, 1);
if (status == 1)
status = count;
@@ -495,7 +540,9 @@ static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf,
if (status == count)
return count;
- }
+
+ usleep_range(1000, 1500);
+ } while (time_before(write_time, timeout));
return -ETIMEDOUT;
}
@@ -787,7 +834,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
at24->nvmem_config.name = dev_name(&client->dev);
at24->nvmem_config.dev = &client->dev;
at24->nvmem_config.read_only = !writable;
- at24->nvmem_config.root_only = true;
+ at24->nvmem_config.root_only = !(chip.flags & AT24_FLAG_IRUGO);
at24->nvmem_config.owner = THIS_MODULE;
at24->nvmem_config.compat = true;
at24->nvmem_config.base_dev = &client->dev;