aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-omap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses/i2c-omap.c')
-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;