Skip to content
Snippets Groups Projects
Commit b0338080 authored by Marek Vasut's avatar Marek Vasut Committed by Heiko Schocher
Browse files

i2c: designware: Avoid overwriting the cmd_data register


Make sure the driver writes the cmd_data register only once per
read transfer instead of doing so potentially repeatedly.

In case the read transfer didn't finish quickly enough, the loop
in the driver code would spin fast enough to write the same value
into the cmd_data register again before re-checking whether the
transfer completed, which would cause another spurious read transfer
on the bus.

Signed-off-by: default avatarMarek Vasut <marex@denx.de>
Cc: Stefan Roese <sr@denx.de>
Cc: Alexey Brodkin <abrodkin@synopsys.com>
Cc: Heiko Schocher <hs@denx.de>
Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
Cc: Chin Liang See <clsee@altera.com>
parent 5ac5861c
No related branches found
No related tags found
No related merge requests found
...@@ -249,6 +249,7 @@ static int __dw_i2c_read(struct i2c_regs *i2c_base, u8 dev, uint addr, ...@@ -249,6 +249,7 @@ static int __dw_i2c_read(struct i2c_regs *i2c_base, u8 dev, uint addr,
int alen, u8 *buffer, int len) int alen, u8 *buffer, int len)
{ {
unsigned long start_time_rx; unsigned long start_time_rx;
unsigned int active = 0;
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW #ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/* /*
...@@ -274,18 +275,28 @@ static int __dw_i2c_read(struct i2c_regs *i2c_base, u8 dev, uint addr, ...@@ -274,18 +275,28 @@ static int __dw_i2c_read(struct i2c_regs *i2c_base, u8 dev, uint addr,
start_time_rx = get_timer(0); start_time_rx = get_timer(0);
while (len) { while (len) {
if (len == 1) if (!active) {
writel(IC_CMD | IC_STOP, &i2c_base->ic_cmd_data); /*
else * Avoid writing to ic_cmd_data multiple times
writel(IC_CMD, &i2c_base->ic_cmd_data); * in case this loop spins too quickly and the
* ic_status RFNE bit isn't set after the first
* write. Subsequent writes to ic_cmd_data can
* trigger spurious i2c transfer.
*/
if (len == 1)
writel(IC_CMD | IC_STOP, &i2c_base->ic_cmd_data);
else
writel(IC_CMD, &i2c_base->ic_cmd_data);
active = 1;
}
if (readl(&i2c_base->ic_status) & IC_STATUS_RFNE) { if (readl(&i2c_base->ic_status) & IC_STATUS_RFNE) {
*buffer++ = (uchar)readl(&i2c_base->ic_cmd_data); *buffer++ = (uchar)readl(&i2c_base->ic_cmd_data);
len--; len--;
start_time_rx = get_timer(0); start_time_rx = get_timer(0);
active = 0;
} else if (get_timer(start_time_rx) > I2C_BYTE_TO) { } else if (get_timer(start_time_rx) > I2C_BYTE_TO) {
return 1; return 1;
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment