[U-Boot] [PATCH] fsl_i2c: Add write-then-read transaction interface for I2C slave

Shaveta Leekha shaveta at freescale.com
Mon Mar 3 09:58:38 CET 2014


Most of the I2C slaves support accesses in the typical style
viz.read/write series of bytes at particular address offset.
These transactions are currently supportd in the
i2c driver using i2c_read and i2c_write APIs. I2C EEPROMs,
RTC, etc fall in this category.
The transactions look like:"
START:Address:Tx:Offset:RESTART:Address[0..4]:Tx/Rx:data[0..n]:STOP"

However there are certain devices which support accesses in
terms of the transactions as follows:
"START:Address:Tx:Txdata[0..n1]:Clock_stretching:
        RESTART:Address:Rx:data[0..n2]"

The Txdata is typically a command and some associated data,
similarly Rxdata could be command status plus some data received
as a response to the command sent.
i2c_write_read() function provides support for such transactions
(multiple bytes write followed by read)

Signed-off-by: Poonam Aggrwal <poonam.aggrwal at freescale.com>
Signed-off-by: Shaveta Leekha <shaveta at freescale.com>
---
 drivers/i2c/fsl_i2c.c  |   64 ++++++++++++++++++++++++++++++++++++++++++-----
 drivers/i2c/i2c_core.c |    7 +++++
 include/i2c.h          |   19 ++++++++++---
 3 files changed, 78 insertions(+), 12 deletions(-)

diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index 291ad94..838c1b1 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -472,6 +472,56 @@ fsl_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr, int alen,
 
 	return -1;
 }
+/* To perform any generic transaction on a I2C slave which involves
+
+   START: Address: Write bytes(cmd + data): clock extension:
+   RESTART: Address: Read bytes (data + status): STOP
+
+   This is different from standard I2C devices which are supported
+   in existing i2c_read and i2c_write functions.
+   */
+int
+fsl_i2c_write_read(struct i2c_adapter *adap, u8 dev, u8 *wdata, int wlength,
+		   u8 *rdata, int rlength)
+{
+	struct fsl_i2c *device = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
+
+	int i = -1; /* signal error */
+
+	if (i2c_wait4bus(adap))
+		return -1;
+
+/* Generate a START and send the Address and the Tx Bytes to the slave.
+ * "START: Address: Write bytes wdata[wlength]"
+ */
+	if (i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0)
+		i = __i2c_write(adap, wdata, wlength);
+
+	if (i != wlength)
+		return -1;
+
+/* Now issue a READ by generating a RESTART condition
+ * "RESTART: Address: Read bytes rdata[rlength]"
+ * Some slaves may also do clock stretching and keep the SCL low until
+ * they finish some command processing at their end. The I2C controller
+ * will wait for the clock stretching period to get over before generating
+ * the RESTART condition on the bus.
+ */
+	if (rlength
+	    && i2c_write_addr(adap, dev, I2C_READ_BIT, 1) != 0)
+		i = __i2c_read(adap, rdata, rlength);
+
+/* Generate STOP */
+	writeb(I2C_CR_MEN, &device->cr);
+
+	if (i2c_wait4bus(adap)) /* Wait until STOP */
+		debug("i2c_write_read: wait4bus timed out\n");
+
+	if (i != rlength)
+		return -1;
+
+	return 0;
+}
 
 static int
 fsl_i2c_probe(struct i2c_adapter *adap, uchar chip)
@@ -503,12 +553,12 @@ static unsigned int fsl_i2c_set_bus_speed(struct i2c_adapter *adap,
  * Register fsl i2c adapters
  */
 U_BOOT_I2C_ADAP_COMPLETE(fsl_0, fsl_i2c_init, fsl_i2c_probe, fsl_i2c_read,
-			 fsl_i2c_write, fsl_i2c_set_bus_speed,
-			 CONFIG_SYS_FSL_I2C_SPEED, CONFIG_SYS_FSL_I2C_SLAVE,
-			 0)
-#ifdef CONFIG_SYS_FSL_I2C2_OFFSET
+			 fsl_i2c_write, fsl_i2c_write_read,
+			 fsl_i2c_set_bus_speed, CONFIG_SYS_FSL_I2C_SPEED,
+			 CONFIG_SYS_FSL_I2C_SLAVE,  0);
+#ifdef CONFIG_SYS_I2C2_OFFSET
 U_BOOT_I2C_ADAP_COMPLETE(fsl_1, fsl_i2c_init, fsl_i2c_probe, fsl_i2c_read,
-			 fsl_i2c_write, fsl_i2c_set_bus_speed,
-			 CONFIG_SYS_FSL_I2C2_SPEED, CONFIG_SYS_FSL_I2C2_SLAVE,
-			 1)
+			 fsl_i2c_write, fsl_i2c_write_read,
+			 fsl_i2c_set_bus_speed, CONFIG_SYS_FSL_I2C2_SPEED,
+			 CONFIG_SYS_FSL_I2C2_SLAVE, 1);
 #endif
diff --git a/drivers/i2c/i2c_core.c b/drivers/i2c/i2c_core.c
index 18d6736..6647856 100644
--- a/drivers/i2c/i2c_core.c
+++ b/drivers/i2c/i2c_core.c
@@ -341,6 +341,13 @@ int i2c_write(uint8_t chip, unsigned int addr, int alen,
 	return I2C_ADAP->write(I2C_ADAP, chip, addr, alen, buffer, len);
 }
 
+int i2c_write_read(uchar chip, uint8_t *wbuffer, int wlen, uint8_t *rbuffer,
+								int rlen)
+{
+	return I2C_ADAP->write_read(I2C_ADAP, chip, wbuffer, wlen,
+				    rbuffer, rlen);
+}
+
 unsigned int i2c_set_bus_speed(unsigned int speed)
 {
 	unsigned int ret;
diff --git a/include/i2c.h b/include/i2c.h
index 1b4078e..7bac20a 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -65,6 +65,9 @@ struct i2c_adapter {
 	int		(*write)(struct i2c_adapter *adap, uint8_t chip,
 				uint addr, int alen, uint8_t *buffer,
 				int len);
+	int		(*write_read)(struct i2c_adapter *adap, uint8_t chip,
+				uint8_t *wbuffer, int wlength, uint8_t *rbuffer,
+				int rlength);
 	uint		(*set_bus_speed)(struct i2c_adapter *adap,
 				uint speed);
 	int		speed;
@@ -75,13 +78,14 @@ struct i2c_adapter {
 	char		*name;
 };
 
-#define U_BOOT_I2C_MKENT_COMPLETE(_init, _probe, _read, _write, \
+#define U_BOOT_I2C_MKENT_COMPLETE(_init, _probe, _read, _write, _write_read, \
 		_set_speed, _speed, _slaveaddr, _hwadapnr, _name) \
 	{ \
 		.init		=	_init, \
 		.probe		=	_probe, \
 		.read		=	_read, \
 		.write		=	_write, \
+		.write_read	=	_write_read, \
 		.set_bus_speed	=	_set_speed, \
 		.speed		=	_speed, \
 		.slaveaddr	=	_slaveaddr, \
@@ -90,10 +94,11 @@ struct i2c_adapter {
 		.name		=	#_name \
 };
 
-#define U_BOOT_I2C_ADAP_COMPLETE(_name, _init, _probe, _read, _write, \
-			_set_speed, _speed, _slaveaddr, _hwadapnr) \
-	ll_entry_declare(struct i2c_adapter, _name, i2c) = \
-	U_BOOT_I2C_MKENT_COMPLETE(_init, _probe, _read, _write, \
+#define U_BOOT_I2C_ADAP_COMPLETE(_name, _init, _probe, _read, _write,	\
+			_write_read, _set_speed, _speed, _slaveaddr,	\
+			_hwadapnr)					\
+	ll_entry_declare(struct i2c_adapter, _name, i2c) =		\
+	U_BOOT_I2C_MKENT_COMPLETE(_init, _probe, _read, _write,  _write_read, \
 		 _set_speed, _speed, _slaveaddr, _hwadapnr, _name);
 
 struct i2c_adapter *i2c_get_adapter(int index);
@@ -237,6 +242,8 @@ int i2c_read(uint8_t chip, unsigned int addr, int alen,
 
 int i2c_write(uint8_t chip, unsigned int addr, int alen,
 				uint8_t *buffer, int len);
+int i2c_write_read(uint8_t chip, uchar *wbuffer, int wlen, uchar *rbuffer,
+								int rlen);
 
 /*
  * Utility routines to read/write registers.
@@ -302,6 +309,8 @@ int i2c_probe(uchar chip);
  */
 int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len);
 int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len);
+int i2c_write_read(uchar chip, uchar *wbuffer, int wlen, uchar *rbuffer,
+								int rlen);
 
 /*
  * Utility routines to read/write registers.
-- 
1.7.6.GIT




More information about the U-Boot mailing list