summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gonzalez <alex.gonzalez@digi.com>2012-02-01 19:08:24 +0100
committerAlex Gonzalez <alex.gonzalez@digi.com>2012-02-01 19:08:24 +0100
commit9bfc8ddc66fafa26330ebd67cf9f152c85c58de1 (patch)
tree1c26cdc74d26c0bc086eb242f1f8edad767abbcd
parent7fba7b287bb80cbb0803c3189fba47d16b3d7a6e (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.c106
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__);