aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorTroy Kisky <troy.kisky@boundarydevices.com>2008-07-14 16:38:21 -0400
committerJean Delvare <khali@mahadeva.delvare>2008-07-14 16:38:21 -0400
commit5a0d5f5ffa5d294d895ef54fc220c6182db63998 (patch)
tree6839d7a2dcb7beac8c9163a23c0afc2728fed8fa /drivers/i2c
parent0ab56e20674b41dd0203d16b602aac8d9d26a70a (diff)
i2c-davinci: Fix signal handling bug
If wait_for_completion_interruptible_timeout exits due to a signal, the i2c bus was locking up. Signed-off-by: Troy Kisky <troy.kisky@boundarydevices.com> Signed-off-by: Kevin Hilman <khilman@mvista.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-davinci.c62
1 files changed, 52 insertions, 10 deletions
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index c56f8fe4efe5..160857296952 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -85,6 +85,7 @@
85#define DAVINCI_I2C_MDR_MST (1 << 10) 85#define DAVINCI_I2C_MDR_MST (1 << 10)
86#define DAVINCI_I2C_MDR_TRX (1 << 9) 86#define DAVINCI_I2C_MDR_TRX (1 << 9)
87#define DAVINCI_I2C_MDR_XA (1 << 8) 87#define DAVINCI_I2C_MDR_XA (1 << 8)
88#define DAVINCI_I2C_MDR_RM (1 << 7)
88#define DAVINCI_I2C_MDR_IRS (1 << 5) 89#define DAVINCI_I2C_MDR_IRS (1 << 5)
89 90
90#define DAVINCI_I2C_IMR_AAS (1 << 6) 91#define DAVINCI_I2C_IMR_AAS (1 << 6)
@@ -112,6 +113,7 @@ struct davinci_i2c_dev {
112 u8 *buf; 113 u8 *buf;
113 size_t buf_len; 114 size_t buf_len;
114 int irq; 115 int irq;
116 u8 terminate;
115 struct i2c_adapter adapter; 117 struct i2c_adapter adapter;
116}; 118};
117 119
@@ -283,20 +285,34 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
283 MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 1); 285 MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 1);
284 davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w); 286 davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w);
285 287
288 dev->terminate = 0;
286 /* write the data into mode register */ 289 /* write the data into mode register */
287 davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); 290 davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
288 291
289 r = wait_for_completion_interruptible_timeout(&dev->cmd_complete, 292 r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
290 DAVINCI_I2C_TIMEOUT); 293 DAVINCI_I2C_TIMEOUT);
291 dev->buf_len = 0;
292 if (r < 0)
293 return r;
294
295 if (r == 0) { 294 if (r == 0) {
296 dev_err(dev->dev, "controller timed out\n"); 295 dev_err(dev->dev, "controller timed out\n");
297 i2c_davinci_init(dev); 296 i2c_davinci_init(dev);
297 dev->buf_len = 0;
298 return -ETIMEDOUT; 298 return -ETIMEDOUT;
299 } 299 }
300 if (dev->buf_len) {
301 /* This should be 0 if all bytes were transferred
302 * or dev->cmd_err denotes an error.
303 * A signal may have aborted the transfer.
304 */
305 if (r >= 0) {
306 dev_err(dev->dev, "abnormal termination buf_len=%i\n",
307 dev->buf_len);
308 r = -EREMOTEIO;
309 }
310 dev->terminate = 1;
311 wmb();
312 dev->buf_len = 0;
313 }
314 if (r < 0)
315 return r;
300 316
301 /* no error */ 317 /* no error */
302 if (likely(!dev->cmd_err)) 318 if (likely(!dev->cmd_err))
@@ -354,6 +370,27 @@ static u32 i2c_davinci_func(struct i2c_adapter *adap)
354 return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); 370 return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
355} 371}
356 372
373static void terminate_read(struct davinci_i2c_dev *dev)
374{
375 u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
376 w |= DAVINCI_I2C_MDR_NACK;
377 davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
378
379 /* Throw away data */
380 davinci_i2c_read_reg(dev, DAVINCI_I2C_DRR_REG);
381 if (!dev->terminate)
382 dev_err(dev->dev, "RDR IRQ while no data requested\n");
383}
384static void terminate_write(struct davinci_i2c_dev *dev)
385{
386 u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
387 w |= DAVINCI_I2C_MDR_RM | DAVINCI_I2C_MDR_STP;
388 davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
389
390 if (!dev->terminate)
391 dev_err(dev->dev, "TDR IRQ while no data to send\n");
392}
393
357/* 394/*
358 * Interrupt service routine. This gets called whenever an I2C interrupt 395 * Interrupt service routine. This gets called whenever an I2C interrupt
359 * occurs. 396 * occurs.
@@ -374,12 +411,15 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
374 411
375 switch (stat) { 412 switch (stat) {
376 case DAVINCI_I2C_IVR_AL: 413 case DAVINCI_I2C_IVR_AL:
414 /* Arbitration lost, must retry */
377 dev->cmd_err |= DAVINCI_I2C_STR_AL; 415 dev->cmd_err |= DAVINCI_I2C_STR_AL;
416 dev->buf_len = 0;
378 complete(&dev->cmd_complete); 417 complete(&dev->cmd_complete);
379 break; 418 break;
380 419
381 case DAVINCI_I2C_IVR_NACK: 420 case DAVINCI_I2C_IVR_NACK:
382 dev->cmd_err |= DAVINCI_I2C_STR_NACK; 421 dev->cmd_err |= DAVINCI_I2C_STR_NACK;
422 dev->buf_len = 0;
383 complete(&dev->cmd_complete); 423 complete(&dev->cmd_complete);
384 break; 424 break;
385 425
@@ -401,9 +441,10 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
401 davinci_i2c_write_reg(dev, 441 davinci_i2c_write_reg(dev,
402 DAVINCI_I2C_STR_REG, 442 DAVINCI_I2C_STR_REG,
403 DAVINCI_I2C_IMR_RRDY); 443 DAVINCI_I2C_IMR_RRDY);
404 } else 444 } else {
405 dev_err(dev->dev, "RDR IRQ while no " 445 /* signal can terminate transfer */
406 "data requested\n"); 446 terminate_read(dev);
447 }
407 break; 448 break;
408 449
409 case DAVINCI_I2C_IVR_XRDY: 450 case DAVINCI_I2C_IVR_XRDY:
@@ -420,9 +461,10 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
420 davinci_i2c_write_reg(dev, 461 davinci_i2c_write_reg(dev,
421 DAVINCI_I2C_IMR_REG, 462 DAVINCI_I2C_IMR_REG,
422 w); 463 w);
423 } else 464 } else {
424 dev_err(dev->dev, "TDR IRQ while no data to " 465 /* signal can terminate transfer */
425 "send\n"); 466 terminate_write(dev);
467 }
426 break; 468 break;
427 469
428 case DAVINCI_I2C_IVR_SCD: 470 case DAVINCI_I2C_IVR_SCD: