Patchwork [U-Boot,V2,2/5] designware_i2c: Added s/w generation of stop bit

login
register
mail settings
Submitter Armando Visconti
Date Dec. 6, 2012, 10:04 a.m.
Message ID <1354788259-32688-3-git-send-email-armando.visconti@st.com>
Download mbox | patch
Permalink /patch/204207/
State Accepted
Delegated to: Heiko Schocher
Headers show

Comments

Armando Visconti - Dec. 6, 2012, 10:04 a.m.
In the newer versions of designware i2c IP there is the possibility
of configuring it with IC_EMPTYFIFO_HOLD_MASTER_EN=1, which basically
requires the s/w to generate the stop bit condition directly, as
the h/w will not automatically generate it when TX_FIFO is empty.

To avoid generation of an extra 0x0 byte sent as data, the
IC_STOP command must be sent along with the last IC_CMD.

This patch always writes bit[9] of ic_data_cmd even in the
older versions, assuming that it is a noop there.

Signed-off-by: Armando Visconti <armando.visconti@st.com>
---
 drivers/i2c/designware_i2c.c |   11 ++++++++---
 drivers/i2c/designware_i2c.h |    1 +
 2 files changed, 9 insertions(+), 3 deletions(-)

Patch

diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c
index 4e4bfd4..eab3131 100644
--- a/drivers/i2c/designware_i2c.c
+++ b/drivers/i2c/designware_i2c.c
@@ -283,7 +283,10 @@  int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
 
 	start_time_rx = get_timer(0);
 	while (len) {
-		writel(IC_CMD, &i2c_regs_p->ic_cmd_data);
+		if (len == 1)
+			writel(IC_CMD | IC_STOP, &i2c_regs_p->ic_cmd_data);
+		else
+			writel(IC_CMD, &i2c_regs_p->ic_cmd_data);
 
 		if (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) {
 			*buffer++ = (uchar)readl(&i2c_regs_p->ic_cmd_data);
@@ -322,9 +325,11 @@  int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
 	start_time_tx = get_timer(0);
 	while (len) {
 		if (readl(&i2c_regs_p->ic_status) & IC_STATUS_TFNF) {
-			writel(*buffer, &i2c_regs_p->ic_cmd_data);
+			if (--len == 0)
+				writel(*buffer | IC_STOP, &i2c_regs_p->ic_cmd_data);
+			else
+				writel(*buffer, &i2c_regs_p->ic_cmd_data);
 			buffer++;
-			len--;
 			start_time_tx = get_timer(0);
 
 		} else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) {
diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h
index 03b520e..e004152 100644
--- a/drivers/i2c/designware_i2c.h
+++ b/drivers/i2c/designware_i2c.h
@@ -95,6 +95,7 @@  struct i2c_regs {
 
 /* i2c data buffer and command register definitions */
 #define IC_CMD			0x0100
+#define IC_STOP			0x0200
 
 /* i2c interrupt status register definitions */
 #define IC_GEN_CALL		0x0800