diff options
author | Alex Gonzalez <alex.gonzalez@digi.com> | 2012-02-01 19:08:24 +0100 |
---|---|---|
committer | Alex Gonzalez <alex.gonzalez@digi.com> | 2012-02-01 19:08:24 +0100 |
commit | 9bfc8ddc66fafa26330ebd67cf9f152c85c58de1 (patch) | |
tree | 1c26cdc74d26c0bc086eb242f1f8edad767abbcd | |
parent | 7fba7b287bb80cbb0803c3189fba47d16b3d7a6e (diff) |
ccxmx53: da9053 I2C, recover the read_many function from Dialog patch
Although DEL is working fine with the previous I2C park fixes, we have
seen spurious events coming from the PMIC running Android.
This was traced down to using the read_many function. If the events
registers were read using four different reads the contents of the
registers are read OK. But if we use the read_many, some times the
register contents are read incorrectly.
Using the read_many function from Dialog's latest patch seems to solve
this, although both implementations should work OK.
Given that Dialog's PMIC has not well documented I2C access issues,
we may not get a complete understanding on the problem.
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
-rw-r--r-- | drivers/mfd/da9052-i2c.c | 106 |
1 files changed, 36 insertions, 70 deletions
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c index 856f482414b1..7e4004db76de 100644 --- a/drivers/mfd/da9052-i2c.c +++ b/drivers/mfd/da9052-i2c.c @@ -345,89 +345,55 @@ int da9052_i2c_write_many(struct da9052 *da9052, int da9052_i2c_read_many(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg, int msg_no) { - - struct i2c_msg i2cmsg; + struct i2c_msg i2cmsg[2]; unsigned char data_buf[MAX_READ_WRITE_CNT]; - struct da9052_ssc_msg *msg_queue = sscmsg; int ret = 0; - /* Flag to check if requested registers are contiguous */ - unsigned char cont_data = 1; - unsigned char cnt = 0; + int expected_addr = 0xFF; + int cnt; - /* Check if requested registers are contiguous */ - for (cnt = 1; cnt < msg_no; cnt++) { - if ((msg_queue[cnt].addr - msg_queue[cnt-1].addr) != 1) { - /* Difference is not 1, i.e. non-contiguous registers */ - cont_data = 0; - break; - } + if( msg_no < 0 || msg_no >= MAX_READ_WRITE_CNT ){ + pr_err("da9052_i2c_read_many: Out of order %d\n",msg_no); + return -EINVAL; } - if (cont_data == 0) { - /* Requested registers are non-contiguous */ - for (cnt = 0; cnt < msg_no; cnt++) { - ret = da9052->read(da9052, &msg_queue[cnt]); - if (ret != 0) { - dev_info(&da9052->i2c_client->dev,\ - "Error in %s", __func__); - return ret; - } + /* Construct a i2c msgs for a da9052 driver ssc message request */ + cnt = 0; + do { + /* Build messages for read transaction */ + i2cmsg[0].addr = da9052->slave_addr; + i2cmsg[0].buf = &sscmsg[cnt].addr; + i2cmsg[0].flags = 0; + i2cmsg[0].len = 1; + i2cmsg[1].addr = da9052->slave_addr; + i2cmsg[1].buf = &data_buf[cnt]; + i2cmsg[1].flags = I2C_M_RD; + /* Grab consecutive register reads into one message */ + for (i2cmsg[1].len = 0, expected_addr = sscmsg[cnt].addr; + (cnt < msg_no) && (sscmsg[cnt].addr == expected_addr); + cnt++, expected_addr++) + { + i2cmsg[1].len++; } - return 0; - } - - /* - * We want to perform PAGE READ via I2C - * For PAGE READ sequence of I2C transactions is as below - * (slave_addr + reg_addr) + (slave_addr + data_1 + data_2 + ...) - */ - /* Copy address of first register */ - data_buf[0] = msg_queue[0].addr; - - /* Construct a i2c msg for first transaction of PAGE READ i.e. write */ - i2cmsg.addr = da9052->slave_addr ; - i2cmsg.len = 1; - i2cmsg.buf = data_buf; - /*To write the data on I2C set flag to zero */ - i2cmsg.flags = 0; - - /* Start the i2c transfer by calling host i2c driver function */ - ret = i2c_transfer(da9052->adapter, &i2cmsg, 1); - if (ret < 0) { - dev_info(&da9052->i2c_client->dev,\ - "1 - i2c_transfer function falied in [%s]!!!\n", __func__); - return ret; - } - - /* Now Read the data from da9052 */ - /* Construct a i2c msg for second transaction of PAGE READ i.e. read */ - i2cmsg.addr = da9052->slave_addr ; - i2cmsg.len = msg_no; - i2cmsg.buf = data_buf; - - /*To read the data on I2C set flag to I2C_M_RD */ - i2cmsg.flags = I2C_M_RD; - - /* Start the i2c transfer by calling host i2c driver function */ - ret = i2c_transfer(da9052->adapter, - &i2cmsg, 1); - if (ret < 0) { - dev_info(&da9052->i2c_client->dev,\ - "2 - i2c_transfer function falied in [%s]!!!\n", __func__); - return ret; - } + /* Perform read transaction */ + ret = i2c_transfer(da9052->adapter, i2cmsg, 2); + if (ret < 0) { + dev_info(&da9052->i2c_client->dev, + "%s: i2c_transfer failed!!!\n", __func__); + return ret; + } + } while (cnt < msg_no); if( da9052->chip_version <= DA9053_VERSION_BB ) { /* Test, whether last register to be accessed needs to be flushed */ if (!da9052_is_i2c_reg_safe(sscmsg[msg_no-1].addr)) { - i2cmsg.addr = da9052->slave_addr; - i2cmsg.len = 2; - i2cmsg.flags = 0; /* Write operation */ + i2cmsg[0].addr = da9052->slave_addr; + i2cmsg[0].len = 2; + i2cmsg[0].flags = 0; /* Write operation */ /* i2c_flush_data is only to read from */ - i2cmsg.buf = (unsigned char *)i2c_flush_data; + i2cmsg[0].buf = (unsigned char *)i2c_flush_data; - ret = i2c_transfer(da9052->adapter, &i2cmsg, 1); + ret = i2c_transfer(da9052->adapter, i2cmsg, 1); if (ret < 0) { dev_info(&da9052->i2c_client->dev, "%s: i2c_transfer failed!!!\n", __func__); |