[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