diff options
-rw-r--r-- | drivers/mfd/da9052-i2c.c | 336 |
1 files changed, 159 insertions, 177 deletions
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c index 1a9fd368db66..3a1011682224 100644 --- a/drivers/mfd/da9052-i2c.c +++ b/drivers/mfd/da9052-i2c.c @@ -19,8 +19,6 @@ static struct da9052 *da9052_i2c; #define I2C_CONNECTED 0 -#define I2C_BUG_WORKAROUND - static int da9052_i2c_is_connected(void) { struct da9052_ssc_msg msg; @@ -78,15 +76,6 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client, /* Validate I2C connectivity */ if ( I2C_CONNECTED == da9052_i2c_is_connected()) { - /* Enable Repeated Write Mode permanently */ - struct da9052_ssc_msg ctrl_msg = - {DA9052_CONTROLB_REG, DA9052_CONTROLB_WRITEMODE}; - if (da9052_i2c_write(da9052_i2c, &ctrl_msg) < 0) { - dev_info(&da9052_i2c->i2c_client->dev, - "%s: repeated mode not set!!\n", __func__); - return -ENODEV; - } - /* I2C is connected */ da9052_i2c->connecting_device = I2C; if( 0!= da9052_ssc_init(da9052_i2c) ) @@ -111,77 +100,30 @@ static int da9052_i2c_remove(struct i2c_client *client) return 0; } -#ifdef I2C_BUG_WORKAROUND -#define I2C_DUMMY_REG 0xFF -const unsigned char i2c_flush_data[] = {I2C_DUMMY_REG, 0xFF}; - -#if 1 /* Enable safe register addresses checking */ -/* DLG TODO: Add read only registers here (they are not affected with write) */ -static inline int da9052_is_i2c_reg_safe(unsigned char reg) -{ - const char safe_table[256] = { - [DA9052_STATUSA_REG] = 1, - [DA9052_STATUSB_REG] = 1, - [DA9052_STATUSC_REG] = 1, - [DA9052_STATUSD_REG] = 1, - [DA9052_EVENTA_REG] = 1, - [DA9052_EVENTB_REG] = 1, - [DA9052_EVENTC_REG] = 1, - [DA9052_EVENTD_REG] = 1, - [DA9052_ADCRESL_REG] = 1, - [DA9052_ADCRESH_REG] = 1, - [DA9052_VDDRES_REG] = 1, - [DA9052_ICHGAV_REG] = 1, - [DA9052_TBATRES_REG] = 1, - [DA9052_ADCIN4RES_REG] = 1, - [DA9052_ADCIN5RES_REG] = 1, - [DA9052_ADCIN6RES_REG] = 1, - [DA9052_TJUNCRES_REG] = 1, - [DA9052_TSIXMSB_REG] = 1, - [DA9052_TSIYMSB_REG] = 1, - [DA9052_TSILSB_REG] = 1, - [DA9052_TSIZMSB_REG] = 1, - [I2C_DUMMY_REG] = 1, /* Dummy reg must be a save reg */ - }; - - return safe_table[reg]; -} -#else -static inline int da9052_is_i2c_reg_safe(unsigned char reg) -{ - return 0; -} -#endif -#endif - int da9052_i2c_write(struct da9052 *da9052, struct da9052_ssc_msg *msg) { struct i2c_msg i2cmsg; - unsigned char buf[4]; + unsigned char buf[2] = {0}; int ret = 0; + /* Copy the ssc msg to local character buffer */ + buf[0] = msg->addr; + buf[1] = msg->data; + /*Construct a i2c msg for a da9052 driver ssc message request */ i2cmsg.addr = da9052->slave_addr; - i2cmsg.buf = buf; - i2cmsg.flags = 0; i2cmsg.len = 2; + i2cmsg.buf = buf; - /* Copy the ssc msg and additional data to flush chip I2C registers */ - buf[0] = msg->addr; - buf[1] = msg->data; + /* To write the data on I2C set flag to zero */ + i2cmsg.flags = 0; -#ifdef I2C_BUG_WORKAROUND - /* Test, whether register to be accessed needs to be flushed */ - if (!da9052_is_i2c_reg_safe(msg->addr)) { - i2cmsg.len = 4; - buf[2] = i2c_flush_data[0]; - buf[3] = i2c_flush_data[1]; - } -#endif /* 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, - "%s: i2c_transfer failed!!!\n", __func__); + ret = i2c_transfer(da9052->adapter, &i2cmsg, 1); + + if (ret < 0) { + dev_info(&da9052->i2c_client->dev,\ + "_%s:master_xfer Failed!!\n", __func__); return ret; } @@ -190,8 +132,10 @@ int da9052_i2c_write(struct da9052 *da9052, struct da9052_ssc_msg *msg) int da9052_i2c_read(struct da9052 *da9052, struct da9052_ssc_msg *msg) { + + /*Get the da9052_i2c client details*/ unsigned char buf[2] = {0, 0}; - struct i2c_msg i2cmsg[3]; + struct i2c_msg i2cmsg[2]; int ret = 0; /* Copy SSC Msg to local character buffer */ @@ -201,86 +145,107 @@ int da9052_i2c_read(struct da9052 *da9052, struct da9052_ssc_msg *msg) i2cmsg[0].addr = da9052->slave_addr ; i2cmsg[0].len = 1; i2cmsg[0].buf = &buf[0]; + + /*To write the data on I2C set flag to zero */ i2cmsg[0].flags = 0; + /* Read the data from da9052*/ /*Construct a i2c msg for a da9052 driver ssc message request */ i2cmsg[1].addr = da9052->slave_addr ; i2cmsg[1].len = 1; i2cmsg[1].buf = &buf[1]; + + /*To read the data on I2C set flag to I2C_M_RD */ i2cmsg[1].flags = I2C_M_RD; - /* Standard read transfer */ + /* Start the i2c transfer by calling host i2c driver function */ ret = i2c_transfer(da9052->adapter, i2cmsg, 2); - -#ifdef I2C_BUG_WORKAROUND - /* Test, whether register to be accessed needs to be flushed */ - if (!da9052_is_i2c_reg_safe(msg->addr)) { - i2cmsg[2].addr = da9052->slave_addr; - i2cmsg[2].len = 2; - i2cmsg[2].flags = 0; /* Write operation */ - /* i2c_flush_data is only to read from */ - i2cmsg[2].buf = (unsigned char *)i2c_flush_data; - - /* Read transfer with additional flush write */ - ret = i2c_transfer(da9052->adapter, &i2cmsg[2], 1); - } -#endif - if (ret < 0) { - dev_info(&da9052->i2c_client->dev, - "%s: i2c_transfer failed!!!\n", __func__); - return ret; + dev_info(&da9052->i2c_client->dev,\ + "2 - %s:master_xfer Failed!!\n", __func__); + return ret; } - msg->data = buf[1]; + msg->data = *i2cmsg[1].buf; + return 0; } int da9052_i2c_write_many(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg, int msg_no) { + struct i2c_msg i2cmsg; + unsigned char data_buf[MAX_READ_WRITE_CNT+1]; + struct da9052_ssc_msg ctrlb_msg; + struct da9052_ssc_msg *msg_queue = sscmsg; int ret = 0; - int cnt; - unsigned char *data_ptr; -#ifdef I2C_BUG_WORKAROUND - unsigned char data_buf[2*MAX_READ_WRITE_CNT + 2]; -#else - unsigned char data_buf[2*MAX_READ_WRITE_CNT]; -#endif - - BUG_ON(msg_no < 0); - BUG_ON(msg_no >= MAX_READ_WRITE_CNT); -/* - printk(KERN_CRIT "D9053: %s: write %d messages starting from %hhu reg\n", - __func__, msg_no, sscmsg->addr); -*/ + /* Flag to check if requested registers are contiguous */ + unsigned char cont_data = 1; + unsigned char cnt = 0; + + /* 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 (cont_data == 0) { + /* Requested registers are non-contiguous */ + for (cnt = 0; cnt < msg_no; cnt++) { + ret = da9052->write(da9052, &msg_queue[cnt]); + if (ret != 0) + return ret; + } + return 0; + } + /* + * Requested registers are contiguous + * or PAGE WRITE sequence of I2C transactions is as below + * (slave_addr + reg_addr + data_1 + data_2 + ...) + * First read current WRITE MODE via CONTROL_B register of DA9052 + */ + ctrlb_msg.addr = DA9052_CONTROLB_REG; + ctrlb_msg.data = 0x0; + ret = da9052->read(da9052, &ctrlb_msg); + + if (ret != 0) + return ret; + + /* Check if PAGE WRITE mode is set */ + if (ctrlb_msg.data & DA9052_CONTROLB_WRITEMODE) { + /* REPEAT WRITE mode is configured */ + /* Now set DA9052 into PAGE WRITE mode */ + ctrlb_msg.data &= ~DA9052_CONTROLB_WRITEMODE; + ret = da9052->write(da9052, &ctrlb_msg); - /* Construct a i2c msg for REPEATED WRITE */ + if (ret != 0) + return ret; + } + + /* Put first register address */ + data_buf[0] = msg_queue[0].addr; + + for (cnt = 0; cnt < msg_no; cnt++) + data_buf[cnt+1] = msg_queue[cnt].data; + + /* Construct a i2c msg for PAGE WRITE */ i2cmsg.addr = da9052->slave_addr ; - i2cmsg.len = 2*msg_no; + /* First register address + all data*/ + i2cmsg.len = (msg_no + 1); i2cmsg.buf = data_buf; - i2cmsg.flags = 0; - for (data_ptr = data_buf, cnt = msg_no; cnt; cnt--) { - *(data_ptr++) = sscmsg->addr; - *(data_ptr++) = sscmsg->data; - sscmsg++; - } -#ifdef I2C_BUG_WORKAROUND - /* Test, whether last register to be accessed needs to be flushed */ - if (msg_no != 0 && !da9052_is_i2c_reg_safe(sscmsg[-1].addr)) { - i2cmsg.len += 2; - *(data_ptr++) = i2c_flush_data[0]; - *data_ptr = i2c_flush_data[1]; - } -#endif + /*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, - "%s: i2c_transfer failed!!!\n", __func__); + dev_info(&da9052->i2c_client->dev,\ + "1 - i2c_transfer function falied in [%s]!!!\n", __func__); return ret; } @@ -290,66 +255,83 @@ 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[2]; + + struct i2c_msg i2cmsg; unsigned char data_buf[MAX_READ_WRITE_CNT]; + struct da9052_ssc_msg *msg_queue = sscmsg; int ret = 0; - int expected_addr = 0xFF; - int cnt; - - BUG_ON(msg_no < 0); - BUG_ON(msg_no >= MAX_READ_WRITE_CNT); -/* - printk(KERN_CRIT "D9053: %s: read %d messages starting from %hhu reg\n", - __func__, msg_no, sscmsg->addr); -*/ - - /* 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++; + /* Flag to check if requested registers are contiguous */ + unsigned char cont_data = 1; + unsigned char cnt = 0; + + /* 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; } + } - /* 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); - -#ifdef I2C_BUG_WORKAROUND - /* Test, whether last register to be accessed needs to be flushed */ - if (!da9052_is_i2c_reg_safe(sscmsg[msg_no-1].addr)) { - 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[0].buf = (unsigned char *)i2c_flush_data; - - ret = i2c_transfer(da9052->adapter, i2cmsg, 1); - if (ret < 0) { - dev_info(&da9052->i2c_client->dev, - "%s: i2c_transfer failed!!!\n", __func__); - return ret; + 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; + } } + 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; } -#endif - for (cnt = 0; cnt < msg_no; cnt++) sscmsg[cnt].data = data_buf[cnt]; + /* 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; + } + + /* Gather READ data */ + for (cnt = 0; cnt < msg_no; cnt++) + sscmsg[cnt].data = data_buf[cnt]; + return 0; } |