aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorShinya Kuribayashi <shinya.kuribayashi@necel.com>2009-11-06 07:44:37 -0500
committerBen Dooks <ben-linux@fluff.org>2009-12-08 19:19:09 -0500
commite28000a38da803de8d90727bec45f3d7c831a59a (patch)
tree1d6c6e6294c91cffb32ec05ff3295e2472338938 /drivers/i2c
parented5e1dd5f2daa8a59bc8116888417a6ff96d2ae9 (diff)
i2c-designware: Don't use the IC_CLR_INTR register to clear interrupts
We're strongly discouraged from using the IC_CLR_INTR register because it clears all software-clearable interrupts asserted at the moment. stat = readl(IC_INTR_STAT); : : <=== Interrupts asserted during this period will be lost : readl(IC_CLR_INTR); Instead, use the separately-prepared IC_CLR_* registers. At the same time, this patch adds all remaining interrupt definitions available in the DesignWare I2C hardware. Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com> Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-designware.c84
1 files changed, 79 insertions, 5 deletions
diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c
index a4f928e1fc5b..eeb1915c59e3 100644
--- a/drivers/i2c/busses/i2c-designware.c
+++ b/drivers/i2c/busses/i2c-designware.c
@@ -49,7 +49,18 @@
49#define DW_IC_FS_SCL_LCNT 0x20 49#define DW_IC_FS_SCL_LCNT 0x20
50#define DW_IC_INTR_STAT 0x2c 50#define DW_IC_INTR_STAT 0x2c
51#define DW_IC_INTR_MASK 0x30 51#define DW_IC_INTR_MASK 0x30
52#define DW_IC_RAW_INTR_STAT 0x34
52#define DW_IC_CLR_INTR 0x40 53#define DW_IC_CLR_INTR 0x40
54#define DW_IC_CLR_RX_UNDER 0x44
55#define DW_IC_CLR_RX_OVER 0x48
56#define DW_IC_CLR_TX_OVER 0x4c
57#define DW_IC_CLR_RD_REQ 0x50
58#define DW_IC_CLR_TX_ABRT 0x54
59#define DW_IC_CLR_RX_DONE 0x58
60#define DW_IC_CLR_ACTIVITY 0x5c
61#define DW_IC_CLR_STOP_DET 0x60
62#define DW_IC_CLR_START_DET 0x64
63#define DW_IC_CLR_GEN_CALL 0x68
53#define DW_IC_ENABLE 0x6c 64#define DW_IC_ENABLE 0x6c
54#define DW_IC_STATUS 0x70 65#define DW_IC_STATUS 0x70
55#define DW_IC_TXFLR 0x74 66#define DW_IC_TXFLR 0x74
@@ -64,9 +75,18 @@
64#define DW_IC_CON_RESTART_EN 0x20 75#define DW_IC_CON_RESTART_EN 0x20
65#define DW_IC_CON_SLAVE_DISABLE 0x40 76#define DW_IC_CON_SLAVE_DISABLE 0x40
66 77
67#define DW_IC_INTR_TX_EMPTY 0x10 78#define DW_IC_INTR_RX_UNDER 0x001
68#define DW_IC_INTR_TX_ABRT 0x40 79#define DW_IC_INTR_RX_OVER 0x002
80#define DW_IC_INTR_RX_FULL 0x004
81#define DW_IC_INTR_TX_OVER 0x008
82#define DW_IC_INTR_TX_EMPTY 0x010
83#define DW_IC_INTR_RD_REQ 0x020
84#define DW_IC_INTR_TX_ABRT 0x040
85#define DW_IC_INTR_RX_DONE 0x080
86#define DW_IC_INTR_ACTIVITY 0x100
69#define DW_IC_INTR_STOP_DET 0x200 87#define DW_IC_INTR_STOP_DET 0x200
88#define DW_IC_INTR_START_DET 0x400
89#define DW_IC_INTR_GEN_CALL 0x800
70 90
71#define DW_IC_STATUS_ACTIVITY 0x1 91#define DW_IC_STATUS_ACTIVITY 0x1
72 92
@@ -439,6 +459,61 @@ static void dw_i2c_pump_msg(unsigned long data)
439 writel(intr_mask, dev->base + DW_IC_INTR_MASK); 459 writel(intr_mask, dev->base + DW_IC_INTR_MASK);
440} 460}
441 461
462static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
463{
464 u32 stat;
465
466 /*
467 * The IC_INTR_STAT register just indicates "enabled" interrupts.
468 * Ths unmasked raw version of interrupt status bits are available
469 * in the IC_RAW_INTR_STAT register.
470 *
471 * That is,
472 * stat = readl(IC_INTR_STAT);
473 * equals to,
474 * stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK);
475 *
476 * The raw version might be useful for debugging purposes.
477 */
478 stat = readl(dev->base + DW_IC_INTR_STAT);
479
480 /*
481 * Do not use the IC_CLR_INTR register to clear interrupts, or
482 * you'll miss some interrupts, triggered during the period from
483 * readl(IC_INTR_STAT) to readl(IC_CLR_INTR).
484 *
485 * Instead, use the separately-prepared IC_CLR_* registers.
486 */
487 if (stat & DW_IC_INTR_RX_UNDER)
488 readl(dev->base + DW_IC_CLR_RX_UNDER);
489 if (stat & DW_IC_INTR_RX_OVER)
490 readl(dev->base + DW_IC_CLR_RX_OVER);
491 if (stat & DW_IC_INTR_TX_OVER)
492 readl(dev->base + DW_IC_CLR_TX_OVER);
493 if (stat & DW_IC_INTR_RD_REQ)
494 readl(dev->base + DW_IC_CLR_RD_REQ);
495 if (stat & DW_IC_INTR_TX_ABRT) {
496 /*
497 * The IC_TX_ABRT_SOURCE register is cleared whenever
498 * the IC_CLR_TX_ABRT is read. Preserve it beforehand.
499 */
500 dev->abort_source = readl(dev->base + DW_IC_TX_ABRT_SOURCE);
501 readl(dev->base + DW_IC_CLR_TX_ABRT);
502 }
503 if (stat & DW_IC_INTR_RX_DONE)
504 readl(dev->base + DW_IC_CLR_RX_DONE);
505 if (stat & DW_IC_INTR_ACTIVITY)
506 readl(dev->base + DW_IC_CLR_ACTIVITY);
507 if (stat & DW_IC_INTR_STOP_DET)
508 readl(dev->base + DW_IC_CLR_STOP_DET);
509 if (stat & DW_IC_INTR_START_DET)
510 readl(dev->base + DW_IC_CLR_START_DET);
511 if (stat & DW_IC_INTR_GEN_CALL)
512 readl(dev->base + DW_IC_CLR_GEN_CALL);
513
514 return stat;
515}
516
442/* 517/*
443 * Interrupt service routine. This gets called whenever an I2C interrupt 518 * Interrupt service routine. This gets called whenever an I2C interrupt
444 * occurs. 519 * occurs.
@@ -448,16 +523,15 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
448 struct dw_i2c_dev *dev = dev_id; 523 struct dw_i2c_dev *dev = dev_id;
449 u32 stat; 524 u32 stat;
450 525
451 stat = readl(dev->base + DW_IC_INTR_STAT); 526 stat = i2c_dw_read_clear_intrbits(dev);
452 dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat); 527 dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat);
528
453 if (stat & DW_IC_INTR_TX_ABRT) { 529 if (stat & DW_IC_INTR_TX_ABRT) {
454 dev->abort_source = readl(dev->base + DW_IC_TX_ABRT_SOURCE);
455 dev->cmd_err |= DW_IC_ERR_TX_ABRT; 530 dev->cmd_err |= DW_IC_ERR_TX_ABRT;
456 dev->status = STATUS_IDLE; 531 dev->status = STATUS_IDLE;
457 } else if (stat & DW_IC_INTR_TX_EMPTY) 532 } else if (stat & DW_IC_INTR_TX_EMPTY)
458 tasklet_schedule(&dev->pump_msg); 533 tasklet_schedule(&dev->pump_msg);
459 534
460 readl(dev->base + DW_IC_CLR_INTR); /* clear interrupts */
461 writel(0, dev->base + DW_IC_INTR_MASK); /* disable interrupts */ 535 writel(0, dev->base + DW_IC_INTR_MASK); /* disable interrupts */
462 if (stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) 536 if (stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET))
463 complete(&dev->cmd_complete); 537 complete(&dev->cmd_complete);