Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d29196c authored by Wolfram Sang's avatar Wolfram Sang Committed by Jean Delvare
Browse files

at24: Use timeout also for read

Writes may take some time on EEPROMs, so for consecutive writes, we already
have a loop waiting for the EEPROM to become ready. Use such a loop for reads,
too, in case somebody wants to immediately read after a write. Detailed bug
report and test case can be found here:

http://article.gmane.org/gmane.linux.drivers.i2c/4660



Reported-by: default avatarAleksandar Ivanov <ivanov.aleks@gmail.com>
Signed-off-by: default avatarWolfram Sang <w.sang@pengutronix.de>
Tested-by: default avatarAleksandar Ivanov <ivanov.aleks@gmail.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
parent bbd2d9c9
Loading
Loading
Loading
Loading
+45 −31
Original line number Diff line number Diff line
@@ -158,6 +158,7 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
	struct i2c_msg msg[2];
	u8 msgbuf[2];
	struct i2c_client *client;
	unsigned long timeout, read_time;
	int status, i;

	memset(msg, 0, sizeof(msg));
@@ -183,22 +184,17 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
	if (count > io_limit)
		count = io_limit;

	/* Smaller eeproms can work given some SMBus extension calls */
	if (at24->use_smbus) {
		/* Smaller eeproms can work given some SMBus extension calls */
		if (count > I2C_SMBUS_BLOCK_MAX)
			count = I2C_SMBUS_BLOCK_MAX;
		status = i2c_smbus_read_i2c_block_data(client, offset,
				count, buf);
		dev_dbg(&client->dev, "smbus read %zu@%d --> %d\n",
				count, offset, status);
		return (status < 0) ? -EIO : status;
	}

	} else {
		/*
	 * When we have a better choice than SMBus calls, use a combined
	 * I2C message. Write address; then read up to io_limit data bytes.
	 * Note that read page rollover helps us here (unlike writes).
	 * msgbuf is u8 and will cast to our needs.
		 * When we have a better choice than SMBus calls, use a
		 * combined I2C message. Write address; then read up to
		 * io_limit data bytes. Note that read page rollover helps us
		 * here (unlike writes). msgbuf is u8 and will cast to our
		 * needs.
		 */
		i = 0;
		if (at24->chip.flags & AT24_FLAG_ADDR16)
@@ -213,17 +209,35 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
		msg[1].flags = I2C_M_RD;
		msg[1].buf = buf;
		msg[1].len = count;
	}

	/*
	 * Reads fail if the previous write didn't complete yet. We may
	 * loop a few times until this one succeeds, waiting at least
	 * long enough for one entire page write to work.
	 */
	timeout = jiffies + msecs_to_jiffies(write_timeout);
	do {
		read_time = jiffies;
		if (at24->use_smbus) {
			status = i2c_smbus_read_i2c_block_data(client, offset,
					count, buf);
		} else {
			status = i2c_transfer(client->adapter, msg, 2);
	dev_dbg(&client->dev, "i2c read %zu@%d --> %d\n",
			count, offset, status);

			if (status == 2)
				status = count;
		}
		dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
				count, offset, status, jiffies);

		if (status == count)
			return count;
	else if (status >= 0)
		return -EIO;
	else
		return status;

		/* REVISIT: at HZ=100, this is sloooow */
		msleep(1);
	} while (time_before(read_time, timeout));

	return -ETIMEDOUT;
}

static ssize_t at24_read(struct at24_data *at24,