Skip to contentSkip to conversation

i2c-omap patches for 2.6.35 merge window

PATCH Applied Tony Lindgren 3 participants 9 messages May 11, 2010 1 message not in the archive

Subsystems (6)
lore
Share & tools
lore

Tony Lindgren

author maintainer
#0 lore raw

cover i2c-omap patches for 2.6.35 merge window

Hi all,

Here are the i2c-omap patches that we'd like to get in for 2.6.35.

I believe all of these patches have been posted earlier already to the i2c list. They all have been merged into the linux-omap master branch for testing.

I've removed some duplicate Cc fields from the commit messages for the obvious mailings lists and the people who will be merging them.

Anyways, if no comments over the next few days, I'll reply to this message with a pull request for Ben.

Regards,

Tony

---

Alexander Shishkin (2):
omap: i2c: make errata 1.153 workaround a separate function
omap: i2c: add a timeout to the busy waiting

Kalle Jokiniemi (1):
i2c-omap: add mpu wake up latency constraint in i2c

Santosh Shilimkar (1):
omap: i2c: Add i2c support on omap4 platform

manjugk manjugk (2):
OMAP2/3: I2C: Errata ID i207: Clear wrong RDR interrupt
OMAP3: I2C: Clean up Errata 1p153 handling

 arch/arm/plat-omap/i2c.c      |   39 ++++--
 drivers/i2c/busses/i2c-omap.c |  265 ++++++++++++++++++++++++++++++++---------
 include/linux/i2c-omap.h      |    9 +
 3 files changed, 246 insertions(+), 67 deletions(-)
 create mode 100644 include/linux/i2c-omap.h
Signature · 1 line
Signature

A message that is not in the archive (sent off-list or not yet received): 20100511182854.15596.56293.stgit-XB442sTQ5VIxQTnqJstS8Q@public.gmane.org

#2 lore raw

PATCH 1/6 omap: i2c: Add i2c support on omap4 platform

From: Santosh Shilimkar <[email protected]>

This patch is rebased version of earlier post to add I2C driver support to OMAP4 platform. On OMAP4, all I2C register address offsets are changed from OMAP1/2/3 I2C. In order to not have #ifdef's at various places in code, as well as to support multi-OMAP build, an array is created to hold the register addresses with it's offset.

This patch was submitted, reviewed and acked on mailing list already. For more details refer below link
http://www.mail-archive.com/[email protected]/msg02281.html

This updated verion has a depedancy on "Add support for 16-bit registers" posted on linux-omap. Below is the patch-works link for the same

http://patchwork.kernel.org/patch/72295/

---
 drivers/i2c/busses/i2c-omap.c |  146 ++++++++++++++++++++++++++++++++---------
 1 files changed, 114 insertions(+), 32 deletions(-)
drivers/i2c/busses/i2c-omap.c +114 -32
index 389ac60..46111ff 100644
@@ -45,29 +45,37 @@
 /* I2C controller revisions present on specific hardware */
 #define OMAP_I2C_REV_ON_2430		0x36
 #define OMAP_I2C_REV_ON_3430		0x3C
+#define OMAP_I2C_REV_ON_4430		0x40
 
 /* timeout waiting for the controller to respond */
 #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) */
-#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): */
 #define OMAP_I2C_IE_XDR		(1 << 14)	/* TX Buffer drain int enable */
@@ -170,6 +178,7 @@ struct omap_i2c_dev {
 	u32			speed;		/* Speed of bus in Khz */
 	u16			cmd_err;
 	u8			*buf;
+	u8			*regs;
 	size_t			buf_len;
 	struct i2c_adapter	adapter;
 	u8			fifo_size;	/* use as flag and value
@@ -188,15 +197,64 @@ struct omap_i2c_dev {
 	u16			westate;
 };
 
+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,
 				      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)
 {
-	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)
@@ -265,7 +323,11 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)
 	WARN_ON(dev->idle);
 
 	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) {
 		iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
 	} else {
@@ -330,7 +392,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
 			 * REVISIT: Some wkup sources might not be needed.
 			 */
 			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);
@@ -357,7 +421,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
 			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
@@ -747,9 +811,12 @@ complete:
 				if (dev->buf_len) {
 					*dev->buf++ = w;
 					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) {
 							*dev->buf++ = w >> 8;
 							dev->buf_len--;
@@ -787,9 +854,12 @@ complete:
 				if (dev->buf_len) {
 					w = *dev->buf++;
 					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) {
 							w |= *dev->buf++ << 8;
 							dev->buf_len--;
@@ -905,17 +975,24 @@ omap_i2c_probe(struct platform_device *pdev)
 
 	if (cpu_is_omap7xx())
 		dev->reg_shift = 1;
+	else if (cpu_is_omap44xx())
+		dev->reg_shift = 0;
 	else
 		dev->reg_shift = 2;
 
 	if ((r = omap_i2c_get_clocks(dev)) != 0)
 		goto err_iounmap;
 
+	if (cpu_is_omap44xx())
+		dev->regs = (u8 *) omap4_reg_map;
+	else
+		dev->regs = (u8 *) reg_map;
+
 	omap_i2c_unidle(dev);
 
 	dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
 
-	if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+	if (!(cpu_class_is_omap1() || cpu_is_omap2420())) {
 		u16 s;
 
 		/* Set up the fifo size - Get total size */
@@ -927,8 +1004,13 @@ omap_i2c_probe(struct platform_device *pdev)
 		 * size. This is to ensure that we can handle the status on int
 		 * 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 */
+		}
 	}
 
 	/* reset ASAP, clearing any IRQs */
#3 lore raw

PATCH 2/6 i2c-omap: add mpu wake up latency constraint in i2c

In reply to a message not in the archive

From: Kalle Jokiniemi <[email protected]>

While waiting for completion of the i2c transfer, the MPU could hit OFF mode and cause several msecs of delay that made i2c transfers fail more often. The extra delays and subsequent re-trys cause i2c clocks to be active more often. This has also an negative effect on power consumption.

Created a mechanism for passing and using the constraint setting function in driver code. The used mpu wake up latency constraints are now set individually per bus, and they are calculated based on clock rate and fifo size.

Thanks to Jarkko Nikula, Moiz Sonasath, Paul Walmsley, and Nishanth Menon for tuning out the details of this patch.

Updates by Kevin as requested by Tony:

- Remove omap_set_i2c_constraint_func() in favor of conditionally adding the flag in omap_i2c_add_bus() in order to keep all the OMAP conditional checking in a single location.
- Update set_mpu_wkup_lat prototypes to match OMAP PM layer so OMAP PM function can be used directly in pdata.

Cc Moiz Sonasath <[email protected]>
Cc Jarkko Nikula <[email protected]>
Cc Paul Walmsley <[email protected]>
Cc Nishanth Menon <[email protected]>
---
 arch/arm/plat-omap/i2c.c      |   39 +++++++++++++++++++++++++++------------
 drivers/i2c/busses/i2c-omap.c |   24 ++++++++++++++++++++----
 include/linux/i2c-omap.h      |    9 +++++++++
 3 files changed, 56 insertions(+), 16 deletions(-)
 create mode 100644 include/linux/i2c-omap.h
arch/arm/plat-omap/i2c.c +27 -12
index 624e262..f044b59 100644
@@ -26,9 +26,12 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
+#include <linux/i2c-omap.h>
+
 #include <mach/irqs.h>
 #include <plat/mux.h>
 #include <plat/i2c.h>
+#include <plat/omap-pm.h>
 
 #define OMAP_I2C_SIZE		0x3f
 #define OMAP1_I2C_BASE		0xfffb3800
@@ -70,14 +73,14 @@ static struct resource i2c_resources[][2] = {
 		},					\
 	}
 
-static u32 i2c_rate[ARRAY_SIZE(i2c_resources)];
+static struct omap_i2c_bus_platform_data i2c_pdata[ARRAY_SIZE(i2c_resources)];
 static struct platform_device omap_i2c_devices[] = {
-	I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_rate[0]),
+	I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_pdata[0]),
 #if	defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-	I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_rate[1]),
+	I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_pdata[1]),
 #endif
 #if	defined(CONFIG_ARCH_OMAP3)
-	I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_rate[2]),
+	I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_pdata[2]),
 #endif
 };
 
@@ -100,10 +103,12 @@ static int __init omap_i2c_nr_ports(void)
 static int __init omap_i2c_add_bus(int bus_id)
 {
 	struct platform_device *pdev;
+	struct omap_i2c_bus_platform_data *pd;
 	struct resource *res;
 	resource_size_t base, irq;
 
 	pdev = &omap_i2c_devices[bus_id - 1];
+	pd = pdev->dev.platform_data;
 	if (bus_id == 1) {
 		res = pdev->resource;
 		if (cpu_class_is_omap1()) {
@@ -123,6 +128,15 @@ static int __init omap_i2c_add_bus(int bus_id)
 	if (cpu_class_is_omap2())
 		omap2_i2c_mux_pins(bus_id);
 
+	/*
+	 * When waiting for completion of a i2c transfer, we need to
+	 * set a wake up latency constraint for the MPU. This is to
+	 * ensure quick enough wakeup from idle, when transfer
+	 * completes.
+	 */
+	if (cpu_is_omap34xx())
+		pd->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat;
+
 	return platform_device_register(pdev);
 }
 
@@ -146,8 +160,8 @@ static int __init omap_i2c_bus_setup(char *str)
 	get_options(str, 3, ints);
 	if (ints[0] < 2 || ints[1] < 1 || ints[1] > ports)
 		return 0;
-	i2c_rate[ints[1] - 1] = ints[2];
-	i2c_rate[ints[1] - 1] |= OMAP_I2C_CMDLINE_SETUP;
+	i2c_pdata[ints[1] - 1].clkrate = ints[2];
+	i2c_pdata[ints[1] - 1].clkrate |= OMAP_I2C_CMDLINE_SETUP;
 
 	return 1;
 }
@@ -161,9 +175,9 @@ static int __init omap_register_i2c_bus_cmdline(void)
 {
 	int i, err = 0;
 
-	for (i = 0; i < ARRAY_SIZE(i2c_rate); i++)
-		if (i2c_rate[i] & OMAP_I2C_CMDLINE_SETUP) {
-			i2c_rate[i] &= ~OMAP_I2C_CMDLINE_SETUP;
+	for (i = 0; i < ARRAY_SIZE(i2c_pdata); i++)
+		if (i2c_pdata[i].clkrate & OMAP_I2C_CMDLINE_SETUP) {
+			i2c_pdata[i].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
 			err = omap_i2c_add_bus(i + 1);
 			if (err)
 				goto out;
@@ -197,9 +211,10 @@ int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
 			return err;
 	}
 
-	if (!i2c_rate[bus_id - 1])
-		i2c_rate[bus_id - 1] = clkrate;
-	i2c_rate[bus_id - 1] &= ~OMAP_I2C_CMDLINE_SETUP;
+	if (!i2c_pdata[bus_id - 1].clkrate)
+		i2c_pdata[bus_id - 1].clkrate = clkrate;
+
+	i2c_pdata[bus_id - 1].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
 
 	return omap_i2c_add_bus(bus_id);
 }
drivers/i2c/busses/i2c-omap.c +20 -4
index 46111ff..42c0b91 100644
@@ -38,6 +38,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/i2c-omap.h>
 
 /* I2C controller revisions */
 #define OMAP_I2C_REV_2			0x20
@@ -175,6 +176,9 @@ struct omap_i2c_dev {
 	struct clk		*fclk;		/* Functional clock */
 	struct completion	cmd_complete;
 	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 */
 	u16			cmd_err;
 	u8			*buf;
@@ -603,8 +607,12 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
 	 * REVISIT: We should abort the transfer on signals, but the bus goes
 	 * 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,
 					OMAP_I2C_TIMEOUT);
+	if (dev->set_mpu_wkup_lat != NULL)
+		dev->set_mpu_wkup_lat(dev->dev, -1);
 	dev->buf_len = 0;
 	if (r < 0)
 		return r;
@@ -927,6 +935,7 @@ omap_i2c_probe(struct platform_device *pdev)
 	struct omap_i2c_dev	*dev;
 	struct i2c_adapter	*adap;
 	struct resource		*mem, *irq, *ioarea;
+	struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;
 	irq_handler_t isr;
 	int r;
 	u32 speed = 0;
@@ -956,10 +965,13 @@ omap_i2c_probe(struct platform_device *pdev)
 		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->idle = 1;
@@ -1011,6 +1023,10 @@ omap_i2c_probe(struct platform_device *pdev)
 			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 */
include/linux/i2c-omap.h new file +9 -0
new file mode 100644
index 0000000..78ebf50
@@ -0,0 +1,9 @@
+#ifndef __I2C_OMAP_H__
+#define __I2C_OMAP_H__
+
+struct omap_i2c_bus_platform_data {
+	u32		clkrate;
+	void		(*set_mpu_wkup_lat)(struct device *dev, long set);
+};
+
+#endif
#4 lore raw

PATCH 3/6 omap: i2c: make errata 1.153 workaround a separate function

In reply to a message not in the archive

From: Alexander Shishkin <[email protected]>

This is to avoid insanely long lines and levels of indentation.

---
 drivers/i2c/busses/i2c-omap.c |   43 +++++++++++++++++++++++------------------
 1 files changed, 24 insertions(+), 19 deletions(-)
drivers/i2c/busses/i2c-omap.c +24 -19
index 42c0b91..ef73483 100644
@@ -756,6 +756,27 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
 #define omap_i2c_rev1_isr		NULL
 #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)
+{
+	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;
+			return -ETIMEDOUT;
+		}
+		cpu_relax();
+		*stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+	}
+
+	return 0;
+}
+
 static irqreturn_t
 omap_i2c_isr(int this_irq, void *dev_id)
 {
@@ -885,25 +906,9 @@ complete:
 					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->rev <= OMAP_I2C_REV_ON_3430) &&
+				    errata_omap3_1p153(dev, &stat, &err))
+					goto complete;
 
 				omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
 			}
#5 lore raw

PATCH 4/6 omap: i2c: add a timeout to the busy waiting

In reply to a message not in the archive

From: Alexander Shishkin <[email protected]>

The errata 1.153 workaround is busy waiting on XUDF bit in interrupt context, which may lead to kernel hangs. The problem can be reproduced by running the bus with wrong (too high) speed.

---
 drivers/i2c/busses/i2c-omap.c |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)
drivers/i2c/busses/i2c-omap.c +9 -1
index ef73483..00fd02e 100644
@@ -763,17 +763,25 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
  */
 static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
 {
-	while (!(*stat & OMAP_I2C_STAT_XUDF)) {
+	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;
 }
 
#6 lore raw

PATCH 5/6 OMAP2/3: I2C: Errata ID i207: Clear wrong RDR interrupt

In reply to a message not in the archive

From: manjugk manjugk <[email protected]>

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).

Cc Hema Kalliguddi <[email protected]>
Cc Nishanth Menon <[email protected]>
Cc Aaro Koskinen <[email protected]>
---
 drivers/i2c/busses/i2c-omap.c |   40 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 40 insertions(+), 0 deletions(-)
drivers/i2c/busses/i2c-omap.c +40 -0
index 00fd02e..fdba131 100644
@@ -166,6 +166,8 @@ enum {
 #define SYSC_IDLEMODE_SMART		0x2
 #define SYSC_CLOCKACTIVITY_FCLK		0x2
 
+/* Errata definitions */
+#define I2C_OMAP_ERRATA_I207		(1 << 0)
 
 struct omap_i2c_dev {
 	struct device		*dev;
@@ -199,6 +201,7 @@ struct omap_i2c_dev {
 	u16			bufstate;
 	u16			syscstate;
 	u16			westate;
+	u16			errata;
 };
 
 const static u8 reg_map[] = {
@@ -498,6 +501,11 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
 	/* Take the I2C module out of reset: */
 	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 */
 	dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
 			OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
@@ -695,6 +703,34 @@ omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 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 */
 #ifdef CONFIG_ARCH_OMAP15XX
 
@@ -834,6 +870,10 @@ complete:
 		}
 		if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
 			u8 num_bytes = 1;
+
+			if (dev->errata & I2C_OMAP_ERRATA_I207)
+				i2c_omap_errata_i207(dev, stat);
+
 			if (dev->fifo_size) {
 				if (stat & OMAP_I2C_STAT_RRDY)
 					num_bytes = dev->fifo_size;
Applied
#7 lore raw
In reply to a message not in the archive
Quoted 8 lines · Tony Lindgren

Hi all,

Here are the i2c-omap patches that we'd like to get in for 2.6.35.

I believe all of these patches have been posted earlier already to the i2c list. They all have been merged into the linux-omap master branch for testing.

Quoted 6 lines

I've removed some duplicate Cc fields from the commit messages for the obvious mailings lists and the people who will be merging them.

Anyways, if no comments over the next few days, I'll reply to this message with a pull request for Ben.

I've applied these to for-2635/i2c-omap to get them into -next

please keep the start of each commit the same, I prefer i2c-omap:

thanks.

Quoted 33 lines

Regards,

Tony

---

Alexander Shishkin (2):
omap: i2c: make errata 1.153 workaround a separate function
omap: i2c: add a timeout to the busy waiting

Kalle Jokiniemi (1):
i2c-omap: add mpu wake up latency constraint in i2c

Santosh Shilimkar (1):
omap: i2c: Add i2c support on omap4 platform

manjugk manjugk (2):
OMAP2/3: I2C: Errata ID i207: Clear wrong RDR interrupt
OMAP3: I2C: Clean up Errata 1p153 handling

 arch/arm/plat-omap/i2c.c      |   39 ++++--
 drivers/i2c/busses/i2c-omap.c |  265 ++++++++++++++++++++++++++++++++---------
 include/linux/i2c-omap.h      |    9 +
 3 files changed, 246 insertions(+), 67 deletions(-)
 create mode 100644 include/linux/i2c-omap.h
Signature · 5 lines
Signature
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
author maintainer
#8 lore raw
Quoted 9 lines · Ben Dooks
Quoted 8 lines · Tony Lindgren

Hi all,

Here are the i2c-omap patches that we'd like to get in for 2.6.35.

I believe all of these patches have been posted earlier already to the i2c list. They all have been merged into the linux-omap master branch for testing.

Quoted 8 lines
Quoted 6 lines

I've removed some duplicate Cc fields from the commit messages for the obvious mailings lists and the people who will be merging them.

Anyways, if no comments over the next few days, I'll reply to this message with a pull request for Ben.

I've applied these to for-2635/i2c-omap to get them into -next

OK, thanks!

Quoted 1 line

please keep the start of each commit the same, I prefer i2c-omap:

OK

Regards,

Tony

author maintainer
#9 lore raw

PATCH 6/6 OMAP3: I2C: Clean up Errata 1p153 handling

In reply to Tony Lindgren

From: manjugk manjugk <[email protected]>

Clean up existing Errata 1p153 handling to use generic errata handling mechanism through dev flag.

Cc Nishanth Menon <[email protected]>
Cc Alexander Shishkin <[email protected]>
---
 drivers/i2c/busses/i2c-omap.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)
drivers/i2c/busses/i2c-omap.c +5 -1
index fdba131..7674efb 100644
@@ -168,6 +168,7 @@ enum {
 
 /* Errata definitions */
 #define I2C_OMAP_ERRATA_I207		(1 << 0)
+#define I2C_OMAP3_1P153			(1 << 1)
 
 struct omap_i2c_dev {
 	struct device		*dev;
@@ -954,7 +955,7 @@ complete:
 					break;
 				}
 
-				if ((dev->rev <= OMAP_I2C_REV_ON_3430) &&
+				if ((dev->errata & I2C_OMAP3_1P153) &&
 				    errata_omap3_1p153(dev, &stat, &err))
 					goto complete;
 
@@ -1057,6 +1058,9 @@ omap_i2c_probe(struct platform_device *pdev)
 
 	dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
 
+	if (dev->rev <= OMAP_I2C_REV_ON_3430)
+		dev->errata |= I2C_OMAP3_1P153;
+
 	if (!(cpu_class_is_omap1() || cpu_is_omap2420())) {
 		u16 s;