aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-bfin-twi.c
diff options
context:
space:
mode:
authorSonic Zhang <sonic.zhang@analog.com>2010-03-22 03:23:18 -0400
committerBen Dooks <ben-linux@fluff.org>2010-05-19 19:18:58 -0400
commit5481d0753e7a78bff7550a8165b7924baa74e9cf (patch)
treed73b29d04e152042eaa353e9c66988d56a527379 /drivers/i2c/busses/i2c-bfin-twi.c
parent5cfafc18f38aa6701f581bee875fb0b19f3b3b4b (diff)
i2c-bfin-twi: fix lost interrupts at high speeds
i2c event of next read/write byte may trigger before current int state is cleared in the interrupt handler. So, this should be done at the beginning of interrupt handler to avoid losing new i2c events. Signed-off-by: Sonic Zhang <sonic.zhang@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers/i2c/busses/i2c-bfin-twi.c')
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c37
1 files changed, 13 insertions, 24 deletions
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 0279a7a6b86c..ff61c4b22095 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -81,14 +81,15 @@ static const u16 pin_req[2][3] = {
81 {P_TWI1_SCL, P_TWI1_SDA, 0}, 81 {P_TWI1_SCL, P_TWI1_SDA, 0},
82}; 82};
83 83
84static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) 84static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
85 unsigned short twi_int_status)
85{ 86{
86 unsigned short twi_int_status = read_INT_STAT(iface);
87 unsigned short mast_stat = read_MASTER_STAT(iface); 87 unsigned short mast_stat = read_MASTER_STAT(iface);
88 88
89 if (twi_int_status & XMTSERV) { 89 if (twi_int_status & XMTSERV) {
90 /* Transmit next data */ 90 /* Transmit next data */
91 if (iface->writeNum > 0) { 91 if (iface->writeNum > 0) {
92 SSYNC();
92 write_XMT_DATA8(iface, *(iface->transPtr++)); 93 write_XMT_DATA8(iface, *(iface->transPtr++));
93 iface->writeNum--; 94 iface->writeNum--;
94 } 95 }
@@ -110,10 +111,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
110 write_MASTER_CTL(iface, 111 write_MASTER_CTL(iface,
111 (read_MASTER_CTL(iface) | RSTART) & ~MDIR); 112 (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
112 } 113 }
113 SSYNC();
114 /* Clear status */
115 write_INT_STAT(iface, XMTSERV);
116 SSYNC();
117 } 114 }
118 if (twi_int_status & RCVSERV) { 115 if (twi_int_status & RCVSERV) {
119 if (iface->readNum > 0) { 116 if (iface->readNum > 0) {
@@ -135,7 +132,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
135 } else if (iface->manual_stop) { 132 } else if (iface->manual_stop) {
136 write_MASTER_CTL(iface, 133 write_MASTER_CTL(iface,
137 read_MASTER_CTL(iface) | STOP); 134 read_MASTER_CTL(iface) | STOP);
138 SSYNC();
139 } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && 135 } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
140 iface->cur_msg + 1 < iface->msg_num) { 136 iface->cur_msg + 1 < iface->msg_num) {
141 if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) 137 if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
@@ -144,18 +140,12 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
144 else 140 else
145 write_MASTER_CTL(iface, 141 write_MASTER_CTL(iface,
146 (read_MASTER_CTL(iface) | RSTART) & ~MDIR); 142 (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
147 SSYNC();
148 } 143 }
149 /* Clear interrupt source */
150 write_INT_STAT(iface, RCVSERV);
151 SSYNC();
152 } 144 }
153 if (twi_int_status & MERR) { 145 if (twi_int_status & MERR) {
154 write_INT_STAT(iface, MERR);
155 write_INT_MASK(iface, 0); 146 write_INT_MASK(iface, 0);
156 write_MASTER_STAT(iface, 0x3e); 147 write_MASTER_STAT(iface, 0x3e);
157 write_MASTER_CTL(iface, 0); 148 write_MASTER_CTL(iface, 0);
158 SSYNC();
159 iface->result = -EIO; 149 iface->result = -EIO;
160 150
161 if (mast_stat & LOSTARB) 151 if (mast_stat & LOSTARB)
@@ -173,10 +163,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
173 * results. 163 * results.
174 */ 164 */
175 if (twi_int_status & MCOMP) { 165 if (twi_int_status & MCOMP) {
176 write_INT_STAT(iface, MCOMP);
177 write_INT_MASK(iface, 0);
178 write_MASTER_CTL(iface, 0);
179 SSYNC();
180 /* If it is a quick transfer, only address without data, 166 /* If it is a quick transfer, only address without data,
181 * not an err, return 1. 167 * not an err, return 1.
182 * If address is acknowledged return 1. 168 * If address is acknowledged return 1.
@@ -189,8 +175,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
189 return; 175 return;
190 } 176 }
191 if (twi_int_status & MCOMP) { 177 if (twi_int_status & MCOMP) {
192 write_INT_STAT(iface, MCOMP);
193 SSYNC();
194 if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { 178 if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
195 if (iface->readNum == 0) { 179 if (iface->readNum == 0) {
196 /* set the read number to 1 and ask for manual 180 /* set the read number to 1 and ask for manual
@@ -212,7 +196,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
212 /* remove restart bit and enable master receive */ 196 /* remove restart bit and enable master receive */
213 write_MASTER_CTL(iface, 197 write_MASTER_CTL(iface,
214 read_MASTER_CTL(iface) & ~RSTART); 198 read_MASTER_CTL(iface) & ~RSTART);
215 SSYNC();
216 } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && 199 } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
217 iface->cur_msg+1 < iface->msg_num) { 200 iface->cur_msg+1 < iface->msg_num) {
218 iface->cur_msg++; 201 iface->cur_msg++;
@@ -231,7 +214,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
231 write_XMT_DATA8(iface, 214 write_XMT_DATA8(iface,
232 *(iface->transPtr++)); 215 *(iface->transPtr++));
233 iface->writeNum--; 216 iface->writeNum--;
234 SSYNC();
235 } 217 }
236 } 218 }
237 219
@@ -249,12 +231,10 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
249 /* remove restart bit and enable master receive */ 231 /* remove restart bit and enable master receive */
250 write_MASTER_CTL(iface, 232 write_MASTER_CTL(iface,
251 read_MASTER_CTL(iface) & ~RSTART); 233 read_MASTER_CTL(iface) & ~RSTART);
252 SSYNC();
253 } else { 234 } else {
254 iface->result = 1; 235 iface->result = 1;
255 write_INT_MASK(iface, 0); 236 write_INT_MASK(iface, 0);
256 write_MASTER_CTL(iface, 0); 237 write_MASTER_CTL(iface, 0);
257 SSYNC();
258 } 238 }
259 } 239 }
260 complete(&iface->complete); 240 complete(&iface->complete);
@@ -265,9 +245,18 @@ static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
265{ 245{
266 struct bfin_twi_iface *iface = dev_id; 246 struct bfin_twi_iface *iface = dev_id;
267 unsigned long flags; 247 unsigned long flags;
248 unsigned short twi_int_status;
268 249
269 spin_lock_irqsave(&iface->lock, flags); 250 spin_lock_irqsave(&iface->lock, flags);
270 bfin_twi_handle_interrupt(iface); 251 while (1) {
252 twi_int_status = read_INT_STAT(iface);
253 if (!twi_int_status)
254 break;
255 /* Clear interrupt status */
256 write_INT_STAT(iface, twi_int_status);
257 bfin_twi_handle_interrupt(iface, twi_int_status);
258 SSYNC();
259 }
271 spin_unlock_irqrestore(&iface->lock, flags); 260 spin_unlock_irqrestore(&iface->lock, flags);
272 return IRQ_HANDLED; 261 return IRQ_HANDLED;
273} 262}