diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-omap.c')
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 40 |
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 | ||
170 | struct omap_i2c_dev { | 172 | struct 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 | ||
204 | const static u8 reg_map[] = { | 207 | const 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 | ||
706 | static 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; |