From 540ac5553e8169413a90a8e68b3a10f801640eb7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 11 Jan 2011 00:25:08 -0500 Subject: 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 Signed-off-by: Mike Frysinger Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-bfin-twi.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index fb26e5c..1ee9d5a 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -159,6 +160,27 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, if (mast_stat & BUFWRERR) dev_dbg(&iface->adap.dev, "Buffer Write Error\n"); + /* Faulty slave devices, may drive SDA low after a transfer + * finishes. To release the bus this code generates up to 9 + * extra clocks until SDA is released. + */ + + if (read_MASTER_STAT(iface) & SDASEN) { + int cnt = 9; + do { + write_MASTER_CTL(iface, SCLOVR); + udelay(6); + write_MASTER_CTL(iface, 0); + udelay(6); + } while ((read_MASTER_STAT(iface) & SDASEN) && cnt--); + + write_MASTER_CTL(iface, SDAOVR | SCLOVR); + udelay(6); + write_MASTER_CTL(iface, SDAOVR); + udelay(6); + write_MASTER_CTL(iface, 0); + } + /* If it is a quick transfer, only address without data, * not an err, return 1. */ -- cgit v1.1 From 74f56c4ad4e4627862bddb0b8c3ab394e3c004f7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 11 Jan 2011 00:25:09 -0500 Subject: i2c-bfin-twi: move setup to the earlier subsys initcall Some systems using this bus sometimes have very basic devices such as regulators on the bus, so the I2C bus master needs to be loaded early. This also matches the behavior of many other I2C bus master drivers. Therefore initialize via subsys_initcall(). Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-bfin-twi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 1ee9d5a..52b545a 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -782,7 +782,7 @@ static void __exit i2c_bfin_twi_exit(void) platform_driver_unregister(&i2c_bfin_twi_driver); } -module_init(i2c_bfin_twi_init); +subsys_initcall(i2c_bfin_twi_init); module_exit(i2c_bfin_twi_exit); MODULE_AUTHOR("Bryan Wu, Sonic Zhang"); -- cgit v1.1