
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@freescale.com Signed-off-by: Shaveta Leekha shaveta@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.