[FE training-materials-updates] sysdev-u-boot: switch to a better patch provided by upstream

Thomas Petazzoni thomas.petazzoni at free-electrons.com
Mon Dec 2 13:54:14 CET 2013


Repository : git://git.free-electrons.com/training-materials.git

On branch  : master
Link       : http://git.free-electrons.com/training-materials/commit/?id=d65519542f9bc50185f766355b715b6dc17874ed

>---------------------------------------------------------------

commit d65519542f9bc50185f766355b715b6dc17874ed
Author: Thomas Petazzoni <thomas.petazzoni at free-electrons.com>
Date:   Mon Dec 2 13:53:45 2013 +0100

    sysdev-u-boot: switch to a better patch provided by upstream
    
    Signed-off-by: Thomas Petazzoni <thomas.petazzoni at free-electrons.com>


>---------------------------------------------------------------

d65519542f9bc50185f766355b715b6dc17874ed
 ...OMAP-I2C-New-read-write-and-probe-functio.patch |  664 --------------------
 ...-arm-omap-i2c-don-t-zero-cnt-in-i2c_write.patch |   85 +++
 labs/sysdev-u-boot/sysdev-u-boot.tex               |    6 +-
 3 files changed, 88 insertions(+), 667 deletions(-)

diff --git a/lab-data/sysdev/bootloader/data/0001-Revert-ARM-OMAP-I2C-New-read-write-and-probe-functio.patch b/lab-data/sysdev/bootloader/data/0001-Revert-ARM-OMAP-I2C-New-read-write-and-probe-functio.patch
deleted file mode 100644
index 107ae78..0000000
--- a/lab-data/sysdev/bootloader/data/0001-Revert-ARM-OMAP-I2C-New-read-write-and-probe-functio.patch
+++ /dev/null
@@ -1,664 +0,0 @@
-From 9413ec0ce7afbc9eba7fe26ad8527d4231a65fbd Mon Sep 17 00:00:00 2001
-From: Thomas Petazzoni <thomas.petazzoni at free-electrons.com>
-Date: Wed, 27 Nov 2013 10:48:45 +0100
-Subject: [PATCH] Revert "ARM: OMAP: I2C: New read, write and probe functions"
-
-This reverts commit 960187ffa125b3938fec4b827bd9e8c04a204af8.
-
-Signed-off-by: Thomas Petazzoni <thomas.petazzoni at free-electrons.com>
----
- drivers/i2c/omap24xx_i2c.c | 490 ++++++++++++++++++---------------------------
- 1 file changed, 191 insertions(+), 299 deletions(-)
-
-diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
-index ef38d71..54e9b15 100644
---- a/drivers/i2c/omap24xx_i2c.c
-+++ b/drivers/i2c/omap24xx_i2c.c
-@@ -18,20 +18,6 @@
-  *
-  * Adapted for OMAP2420 I2C, r-woodruff2 at ti.com
-  *
-- * Copyright (c) 2013 Lubomir Popov <lpopov at mm-sol.com>, MM Solutions
-- * New i2c_read, i2c_write and i2c_probe functions, tested on OMAP4
-- * (4430/60/70), OMAP5 (5430) and AM335X (3359); should work on older
-- * OMAPs and derivatives as well. The only anticipated exception would
-- * be the OMAP2420, which shall require driver modification.
-- * - Rewritten i2c_read to operate correctly with all types of chips
-- *   (old function could not read consistent data from some I2C slaves).
-- * - Optimized i2c_write.
-- * - New i2c_probe, performs write access vs read. The old probe could
-- *   hang the system under certain conditions (e.g. unconfigured pads).
-- * - The read/write/probe functions try to identify unconfigured bus.
-- * - Status functions now read irqstatus_raw as per TRM guidelines
-- *   (except for OMAP243X and OMAP34XX).
-- * - Driver now supports up to I2C5 (OMAP5).
-  */
- 
- #include <common.h>
-@@ -45,11 +31,8 @@ DECLARE_GLOBAL_DATA_PTR;
- 
- #define I2C_TIMEOUT	1000
- 
--/* Absolutely safe for status update at 100 kHz I2C: */
--#define I2C_WAIT	200
--
- static int wait_for_bb(void);
--static u16 wait_for_event(void);
-+static u16 wait_for_pin(void);
- static void flush_fifo(void);
- 
- /*
-@@ -154,14 +137,10 @@ void i2c_init(int speed, int slaveadd)
- 	/* own address */
- 	writew(slaveadd, &i2c_base->oa);
- 	writew(I2C_CON_EN, &i2c_base->con);
--#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
--	/*
--	 * Have to enable interrupts for OMAP2/3, these IPs don't have
--	 * an 'irqstatus_raw' register and we shall have to poll 'stat'
--	 */
-+
-+	/* have to enable intrrupts or OMAP i2c module doesn't work */
- 	writew(I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
--	       I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie);
--#endif
-+		I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie);
- 	udelay(1000);
- 	flush_fifo();
- 	writew(0xFFFF, &i2c_base->stat);
-@@ -171,6 +150,88 @@ void i2c_init(int speed, int slaveadd)
- 		bus_initialized[current_bus] = 1;
- }
- 
-+static int i2c_read_byte(u8 devaddr, u16 regoffset, u8 alen, u8 *value)
-+{
-+	int i2c_error = 0;
-+	u16 status;
-+	int i = 2 - alen;
-+	u8 tmpbuf[2] = {(regoffset) >> 8, regoffset & 0xff};
-+	u16 w;
-+
-+	/* wait until bus not busy */
-+	if (wait_for_bb())
-+		return 1;
-+
-+	/* one byte only */
-+	writew(alen, &i2c_base->cnt);
-+	/* set slave address */
-+	writew(devaddr, &i2c_base->sa);
-+	/* no stop bit needed here */
-+	writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
-+	      I2C_CON_TRX, &i2c_base->con);
-+
-+	/* send register offset */
-+	while (1) {
-+		status = wait_for_pin();
-+		if (status == 0 || status & I2C_STAT_NACK) {
-+			i2c_error = 1;
-+			goto read_exit;
-+		}
-+		if (status & I2C_STAT_XRDY) {
-+			w = tmpbuf[i++];
-+#if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
-+	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
-+	defined(CONFIG_OMAP54XX))
-+			w |= tmpbuf[i++] << 8;
-+#endif
-+			writew(w, &i2c_base->data);
-+			writew(I2C_STAT_XRDY, &i2c_base->stat);
-+		}
-+		if (status & I2C_STAT_ARDY) {
-+			writew(I2C_STAT_ARDY, &i2c_base->stat);
-+			break;
-+		}
-+	}
-+
-+	/* set slave address */
-+	writew(devaddr, &i2c_base->sa);
-+	/* read one byte from slave */
-+	writew(1, &i2c_base->cnt);
-+	/* need stop bit here */
-+	writew(I2C_CON_EN | I2C_CON_MST |
-+		I2C_CON_STT | I2C_CON_STP,
-+		&i2c_base->con);
-+
-+	/* receive data */
-+	while (1) {
-+		status = wait_for_pin();
-+		if (status == 0 || status & I2C_STAT_NACK) {
-+			i2c_error = 1;
-+			goto read_exit;
-+		}
-+		if (status & I2C_STAT_RRDY) {
-+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
-+	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
-+	defined(CONFIG_OMAP54XX)
-+			*value = readb(&i2c_base->data);
-+#else
-+			*value = readw(&i2c_base->data);
-+#endif
-+			writew(I2C_STAT_RRDY, &i2c_base->stat);
-+		}
-+		if (status & I2C_STAT_ARDY) {
-+			writew(I2C_STAT_ARDY, &i2c_base->stat);
-+			break;
-+		}
-+	}
-+
-+read_exit:
-+	flush_fifo();
-+	writew(0xFFFF, &i2c_base->stat);
-+	writew(0, &i2c_base->cnt);
-+	return i2c_error;
-+}
-+
- static void flush_fifo(void)
- {	u16 stat;
- 
-@@ -180,7 +241,13 @@ static void flush_fifo(void)
- 	while (1) {
- 		stat = readw(&i2c_base->stat);
- 		if (stat == I2C_STAT_RRDY) {
-+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
-+	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
-+	defined(CONFIG_OMAP54XX)
- 			readb(&i2c_base->data);
-+#else
-+			readw(&i2c_base->data);
-+#endif
- 			writew(I2C_STAT_RRDY, &i2c_base->stat);
- 			udelay(1000);
- 		} else
-@@ -188,10 +255,6 @@ static void flush_fifo(void)
- 	}
- }
- 
--/*
-- * i2c_probe: Use write access. Allows to identify addresses that are
-- *            write-only (like the config register of dual-port EEPROMs)
-- */
- int i2c_probe(uchar chip)
- {
- 	u16 status;
-@@ -200,81 +263,61 @@ int i2c_probe(uchar chip)
- 	if (chip == readw(&i2c_base->oa))
- 		return res;
- 
--	/* Wait until bus is free */
-+	/* wait until bus not busy */
- 	if (wait_for_bb())
- 		return res;
- 
--	/* No data transfer, slave addr only */
--	writew(0, &i2c_base->cnt);
--	/* Set slave address */
-+	/* try to read one byte */
-+	writew(1, &i2c_base->cnt);
-+	/* set slave address */
- 	writew(chip, &i2c_base->sa);
--	/* Stop bit needed here */
--	writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
--	       I2C_CON_STP, &i2c_base->con);
--
--	status = wait_for_event();
--
--	if ((status & ~I2C_STAT_XRDY) == 0 || (status & I2C_STAT_AL)) {
--		/*
--		 * With current high-level command implementation, notifying
--		 * the user shall flood the console with 127 messages. If
--		 * silent exit is desired upon unconfigured bus, remove the
--		 * following 'if' section:
--		 */
--		if (status == I2C_STAT_XRDY)
--			printf("i2c_probe: pads on bus %d probably not configured (status=0x%x)\n",
--			       current_bus, status);
--
--		goto pr_exit;
--	}
-+	/* stop bit needed here */
-+	writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, &i2c_base->con);
- 
--	/* Check for ACK (!NAK) */
--	if (!(status & I2C_STAT_NACK)) {
--		res = 0;			/* Device found */
--		udelay(I2C_WAIT);		/* Required by AM335X in SPL */
--		/* Abort transfer (force idle state) */
--		writew(I2C_CON_MST | I2C_CON_TRX, &i2c_base->con); /* Reset */
--		udelay(1000);
--		writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_TRX |
--		       I2C_CON_STP, &i2c_base->con);		/* STP */
-+	while (1) {
-+		status = wait_for_pin();
-+		if (status == 0 || status & I2C_STAT_AL) {
-+			res = 1;
-+			goto probe_exit;
-+		}
-+		if (status & I2C_STAT_NACK) {
-+			res = 1;
-+			writew(0xff, &i2c_base->stat);
-+			writew (readw (&i2c_base->con) | I2C_CON_STP, &i2c_base->con);
-+
-+			if (wait_for_bb())
-+				res = 1;
-+
-+			break;
-+		}
-+		if (status & I2C_STAT_ARDY) {
-+			writew(I2C_STAT_ARDY, &i2c_base->stat);
-+			break;
-+		}
-+		if (status & I2C_STAT_RRDY) {
-+			res = 0;
-+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
-+	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
-+	defined(CONFIG_OMAP54XX)
-+			readb(&i2c_base->data);
-+#else
-+			readw(&i2c_base->data);
-+#endif
-+			writew(I2C_STAT_RRDY, &i2c_base->stat);
-+		}
- 	}
--pr_exit:
-+
-+probe_exit:
- 	flush_fifo();
--	writew(0xFFFF, &i2c_base->stat);
-+	/* don't allow any more data in... we don't want it. */
- 	writew(0, &i2c_base->cnt);
-+	writew(0xFFFF, &i2c_base->stat);
- 	return res;
- }
- 
--/*
-- * i2c_read: Function now uses a single I2C read transaction with bulk transfer
-- *           of the requested number of bytes (note that the 'i2c md' command
-- *           limits this to 16 bytes anyway). If CONFIG_I2C_REPEATED_START is
-- *           defined in the board config header, this transaction shall be with
-- *           Repeated Start (Sr) between the address and data phases; otherwise
-- *           Stop-Start (P-S) shall be used (some I2C chips do require a P-S).
-- *           The address (reg offset) may be 0, 1 or 2 bytes long.
-- *           Function now reads correctly from chips that return more than one
-- *           byte of data per addressed register (like TI temperature sensors),
-- *           or that do not need a register address at all (such as some clock
-- *           distributors).
-- */
- int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
- {
--	int i2c_error = 0;
--	u16 status;
--
--	if (alen < 0) {
--		puts("I2C read: addr len < 0\n");
--		return 1;
--	}
--	if (len < 0) {
--		puts("I2C read: data len < 0\n");
--		return 1;
--	}
--	if (buffer == NULL) {
--		puts("I2C read: NULL pointer passed\n");
--		return 1;
--	}
-+	int i;
- 
- 	if (alen > 2) {
- 		printf("I2C read: addr len %d not supported\n", alen);
-@@ -286,122 +329,24 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
- 		return 1;
- 	}
- 
--	/* Wait until bus not busy */
--	if (wait_for_bb())
--		return 1;
--
--	/* Zero, one or two bytes reg address (offset) */
--	writew(alen, &i2c_base->cnt);
--	/* Set slave address */
--	writew(chip, &i2c_base->sa);
--
--	if (alen) {
--		/* Must write reg offset first */
--#ifdef CONFIG_I2C_REPEATED_START
--		/* No stop bit, use Repeated Start (Sr) */
--		writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
--		       I2C_CON_TRX, &i2c_base->con);
--#else
--		/* Stop - Start (P-S) */
--		writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP |
--		       I2C_CON_TRX, &i2c_base->con);
--#endif
--		/* Send register offset */
--		while (1) {
--			status = wait_for_event();
--			/* Try to identify bus that is not padconf'd for I2C */
--			if (status == I2C_STAT_XRDY) {
--				i2c_error = 2;
--				printf("i2c_read (addr phase): pads on bus %d probably not configured (status=0x%x)\n",
--				       current_bus, status);
--				goto rd_exit;
--			}
--			if (status == 0 || status & I2C_STAT_NACK) {
--				i2c_error = 1;
--				printf("i2c_read: error waiting for addr ACK (status=0x%x)\n",
--				       status);
--				goto rd_exit;
--			}
--			if (alen) {
--				if (status & I2C_STAT_XRDY) {
--					alen--;
--					/* Do we have to use byte access? */
--					writeb((addr >> (8 * alen)) & 0xff,
--					       &i2c_base->data);
--					writew(I2C_STAT_XRDY, &i2c_base->stat);
--				}
--			}
--			if (status & I2C_STAT_ARDY) {
--				writew(I2C_STAT_ARDY, &i2c_base->stat);
--				break;
--			}
--		}
--	}
--	/* Set slave address */
--	writew(chip, &i2c_base->sa);
--	/* Read len bytes from slave */
--	writew(len, &i2c_base->cnt);
--	/* Need stop bit here */
--	writew(I2C_CON_EN | I2C_CON_MST |
--	       I2C_CON_STT | I2C_CON_STP,
--	       &i2c_base->con);
--
--	/* Receive data */
--	while (1) {
--		status = wait_for_event();
--		/*
--		 * Try to identify bus that is not padconf'd for I2C. This
--		 * state could be left over from previous transactions if
--		 * the address phase is skipped due to alen=0.
--		 */
--		if (status == I2C_STAT_XRDY) {
--			i2c_error = 2;
--			printf("i2c_read (data phase): pads on bus %d probably not configured (status=0x%x)\n",
--			       current_bus, status);
--			goto rd_exit;
--		}
--		if (status == 0 || status & I2C_STAT_NACK) {
--			i2c_error = 1;
--			goto rd_exit;
--		}
--		if (status & I2C_STAT_RRDY) {
--			*buffer++ = readb(&i2c_base->data);
--			writew(I2C_STAT_RRDY, &i2c_base->stat);
--		}
--		if (status & I2C_STAT_ARDY) {
--			writew(I2C_STAT_ARDY, &i2c_base->stat);
--			break;
-+	for (i = 0; i < len; i++) {
-+		if (i2c_read_byte(chip, addr + i, alen, &buffer[i])) {
-+			puts("I2C read: I/O error\n");
-+			i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
-+			return 1;
- 		}
- 	}
- 
--rd_exit:
--	flush_fifo();
--	writew(0xFFFF, &i2c_base->stat);
--	writew(0, &i2c_base->cnt);
--	return i2c_error;
-+	return 0;
- }
- 
--/* i2c_write: Address (reg offset) may be 0, 1 or 2 bytes long. */
- int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
- {
- 	int i;
- 	u16 status;
- 	int i2c_error = 0;
--
--	if (alen < 0) {
--		puts("I2C write: addr len < 0\n");
--		return 1;
--	}
--
--	if (len < 0) {
--		puts("I2C write: data len < 0\n");
--		return 1;
--	}
--
--	if (buffer == NULL) {
--		puts("I2C write: NULL pointer passed\n");
--		return 1;
--	}
-+	u16 w;
-+	u8 tmpbuf[2] = {addr >> 8, addr & 0xff};
- 
- 	if (alen > 2) {
- 		printf("I2C write: addr len %d not supported\n", alen);
-@@ -410,137 +355,92 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
- 
- 	if (addr + len > (1 << 16)) {
- 		printf("I2C write: address 0x%x + 0x%x out of range\n",
--		       addr, len);
-+				addr, len);
- 		return 1;
- 	}
- 
--	/* Wait until bus not busy */
-+	/* wait until bus not busy */
- 	if (wait_for_bb())
- 		return 1;
- 
--	/* Start address phase - will write regoffset + len bytes data */
-+	/* start address phase - will write regoffset + len bytes data */
-+	/* TODO consider case when !CONFIG_OMAP243X/34XX/44XX */
- 	writew(alen + len, &i2c_base->cnt);
--	/* Set slave address */
-+	/* set slave address */
- 	writew(chip, &i2c_base->sa);
--	/* Stop bit needed here */
-+	/* stop bit needed here */
- 	writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
--	       I2C_CON_STP, &i2c_base->con);
--
--	while (alen) {
--		/* Must write reg offset (one or two bytes) */
--		status = wait_for_event();
--		/* Try to identify bus that is not padconf'd for I2C */
--		if (status == I2C_STAT_XRDY) {
--			i2c_error = 2;
--			printf("i2c_write: pads on bus %d probably not configured (status=0x%x)\n",
--			       current_bus, status);
--			goto wr_exit;
--		}
--		if (status == 0 || status & I2C_STAT_NACK) {
--			i2c_error = 1;
--			printf("i2c_write: error waiting for addr ACK (status=0x%x)\n",
--			       status);
--			goto wr_exit;
--		}
--		if (status & I2C_STAT_XRDY) {
--			alen--;
--			writeb((addr >> (8 * alen)) & 0xff, &i2c_base->data);
--			writew(I2C_STAT_XRDY, &i2c_base->stat);
--		} else {
--			i2c_error = 1;
--			printf("i2c_write: bus not ready for addr Tx (status=0x%x)\n",
--			       status);
--			goto wr_exit;
--		}
--	}
--	/* Address phase is over, now write data */
--	for (i = 0; i < len; i++) {
--		status = wait_for_event();
-+		I2C_CON_STP, &i2c_base->con);
-+
-+	/* Send address and data */
-+	for (i = -alen; i < len; i++) {
-+		status = wait_for_pin();
-+
- 		if (status == 0 || status & I2C_STAT_NACK) {
- 			i2c_error = 1;
--			printf("i2c_write: error waiting for data ACK (status=0x%x)\n",
--			       status);
--			goto wr_exit;
-+			printf("i2c error waiting for data ACK (status=0x%x)\n",
-+					status);
-+			goto write_exit;
- 		}
-+
- 		if (status & I2C_STAT_XRDY) {
--			writeb(buffer[i], &i2c_base->data);
-+			w = (i < 0) ? tmpbuf[2+i] : buffer[i];
-+#if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
-+	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
-+	defined(CONFIG_OMAP54XX))
-+			w |= ((++i < 0) ? tmpbuf[2+i] : buffer[i]) << 8;
-+#endif
-+			writew(w, &i2c_base->data);
- 			writew(I2C_STAT_XRDY, &i2c_base->stat);
- 		} else {
- 			i2c_error = 1;
--			printf("i2c_write: bus not ready for data Tx (i=%d)\n",
--			       i);
--			goto wr_exit;
-+			printf("i2c bus not ready for Tx (i=%d)\n", i);
-+			goto write_exit;
- 		}
- 	}
- 
--wr_exit:
-+write_exit:
- 	flush_fifo();
- 	writew(0xFFFF, &i2c_base->stat);
--	writew(0, &i2c_base->cnt);
- 	return i2c_error;
- }
- 
--/*
-- * Wait for the bus to be free by checking the Bus Busy (BB)
-- * bit to become clear
-- */
- static int wait_for_bb(void)
- {
- 	int timeout = I2C_TIMEOUT;
- 	u16 stat;
- 
- 	writew(0xFFFF, &i2c_base->stat);	/* clear current interrupts...*/
--#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
- 	while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) {
--#else
--	/* Read RAW status */
--	while ((stat = readw(&i2c_base->irqstatus_raw) &
--		I2C_STAT_BB) && timeout--) {
--#endif
- 		writew(stat, &i2c_base->stat);
--		udelay(I2C_WAIT);
-+		udelay(1000);
- 	}
- 
- 	if (timeout <= 0) {
--		printf("Timed out in wait_for_bb: status=%04x\n",
--		       stat);
-+		printf("timed out in wait_for_bb: I2C_STAT=%x\n",
-+			readw(&i2c_base->stat));
- 		return 1;
- 	}
- 	writew(0xFFFF, &i2c_base->stat);	 /* clear delayed stuff*/
- 	return 0;
- }
- 
--/*
-- * Wait for the I2C controller to complete current action
-- * and update status
-- */
--static u16 wait_for_event(void)
-+static u16 wait_for_pin(void)
- {
- 	u16 status;
- 	int timeout = I2C_TIMEOUT;
- 
- 	do {
--		udelay(I2C_WAIT);
--#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
-+		udelay(1000);
- 		status = readw(&i2c_base->stat);
--#else
--		/* Read RAW status */
--		status = readw(&i2c_base->irqstatus_raw);
--#endif
- 	} while (!(status &
- 		   (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
- 		    I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
- 		    I2C_STAT_AL)) && timeout--);
- 
- 	if (timeout <= 0) {
--		printf("Timed out in wait_for_event: status=%04x\n",
--		       status);
--		/*
--		 * If status is still 0 here, probably the bus pads have
--		 * not been configured for I2C, and/or pull-ups are missing.
--		 */
--		printf("Check if pads/pull-ups of bus %d are properly configured\n",
--		       current_bus);
-+		printf("timed out in wait_for_pin: I2C_STAT=%x\n",
-+			readw(&i2c_base->stat));
- 		writew(0xFFFF, &i2c_base->stat);
- 		status = 0;
- 	}
-@@ -550,36 +450,28 @@ static u16 wait_for_event(void)
- 
- int i2c_set_bus_num(unsigned int bus)
- {
--	if (bus >= I2C_BUS_MAX) {
--		printf("Bad bus: %x\n", bus);
-+	if ((bus < 0) || (bus >= I2C_BUS_MAX)) {
-+		printf("Bad bus: %d\n", bus);
- 		return -1;
- 	}
- 
--	switch (bus) {
--	default:
--		bus = 0;	/* Fall through */
--	case 0:
--		i2c_base = (struct i2c *)I2C_BASE1;
--		break;
--	case 1:
--		i2c_base = (struct i2c *)I2C_BASE2;
--		break;
--#if (I2C_BUS_MAX > 2)
--	case 2:
--		i2c_base = (struct i2c *)I2C_BASE3;
--		break;
--#if (I2C_BUS_MAX > 3)
--	case 3:
-+#if I2C_BUS_MAX == 4
-+	if (bus == 3)
- 		i2c_base = (struct i2c *)I2C_BASE4;
--		break;
--#if (I2C_BUS_MAX > 4)
--	case 4:
--		i2c_base = (struct i2c *)I2C_BASE5;
--		break;
--#endif
-+	else
-+	if (bus == 2)
-+		i2c_base = (struct i2c *)I2C_BASE3;
-+	else
- #endif
-+#if I2C_BUS_MAX == 3
-+	if (bus == 2)
-+		i2c_base = (struct i2c *)I2C_BASE3;
-+	else
- #endif
--	}
-+	if (bus == 1)
-+		i2c_base = (struct i2c *)I2C_BASE2;
-+	else
-+		i2c_base = (struct i2c *)I2C_BASE1;
- 
- 	current_bus = bus;
- 
--- 
-1.8.1.2
-
diff --git a/lab-data/sysdev/bootloader/data/0001-arm-omap-i2c-don-t-zero-cnt-in-i2c_write.patch b/lab-data/sysdev/bootloader/data/0001-arm-omap-i2c-don-t-zero-cnt-in-i2c_write.patch
new file mode 100644
index 0000000..90e4b9e
--- /dev/null
+++ b/lab-data/sysdev/bootloader/data/0001-arm-omap-i2c-don-t-zero-cnt-in-i2c_write.patch
@@ -0,0 +1,85 @@
+From 6990a273b72507c50639de9fbed69a5e4256a2b3 Mon Sep 17 00:00:00 2001
+From: Nikita Kiryanov <nikita at compulab.co.il>
+Date: Thu, 28 Nov 2013 18:04:42 +0200
+Subject: [PATCH] arm: omap: i2c: don't zero cnt in i2c_write
+
+Writing zero into I2Ci.I2C_CNT register causes random I2C failures in OMAP3
+based devices. This seems to be related to the following advisory which
+apears in multiple erratas for OMAP3 SoCs (OMAP35xx, DM37xx), as well as
+OMAP4430 TRM:
+
+Advisory:
+I2C Module Does Not Allow 0-Byte Data Requests
+Details:
+When configured as the master, the I2C module does not allow 0-byte data
+transfers. Note: Programming I2Ci.I2C_CNT[15:0]: DCOUNT = 0 will cause
+undefined behavior.
+Workaround(s):
+No workaround. Do not use 0-byte data requests.
+
+The writes in question are unnecessary from a functional point of view.
+Most of them are done after I/O has finished, and the only one that preceds
+I/O (in i2c_probe()) is also unnecessary because a stop bit is sent before
+actual data transmission takes place.
+
+Therefore, remove all writes that zero the cnt register.
+
+Cc: Heiko Schocher <hs at denx.de>
+Cc: Thomas Petazzoni <thomas.petazzoni at free-electrons.com>
+Cc: Tom Rini <trini at ti.com>
+Cc: Lubomir Popov <lpopov at mm-sol.com>
+Cc: Enric Balletbo Serra <eballetbo at gmail.com>
+Signed-off-by: Nikita Kiryanov <nikita at compulab.co.il>
+Signed-off-by: Thomas Petazzoni <thomas.petazzoni at free-electrons.com>
+---
+ drivers/i2c/omap24xx_i2c.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
+index ef38d71..4d79005 100644
+--- a/drivers/i2c/omap24xx_i2c.c
++++ b/drivers/i2c/omap24xx_i2c.c
+@@ -165,7 +165,6 @@ void i2c_init(int speed, int slaveadd)
+ 	udelay(1000);
+ 	flush_fifo();
+ 	writew(0xFFFF, &i2c_base->stat);
+-	writew(0, &i2c_base->cnt);
+ 
+ 	if (gd->flags & GD_FLG_RELOC)
+ 		bus_initialized[current_bus] = 1;
+@@ -205,8 +204,6 @@ int i2c_probe(uchar chip)
+ 		return res;
+ 
+ 	/* No data transfer, slave addr only */
+-	writew(0, &i2c_base->cnt);
+-	/* Set slave address */
+ 	writew(chip, &i2c_base->sa);
+ 	/* Stop bit needed here */
+ 	writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
+@@ -241,7 +238,6 @@ int i2c_probe(uchar chip)
+ pr_exit:
+ 	flush_fifo();
+ 	writew(0xFFFF, &i2c_base->stat);
+-	writew(0, &i2c_base->cnt);
+ 	return res;
+ }
+ 
+@@ -377,7 +373,6 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+ rd_exit:
+ 	flush_fifo();
+ 	writew(0xFFFF, &i2c_base->stat);
+-	writew(0, &i2c_base->cnt);
+ 	return i2c_error;
+ }
+ 
+@@ -476,7 +471,6 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+ wr_exit:
+ 	flush_fifo();
+ 	writew(0xFFFF, &i2c_base->stat);
+-	writew(0, &i2c_base->cnt);
+ 	return i2c_error;
+ }
+ 
+-- 
+1.8.1.2
+
diff --git a/labs/sysdev-u-boot/sysdev-u-boot.tex b/labs/sysdev-u-boot/sysdev-u-boot.tex
index cc07ac1..19606d1 100644
--- a/labs/sysdev-u-boot/sysdev-u-boot.tex
+++ b/labs/sysdev-u-boot/sysdev-u-boot.tex
@@ -127,12 +127,12 @@ cd u-boot-2013.10
 \end{verbatim}
 
 Then, apply the
-\code{0001-Revert-ARM-OMAP-I2C-New-read-write-and-probe-functio.patch}
-patch from this lab's \code{data} directory:
+\code{0001-arm-omap-i2c-don-t-zero-cnt-in-i2c_write.patch} patch from
+this lab's \code{data} directory:
 
 {\small
 \begin{verbatim}
-cat /path/to/0001-Revert-ARM-OMAP-I2C-New-read-write-and-probe-functio.patch | \
+cat /path/to/0001-arm-omap-i2c-don-t-zero-cnt-in-i2c_write.patch | \
    patch -p1
 \end{verbatim}
 }



More information about the training-materials-updates mailing list