Skip to contentSkip to conversation

OMAP: I2C: reprogram OCP_SYSCONFIG after device reset

PATCH In review Paul Walmsley 3 participants 6 messages Oct 14, 2008 – Nov 21, 2008

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover OMAP: I2C: reprogram OCP_SYSCONFIG after device reset

Hello,

This patch set programs the I2C controller OCP_SYSCONFIG register after the driver resets the device. It is derived from the changes mentioned by Richard Woodruff <[email protected]> at

http://git.omapzoom.org/?p=omapkernel;a=blob;f=drivers/i2c/busses/i2c-omap.c;hb=d0b4bad4926f9a147a73498f7a62a0ae1cf6f83a

however, the CLOCKACTIVITY change on clk_enable()/clk_disable() in that code currently seems pointless, so it has been excluded until more information is available from TI or until problems are encountered.

This patchset should only change behavior on OMAP2x30 and OMAP3xxx devices.

Boot-tested on 2430SDP and 3430SDP; compile-tested with the 5912OSK (OMAP1) defconfig. Comments welcome,

- Paul

---

text data bss dec hex filename

3472584  160600  105760 3738944  390d40 vmlinux.3430sdp.orig
3472616  160600  105760 3738976  390d60 vmlinux.3430sdp
 drivers/i2c/busses/i2c-omap.c |   65 ++++++++++++++++++++++++++++++++---------
 1 files changed, 50 insertions(+), 15 deletions(-)
#1 lore raw

PATCH 1/2 OMAP: I2C: convert 'rev1' flag to generic 'rev' u8

i2c-omap discriminates only between "revision 1" or "greater than revision 1." A following patch introduces code that must also discriminate between rev2.x, rev3.6, and rev3.12 controllers. Support this by storing the full revision data from the I2C_REV register, rather than just a single bit.

The revision definitions may need to be extended for other ES levels that aren't currently available here. rev3.6 is what's present on the 2430SDP here (unknown ES revision); rev3.12 is used on the 3430ES2 here.

---
 drivers/i2c/busses/i2c-omap.c |   25 ++++++++++++++++---------
 1 files changed, 16 insertions(+), 9 deletions(-)
drivers/i2c/busses/i2c-omap.c +16 -9
index a999606..12bdb69 100644
@@ -38,6 +38,13 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
+/* I2C controller revisions */
+#define OMAP_I2C_REV_2			0x20
+
+/* I2C controller revisions present on specific hardware */
+#define OMAP_I2C_REV_ON_2430		0x36
+#define OMAP_I2C_REV_ON_3430		0x3C
+
 /* timeout waiting for the controller to respond */
 #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
 
@@ -139,7 +146,7 @@ struct omap_i2c_dev {
 						 * fifo_size==0 implies no fifo
 						 * if set, should be trsh+1
 						 */
-	unsigned		rev1:1;
+	u8			rev;
 	unsigned		b_hw:1;		/* bad h/w fixes */
 	unsigned		idle:1;
 	u16			iestate;	/* Saved interrupt register */
@@ -220,7 +227,7 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)
 
 	dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
 	omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
-	if (dev->rev1)
+	if (dev->rev < OMAP_I2C_REV_2)
 		iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
 	else
 		omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
@@ -244,7 +251,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
 	unsigned long timeout;
 	unsigned long internal_clk = 0;
 
-	if (!dev->rev1) {
+	if (dev->rev >= OMAP_I2C_REV_2) {
 		omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
 		/* For some reason we need to set the EN bit before the
 		 * reset done bit gets set. */
@@ -718,6 +725,7 @@ omap_i2c_probe(struct platform_device *pdev)
 	struct omap_i2c_dev	*dev;
 	struct i2c_adapter	*adap;
 	struct resource		*mem, *irq, *ioarea;
+	void *isr;
 	int r;
 	u32 *speed = NULL;
 
@@ -769,8 +777,7 @@ omap_i2c_probe(struct platform_device *pdev)
 
 	omap_i2c_unidle(dev);
 
-	if (cpu_is_omap15xx())
-		dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
+	dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
 
 	if (cpu_is_omap2430() || cpu_is_omap34xx()) {
 		u16 s;
@@ -791,16 +798,16 @@ omap_i2c_probe(struct platform_device *pdev)
 	/* reset ASAP, clearing any IRQs */
 	omap_i2c_init(dev);
 
-	r = request_irq(dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr,
-			0, pdev->name, dev);
+	isr = (dev->rev < OMAP_I2C_REV_2) ? omap_i2c_rev1_isr : omap_i2c_isr;
+	r = request_irq(dev->irq, isr, 0, pdev->name, dev);
 
 	if (r) {
 		dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
 		goto err_unuse_clocks;
 	}
-	r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+
 	dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
-		 pdev->id, r >> 4, r & 0xf, dev->speed);
+		 pdev->id, dev->rev >> 4, dev->rev & 0xf, dev->speed);
 
 	omap_i2c_idle(dev);
 
#2 lore raw

PATCH 2/2 OMAP2/3 I2C: reprogram OCP_SYSCONFIG register after reset

In reply to Paul Walmsley

The I2C controller clears its OCP_SYSCONFIG register after an OCP soft reset. Reprogram OCP_SYSCONFIG for maximum power savings on rev3.6 controllers and beyond. On 2430, this involves setting the module AUTOIDLE bit. On 3430, this includes module AUTOIDLE, wakeup enable, slave smart-idle, and considers only the module functional clock state for idle-ack.

Boot-tested on 2430SDP and 3430SDP.

Cc Richard Woodruff <[email protected]>
---
 drivers/i2c/busses/i2c-omap.c |   40 ++++++++++++++++++++++++++++++++++------
 1 files changed, 34 insertions(+), 6 deletions(-)
drivers/i2c/busses/i2c-omap.c +34 -6
index 12bdb69..d012ad7 100644
@@ -123,11 +123,19 @@
 #define OMAP_I2C_SYSTEST_SDA_O		(1 << 0)	/* SDA line drive out */
 #endif
 
-/* I2C System Status register (OMAP_I2C_SYSS): */
-#define OMAP_I2C_SYSS_RDONE		(1 << 0)	/* Reset Done */
+/* OCP_SYSSTATUS bit definitions */
+#define SYSS_RESETDONE_MASK		(1 << 0)
+
+/* OCP_SYSCONFIG bit definitions */
+#define SYSC_CLOCKACTIVITY_MASK		(0x3 << 8)
+#define SYSC_SIDLEMODE_MASK		(0x3 << 3)
+#define SYSC_ENAWAKEUP_MASK		(1 << 2)
+#define SYSC_SOFTRESET_MASK		(1 << 1)
+#define SYSC_AUTOIDLE_MASK		(1 << 0)
+
+#define SYSC_IDLEMODE_SMART		0x2
+#define SYSC_CLOCKACTIVITY_FCLK		0x2
 
-/* I2C System Configuration Register (OMAP_I2C_SYSC): */
-#define OMAP_I2C_SYSC_SRST		(1 << 1)	/* Soft Reset */
 
 struct omap_i2c_dev {
 	struct device		*dev;
@@ -252,13 +260,13 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
 	unsigned long internal_clk = 0;
 
 	if (dev->rev >= OMAP_I2C_REV_2) {
-		omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
+		omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK);
 		/* For some reason we need to set the EN bit before the
 		 * reset done bit gets set. */
 		timeout = jiffies + OMAP_I2C_TIMEOUT;
 		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
 		while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) &
-			 OMAP_I2C_SYSS_RDONE)) {
+			 SYSS_RESETDONE_MASK)) {
 			if (time_after(jiffies, timeout)) {
 				dev_warn(dev->dev, "timeout waiting "
 						"for controller reset\n");
@@ -266,6 +274,26 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
 			}
 			msleep(1);
 		}
+
+		/* SYSC register is cleared by the reset; rewrite it */
+		if (dev->rev == OMAP_I2C_REV_ON_2430) {
+
+			omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
+					   SYSC_AUTOIDLE_MASK);
+
+		} else if (dev->rev >= OMAP_I2C_REV_ON_3430) {
+			u32 v;
+
+			v = SYSC_AUTOIDLE_MASK;
+			v |= SYSC_ENAWAKEUP_MASK;
+			v |= (SYSC_IDLEMODE_SMART <<
+			      __ffs(SYSC_SIDLEMODE_MASK));
+			v |= (SYSC_CLOCKACTIVITY_FCLK <<
+			      __ffs(SYSC_CLOCKACTIVITY_MASK));
+
+			omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, v);
+
+		}
 	}
 	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
 
#3 lore raw

RE: [PATCH 2/2] OMAP2/3 I2C: reprogram OCP_SYSCONFIG register after reset

Quoted 3 lines

From: Paul Walmsley [mailto:[email protected]]
Sent: Tuesday, October 14, 2008 7:20 AM

From a quick glance that looks ok.

I'll restate old news posted here before:

For OMAP2 the smart-idle handshake for I2C did not make it to the module and was tied off at prcm level. This required a hack to ensure data was not lost if effective power management was in use. McBSP also had this issue.

On OMAP3 it is all hooked up as expected so modifying handshakes does what is expected.

The OMAP2 errata did mention this.

Regards,
Richard W.

#4 lore raw
In reply to Paul Walmsley
Quoted 3 lines

however, the CLOCKACTIVITY change on clk_enable()/clk_disable() in that code currently seems pointless, so it has been excluded until more information is available from TI or until problems are encountered.

IIRC CLOCKACTIVITY settings mainly had to do with if I2C was master or slave. Part of TI patch set allows slave mode. Seems like some GPS chip needed to be master or something along those lines. One of the TI-ASP groups needed it.

Guidance was you should treat internal clocks differently at ocp-segment-idle-request time if you were the one generating the clock or it was coming in from the outside world. It was reported not doing this correctly would result in possible data being lost.

McBSP and audio have a similar relationship when you do master/slave and your sample clock comes from the outside.

------------
GPTIMER CLOCKACTIVTY is more easily understood. At ocp-segment-idle-request for the system heart beat you want to keep that FCLK running so you set it so. There could be a case with other timers that you just let them be shut down.

Regards,
Richard W.

maintainer
#5 lore raw
In reply to Paul Walmsley
Quoted 8 lines · Paul Walmsley

Hello,

This patch set programs the I2C controller OCP_SYSCONFIG register after the driver resets the device. It is derived from the changes mentioned by Richard Woodruff <[email protected]> at

http://git.omapzoom.org/?p=omapkernel;a=blob;f=drivers/i2c/busses/i2c-omap.c;hb=d0b4bad4926f9a147a73498f7a62a0ae1cf6f83a

Quoted 8 lines

however, the CLOCKACTIVITY change on clk_enable()/clk_disable() in that code currently seems pointless, so it has been excluded until more information is available from TI or until problems are encountered.

This patchset should only change behavior on OMAP2x30 and OMAP3xxx devices.

Boot-tested on 2430SDP and 3430SDP; compile-tested with the 5912OSK (OMAP1) defconfig. Comments welcome,

Pushing both to l-o today, also adding to upstream i2c-omap queue.

Tony

Quoted 17 lines

- Paul

---

text data bss dec hex filename

3472584  160600  105760 3738944  390d40 vmlinux.3430sdp.orig
3472616  160600  105760 3738976  390d60 vmlinux.3430sdp
 drivers/i2c/busses/i2c-omap.c |   65 ++++++++++++++++++++++++++++++++---------
 1 files changed, 50 insertions(+), 15 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html