1 From 7c0c7fc3189f456f1899bf4aa0a27e3f71f6a808 Mon Sep 17 00:00:00 2001
2 From: Wayne Zou <b36644@freescale.com>
3 Date: Mon, 21 Nov 2011 14:44:33 +0800
4 Subject: [PATCH] ENGR00162711 DA9053: Add dummy write for DA9053 I2C register access
6 DA9053 i2c issue: Rarely the i2c interface of DA9053 hang and it can
7 not be recovered if not power off totally. The Dialog suggests adding
8 dummy write for DA9053 I2C register access, in order to decrease the failure
9 of DA9053 register access and possibility of i2c failure.
11 Signed-off-by: Wayne Zou <b36644@freescale.com>
12 (cherry picked from commit bfd7cba1eeb46977b18a3c5fa65d812817a8294d)
14 drivers/mfd/da9052-i2c.c | 317 ++++++++++++++++++++++++----------------------
15 1 files changed, 166 insertions(+), 151 deletions(-)
17 diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c
18 index 6209e97..457523f 100644
19 --- a/drivers/mfd/da9052-i2c.c
20 +++ b/drivers/mfd/da9052-i2c.c
21 @@ -19,6 +19,8 @@ static struct da9052 *da9052_i2c;
23 #define I2C_CONNECTED 0
25 +#define DA9052_I2C_BUG_WORKAROUND
27 static int da9052_i2c_is_connected(void)
29 struct da9052_ssc_msg msg;
30 @@ -76,6 +78,15 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client,
32 /* Validate I2C connectivity */
33 if ( I2C_CONNECTED == da9052_i2c_is_connected()) {
34 + /* Enable Repeated Write Mode permanently */
35 + struct da9052_ssc_msg ctrl_msg = {
36 + DA9052_CONTROLB_REG, DA9052_CONTROLB_WRITEMODE};
37 + if (da9052_i2c_write(da9052_i2c, &ctrl_msg) < 0) {
38 + dev_info(&da9052_i2c->i2c_client->dev,
39 + "%s: repeated mode not set!!\n", __func__);
43 /* I2C is connected */
44 da9052_i2c->connecting_device = I2C;
45 if( 0!= da9052_ssc_init(da9052_i2c) )
46 @@ -100,27 +111,59 @@ static int da9052_i2c_remove(struct i2c_client *client)
50 +#ifdef DA9052_I2C_BUG_WORKAROUND
51 +const unsigned char i2c_flush_data[] = {0xFF, 0xFF};
52 +static const char safe_table[256] = {
53 + [DA9052_STATUSA_REG] = 1,
54 + [DA9052_STATUSB_REG] = 1,
55 + [DA9052_STATUSC_REG] = 1,
56 + [DA9052_STATUSD_REG] = 1,
57 + [DA9052_ADCRESL_REG] = 1,
58 + [DA9052_ADCRESH_REG] = 1,
59 + [DA9052_VDDRES_REG] = 1,
60 + [DA9052_ICHGAV_REG] = 1,
61 + [DA9052_TBATRES_REG] = 1,
62 + [DA9052_ADCIN4RES_REG] = 1,
63 + [DA9052_ADCIN5RES_REG] = 1,
64 + [DA9052_ADCIN6RES_REG] = 1,
65 + [DA9052_TJUNCRES_REG] = 1,
66 + [DA9052_TSIXMSB_REG] = 1,
67 + [DA9052_TSIYMSB_REG] = 1,
68 + [DA9052_TSILSB_REG] = 1,
69 + [DA9052_TSIZMSB_REG] = 1,
71 +/* Enable safe register addresses */
72 +static inline int da9052_is_i2c_reg_safe(unsigned char reg)
74 + return safe_table[reg];
78 int da9052_i2c_write(struct da9052 *da9052, struct da9052_ssc_msg *msg)
80 struct i2c_msg i2cmsg;
81 - unsigned char buf[2] = {0};
82 + unsigned char buf[4] = {0};
85 - /* Copy the ssc msg to local character buffer */
89 /*Construct a i2c msg for a da9052 driver ssc message request */
90 i2cmsg.addr = da9052->slave_addr;
94 - /* To write the data on I2C set flag to zero */
98 + /* Copy the ssc msg and additional data to flush chip I2C registers */
100 + buf[1] = msg->data;
102 +#ifdef DA9052_I2C_BUG_WORKAROUND
103 + if (!da9052_is_i2c_reg_safe(msg->addr)) {
105 + buf[2] = i2c_flush_data[0];
106 + buf[3] = i2c_flush_data[1];
109 /* Start the i2c transfer by calling host i2c driver function */
110 ret = i2c_transfer(da9052->adapter, &i2cmsg, 1);
113 dev_info(&da9052->i2c_client->dev,\
114 "_%s:master_xfer Failed!!\n", __func__);
115 @@ -132,10 +175,8 @@ int da9052_i2c_write(struct da9052 *da9052, struct da9052_ssc_msg *msg)
117 int da9052_i2c_read(struct da9052 *da9052, struct da9052_ssc_msg *msg)
120 - /*Get the da9052_i2c client details*/
121 unsigned char buf[2] = {0, 0};
122 - struct i2c_msg i2cmsg[2];
123 + struct i2c_msg i2cmsg[3];
126 /* Copy SSC Msg to local character buffer */
127 @@ -145,107 +186,82 @@ int da9052_i2c_read(struct da9052 *da9052, struct da9052_ssc_msg *msg)
128 i2cmsg[0].addr = da9052->slave_addr ;
130 i2cmsg[0].buf = &buf[0];
132 - /*To write the data on I2C set flag to zero */
135 - /* Read the data from da9052*/
136 /*Construct a i2c msg for a da9052 driver ssc message request */
137 i2cmsg[1].addr = da9052->slave_addr ;
139 i2cmsg[1].buf = &buf[1];
141 - /*To read the data on I2C set flag to I2C_M_RD */
142 i2cmsg[1].flags = I2C_M_RD;
144 - /* Start the i2c transfer by calling host i2c driver function */
145 + /* Standard read transfer */
146 ret = i2c_transfer(da9052->adapter, i2cmsg, 2);
148 +#ifdef DA9052_I2C_BUG_WORKAROUND
149 + if (!da9052_is_i2c_reg_safe(msg->addr)) {
150 + /* Prepare additional message to flush chip I2C registers */
151 + i2cmsg[2].addr = da9052->slave_addr;
153 + i2cmsg[2].flags = 0; /* Write operation */
154 + i2cmsg[2].buf = (unsigned char *)i2c_flush_data;
156 + /* Read transfer with additional flush write */
157 + ret = i2c_transfer(da9052->adapter, &i2cmsg[2], 1);
162 - dev_info(&da9052->i2c_client->dev,\
163 - "2 - %s:master_xfer Failed!!\n", __func__);
164 + dev_info(&da9052->i2c_client->dev,
165 + "2 - %s:master_xfer Failed!!\n", __func__);
169 - msg->data = *i2cmsg[1].buf;
171 + msg->data = buf[1];
175 int da9052_i2c_write_many(struct da9052 *da9052,
176 struct da9052_ssc_msg *sscmsg, int msg_no)
179 struct i2c_msg i2cmsg;
180 - unsigned char data_buf[MAX_READ_WRITE_CNT+1];
181 - struct da9052_ssc_msg ctrlb_msg;
182 - struct da9052_ssc_msg *msg_queue = sscmsg;
184 - /* Flag to check if requested registers are contiguous */
185 - unsigned char cont_data = 1;
186 - unsigned char cnt = 0;
188 - /* Check if requested registers are contiguous */
189 - for (cnt = 1; cnt < msg_no; cnt++) {
190 - if ((msg_queue[cnt].addr - msg_queue[cnt-1].addr) != 1) {
191 - /* Difference is not 1, i.e. non-contiguous registers */
197 - if (cont_data == 0) {
198 - /* Requested registers are non-contiguous */
199 - for (cnt = 0; cnt < msg_no; cnt++) {
200 - ret = da9052->write(da9052, &msg_queue[cnt]);
207 - * Requested registers are contiguous
208 - * or PAGE WRITE sequence of I2C transactions is as below
209 - * (slave_addr + reg_addr + data_1 + data_2 + ...)
210 - * First read current WRITE MODE via CONTROL_B register of DA9052
212 - ctrlb_msg.addr = DA9052_CONTROLB_REG;
213 - ctrlb_msg.data = 0x0;
214 - ret = da9052->read(da9052, &ctrlb_msg);
219 - /* Check if PAGE WRITE mode is set */
220 - if (ctrlb_msg.data & DA9052_CONTROLB_WRITEMODE) {
221 - /* REPEAT WRITE mode is configured */
222 - /* Now set DA9052 into PAGE WRITE mode */
223 - ctrlb_msg.data &= ~DA9052_CONTROLB_WRITEMODE;
224 - ret = da9052->write(da9052, &ctrlb_msg);
230 - /* Put first register address */
231 - data_buf[0] = msg_queue[0].addr;
233 - for (cnt = 0; cnt < msg_no; cnt++)
234 - data_buf[cnt+1] = msg_queue[cnt].data;
236 - /* Construct a i2c msg for PAGE WRITE */
238 + unsigned char *data_ptr;
239 +#ifdef DA9052_I2C_BUG_WORKAROUND
240 + unsigned char data_buf[2 * MAX_READ_WRITE_CNT + 2];
242 + unsigned char data_buf[2 * MAX_READ_WRITE_CNT];
245 + BUG_ON(msg_no < 0);
246 + BUG_ON(msg_no >= MAX_READ_WRITE_CNT);
248 + /* Construct a i2c msg for REPEATED WRITE */
249 i2cmsg.addr = da9052->slave_addr ;
250 - /* First register address + all data*/
251 - i2cmsg.len = (msg_no + 1);
252 + i2cmsg.len = 2*msg_no;
253 i2cmsg.buf = data_buf;
255 - /*To write the data on I2C set flag to zero */
258 + for (data_ptr = data_buf; msg_no; msg_no--) {
259 + safe &= da9052_is_i2c_reg_safe(sscmsg->addr);
260 + *(data_ptr++) = sscmsg->addr;
261 + *(data_ptr++) = sscmsg->data;
264 +#ifdef DA9052_I2C_BUG_WORKAROUND
267 + *(data_ptr++) = i2c_flush_data[0];
268 + *data_ptr = i2c_flush_data[1];
272 /* Start the i2c transfer by calling host i2c driver function */
273 ret = i2c_transfer(da9052->adapter, &i2cmsg, 1);
275 - dev_info(&da9052->i2c_client->dev,\
276 - "1 - i2c_transfer function falied in [%s]!!!\n", __func__);
277 + dev_info(&da9052->i2c_client->dev,
278 + "1 - i2c_transfer function falied in [%s]!!!\n",
283 @@ -255,83 +271,82 @@ int da9052_i2c_write_many(struct da9052 *da9052,
284 int da9052_i2c_read_many(struct da9052 *da9052,
285 struct da9052_ssc_msg *sscmsg, int msg_no)
288 - struct i2c_msg i2cmsg;
289 +#ifdef DA9052_I2C_BUG_WORKAROUND
290 + struct i2c_msg i2cmsg[2 * MAX_READ_WRITE_CNT];
292 + struct i2c_msg i2cmsg[2 * MAX_READ_WRITE_CNT + 1];
294 unsigned char data_buf[MAX_READ_WRITE_CNT];
295 - struct da9052_ssc_msg *msg_queue = sscmsg;
296 + struct i2c_msg *msg_ptr = i2cmsg;
298 - /* Flag to check if requested registers are contiguous */
299 - unsigned char cont_data = 1;
300 - unsigned char cnt = 0;
302 - /* Check if requested registers are contiguous */
303 - for (cnt = 1; cnt < msg_no; cnt++) {
304 - if ((msg_queue[cnt].addr - msg_queue[cnt-1].addr) != 1) {
305 - /* Difference is not 1, i.e. non-contiguous registers */
309 + int last_reg_read = -2;
312 + BUG_ON(msg_no < 0);
313 + BUG_ON(msg_no >= MAX_READ_WRITE_CNT);
315 + /* Construct a i2c msgs for a da9052 driver ssc message request */
316 + for (cnt = 0; cnt < msg_no; cnt++) {
317 + if ((int)sscmsg[cnt].addr != last_reg_read + 1) {
318 + safe &= da9052_is_i2c_reg_safe(sscmsg[cnt].addr);
320 + /* Build messages for first register, read in a row */
321 + msg_ptr->addr = da9052->slave_addr;
323 + msg_ptr->buf = &sscmsg[cnt].addr;
324 + msg_ptr->flags = 0;
327 + msg_ptr->addr = da9052->slave_addr;
329 + msg_ptr->buf = &data_buf[cnt];
330 + msg_ptr->flags = I2C_M_RD;
333 + last_reg_read = sscmsg[cnt].addr;
335 + /* Increase read counter for consecutive reads */
336 + (msg_ptr - 1)->len++;
340 - if (cont_data == 0) {
341 - /* Requested registers are non-contiguous */
342 - for (cnt = 0; cnt < msg_no; cnt++) {
343 - ret = da9052->read(da9052, &msg_queue[cnt]);
345 - dev_info(&da9052->i2c_client->dev,\
346 - "Error in %s", __func__);
351 +#ifdef DA9052_I2C_BUG_WORKAROUND
353 + /* Prepare additional message to flush chip I2C registers */
354 + msg_ptr->addr = da9052->slave_addr;
356 + msg_ptr->flags = 0; /* Write operation */
357 + msg_ptr->buf = (unsigned char *)i2c_flush_data;
362 - * We want to perform PAGE READ via I2C
363 - * For PAGE READ sequence of I2C transactions is as below
364 - * (slave_addr + reg_addr) + (slave_addr + data_1 + data_2 + ...)
366 - /* Copy address of first register */
367 - data_buf[0] = msg_queue[0].addr;
369 - /* Construct a i2c msg for first transaction of PAGE READ i.e. write */
370 - i2cmsg.addr = da9052->slave_addr ;
372 - i2cmsg.buf = data_buf;
374 - /*To write the data on I2C set flag to zero */
377 - /* Start the i2c transfer by calling host i2c driver function */
378 - ret = i2c_transfer(da9052->adapter, &i2cmsg, 1);
380 - dev_info(&da9052->i2c_client->dev,\
381 - "1 - i2c_transfer function falied in [%s]!!!\n", __func__);
385 + /* Using one transfer seems not to work well with D9052.
386 + * Read transfer with additional flush write
387 + * Performing many transfers is stable on D9052
389 + for (cnt = 0; cnt < (msg_ptr - i2cmsg) - 1; cnt += 2) {
390 + ret = i2c_transfer(da9052->adapter, &i2cmsg[cnt], 2);
392 + dev_info(&da9052->i2c_client->dev,
393 + "2 - %s:master_xfer Failed on msg[%d]!!\n",
399 - /* Now Read the data from da9052 */
400 - /* Construct a i2c msg for second transaction of PAGE READ i.e. read */
401 - i2cmsg.addr = da9052->slave_addr ;
402 - i2cmsg.len = msg_no;
403 - i2cmsg.buf = data_buf;
405 - /*To read the data on I2C set flag to I2C_M_RD */
406 - i2cmsg.flags = I2C_M_RD;
408 - /* Start the i2c transfer by calling host i2c driver function */
409 - ret = i2c_transfer(da9052->adapter,
412 - dev_info(&da9052->i2c_client->dev,\
413 - "2 - i2c_transfer function falied in [%s]!!!\n", __func__);
415 + if (cnt < (msg_ptr - i2cmsg)) {
416 + ret = i2c_transfer(da9052->adapter, &i2cmsg[cnt], 1);
418 + dev_info(&da9052->i2c_client->dev,
419 + "2 - %s:master_xfer Failed on msg[%d]!!\n",
425 - /* Gather READ data */
426 for (cnt = 0; cnt < msg_no; cnt++)
427 sscmsg[cnt].data = data_buf[cnt];