]> code.ossystems Code Review - meta-freescale.git/blob
908a3608750db278e93bdb703029d5bd843d0248
[meta-freescale.git] /
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
5
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.
10
11 Signed-off-by: Wayne Zou <b36644@freescale.com>
12 (cherry picked from commit bfd7cba1eeb46977b18a3c5fa65d812817a8294d)
13 ---
14  drivers/mfd/da9052-i2c.c |  317 ++++++++++++++++++++++++----------------------
15  1 files changed, 166 insertions(+), 151 deletions(-)
16
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;
22  
23  #define I2C_CONNECTED 0
24  
25 +#define DA9052_I2C_BUG_WORKAROUND
26 +
27  static int da9052_i2c_is_connected(void)
28  {
29         struct da9052_ssc_msg msg;
30 @@ -76,6 +78,15 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client,
31  
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__);
40 +                       return -ENODEV;
41 +               }
42 +
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)
47         return 0;
48  }
49  
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,
70 +};
71 +/* Enable safe register addresses */
72 +static inline int da9052_is_i2c_reg_safe(unsigned char reg)
73 +{
74 +       return safe_table[reg];
75 +}
76 +#endif
77 +
78  int da9052_i2c_write(struct da9052 *da9052, struct da9052_ssc_msg *msg)
79  {
80         struct i2c_msg i2cmsg;
81 -       unsigned char buf[2] = {0};
82 +       unsigned char buf[4] = {0};
83         int ret = 0;
84  
85 -       /* Copy the ssc msg to local character buffer */
86 -       buf[0] = msg->addr;
87 -       buf[1] = msg->data;
88 -
89         /*Construct a i2c msg for a da9052 driver ssc message request */
90         i2cmsg.addr  = da9052->slave_addr;
91 -       i2cmsg.len   = 2;
92         i2cmsg.buf   = buf;
93 -
94 -       /* To write the data on I2C set flag to zero */
95         i2cmsg.flags = 0;
96 +       i2cmsg.len   = 2;
97 +
98 +       /* Copy the ssc msg and additional data to flush chip I2C registers */
99 +       buf[0] = msg->addr;
100 +       buf[1] = msg->data;
101  
102 +#ifdef DA9052_I2C_BUG_WORKAROUND
103 +       if (!da9052_is_i2c_reg_safe(msg->addr)) {
104 +               i2cmsg.len = 4;
105 +               buf[2] = i2c_flush_data[0];
106 +               buf[3] = i2c_flush_data[1];
107 +       }
108 +#endif
109         /* Start the i2c transfer by calling host i2c driver function */
110         ret = i2c_transfer(da9052->adapter, &i2cmsg, 1);
111 -
112         if (ret < 0) {
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)
116  
117  int da9052_i2c_read(struct da9052 *da9052, struct da9052_ssc_msg *msg)
118  {
119 -
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];
124         int ret = 0;
125  
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 ;
129         i2cmsg[0].len   = 1;
130         i2cmsg[0].buf   = &buf[0];
131 -
132 -       /*To write the data on I2C set flag to zero */
133         i2cmsg[0].flags = 0;
134  
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 ;
138         i2cmsg[1].len   = 1;
139         i2cmsg[1].buf   = &buf[1];
140 -
141 -       /*To read the data on I2C set flag to I2C_M_RD */
142         i2cmsg[1].flags = I2C_M_RD;
143  
144 -       /* Start the i2c transfer by calling host i2c driver function */
145 +       /* Standard read transfer */
146         ret = i2c_transfer(da9052->adapter, i2cmsg, 2);
147 +
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;
152 +               i2cmsg[2].len = 2;
153 +               i2cmsg[2].flags = 0;                     /* Write operation */
154 +               i2cmsg[2].buf = (unsigned char *)i2c_flush_data;
155 +
156 +               /* Read transfer with additional flush write */
157 +               ret = i2c_transfer(da9052->adapter, &i2cmsg[2], 1);
158 +       }
159 +#endif
160 +
161         if (ret < 0) {
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__);
166                 return ret;
167         }
168  
169 -       msg->data = *i2cmsg[1].buf;
170 -
171 +       msg->data = buf[1];
172         return 0;
173  }
174  
175  int da9052_i2c_write_many(struct da9052 *da9052,
176         struct da9052_ssc_msg *sscmsg, int msg_no)
177  {
178 -
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;
183         int ret = 0;
184 -       /* Flag to check if requested registers are contiguous */
185 -       unsigned char cont_data = 1;
186 -       unsigned char cnt = 0;
187 -
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 */
192 -                       cont_data = 0;
193 -                       break;
194 -               }
195 -       }
196 -
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]);
201 -                       if (ret != 0)
202 -                               return ret;
203 -               }
204 -               return 0;
205 -       }
206 -       /*
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
211 -       */
212 -       ctrlb_msg.addr = DA9052_CONTROLB_REG;
213 -       ctrlb_msg.data = 0x0;
214 -       ret = da9052->read(da9052, &ctrlb_msg);
215 -
216 -       if (ret != 0)
217 -               return ret;
218 -
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);
225 -
226 -               if (ret != 0)
227 -                       return ret;
228 -       }
229 -
230 -        /* Put first register address */
231 -       data_buf[0] = msg_queue[0].addr;
232 -
233 -       for (cnt = 0; cnt < msg_no; cnt++)
234 -               data_buf[cnt+1] = msg_queue[cnt].data;
235 -
236 -       /* Construct a i2c msg for PAGE WRITE */
237 +       int safe = 1;
238 +       unsigned char *data_ptr;
239 +#ifdef DA9052_I2C_BUG_WORKAROUND
240 +       unsigned char data_buf[2 * MAX_READ_WRITE_CNT + 2];
241 +#else
242 +       unsigned char data_buf[2 * MAX_READ_WRITE_CNT];
243 +#endif
244 +
245 +       BUG_ON(msg_no < 0);
246 +       BUG_ON(msg_no >= MAX_READ_WRITE_CNT);
247 +
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;
254 -
255 -       /*To write the data on I2C set flag to zero */
256         i2cmsg.flags = 0;
257  
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;
262 +               sscmsg++;
263 +       }
264 +#ifdef DA9052_I2C_BUG_WORKAROUND
265 +       if (!safe) {
266 +               i2cmsg.len += 2;
267 +               *(data_ptr++) = i2c_flush_data[0];
268 +               *data_ptr = i2c_flush_data[1];
269 +       }
270 +#endif
271 +
272         /* Start the i2c transfer by calling host i2c driver function */
273         ret = i2c_transfer(da9052->adapter, &i2cmsg, 1);
274         if (ret < 0) {
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",
279 +                        __func__);
280                 return ret;
281         }
282  
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)
286  {
287 -
288 -       struct i2c_msg i2cmsg;
289 +#ifdef DA9052_I2C_BUG_WORKAROUND
290 +       struct i2c_msg i2cmsg[2 * MAX_READ_WRITE_CNT];
291 +#else
292 +       struct i2c_msg i2cmsg[2 * MAX_READ_WRITE_CNT + 1];
293 +#endif
294         unsigned char data_buf[MAX_READ_WRITE_CNT];
295 -       struct da9052_ssc_msg *msg_queue = sscmsg;
296 +       struct i2c_msg *msg_ptr = i2cmsg;
297         int ret = 0;
298 -       /* Flag to check if requested registers are contiguous */
299 -       unsigned char cont_data = 1;
300 -       unsigned char cnt = 0;
301 -
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 */
306 -                       cont_data = 0;
307 -                       break;
308 +       int safe = 1;
309 +       int last_reg_read = -2;
310 +       int cnt;
311 +
312 +       BUG_ON(msg_no < 0);
313 +       BUG_ON(msg_no >= MAX_READ_WRITE_CNT);
314 +
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);
319 +
320 +                       /* Build messages for first register, read in a row */
321 +                       msg_ptr->addr  = da9052->slave_addr;
322 +                       msg_ptr->len   = 1;
323 +                       msg_ptr->buf   = &sscmsg[cnt].addr;
324 +                       msg_ptr->flags = 0;
325 +                       msg_ptr++;
326 +
327 +                       msg_ptr->addr  = da9052->slave_addr;
328 +                       msg_ptr->len   = 1;
329 +                       msg_ptr->buf   = &data_buf[cnt];
330 +                       msg_ptr->flags = I2C_M_RD;
331 +                       msg_ptr++;
332 +
333 +                       last_reg_read = sscmsg[cnt].addr;
334 +               } else {
335 +                       /* Increase read counter for consecutive reads */
336 +                       (msg_ptr - 1)->len++;
337                 }
338         }
339  
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]);
344 -                       if (ret != 0) {
345 -                               dev_info(&da9052->i2c_client->dev,\
346 -                               "Error in %s", __func__);
347 -                               return ret;
348 -                       }
349 -               }
350 -               return 0;
351 +#ifdef DA9052_I2C_BUG_WORKAROUND
352 +       if (!safe) {
353 +               /* Prepare additional message to flush chip I2C registers */
354 +               msg_ptr->addr = da9052->slave_addr;
355 +               msg_ptr->len = 2;
356 +               msg_ptr->flags = 0;      /* Write operation */
357 +               msg_ptr->buf = (unsigned char *)i2c_flush_data;
358 +               msg_ptr++;
359         }
360 -
361 -       /*
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 + ...)
365 -       */
366 -       /* Copy address of first register */
367 -       data_buf[0] = msg_queue[0].addr;
368 -
369 -       /* Construct a i2c msg for first transaction of PAGE READ i.e. write */
370 -       i2cmsg.addr  = da9052->slave_addr ;
371 -       i2cmsg.len   = 1;
372 -       i2cmsg.buf   = data_buf;
373 -
374 -       /*To write the data on I2C set flag to zero */
375 -       i2cmsg.flags = 0;
376 -
377 -       /* Start the i2c transfer by calling host i2c driver function */
378 -       ret = i2c_transfer(da9052->adapter, &i2cmsg, 1);
379 -       if (ret < 0) {
380 -               dev_info(&da9052->i2c_client->dev,\
381 -               "1 - i2c_transfer function falied in [%s]!!!\n", __func__);
382 -               return ret;
383 +#endif
384 +
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
388 +     */
389 +       for (cnt = 0; cnt < (msg_ptr - i2cmsg) - 1; cnt += 2) {
390 +               ret = i2c_transfer(da9052->adapter, &i2cmsg[cnt], 2);
391 +               if (ret < 0) {
392 +                       dev_info(&da9052->i2c_client->dev,
393 +                                "2 - %s:master_xfer Failed on msg[%d]!!\n",
394 +                               __func__, cnt);
395 +                       return ret;
396 +               }
397         }
398 -
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;
404 -
405 -       /*To read the data on I2C set flag to I2C_M_RD */
406 -       i2cmsg.flags = I2C_M_RD;
407 -
408 -       /* Start the i2c transfer by calling host i2c driver function */
409 -       ret = i2c_transfer(da9052->adapter,
410 -               &i2cmsg, 1);
411 -       if (ret < 0) {
412 -               dev_info(&da9052->i2c_client->dev,\
413 -               "2 - i2c_transfer function falied in [%s]!!!\n", __func__);
414 -               return ret;
415 +       if (cnt < (msg_ptr - i2cmsg)) {
416 +               ret = i2c_transfer(da9052->adapter, &i2cmsg[cnt], 1);
417 +               if (ret < 0) {
418 +                       dev_info(&da9052->i2c_client->dev,
419 +                                "2 - %s:master_xfer Failed on msg[%d]!!\n",
420 +                               __func__, cnt);
421 +                       return ret;
422 +               }
423         }
424  
425 -       /* Gather READ data */
426         for (cnt = 0; cnt < msg_no; cnt++)
427                 sscmsg[cnt].data = data_buf[cnt];
428 -
429         return 0;
430  }
431  
432 -- 
433 1.5.4.4
434