aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMichael Hennerich <michael.hennerich@analog.com>2011-01-11 00:25:08 -0500
committerBen Dooks <ben-linux@fluff.org>2011-01-12 17:23:05 -0500
commit540ac5553e8169413a90a8e68b3a10f801640eb7 (patch)
tree628dcd685d392ddc2c8fe692035050db2609dbcf /drivers
parentf878133bf022717b880d0e0995b8f91436fd605c (diff)
i2c-bfin-twi: handle faulty slave devices better
Faulty slave devices might drive SDA low after a transfer finishes. So, when this scenario is detected, have the master generate up to 9 extra clocks until the SDA is properly released. Signed-off-by: Michael Hennerich <michael.hennerich@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index fb26e5c67515..1ee9d5a31928 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -20,6 +20,7 @@
20#include <linux/completion.h> 20#include <linux/completion.h>
21#include <linux/interrupt.h> 21#include <linux/interrupt.h>
22#include <linux/platform_device.h> 22#include <linux/platform_device.h>
23#include <linux/delay.h>
23 24
24#include <asm/blackfin.h> 25#include <asm/blackfin.h>
25#include <asm/portmux.h> 26#include <asm/portmux.h>
@@ -159,6 +160,27 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
159 if (mast_stat & BUFWRERR) 160 if (mast_stat & BUFWRERR)
160 dev_dbg(&iface->adap.dev, "Buffer Write Error\n"); 161 dev_dbg(&iface->adap.dev, "Buffer Write Error\n");
161 162
163 /* Faulty slave devices, may drive SDA low after a transfer
164 * finishes. To release the bus this code generates up to 9
165 * extra clocks until SDA is released.
166 */
167
168 if (read_MASTER_STAT(iface) & SDASEN) {
169 int cnt = 9;
170 do {
171 write_MASTER_CTL(iface, SCLOVR);
172 udelay(6);
173 write_MASTER_CTL(iface, 0);
174 udelay(6);
175 } while ((read_MASTER_STAT(iface) & SDASEN) && cnt--);
176
177 write_MASTER_CTL(iface, SDAOVR | SCLOVR);
178 udelay(6);
179 write_MASTER_CTL(iface, SDAOVR);
180 udelay(6);
181 write_MASTER_CTL(iface, 0);
182 }
183
162 /* If it is a quick transfer, only address without data, 184 /* If it is a quick transfer, only address without data,
163 * not an err, return 1. 185 * not an err, return 1.
164 */ 186 */