aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authormanjugk manjugk <manjugk@ti.com>2010-05-11 14:35:20 -0400
committerBen Dooks <ben-linux@fluff.org>2010-05-19 19:18:59 -0400
commitf3083d921d8964b66502a0456f62a9d29cd029ef (patch)
tree0e01e2e9844e38babb1a6d4e05cb7a0d09b236e2 /drivers
parente9f59b9c9bc5730152b6a94c47dd90b730a07e35 (diff)
OMAP2/3: I2C: Errata ID i207: Clear wrong RDR interrupt
Under certain rare conditions, I2C_STAT[13].RDR bit may be set and the corresponding interrupt fire, even there is no data in the receive FIFO, or the I2C data transfer is still ongoing. These spurious RDR events must be ignored by the software. This patch handles and ignores RDR spurious interrupts. The below sequence is required in interrupt handler for handling this errata: 1. If RDR is set to 1, clear RDR 2. Read I2C status register and check for BusBusy bit. If BusBusy bit is set, skip remaining steps. 3. If BusBusy bit is not set, perform read operation on I2C status register. 4. If RDR is set, clear the same. Check RDR again and clear if it sets RDR bit again. 5. Perform I2C Data Read operation N number of times(where N is value read from the register BUFSTAT-RXSTAT bit fields). Note: This errata is not applicable for omap2420 and omap4. It is applicable for: 1. omap2430 2. omap34xx(including omap3630). Signed-off-by: Manjunatha GK <manjugk@ti.com> Cc: Hema Kalliguddi <hemahk@ti.com> Cc: Nishanth Menon <nm@ti.com> Cc: Aaro Koskinen <Aaro.Koskinen@nokia.com> Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/i2c-omap.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 00fd02ec1b65..fdba13137daf 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -166,6 +166,8 @@ enum {
166#define SYSC_IDLEMODE_SMART 0x2 166#define SYSC_IDLEMODE_SMART 0x2
167#define SYSC_CLOCKACTIVITY_FCLK 0x2 167#define SYSC_CLOCKACTIVITY_FCLK 0x2
168 168
169/* Errata definitions */
170#define I2C_OMAP_ERRATA_I207 (1 << 0)
169 171
170struct omap_i2c_dev { 172struct omap_i2c_dev {
171 struct device *dev; 173 struct device *dev;
@@ -199,6 +201,7 @@ struct omap_i2c_dev {
199 u16 bufstate; 201 u16 bufstate;
200 u16 syscstate; 202 u16 syscstate;
201 u16 westate; 203 u16 westate;
204 u16 errata;
202}; 205};
203 206
204const static u8 reg_map[] = { 207const static u8 reg_map[] = {
@@ -498,6 +501,11 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
498 /* Take the I2C module out of reset: */ 501 /* Take the I2C module out of reset: */
499 omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); 502 omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
500 503
504 dev->errata = 0;
505
506 if (cpu_is_omap2430() || cpu_is_omap34xx())
507 dev->errata |= I2C_OMAP_ERRATA_I207;
508
501 /* Enable interrupts */ 509 /* Enable interrupts */
502 dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | 510 dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
503 OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | 511 OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
@@ -695,6 +703,34 @@ omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
695 omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat); 703 omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
696} 704}
697 705
706static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat)
707{
708 /*
709 * I2C Errata(Errata Nos. OMAP2: 1.67, OMAP3: 1.8)
710 * Not applicable for OMAP4.
711 * Under certain rare conditions, RDR could be set again
712 * when the bus is busy, then ignore the interrupt and
713 * clear the interrupt.
714 */
715 if (stat & OMAP_I2C_STAT_RDR) {
716 /* Step 1: If RDR is set, clear it */
717 omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
718
719 /* Step 2: */
720 if (!(omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG)
721 & OMAP_I2C_STAT_BB)) {
722
723 /* Step 3: */
724 if (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG)
725 & OMAP_I2C_STAT_RDR) {
726 omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
727 dev_dbg(dev->dev, "RDR when bus is busy.\n");
728 }
729
730 }
731 }
732}
733
698/* rev1 devices are apparently only on some 15xx */ 734/* rev1 devices are apparently only on some 15xx */
699#ifdef CONFIG_ARCH_OMAP15XX 735#ifdef CONFIG_ARCH_OMAP15XX
700 736
@@ -834,6 +870,10 @@ complete:
834 } 870 }
835 if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { 871 if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
836 u8 num_bytes = 1; 872 u8 num_bytes = 1;
873
874 if (dev->errata & I2C_OMAP_ERRATA_I207)
875 i2c_omap_errata_i207(dev, stat);
876
837 if (dev->fifo_size) { 877 if (dev->fifo_size) {
838 if (stat & OMAP_I2C_STAT_RRDY) 878 if (stat & OMAP_I2C_STAT_RRDY)
839 num_bytes = dev->fifo_size; 879 num_bytes = dev->fifo_size;