summaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/linux-imx-2.6.35.3/1140-ENGR00162711-DA9053-Add-dummy-write-for-DA9053-I2C.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes-kernel/linux/linux-imx-2.6.35.3/1140-ENGR00162711-DA9053-Add-dummy-write-for-DA9053-I2C.patch')
-rwxr-xr-xrecipes-kernel/linux/linux-imx-2.6.35.3/1140-ENGR00162711-DA9053-Add-dummy-write-for-DA9053-I2C.patch434
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 @@
1From 7c0c7fc3189f456f1899bf4aa0a27e3f71f6a808 Mon Sep 17 00:00:00 2001
2From: Wayne Zou <b36644@freescale.com>
3Date: Mon, 21 Nov 2011 14:44:33 +0800
4Subject: [PATCH] ENGR00162711 DA9053: Add dummy write for DA9053 I2C register access
5
6DA9053 i2c issue: Rarely the i2c interface of DA9053 hang and it can
7not be recovered if not power off totally. The Dialog suggests adding
8dummy write for DA9053 I2C register access, in order to decrease the failure
9of DA9053 register access and possibility of i2c failure.
10
11Signed-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
17diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c
18index 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--
4331.5.4.4
434