|
@@ -38,6 +38,7 @@
|
|
#include <linux/clk.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/io.h>
|
|
#include <linux/io.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
|
|
+#include <linux/i2c-omap.h>
|
|
|
|
|
|
/* I2C controller revisions */
|
|
/* I2C controller revisions */
|
|
#define OMAP_I2C_REV_2 0x20
|
|
#define OMAP_I2C_REV_2 0x20
|
|
@@ -45,29 +46,37 @@
|
|
/* I2C controller revisions present on specific hardware */
|
|
/* I2C controller revisions present on specific hardware */
|
|
#define OMAP_I2C_REV_ON_2430 0x36
|
|
#define OMAP_I2C_REV_ON_2430 0x36
|
|
#define OMAP_I2C_REV_ON_3430 0x3C
|
|
#define OMAP_I2C_REV_ON_3430 0x3C
|
|
|
|
+#define OMAP_I2C_REV_ON_4430 0x40
|
|
|
|
|
|
/* timeout waiting for the controller to respond */
|
|
/* timeout waiting for the controller to respond */
|
|
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
|
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
|
|
|
|
|
-#define OMAP_I2C_REV_REG 0x00
|
|
|
|
-#define OMAP_I2C_IE_REG 0x01
|
|
|
|
-#define OMAP_I2C_STAT_REG 0x02
|
|
|
|
-#define OMAP_I2C_IV_REG 0x03
|
|
|
|
/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
|
|
/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
|
|
-#define OMAP_I2C_WE_REG 0x03
|
|
|
|
-#define OMAP_I2C_SYSS_REG 0x04
|
|
|
|
-#define OMAP_I2C_BUF_REG 0x05
|
|
|
|
-#define OMAP_I2C_CNT_REG 0x06
|
|
|
|
-#define OMAP_I2C_DATA_REG 0x07
|
|
|
|
-#define OMAP_I2C_SYSC_REG 0x08
|
|
|
|
-#define OMAP_I2C_CON_REG 0x09
|
|
|
|
-#define OMAP_I2C_OA_REG 0x0a
|
|
|
|
-#define OMAP_I2C_SA_REG 0x0b
|
|
|
|
-#define OMAP_I2C_PSC_REG 0x0c
|
|
|
|
-#define OMAP_I2C_SCLL_REG 0x0d
|
|
|
|
-#define OMAP_I2C_SCLH_REG 0x0e
|
|
|
|
-#define OMAP_I2C_SYSTEST_REG 0x0f
|
|
|
|
-#define OMAP_I2C_BUFSTAT_REG 0x10
|
|
|
|
|
|
+enum {
|
|
|
|
+ OMAP_I2C_REV_REG = 0,
|
|
|
|
+ OMAP_I2C_IE_REG,
|
|
|
|
+ OMAP_I2C_STAT_REG,
|
|
|
|
+ OMAP_I2C_IV_REG,
|
|
|
|
+ OMAP_I2C_WE_REG,
|
|
|
|
+ OMAP_I2C_SYSS_REG,
|
|
|
|
+ OMAP_I2C_BUF_REG,
|
|
|
|
+ OMAP_I2C_CNT_REG,
|
|
|
|
+ OMAP_I2C_DATA_REG,
|
|
|
|
+ OMAP_I2C_SYSC_REG,
|
|
|
|
+ OMAP_I2C_CON_REG,
|
|
|
|
+ OMAP_I2C_OA_REG,
|
|
|
|
+ OMAP_I2C_SA_REG,
|
|
|
|
+ OMAP_I2C_PSC_REG,
|
|
|
|
+ OMAP_I2C_SCLL_REG,
|
|
|
|
+ OMAP_I2C_SCLH_REG,
|
|
|
|
+ OMAP_I2C_SYSTEST_REG,
|
|
|
|
+ OMAP_I2C_BUFSTAT_REG,
|
|
|
|
+ OMAP_I2C_REVNB_LO,
|
|
|
|
+ OMAP_I2C_REVNB_HI,
|
|
|
|
+ OMAP_I2C_IRQSTATUS_RAW,
|
|
|
|
+ OMAP_I2C_IRQENABLE_SET,
|
|
|
|
+ OMAP_I2C_IRQENABLE_CLR,
|
|
|
|
+};
|
|
|
|
|
|
/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
|
|
/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
|
|
#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */
|
|
#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */
|
|
@@ -157,6 +166,9 @@
|
|
#define SYSC_IDLEMODE_SMART 0x2
|
|
#define SYSC_IDLEMODE_SMART 0x2
|
|
#define SYSC_CLOCKACTIVITY_FCLK 0x2
|
|
#define SYSC_CLOCKACTIVITY_FCLK 0x2
|
|
|
|
|
|
|
|
+/* Errata definitions */
|
|
|
|
+#define I2C_OMAP_ERRATA_I207 (1 << 0)
|
|
|
|
+#define I2C_OMAP3_1P153 (1 << 1)
|
|
|
|
|
|
struct omap_i2c_dev {
|
|
struct omap_i2c_dev {
|
|
struct device *dev;
|
|
struct device *dev;
|
|
@@ -167,9 +179,13 @@ struct omap_i2c_dev {
|
|
struct clk *fclk; /* Functional clock */
|
|
struct clk *fclk; /* Functional clock */
|
|
struct completion cmd_complete;
|
|
struct completion cmd_complete;
|
|
struct resource *ioarea;
|
|
struct resource *ioarea;
|
|
|
|
+ u32 latency; /* maximum mpu wkup latency */
|
|
|
|
+ void (*set_mpu_wkup_lat)(struct device *dev,
|
|
|
|
+ long latency);
|
|
u32 speed; /* Speed of bus in Khz */
|
|
u32 speed; /* Speed of bus in Khz */
|
|
u16 cmd_err;
|
|
u16 cmd_err;
|
|
u8 *buf;
|
|
u8 *buf;
|
|
|
|
+ u8 *regs;
|
|
size_t buf_len;
|
|
size_t buf_len;
|
|
struct i2c_adapter adapter;
|
|
struct i2c_adapter adapter;
|
|
u8 fifo_size; /* use as flag and value
|
|
u8 fifo_size; /* use as flag and value
|
|
@@ -186,17 +202,67 @@ struct omap_i2c_dev {
|
|
u16 bufstate;
|
|
u16 bufstate;
|
|
u16 syscstate;
|
|
u16 syscstate;
|
|
u16 westate;
|
|
u16 westate;
|
|
|
|
+ u16 errata;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const static u8 reg_map[] = {
|
|
|
|
+ [OMAP_I2C_REV_REG] = 0x00,
|
|
|
|
+ [OMAP_I2C_IE_REG] = 0x01,
|
|
|
|
+ [OMAP_I2C_STAT_REG] = 0x02,
|
|
|
|
+ [OMAP_I2C_IV_REG] = 0x03,
|
|
|
|
+ [OMAP_I2C_WE_REG] = 0x03,
|
|
|
|
+ [OMAP_I2C_SYSS_REG] = 0x04,
|
|
|
|
+ [OMAP_I2C_BUF_REG] = 0x05,
|
|
|
|
+ [OMAP_I2C_CNT_REG] = 0x06,
|
|
|
|
+ [OMAP_I2C_DATA_REG] = 0x07,
|
|
|
|
+ [OMAP_I2C_SYSC_REG] = 0x08,
|
|
|
|
+ [OMAP_I2C_CON_REG] = 0x09,
|
|
|
|
+ [OMAP_I2C_OA_REG] = 0x0a,
|
|
|
|
+ [OMAP_I2C_SA_REG] = 0x0b,
|
|
|
|
+ [OMAP_I2C_PSC_REG] = 0x0c,
|
|
|
|
+ [OMAP_I2C_SCLL_REG] = 0x0d,
|
|
|
|
+ [OMAP_I2C_SCLH_REG] = 0x0e,
|
|
|
|
+ [OMAP_I2C_SYSTEST_REG] = 0x0f,
|
|
|
|
+ [OMAP_I2C_BUFSTAT_REG] = 0x10,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const static u8 omap4_reg_map[] = {
|
|
|
|
+ [OMAP_I2C_REV_REG] = 0x04,
|
|
|
|
+ [OMAP_I2C_IE_REG] = 0x2c,
|
|
|
|
+ [OMAP_I2C_STAT_REG] = 0x28,
|
|
|
|
+ [OMAP_I2C_IV_REG] = 0x34,
|
|
|
|
+ [OMAP_I2C_WE_REG] = 0x34,
|
|
|
|
+ [OMAP_I2C_SYSS_REG] = 0x90,
|
|
|
|
+ [OMAP_I2C_BUF_REG] = 0x94,
|
|
|
|
+ [OMAP_I2C_CNT_REG] = 0x98,
|
|
|
|
+ [OMAP_I2C_DATA_REG] = 0x9c,
|
|
|
|
+ [OMAP_I2C_SYSC_REG] = 0x20,
|
|
|
|
+ [OMAP_I2C_CON_REG] = 0xa4,
|
|
|
|
+ [OMAP_I2C_OA_REG] = 0xa8,
|
|
|
|
+ [OMAP_I2C_SA_REG] = 0xac,
|
|
|
|
+ [OMAP_I2C_PSC_REG] = 0xb0,
|
|
|
|
+ [OMAP_I2C_SCLL_REG] = 0xb4,
|
|
|
|
+ [OMAP_I2C_SCLH_REG] = 0xb8,
|
|
|
|
+ [OMAP_I2C_SYSTEST_REG] = 0xbC,
|
|
|
|
+ [OMAP_I2C_BUFSTAT_REG] = 0xc0,
|
|
|
|
+ [OMAP_I2C_REVNB_LO] = 0x00,
|
|
|
|
+ [OMAP_I2C_REVNB_HI] = 0x04,
|
|
|
|
+ [OMAP_I2C_IRQSTATUS_RAW] = 0x24,
|
|
|
|
+ [OMAP_I2C_IRQENABLE_SET] = 0x2c,
|
|
|
|
+ [OMAP_I2C_IRQENABLE_CLR] = 0x30,
|
|
};
|
|
};
|
|
|
|
|
|
static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
|
|
static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
|
|
int reg, u16 val)
|
|
int reg, u16 val)
|
|
{
|
|
{
|
|
- __raw_writew(val, i2c_dev->base + (reg << i2c_dev->reg_shift));
|
|
|
|
|
|
+ __raw_writew(val, i2c_dev->base +
|
|
|
|
+ (i2c_dev->regs[reg] << i2c_dev->reg_shift));
|
|
}
|
|
}
|
|
|
|
|
|
static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
|
|
static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
|
|
{
|
|
{
|
|
- return __raw_readw(i2c_dev->base + (reg << i2c_dev->reg_shift));
|
|
|
|
|
|
+ return __raw_readw(i2c_dev->base +
|
|
|
|
+ (i2c_dev->regs[reg] << i2c_dev->reg_shift));
|
|
}
|
|
}
|
|
|
|
|
|
static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev)
|
|
static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev)
|
|
@@ -265,7 +331,11 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)
|
|
WARN_ON(dev->idle);
|
|
WARN_ON(dev->idle);
|
|
|
|
|
|
dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
|
|
dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
|
|
- omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
|
|
|
|
|
|
+ if (dev->rev >= OMAP_I2C_REV_ON_4430)
|
|
|
|
+ omap_i2c_write_reg(dev, OMAP_I2C_IRQENABLE_CLR, 1);
|
|
|
|
+ else
|
|
|
|
+ omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
|
|
|
|
+
|
|
if (dev->rev < OMAP_I2C_REV_2) {
|
|
if (dev->rev < OMAP_I2C_REV_2) {
|
|
iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
|
|
iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
|
|
} else {
|
|
} else {
|
|
@@ -330,7 +400,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|
* REVISIT: Some wkup sources might not be needed.
|
|
* REVISIT: Some wkup sources might not be needed.
|
|
*/
|
|
*/
|
|
dev->westate = OMAP_I2C_WE_ALL;
|
|
dev->westate = OMAP_I2C_WE_ALL;
|
|
- omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
|
|
|
|
|
|
+ if (dev->rev < OMAP_I2C_REV_ON_4430)
|
|
|
|
+ omap_i2c_write_reg(dev, OMAP_I2C_WE_REG,
|
|
|
|
+ dev->westate);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
|
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
|
@@ -357,7 +429,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|
psc = fclk_rate / 12000000;
|
|
psc = fclk_rate / 12000000;
|
|
}
|
|
}
|
|
|
|
|
|
- if (cpu_is_omap2430() || cpu_is_omap34xx()) {
|
|
|
|
|
|
+ if (!(cpu_class_is_omap1() || cpu_is_omap2420())) {
|
|
|
|
|
|
/*
|
|
/*
|
|
* HSI2C controller internal clk rate should be 19.2 Mhz for
|
|
* HSI2C controller internal clk rate should be 19.2 Mhz for
|
|
@@ -430,6 +502,11 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|
/* Take the I2C module out of reset: */
|
|
/* Take the I2C module out of reset: */
|
|
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
|
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
|
|
|
|
|
|
|
+ dev->errata = 0;
|
|
|
|
+
|
|
|
|
+ if (cpu_is_omap2430() || cpu_is_omap34xx())
|
|
|
|
+ dev->errata |= I2C_OMAP_ERRATA_I207;
|
|
|
|
+
|
|
/* Enable interrupts */
|
|
/* Enable interrupts */
|
|
dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
|
|
dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
|
|
OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
|
|
OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
|
|
@@ -539,8 +616,12 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
|
* REVISIT: We should abort the transfer on signals, but the bus goes
|
|
* REVISIT: We should abort the transfer on signals, but the bus goes
|
|
* into arbitration and we're currently unable to recover from it.
|
|
* into arbitration and we're currently unable to recover from it.
|
|
*/
|
|
*/
|
|
|
|
+ if (dev->set_mpu_wkup_lat != NULL)
|
|
|
|
+ dev->set_mpu_wkup_lat(dev->dev, dev->latency);
|
|
r = wait_for_completion_timeout(&dev->cmd_complete,
|
|
r = wait_for_completion_timeout(&dev->cmd_complete,
|
|
OMAP_I2C_TIMEOUT);
|
|
OMAP_I2C_TIMEOUT);
|
|
|
|
+ if (dev->set_mpu_wkup_lat != NULL)
|
|
|
|
+ dev->set_mpu_wkup_lat(dev->dev, -1);
|
|
dev->buf_len = 0;
|
|
dev->buf_len = 0;
|
|
if (r < 0)
|
|
if (r < 0)
|
|
return r;
|
|
return r;
|
|
@@ -623,6 +704,34 @@ omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
|
|
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
|
|
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat)
|
|
|
|
+{
|
|
|
|
+ /*
|
|
|
|
+ * I2C Errata(Errata Nos. OMAP2: 1.67, OMAP3: 1.8)
|
|
|
|
+ * Not applicable for OMAP4.
|
|
|
|
+ * Under certain rare conditions, RDR could be set again
|
|
|
|
+ * when the bus is busy, then ignore the interrupt and
|
|
|
|
+ * clear the interrupt.
|
|
|
|
+ */
|
|
|
|
+ if (stat & OMAP_I2C_STAT_RDR) {
|
|
|
|
+ /* Step 1: If RDR is set, clear it */
|
|
|
|
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
|
|
|
|
+
|
|
|
|
+ /* Step 2: */
|
|
|
|
+ if (!(omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG)
|
|
|
|
+ & OMAP_I2C_STAT_BB)) {
|
|
|
|
+
|
|
|
|
+ /* Step 3: */
|
|
|
|
+ if (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG)
|
|
|
|
+ & OMAP_I2C_STAT_RDR) {
|
|
|
|
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
|
|
|
|
+ dev_dbg(dev->dev, "RDR when bus is busy.\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
/* rev1 devices are apparently only on some 15xx */
|
|
/* rev1 devices are apparently only on some 15xx */
|
|
#ifdef CONFIG_ARCH_OMAP15XX
|
|
#ifdef CONFIG_ARCH_OMAP15XX
|
|
|
|
|
|
@@ -684,6 +793,35 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
|
|
#define omap_i2c_rev1_isr NULL
|
|
#define omap_i2c_rev1_isr NULL
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * OMAP3430 Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing
|
|
|
|
+ * data to DATA_REG. Otherwise some data bytes can be lost while transferring
|
|
|
|
+ * them from the memory to the I2C interface.
|
|
|
|
+ */
|
|
|
|
+static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
|
|
|
|
+{
|
|
|
|
+ unsigned long timeout = 10000;
|
|
|
|
+
|
|
|
|
+ while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) {
|
|
|
|
+ if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
|
|
|
|
+ omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY |
|
|
|
|
+ OMAP_I2C_STAT_XDR));
|
|
|
|
+ *err |= OMAP_I2C_STAT_XUDF;
|
|
|
|
+ return -ETIMEDOUT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ cpu_relax();
|
|
|
|
+ *stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!timeout) {
|
|
|
|
+ dev_err(dev->dev, "timeout waiting on XUDF bit\n");
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static irqreturn_t
|
|
static irqreturn_t
|
|
omap_i2c_isr(int this_irq, void *dev_id)
|
|
omap_i2c_isr(int this_irq, void *dev_id)
|
|
{
|
|
{
|
|
@@ -733,6 +871,10 @@ complete:
|
|
}
|
|
}
|
|
if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
|
|
if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
|
|
u8 num_bytes = 1;
|
|
u8 num_bytes = 1;
|
|
|
|
+
|
|
|
|
+ if (dev->errata & I2C_OMAP_ERRATA_I207)
|
|
|
|
+ i2c_omap_errata_i207(dev, stat);
|
|
|
|
+
|
|
if (dev->fifo_size) {
|
|
if (dev->fifo_size) {
|
|
if (stat & OMAP_I2C_STAT_RRDY)
|
|
if (stat & OMAP_I2C_STAT_RRDY)
|
|
num_bytes = dev->fifo_size;
|
|
num_bytes = dev->fifo_size;
|
|
@@ -747,9 +889,12 @@ complete:
|
|
if (dev->buf_len) {
|
|
if (dev->buf_len) {
|
|
*dev->buf++ = w;
|
|
*dev->buf++ = w;
|
|
dev->buf_len--;
|
|
dev->buf_len--;
|
|
- /* Data reg from 2430 is 8 bit wide */
|
|
|
|
- if (!cpu_is_omap2430() &&
|
|
|
|
- !cpu_is_omap34xx()) {
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Data reg in 2430, omap3 and
|
|
|
|
+ * omap4 is 8 bit wide
|
|
|
|
+ */
|
|
|
|
+ if (cpu_class_is_omap1() ||
|
|
|
|
+ cpu_is_omap2420()) {
|
|
if (dev->buf_len) {
|
|
if (dev->buf_len) {
|
|
*dev->buf++ = w >> 8;
|
|
*dev->buf++ = w >> 8;
|
|
dev->buf_len--;
|
|
dev->buf_len--;
|
|
@@ -787,9 +932,12 @@ complete:
|
|
if (dev->buf_len) {
|
|
if (dev->buf_len) {
|
|
w = *dev->buf++;
|
|
w = *dev->buf++;
|
|
dev->buf_len--;
|
|
dev->buf_len--;
|
|
- /* Data reg from 2430 is 8 bit wide */
|
|
|
|
- if (!cpu_is_omap2430() &&
|
|
|
|
- !cpu_is_omap34xx()) {
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Data reg in 2430, omap3 and
|
|
|
|
+ * omap4 is 8 bit wide
|
|
|
|
+ */
|
|
|
|
+ if (cpu_class_is_omap1() ||
|
|
|
|
+ cpu_is_omap2420()) {
|
|
if (dev->buf_len) {
|
|
if (dev->buf_len) {
|
|
w |= *dev->buf++ << 8;
|
|
w |= *dev->buf++ << 8;
|
|
dev->buf_len--;
|
|
dev->buf_len--;
|
|
@@ -807,25 +955,9 @@ complete:
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
- /*
|
|
|
|
- * OMAP3430 Errata 1.153: When an XRDY/XDR
|
|
|
|
- * is hit, wait for XUDF before writing data
|
|
|
|
- * to DATA_REG. Otherwise some data bytes can
|
|
|
|
- * be lost while transferring them from the
|
|
|
|
- * memory to the I2C interface.
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
- if (dev->rev <= OMAP_I2C_REV_ON_3430) {
|
|
|
|
- while (!(stat & OMAP_I2C_STAT_XUDF)) {
|
|
|
|
- if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
|
|
|
|
- omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
|
|
|
|
- err |= OMAP_I2C_STAT_XUDF;
|
|
|
|
- goto complete;
|
|
|
|
- }
|
|
|
|
- cpu_relax();
|
|
|
|
- stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ if ((dev->errata & I2C_OMAP3_1P153) &&
|
|
|
|
+ errata_omap3_1p153(dev, &stat, &err))
|
|
|
|
+ goto complete;
|
|
|
|
|
|
omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
|
|
omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
|
|
}
|
|
}
|
|
@@ -857,6 +989,7 @@ omap_i2c_probe(struct platform_device *pdev)
|
|
struct omap_i2c_dev *dev;
|
|
struct omap_i2c_dev *dev;
|
|
struct i2c_adapter *adap;
|
|
struct i2c_adapter *adap;
|
|
struct resource *mem, *irq, *ioarea;
|
|
struct resource *mem, *irq, *ioarea;
|
|
|
|
+ struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;
|
|
irq_handler_t isr;
|
|
irq_handler_t isr;
|
|
int r;
|
|
int r;
|
|
u32 speed = 0;
|
|
u32 speed = 0;
|
|
@@ -886,10 +1019,13 @@ omap_i2c_probe(struct platform_device *pdev)
|
|
goto err_release_region;
|
|
goto err_release_region;
|
|
}
|
|
}
|
|
|
|
|
|
- if (pdev->dev.platform_data != NULL)
|
|
|
|
- speed = *(u32 *)pdev->dev.platform_data;
|
|
|
|
- else
|
|
|
|
- speed = 100; /* Defualt speed */
|
|
|
|
|
|
+ if (pdata != NULL) {
|
|
|
|
+ speed = pdata->clkrate;
|
|
|
|
+ dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
|
|
|
|
+ } else {
|
|
|
|
+ speed = 100; /* Default speed */
|
|
|
|
+ dev->set_mpu_wkup_lat = NULL;
|
|
|
|
+ }
|
|
|
|
|
|
dev->speed = speed;
|
|
dev->speed = speed;
|
|
dev->idle = 1;
|
|
dev->idle = 1;
|
|
@@ -905,17 +1041,27 @@ omap_i2c_probe(struct platform_device *pdev)
|
|
|
|
|
|
if (cpu_is_omap7xx())
|
|
if (cpu_is_omap7xx())
|
|
dev->reg_shift = 1;
|
|
dev->reg_shift = 1;
|
|
|
|
+ else if (cpu_is_omap44xx())
|
|
|
|
+ dev->reg_shift = 0;
|
|
else
|
|
else
|
|
dev->reg_shift = 2;
|
|
dev->reg_shift = 2;
|
|
|
|
|
|
if ((r = omap_i2c_get_clocks(dev)) != 0)
|
|
if ((r = omap_i2c_get_clocks(dev)) != 0)
|
|
goto err_iounmap;
|
|
goto err_iounmap;
|
|
|
|
|
|
|
|
+ if (cpu_is_omap44xx())
|
|
|
|
+ dev->regs = (u8 *) omap4_reg_map;
|
|
|
|
+ else
|
|
|
|
+ dev->regs = (u8 *) reg_map;
|
|
|
|
+
|
|
omap_i2c_unidle(dev);
|
|
omap_i2c_unidle(dev);
|
|
|
|
|
|
dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
|
|
dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
|
|
|
|
|
|
- if (cpu_is_omap2430() || cpu_is_omap34xx()) {
|
|
|
|
|
|
+ if (dev->rev <= OMAP_I2C_REV_ON_3430)
|
|
|
|
+ dev->errata |= I2C_OMAP3_1P153;
|
|
|
|
+
|
|
|
|
+ if (!(cpu_class_is_omap1() || cpu_is_omap2420())) {
|
|
u16 s;
|
|
u16 s;
|
|
|
|
|
|
/* Set up the fifo size - Get total size */
|
|
/* Set up the fifo size - Get total size */
|
|
@@ -927,8 +1073,17 @@ omap_i2c_probe(struct platform_device *pdev)
|
|
* size. This is to ensure that we can handle the status on int
|
|
* size. This is to ensure that we can handle the status on int
|
|
* call back latencies.
|
|
* call back latencies.
|
|
*/
|
|
*/
|
|
- dev->fifo_size = (dev->fifo_size / 2);
|
|
|
|
- dev->b_hw = 1; /* Enable hardware fixes */
|
|
|
|
|
|
+ if (dev->rev >= OMAP_I2C_REV_ON_4430) {
|
|
|
|
+ dev->fifo_size = 0;
|
|
|
|
+ dev->b_hw = 0; /* Disable hardware fixes */
|
|
|
|
+ } else {
|
|
|
|
+ dev->fifo_size = (dev->fifo_size / 2);
|
|
|
|
+ dev->b_hw = 1; /* Enable hardware fixes */
|
|
|
|
+ }
|
|
|
|
+ /* calculate wakeup latency constraint for MPU */
|
|
|
|
+ if (dev->set_mpu_wkup_lat != NULL)
|
|
|
|
+ dev->latency = (1000000 * dev->fifo_size) /
|
|
|
|
+ (1000 * speed / 8);
|
|
}
|
|
}
|
|
|
|
|
|
/* reset ASAP, clearing any IRQs */
|
|
/* reset ASAP, clearing any IRQs */
|