diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-bfin-twi.c')
-rw-r--r-- | drivers/i2c/busses/i2c-bfin-twi.c | 32 |
1 files changed, 30 insertions, 2 deletions
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index fb26e5c67515..cbc98aea5b09 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 | */ |
@@ -171,7 +193,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, | |||
171 | return; | 193 | return; |
172 | } | 194 | } |
173 | if (twi_int_status & MCOMP) { | 195 | if (twi_int_status & MCOMP) { |
174 | if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { | 196 | if ((read_MASTER_CTL(iface) & MEN) == 0 && |
197 | (iface->cur_mode == TWI_I2C_MODE_REPEAT || | ||
198 | iface->cur_mode == TWI_I2C_MODE_COMBINED)) { | ||
199 | iface->result = -1; | ||
200 | write_INT_MASK(iface, 0); | ||
201 | write_MASTER_CTL(iface, 0); | ||
202 | } else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { | ||
175 | if (iface->readNum == 0) { | 203 | if (iface->readNum == 0) { |
176 | /* set the read number to 1 and ask for manual | 204 | /* set the read number to 1 and ask for manual |
177 | * stop in block combine mode | 205 | * stop in block combine mode |
@@ -760,7 +788,7 @@ static void __exit i2c_bfin_twi_exit(void) | |||
760 | platform_driver_unregister(&i2c_bfin_twi_driver); | 788 | platform_driver_unregister(&i2c_bfin_twi_driver); |
761 | } | 789 | } |
762 | 790 | ||
763 | module_init(i2c_bfin_twi_init); | 791 | subsys_initcall(i2c_bfin_twi_init); |
764 | module_exit(i2c_bfin_twi_exit); | 792 | module_exit(i2c_bfin_twi_exit); |
765 | 793 | ||
766 | MODULE_AUTHOR("Bryan Wu, Sonic Zhang"); | 794 | MODULE_AUTHOR("Bryan Wu, Sonic Zhang"); |