diff options
-rw-r--r-- | drivers/i2c/fsl_i2c.c | 41 | ||||
-rw-r--r-- | drivers/i2c/mxc_i2c.c | 18 | ||||
-rw-r--r-- | include/asm-generic/global_data.h | 3 |
3 files changed, 45 insertions, 17 deletions
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index 291ad94..aa159f8 100644 --- a/drivers/i2c/fsl_i2c.c +++ b/drivers/i2c/fsl_i2c.c @@ -423,18 +423,45 @@ fsl_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr, int alen, u8 *data, struct fsl_i2c *device = (struct fsl_i2c *)i2c_dev[adap->hwadapnr]; int i = -1; /* signal error */ u8 *a = (u8*)&addr; + int len = alen * -1; if (i2c_wait4bus(adap) < 0) return -1; - if ((!length || alen > 0) - && i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0 - && __i2c_write(adap, &a[4 - alen], alen) == alen) - i = 0; /* No error so far */ + /* To handle the need of I2C devices that require to write few bytes + * (more than 4 bytes of address as in the case of else part) + * of data before reading, Negative equivalent of length(bytes to write) + * is passed, but used the +ve part of len for writing data + */ + if (alen < 0) { + /* Generate a START and send the Address and + * the Tx Bytes to the slave. + * "START: Address: Write bytes data[len]" + * IF part supports writing any number of bytes in contrast + * to the else part, which supports writing address offset + * of upto 4 bytes only. + * bytes that need to be written are passed in + * "data", which will eventually keep the data READ, + * after writing the len bytes out of it + */ + if (i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0) + i = __i2c_write(adap, data, len); + + if (i != len) + return -1; - if (length && - i2c_write_addr(adap, dev, I2C_READ_BIT, alen ? 1 : 0) != 0) - i = __i2c_read(adap, data, length); + if (length && i2c_write_addr(adap, dev, I2C_READ_BIT, 1) != 0) + i = __i2c_read(adap, data, length); + } else { + if ((!length || alen > 0) && + i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0 && + __i2c_write(adap, &a[4 - alen], alen) == alen) + i = 0; /* No error so far */ + + if (length && + i2c_write_addr(adap, dev, I2C_READ_BIT, alen ? 1 : 0) != 0) + i = __i2c_read(adap, data, length); + } writeb(I2C_CR_MEN, &device->cr); diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 595019b..48468d7 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -22,6 +22,8 @@ #include <i2c.h> #include <watchdog.h> +DECLARE_GLOBAL_DATA_PTR; + #ifdef I2C_QUIRK_REG struct mxc_i2c_regs { uint8_t iadr; @@ -411,12 +413,6 @@ struct sram_data { struct i2c_parms i2c_data[3]; }; -/* - * For SPL boot some boards need i2c before SDRAM is initialized so force - * variables to live in SRAM - */ -static struct sram_data __attribute__((section(".data"))) srdata; - static void * const i2c_bases[] = { #if defined(CONFIG_MX25) (void *)IMX_I2C_BASE, @@ -445,9 +441,10 @@ void *i2c_get_base(struct i2c_adapter *adap) static struct i2c_parms *i2c_get_parms(void *base) { + struct sram_data *srdata = (void *)gd->srdata; int i = 0; - struct i2c_parms *p = srdata.i2c_data; - while (i < ARRAY_SIZE(srdata.i2c_data)) { + struct i2c_parms *p = srdata->i2c_data; + while (i < ARRAY_SIZE(srdata->i2c_data)) { if (p->base == base) return p; p++; @@ -490,8 +487,9 @@ static int mxc_i2c_probe(struct i2c_adapter *adap, uint8_t chip) void bus_i2c_init(void *base, int speed, int unused, int (*idle_bus_fn)(void *p), void *idle_bus_data) { + struct sram_data *srdata = (void *)gd->srdata; int i = 0; - struct i2c_parms *p = srdata.i2c_data; + struct i2c_parms *p = srdata->i2c_data; if (!base) return; for (;;) { @@ -505,7 +503,7 @@ void bus_i2c_init(void *base, int speed, int unused, } p++; i++; - if (i >= ARRAY_SIZE(srdata.i2c_data)) + if (i >= ARRAY_SIZE(srdata->i2c_data)) return; } bus_i2c_set_bus_speed(base, speed); diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 707400e..e98b661 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -80,6 +80,9 @@ typedef struct global_data { #if defined(CONFIG_SYS_I2C) int cur_i2c_bus; /* current used i2c bus */ #endif +#ifdef CONFIG_SYS_I2C_MXC + void *srdata[10]; +#endif unsigned long timebase_h; unsigned long timebase_l; struct arch_global_data arch; /* architecture-specific data */ |