diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 21:40:57 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 21:40:57 +0300 |
commit | fe3c560b8a22cb28e54fe8950abef38e88d75831 (patch) | |
tree | 88db8742152559e1840832970066816e72a9009b /drivers/i2c/busses/i2c-bfin-twi.c | |
parent | d20056032e20061db6583f517a4d3ea4492a94f1 (diff) | |
parent | dad92924ea4c9167e64a2835ec9310c73570b10b (diff) | |
download | linux-fe3c560b8a22cb28e54fe8950abef38e88d75831.tar.xz |
Merge branch 'for-linus/i2c-2638' of git://git.fluff.org/bjdooks/linux
* 'for-linus/i2c-2638' of git://git.fluff.org/bjdooks/linux:
i2c-bfin-twi: move setup to the earlier subsys initcall
i2c-bfin-twi: handle faulty slave devices better
i2c-mv64xxx: send repeated START between messages in xfer
i2c-nomadik: fix regression on adapter name
i2c-omap: Set latency requirements only once for several messages
i2c-eg20t: add driver for Intel EG20T
i2c-ocores: add some device tree documentation
i2c-ocores: Use devres for resource allocation
i2c-ocores: Adapt for device tree
i2c-iop3xx: add iomem annotation
Diffstat (limited to 'drivers/i2c/busses/i2c-bfin-twi.c')
-rw-r--r-- | drivers/i2c/busses/i2c-bfin-twi.c | 24 |
1 files changed, 23 insertions, 1 deletions
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index fb26e5c67515..52b545a795f2 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -20,6 +20,7 @@ #include <linux/completion.h> #include <linux/interrupt.h> #include <linux/platform_device.h> +#include <linux/delay.h> #include <asm/blackfin.h> #include <asm/portmux.h> @@ -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. */ @@ -760,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"); |