diff options
Diffstat (limited to 'recipes-kernel/linux/linux-imx-2.6.35.3/1140-ENGR00162711-DA9053-Add-dummy-write-for-DA9053-I2C.patch')
-rwxr-xr-x | recipes-kernel/linux/linux-imx-2.6.35.3/1140-ENGR00162711-DA9053-Add-dummy-write-for-DA9053-I2C.patch | 434 |
1 files changed, 0 insertions, 434 deletions
diff --git a/recipes-kernel/linux/linux-imx-2.6.35.3/1140-ENGR00162711-DA9053-Add-dummy-write-for-DA9053-I2C.patch b/recipes-kernel/linux/linux-imx-2.6.35.3/1140-ENGR00162711-DA9053-Add-dummy-write-for-DA9053-I2C.patch deleted file mode 100755 index 908a360..0000000 --- a/recipes-kernel/linux/linux-imx-2.6.35.3/1140-ENGR00162711-DA9053-Add-dummy-write-for-DA9053-I2C.patch +++ /dev/null | |||
@@ -1,434 +0,0 @@ | |||
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 | |||