40b1f6dfe4a43f615fcdb9db5c46dd05c19324a3
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / input / touchscreen / ist30xxb / ist30xxb_update.c
1 /*\r
2  *  Copyright (C) 2010,Imagis Technology Co. Ltd. All Rights Reserved.\r
3  *\r
4  *  This program is free software; you can redistribute it and/or modify\r
5  *  it under the terms of the GNU General Public License as published by\r
6  *  the Free Software Foundation; either version 2 of the License, or\r
7  *  (at your option) any later version.\r
8  *\r
9  *  This program is distributed in the hope that it will be useful,\r
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  *  GNU General Public License for more details.\r
13  *\r
14  */\r
15 \r
16 #include <linux/i2c.h>\r
17 #include <linux/delay.h>\r
18 #include <linux/slab.h>\r
19 #include <linux/firmware.h>\r
20 #include <asm/unaligned.h>\r
21 \r
22 #include <linux/input/ist30xxb.h>\r
23 #include "ist30xxb_update.h"\r
24 \r
25 #if IST30XX_DEBUG\r
26 #include "ist30xxb_misc.h"\r
27 #endif\r
28 \r
29 #if IST30XX_INTERNAL_BIN\r
30 #if defined(CONFIG_MACH_POCKET2)\r
31 #include "IST30xxB_FW_Star2_Ver0002.h"\r
32 #elif defined(CONFIG_MACH_YOUNG2)\r
33 #include "ist30xxb_fw_young2_ver0001.h"\r
34 #elif defined(CONFIG_MACH_PIKEAYOUNG2DTV)\r
35 #include "ist30xxb_fw_pikeayoung2dtv_ver0001.h"\r
36 #elif defined(CONFIG_MACH_CORSICA_VE)
37 #include "IST30xxB_FW_Corsica_VE_Ver0007.h"\r
38 #elif defined(CONFIG_MACH_VIVALTO)
39 #include "IST30xxB_FW_vivalto_Ver0001_fw.h"\r
40 #endif\r
41 #endif // IST30XX_INTERNAL_BIN\r
42 \r
43 struct ist30xx_tags *ts_tags;\r
44 \r
45 u32 ist30xx_fw_ver = 0;\r
46 u32 ist30xx_param_ver = 0;\r
47 \r
48 extern struct ist30xx_data *ts_data;\r
49 \r
50 extern void ist30xx_disable_irq(struct ist30xx_data *data);\r
51 extern void ist30xx_enable_irq(struct ist30xx_data *data);\r
52 \r
53 \r
54 int ist30xx_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,\r
55                          int msg_num, u8 *cmd_buf)\r
56 {\r
57         int ret = 0;\r
58         int idx = msg_num - 1;\r
59         int size = msgs[idx].len;\r
60         u8 *msg_buf = NULL;\r
61         u8 *pbuf = NULL;\r
62         int trans_size, max_size = 0;\r
63 \r
64         if (msg_num == WRITE_CMD_MSG_LEN)\r
65                 max_size = I2C_MAX_WRITE_SIZE;\r
66         else if (msg_num == READ_CMD_MSG_LEN)\r
67                 max_size = I2C_MAX_READ_SIZE;\r
68 \r
69         if (max_size == 0) {\r
70                 tsp_err("%s() : transaction size(%d)\n", __func__, max_size);\r
71                 return -EINVAL;\r
72         }\r
73 \r
74         if (msg_num == WRITE_CMD_MSG_LEN) {\r
75                 msg_buf = kmalloc(max_size + IST30XX_ADDR_LEN, GFP_KERNEL);\r
76                 if (!msg_buf)\r
77                         return -ENOMEM;\r
78                 memcpy(msg_buf, cmd_buf, IST30XX_ADDR_LEN);\r
79                 pbuf = msgs[idx].buf;\r
80         }\r
81 \r
82         while (size > 0) {\r
83                 trans_size = (size >= max_size ? max_size : size);\r
84 \r
85                 msgs[idx].len = trans_size;\r
86                 if (msg_num == WRITE_CMD_MSG_LEN) {\r
87                         memcpy(&msg_buf[IST30XX_ADDR_LEN], pbuf, trans_size);\r
88                         msgs[idx].buf = msg_buf;\r
89                         msgs[idx].len += IST30XX_ADDR_LEN;\r
90                 }\r
91                 ret = i2c_transfer(adap, msgs, msg_num);\r
92                 if (ret != msg_num) {\r
93                         tsp_err("%s() : i2c_transfer failed(%d), num=%d\n",\r
94                                 __func__, ret, msg_num);\r
95                         break;\r
96                 }\r
97 \r
98                 if (msg_num == WRITE_CMD_MSG_LEN)\r
99                         pbuf += trans_size;\r
100                 else\r
101                         msgs[idx].buf += trans_size;\r
102 \r
103                 size -= trans_size;\r
104         }\r
105 \r
106         if (msg_num == WRITE_CMD_MSG_LEN)\r
107                 kfree(msg_buf);\r
108 \r
109         return ret;\r
110 }\r
111 \r
112 int ist30xx_read_buf(struct i2c_client *client, u32 cmd, u32 *buf, u16 len)\r
113 {\r
114         int ret, i;\r
115         u32 le_reg = cpu_to_be32(cmd);\r
116 \r
117         struct i2c_msg msg[READ_CMD_MSG_LEN] = {\r
118                 {\r
119                         .addr = client->addr,\r
120                         .flags = 0,\r
121                         .len = IST30XX_ADDR_LEN,\r
122                         .buf = (u8 *)&le_reg,\r
123                 },\r
124                 {\r
125                         .addr = client->addr,\r
126                         .flags = I2C_M_RD,\r
127                         .len = len * IST30XX_DATA_LEN,\r
128                         .buf = (u8 *)buf,\r
129                 },\r
130         };\r
131 \r
132         ret = ist30xx_i2c_transfer(client->adapter, msg, READ_CMD_MSG_LEN, NULL);\r
133         if (ret != READ_CMD_MSG_LEN)\r
134                 return -EIO;\r
135 \r
136         for (i = 0; i < len; i++)\r
137                 buf[i] = cpu_to_be32(buf[i]);\r
138 \r
139         return 0;\r
140 }\r
141 \r
142 int ist30xx_write_buf(struct i2c_client *client, u32 cmd, u32 *buf, u16 len)\r
143 {\r
144         int i;\r
145         int ret;\r
146         struct i2c_msg msg;\r
147         u8 cmd_buf[IST30XX_ADDR_LEN];\r
148         u8 msg_buf[IST30XX_DATA_LEN * (len + 1)];\r
149 \r
150         put_unaligned_be32(cmd, cmd_buf);\r
151 \r
152         if (len > 0) {\r
153                 for (i = 0; i < len; i++)\r
154                         put_unaligned_be32(buf[i], msg_buf + (i * IST30XX_DATA_LEN));\r
155         } else {\r
156                 /* then add dummy data(4byte) */\r
157                 put_unaligned_be32(0, msg_buf);\r
158                 len = 1;\r
159         }\r
160 \r
161         msg.addr = client->addr;\r
162         msg.flags = 0;\r
163         msg.len = IST30XX_DATA_LEN * len;\r
164         msg.buf = msg_buf;\r
165 \r
166         ret = ist30xx_i2c_transfer(client->adapter, &msg, WRITE_CMD_MSG_LEN, cmd_buf);\r
167         if (ret != WRITE_CMD_MSG_LEN)\r
168                 return -EIO;\r
169 \r
170         return 0;\r
171 }\r
172 \r
173 int ist30xxb_burst_read(struct i2c_client *client, u32 addr,\r
174                         u32 *buf32, int len)\r
175 {\r
176         int ret = 0;\r
177         int i;\r
178         int max_len = I2C_MAX_READ_SIZE / IST30XX_DATA_LEN;\r
179 \r
180         addr |= IST30XXB_BURST_ACCESS;\r
181 \r
182         for (i = 0; i < len; i += max_len) {\r
183                 if (len < max_len) max_len = len;\r
184 \r
185                 ret = ist30xx_read_buf(client, addr, buf32, max_len);\r
186                 if (ret) {\r
187                         tsp_err("Burst fail, addr: %x\n", __func__, addr);\r
188                         return ret;\r
189                 }\r
190 \r
191                 addr += max_len * IST30XX_DATA_LEN;\r
192                 buf32 += max_len;\r
193         }\r
194 \r
195         return 0;\r
196 }\r
197 \r
198 #define IST30XXB_ISP_READ       (1)\r
199 #define IST30XXB_ISP_WRITE      (2)\r
200 #define IST30XXB_ISP_ERASE_ALL  (3)\r
201 #define IST30XXB_ISP_ERASE_PAGE (4)\r
202 \r
203 int ist30xxb_isp_enable(bool enable)\r
204 {\r
205         int ret = 0;\r
206 \r
207         if (enable) {\r
208                 ret = ist30xx_write_cmd(ts_data->client, IST30XXB_REG_EEPISPEN, 0x3);\r
209                 if (ret) return ret;\r
210 \r
211                 ret = ist30xx_write_cmd(ts_data->client, IST30XXB_REG_LDOOSC, 0xF4C8);\r
212                 if (ret) return ret;\r
213 \r
214                 ret = ist30xx_write_cmd(ts_data->client, IST30XXB_REG_CLKDIV, 0x3);\r
215                 if (ret) return ret;\r
216 \r
217                 msleep(5);\r
218         } else {\r
219                 ret = ist30xx_write_cmd(ts_data->client, IST30XXB_REG_EEPISPEN, 0x2);\r
220                 if (ret) return ret;\r
221 \r
222                 msleep(1);\r
223         }\r
224 \r
225         return 0;\r
226 }\r
227 \r
228 int ist30xxb_isp_mode(int mode)\r
229 {\r
230         int ret = 0;\r
231         u32 val = 0;\r
232 \r
233         switch (mode) {\r
234         case IST30XXB_ISP_READ:\r
235                 val = 0x1C0;\r
236                 break;\r
237         case IST30XXB_ISP_WRITE:\r
238                 val = 0x1A8;\r
239                 break;\r
240         case IST30XXB_ISP_ERASE_ALL:\r
241                 val = 0x1A7;\r
242                 break;\r
243         case IST30XXB_ISP_ERASE_PAGE:\r
244                 val = 0x1A3;\r
245                 break;\r
246         default:\r
247                 tsp_err("ISP fail, unknown mode\n");\r
248                 return -EINVAL;\r
249         }\r
250 \r
251         ret = ist30xx_write_cmd(ts_data->client, IST30XXB_REG_EEPMODE, val);\r
252         if (ret) {\r
253                 tsp_err("ISP fail, IST30XXB_REG_EEPMODE\n");\r
254                 return ret;\r
255         }\r
256 \r
257         return 0;\r
258 }\r
259 \r
260 int ist30xxb_isp_erase(struct i2c_client *client, int mode, u32 addr)\r
261 {\r
262         int ret = 0;\r
263         u32 val = 0x1A0;\r
264         u8 buf[EEPROM_PAGE_SIZE] = { 0, };\r
265 \r
266         ret = ist30xxb_isp_mode(mode);\r
267         if (ret) return ret;\r
268 \r
269         ret = ist30xx_write_cmd(client, IST30XXB_REG_EEPADDR, addr);\r
270         if (ret) {\r
271                 tsp_err("ISP fail, IST30XXB_REG_EEPADDR\n");\r
272                 return ret;\r
273         }\r
274 \r
275         val = (EEPROM_PAGE_SIZE / IST30XX_DATA_LEN);\r
276         ret = ist30xx_write_buf(client, IST30XXB_REG_EEPWDAT, (u32 *)buf, val);\r
277         if (ret) {\r
278                 tsp_err("ISP fail, IST30XXB_REG_EEPWDAT\n");\r
279                 return ret;\r
280         }\r
281 \r
282         msleep(30);\r
283 \r
284         return 0;\r
285 }\r
286 \r
287 int ist30xxb_isp_write(struct i2c_client *client, u32 addr,\r
288                        const u32 *buf32, int len)\r
289 {\r
290         int ret = 0;\r
291 \r
292         ret = ist30xx_write_cmd(client, IST30XXB_REG_EEPADDR, addr);\r
293         if (ret) {\r
294                 tsp_err("ISP fail, IST30XXB_REG_EEPADDR\n");\r
295                 return ret;\r
296         }\r
297 \r
298         ret = ist30xx_write_buf(client, IST30XXB_REG_EEPWDAT, (u32 *)buf32, len);\r
299         if (ret) {\r
300                 tsp_err("ISP fail, IST30XXB_REG_EEPWDAT\n");\r
301                 return ret;\r
302         }\r
303 \r
304         return 0;\r
305 }\r
306 \r
307 int ist30xxb_isp_read(struct i2c_client *client, u32 addr,\r
308                       u32 *buf32, int len)\r
309 {\r
310         int ret = 0;\r
311         int i;\r
312         int max_len = I2C_MAX_READ_SIZE / IST30XX_DATA_LEN;\r
313 \r
314         for (i = 0; i < len; i += max_len) {\r
315                 if (len < max_len) max_len = len;\r
316 \r
317                 /* IST30xxB ISP read mode */\r
318                 ret = ist30xxb_isp_mode(IST30XXB_ISP_READ);\r
319                 if (ret) return ret;\r
320 \r
321                 ret = ist30xx_write_cmd(client, IST30XXB_REG_EEPADDR, addr);\r
322                 if (ret) {\r
323                         tsp_err("ISP fail, IST30XXB_REG_EEPADDR\n");\r
324                         return ret;\r
325                 }\r
326 \r
327                 ret = ist30xx_read_buf(client, IST30XXB_REG_EEPRDAT, buf32, max_len);\r
328                 if (ret) {\r
329                         tsp_err("ISP fail, IST30XXB_REG_EEPWDAT\n");\r
330                         return ret;\r
331                 }\r
332 \r
333                 addr += max_len * IST30XX_DATA_LEN;\r
334                 buf32 += max_len;\r
335         }\r
336 \r
337         return 0;\r
338 }\r
339 \r
340 int ist30xxb_cmd_read_chksum(struct i2c_client *client,\r
341                              u32 start_addr, u32 end_addr, u32 *chksum)\r
342 {\r
343         int ret = 0;\r
344         u32 val = (1 << 31); // Chkecksum enable\r
345 \r
346         val |= start_addr;\r
347         val |= (end_addr / IST30XX_DATA_LEN - 1) << 16;\r
348 \r
349         ret = ist30xx_write_cmd(client, IST30XXB_REG_CHKSMOD, val);\r
350         if (ret) {\r
351                 tsp_err("ISP fail, IST30XXB_REG_CHKSMOD (%x)\n", val);\r
352                 return ret;\r
353         }\r
354 \r
355         msleep(10);\r
356 \r
357         ret = ist30xx_read_cmd(client, IST30XXB_REG_CHKSDAT, chksum);\r
358         if (ret) {\r
359                 tsp_err("ISP fail, IST30XXB_REG_CHKSDAT (%x)\n", chksum);\r
360                 return ret;\r
361         }\r
362 \r
363         tsp_verb("chksum: %x (%x~%x)\n", *chksum, start_addr, end_addr);\r
364 \r
365         return 0;\r
366 }\r
367 \r
368 int ist30xxb_read_chksum(struct i2c_client *client, u32 *chksum)\r
369 {\r
370         int ret = 0;\r
371         u32 start_addr, end_addr;\r
372         u32 chksum1 = 0, chksum2 = 0;\r
373 \r
374         start_addr = 0;\r
375         end_addr = ts_data->tags.flag_addr;\r
376         ret = ist30xxb_cmd_read_chksum(client, start_addr, end_addr, &chksum1);\r
377         if (ret) return ret;\r
378 \r
379         start_addr = ts_data->tags.flag_addr + ts_data->tags.flag_size;\r
380         end_addr = ts_data->tags.sensor2_addr + ts_data->tags.sensor2_size;\r
381         ret = ist30xxb_cmd_read_chksum(client, start_addr, end_addr, &chksum2);\r
382         if (ret) return ret;\r
383 \r
384         *chksum = chksum1 | (chksum2 << 16);\r
385 \r
386         tsp_info("Chksum: %x(%x~%x, %x~%x)\n", *chksum, 0, ts_data->tags.flag_addr,\r
387                  start_addr, end_addr);\r
388 \r
389         return 0;\r
390 }\r
391 \r
392 \r
393 int ist30xxb_isp_fw_read(struct i2c_client *client, u32 *buf32)\r
394 {\r
395         int ret = 0;\r
396         int i;\r
397 \r
398         u16 addr = EEPROM_BASE_ADDR;\r
399         int len = EEPROM_PAGE_SIZE / IST30XX_DATA_LEN;\r
400 \r
401         ist30xx_reset();\r
402 \r
403         /* IST30xxB ISP enable */\r
404         ret = ist30xxb_isp_enable(true);\r
405         if (ret) return ret;\r
406 \r
407         for (i = 0; i < IST30XX_EEPROM_SIZE; i += EEPROM_PAGE_SIZE) {\r
408                 ret = ist30xxb_isp_read(client, addr, buf32, len);\r
409                 if (ret) goto isp_fw_read_end;\r
410 \r
411                 addr += EEPROM_PAGE_SIZE;\r
412                 buf32 += len;\r
413         }\r
414 \r
415 isp_fw_read_end:\r
416         /* IST30xxB ISP disable */\r
417         ist30xxb_isp_enable(false);\r
418         return ret;\r
419 }\r
420 \r
421 int ist30xxb_isp_fw_update(struct i2c_client *client, const u8 *buf, u32 *chksum)\r
422 {\r
423         int ret = 0;\r
424         int i;\r
425         u32 page_cnt = IST30XX_EEPROM_SIZE / EEPROM_PAGE_SIZE;\r
426         u16 addr = EEPROM_BASE_ADDR;\r
427         int len = EEPROM_PAGE_SIZE / IST30XX_DATA_LEN;\r
428 \r
429         /* IST30xxB ISP enable */\r
430         ret = ist30xxb_isp_enable(true);\r
431 \r
432         ret = ist30xxb_isp_erase(client, IST30XXB_ISP_ERASE_ALL, 0);\r
433         if (ret) goto isp_fw_update_end;\r
434 \r
435         for (i = 0; i < page_cnt; i++) {\r
436                 /* IST30xxB ISP write mode */\r
437                 ret = ist30xxb_isp_mode(IST30XXB_ISP_WRITE);\r
438                 if (ret) goto isp_fw_update_end;\r
439 \r
440                 ret = ist30xxb_isp_write(client, addr, (u32 *)buf, len);\r
441                 if (ret) goto isp_fw_update_end;\r
442 \r
443                 addr += EEPROM_PAGE_SIZE;\r
444                 buf += EEPROM_PAGE_SIZE;\r
445 \r
446                 msleep(5);\r
447         }\r
448 \r
449         /* IST30xxB ISP disable */\r
450         ret = ist30xxb_isp_enable(false);\r
451         if (ret) return ret;\r
452         return 0;\r
453 \r
454 isp_fw_update_end:\r
455         ist30xxb_isp_enable(false);\r
456         return ret;\r
457 }\r
458 \r
459 int ist30xxb_isp_bootloader(struct i2c_client *client, const u8 *buf)\r
460 {\r
461         int ret = 0;\r
462         int i;\r
463         u16 addr = EEPROM_BASE_ADDR;\r
464         u32 page_cnt = (ts_data->fw.index) / EEPROM_PAGE_SIZE;\r
465         int buf_cnt = EEPROM_PAGE_SIZE / IST30XX_DATA_LEN;\r
466 \r
467         tsp_info("*** Bootloader update (0x%x~0x%x) ***\n",\r
468                  EEPROM_BASE_ADDR, ts_data->fw.index);\r
469 \r
470         /* IST30xxB ISP enable */\r
471         ret = ist30xxb_isp_enable(true);\r
472 \r
473         ret = ist30xxb_isp_erase(client, IST30XXB_ISP_ERASE_ALL, 0);\r
474         if (ret) goto ist30xxb_isp_bootloader;\r
475 \r
476         for (i = 0; i < page_cnt; i++) {\r
477                 /* IST30xxB ISP write mode */\r
478                 ret = ist30xxb_isp_mode(IST30XXB_ISP_WRITE);\r
479                 if (ret) goto ist30xxb_isp_bootloader;\r
480 \r
481                 ret = ist30xxb_isp_write(client, addr, (u32 *)buf, buf_cnt);\r
482                 if (ret) goto ist30xxb_isp_bootloader;\r
483 \r
484                 addr += EEPROM_PAGE_SIZE;\r
485                 buf += EEPROM_PAGE_SIZE;\r
486 \r
487                 msleep(5);\r
488         }\r
489 \r
490         /* IST30xxB ISP disable */\r
491         ret = ist30xxb_isp_enable(false);\r
492         if (ret) return ret;\r
493         return 0;\r
494 \r
495 ist30xxb_isp_bootloader:\r
496         ist30xxb_isp_enable(false);\r
497         return ret;\r
498 }\r
499 \r
500 \r
501 int ist30xx_fw_write(struct i2c_client *client, const u8 *buf)\r
502 {\r
503         int ret;\r
504         int len;\r
505         u32 *buf32 = (u32 *)(buf + ts_data->fw.index);\r
506         u32 size = ts_data->fw.size;\r
507 \r
508         if (size < 0 || size > IST30XX_EEPROM_SIZE)\r
509                 return -ENOEXEC;\r
510 \r
511         while (size > 0) {\r
512                 len = (size >= EEPROM_PAGE_SIZE ? EEPROM_PAGE_SIZE : size);\r
513 \r
514                 ret = ist30xx_write_buf(client, CMD_ENTER_FW_UPDATE, buf32, (len >> 2));\r
515                 if (ret)\r
516                         return ret;\r
517 \r
518                 buf32 += (len >> 2);\r
519                 size -= len;\r
520 \r
521                 msleep(5);\r
522         }\r
523         return 0;\r
524 }\r
525 \r
526 \r
527 u32 ist30xx_parse_ver(int flag, const u8 *buf)\r
528 {\r
529         u32 ver = 0;\r
530         u32 *buf32 = (u32 *)buf;\r
531 \r
532         if (flag == FLAG_FW)\r
533                 ver = (u32)buf32[(ts_data->tags.flag_addr + 4) >> 2];\r
534         else if (flag == FLAG_PARAM)\r
535                 ver = (u32)(buf32[(ts_data->tags.cfg_addr + 4) >> 2] & 0xFFFF);\r
536         else\r
537                 tsp_warn("Parsing ver's flag is not corrent!\n");\r
538 \r
539         return ver;\r
540 }\r
541 \r
542 \r
543 int calib_ms_delay = WAIT_CALIB_CNT;\r
544 int ist30xx_calib_wait(void)\r
545 {\r
546         int cnt = calib_ms_delay;\r
547 \r
548         ts_data->status.calib_msg = 0;\r
549         while (cnt-- > 0) {\r
550                 msleep(100);\r
551 \r
552                 if (ts_data->status.calib_msg) {\r
553                         tsp_info("Calibration status : %d, Max raw gap : %d - (%08x)\n",\r
554                                  CALIB_TO_STATUS(ts_data->status.calib_msg),\r
555                                  CALIB_TO_GAP(ts_data->status.calib_msg),\r
556                                  ts_data->status.calib_msg);\r
557 \r
558                         if (CALIB_TO_GAP(ts_data->status.calib_msg) < CALIB_THRESHOLD)\r
559                                 return 0;  // Calibrate success\r
560                         else\r
561                                 return -EAGAIN;\r
562                 }\r
563         }\r
564         tsp_warn("Calibration time out\n");\r
565 \r
566         return -EPERM;\r
567 }\r
568 \r
569 int ist30xx_calibrate(int wait_cnt)\r
570 {\r
571         int ret = -ENOEXEC;\r
572 \r
573         tsp_info("*** Calibrate %ds ***\n", calib_ms_delay / 10);\r
574 \r
575         ts_data->status.update = 1;\r
576         while (wait_cnt--) {\r
577                 ist30xx_disable_irq(ts_data);\r
578                 ret = ist30xx_cmd_run_device(ts_data->client);\r
579                 if (ret) continue;\r
580 \r
581                 ret = ist30xx_cmd_calibrate(ts_data->client);\r
582                 if (ret) continue;\r
583 \r
584                 ist30xx_enable_irq(ts_data);\r
585                 ret = ist30xx_calib_wait();\r
586                 if (!ret) break;\r
587         }\r
588 \r
589         ist30xx_disable_irq(ts_data);\r
590         ist30xx_cmd_run_device(ts_data->client);\r
591 \r
592         ts_data->status.update = 2;\r
593 \r
594         ist30xx_enable_irq(ts_data);\r
595 \r
596         return ret;\r
597 }\r
598 \r
599 \r
600 int ist30xx_parse_tags(struct ist30xx_data *data, const u8 *buf, const u32 size)\r
601 {\r
602         int ret = -EPERM;\r
603 \r
604         ts_tags = (struct ist30xx_tags *)(&buf[size - sizeof(struct ist30xx_tags)]);\r
605 \r
606         if (!strncmp(ts_tags->magic1, IST30XX_TAG_MAGIC, sizeof(ts_tags->magic1))\r
607             && !strncmp(ts_tags->magic2, IST30XX_TAG_MAGIC, sizeof(ts_tags->magic2))) {\r
608                 data->fw.index = ts_tags->fw_addr;\r
609                 data->fw.size = ts_tags->flag_addr - ts_tags->fw_addr +\r
610                                 ts_tags->flag_size;\r
611                 data->fw.chksum = ts_tags->chksum;\r
612                 data->tags = *ts_tags;\r
613 \r
614                 ret = 0;\r
615         }\r
616 \r
617         tsp_verb("Tagts magic1: %s, magic2: %s\n",\r
618                  ts_tags->magic1, ts_tags->magic2);\r
619         tsp_verb(" fw: %x(%x)\n", ts_tags->fw_addr, ts_tags->fw_size);\r
620         tsp_verb(" flag: %x(%x)\n", ts_tags->flag_addr, ts_tags->flag_size);\r
621         tsp_verb(" cfg: %x(%x)\n", ts_tags->cfg_addr, ts_tags->cfg_size);\r
622         tsp_verb(" sensor1: %x(%x)\n", ts_tags->sensor1_addr, ts_tags->sensor1_size);\r
623         tsp_verb(" sensor2: %x(%x)\n", ts_tags->sensor2_addr, ts_tags->sensor2_size);\r
624         tsp_verb(" sensor3: %x(%x)\n", ts_tags->sensor3_addr, ts_tags->sensor3_size);\r
625         tsp_verb(" chksum: %x\n", ts_tags->chksum);\r
626 \r
627         return ret;\r
628 }\r
629 \r
630 void ist30xx_get_update_info(struct ist30xx_data *data, const u8 *buf, const u32 size)\r
631 {\r
632         int ret;\r
633 \r
634         ret = ist30xx_parse_tags(data, buf, size);\r
635         if (ret != TAGS_PARSE_OK)\r
636                 tsp_warn("Cannot find tags of F/W, make a tags by 'tagts.exe'\n");\r
637 }\r
638 \r
639 #if (IST30XX_DEBUG) && (IST30XX_INTERNAL_BIN)\r
640 extern TSP_INFO ist30xx_tsp_info;\r
641 extern TKEY_INFO ist30xx_tkey_info;\r
642 int ist30xx_get_tkey_info(struct ist30xx_data *data)\r
643 {\r
644         int ret = 0;\r
645         TSP_INFO *tsp = &ist30xx_tsp_info;\r
646         TKEY_INFO *tkey = &ist30xx_tkey_info;\r
647         u8 *cfg_buf;\r
648 \r
649         ist30xx_get_update_info(data, data->fw.buf, data->fw.buf_size);\r
650         cfg_buf = (u8 *)&data->fw.buf[data->tags.cfg_addr];\r
651 \r
652         tkey->enable = (bool)(cfg_buf[0x14] & 1);\r
653         tkey->axis_rx = (bool)((cfg_buf[0x14] >> 1) & 1);\r
654         tkey->key_num = (u8)cfg_buf[0x15];\r
655         tkey->ch_num[0] = (u8)cfg_buf[0x16];\r
656         tkey->ch_num[1] = (u8)cfg_buf[0x17];\r
657         tkey->ch_num[2] = (u8)cfg_buf[0x18];\r
658         tkey->ch_num[3] = (u8)cfg_buf[0x19];\r
659         tkey->ch_num[4] = (u8)cfg_buf[0x1A];\r
660 \r
661         if (tkey->axis_rx) {\r
662                 if (tsp->dir.swap_xy) tsp->height -= 1;\r
663                 else tsp->width -= 1;\r
664         } else {\r
665                 if (tsp->dir.swap_xy) tsp->width -= 1;\r
666                 else tsp->height -= 1;\r
667         }\r
668 \r
669         return ret;\r
670 }\r
671 \r
672 #define TSP_INFO_SWAP_XY    (1 << 0)\r
673 #define TSP_INFO_FLIP_X     (1 << 1)\r
674 #define TSP_INFO_FLIP_Y     (1 << 2)\r
675 int ist30xx_get_tsp_info(struct ist30xx_data *data)\r
676 {\r
677         int ret = 0;\r
678         TSP_INFO *tsp = &ist30xx_tsp_info;\r
679         u8 *cfg_buf, *sensor_buf;\r
680 \r
681         ist30xx_get_update_info(data, data->fw.buf, data->fw.buf_size);\r
682         cfg_buf = (u8 *)&data->fw.buf[data->tags.cfg_addr];\r
683         sensor_buf = (u8 *)&data->fw.buf[data->tags.sensor1_addr];\r
684 \r
685         tsp->finger_num = (u8)cfg_buf[0x0E];\r
686         tsp->dir.swap_xy = (bool)(cfg_buf[0xF] & TSP_INFO_SWAP_XY ? true : false);\r
687         tsp->dir.flip_x = (bool)(cfg_buf[0xF] & TSP_INFO_FLIP_X ? true : false);\r
688         tsp->dir.flip_y = (bool)(cfg_buf[0xF] & TSP_INFO_FLIP_Y ? true : false);\r
689 \r
690         tsp->ch_num.tx = (u8)sensor_buf[0x40];\r
691         tsp->ch_num.rx = (u8)sensor_buf[0x41];\r
692 \r
693         tsp->node.len = tsp->ch_num.tx * tsp->ch_num.rx;\r
694         tsp->height = (tsp->dir.swap_xy ? tsp->ch_num.rx : tsp->ch_num.tx);\r
695         tsp->width = (tsp->dir.swap_xy ? tsp->ch_num.tx : tsp->ch_num.rx);\r
696 \r
697         return ret;\r
698 }\r
699 #endif // (IST30XX_DEBUG) && (IST30XX_INTERNAL_BIN)\r
700 \r
701 \r
702 #define update_next_step(ret)   { if (ret) goto end; }\r
703 int ist30xx_fw_update(struct i2c_client *client, const u8 *buf, int size, bool mode)\r
704 {\r
705         int ret = 0;\r
706         u32 chksum = 0;\r
707         struct ist30xx_fw *fw = &ts_data->fw;\r
708 \r
709         tsp_info("*** Firmware update ***\n");\r
710         tsp_info(" core: %x, param: %x, addr: 0x%x ~ 0x%x\n",\r
711                  ist30xx_fw_ver, ist30xx_param_ver, fw->index, (fw->index + fw->size));\r
712 \r
713         ts_data->status.update = 1;\r
714 \r
715         ist30xx_disable_irq(ts_data);\r
716 \r
717         ist30xx_reset();\r
718 \r
719         if (mode) { /* ISP Mode */\r
720                 ret = ist30xxb_isp_fw_update(client, buf, &chksum);\r
721                 update_next_step(ret);\r
722         } else { /* I2C SW Mode */\r
723                 ret = ist30xx_cmd_update(client, CMD_ENTER_FW_UPDATE);\r
724                 update_next_step(ret);\r
725 \r
726                 ret = ist30xx_fw_write(client, buf);\r
727                 update_next_step(ret);\r
728         }\r
729         msleep(50);\r
730 \r
731         buf += IST30XX_EEPROM_SIZE;\r
732         size -= IST30XX_EEPROM_SIZE;\r
733 \r
734         ret = ist30xx_cmd_run_device(client);\r
735         update_next_step(ret);\r
736 \r
737         ret = ist30xx_read_cmd(client, CMD_GET_CHECKSUM, &chksum);\r
738         if ((ret) || (chksum != fw->chksum))\r
739                 goto end;\r
740 \r
741         if ((ret) || (chksum != fw->chksum))\r
742                 goto end;\r
743 \r
744         ret = ist30xx_get_ver_info(ts_data);\r
745         update_next_step(ret);\r
746 \r
747 end:\r
748         if (ret) {\r
749                 tsp_warn("Firmware update Fail!, ret=%d\n", ret);\r
750         } else if (chksum != fw->chksum) {\r
751                 tsp_warn("Error CheckSum: %x(%x)\n", chksum, fw->chksum);\r
752                 ret = -ENOEXEC;\r
753         }\r
754 \r
755         ist30xx_enable_irq(ts_data);\r
756 \r
757         ts_data->status.update = 2;\r
758 \r
759         return ret;\r
760 }\r
761 \r
762 int ist30xx_fw_recovery(struct ist30xx_data *data)\r
763 {\r
764         int ret = -EPERM;\r
765         u8 *fw = data->fw.buf;\r
766         int fw_size = data->fw.buf_size;\r
767 \r
768         ist30xx_get_update_info(data, fw, fw_size);\r
769         ist30xx_fw_ver = ist30xx_parse_ver(FLAG_FW, fw);\r
770         ist30xx_param_ver = ist30xx_parse_ver(FLAG_PARAM, fw);\r
771 \r
772         mutex_lock(&ist30xx_mutex);\r
773         ret = ist30xx_fw_update(data->client, fw, fw_size, true);\r
774         mutex_unlock(&ist30xx_mutex);\r
775 \r
776         ist30xx_calibrate(1);\r
777 \r
778         ist30xx_init_touch_driver(data);\r
779 \r
780         return ret;\r
781 }\r
782 \r
783 \r
784 #define fw_update_next_step(ret)   { if (ret) { step = 1; goto end; } }\r
785 #define param_update_next_step(ret)   { if (ret) { step = 2; goto end; } }\r
786 int ist30xx_fw_param_update(struct i2c_client *client, const u8 *buf)\r
787 {\r
788         int ret = 0;\r
789         int step = 0;\r
790         u16 len = 0;\r
791         int size = IST30XX_EEPROM_SIZE;\r
792         u32 chksum = 0, ver = 0;\r
793         u32 *param = (u32 *)buf;\r
794         struct ist30xx_fw *fw = &ts_data->fw;\r
795 \r
796         tsp_info("*** FW param update ***\n");\r
797         tsp_info(" core: %x, param: %x, addr: 0x%x ~ 0x%x\n",\r
798                  ist30xx_fw_ver, ist30xx_param_ver, fw->index, (fw->index + fw->size));\r
799 \r
800         ts_data->status.update = 1;\r
801 \r
802         ist30xx_disable_irq(ts_data);\r
803         ist30xx_reset();\r
804 \r
805         /* FW update by SW */\r
806         ret = ist30xx_cmd_update(client, CMD_ENTER_FW_UPDATE);\r
807         fw_update_next_step(ret);\r
808 \r
809         ret = ist30xx_fw_write(client, buf);\r
810         fw_update_next_step(ret);\r
811 \r
812         msleep(50);\r
813 \r
814         param = (u32 *)(buf + (fw->index + fw->size));\r
815         size -= fw->size;\r
816 \r
817         ret = ist30xx_cmd_run_device(client);\r
818         fw_update_next_step(ret);\r
819 \r
820         ret = ist30xx_read_cmd(client, CMD_GET_CHECKSUM, &chksum);\r
821         if ((ret) || (chksum != fw->chksum))\r
822                 goto end;\r
823 \r
824         ret = ist30xx_read_cmd(client, CMD_GET_FW_VER, &ver);\r
825         update_next_step(ret);\r
826         fw->prev_core_ver = fw->core_ver;\r
827         fw->core_ver = ver;\r
828         tsp_info("F/W core version : %x\n", fw->core_ver);\r
829 \r
830         /* update parameters */\r
831         ret = ist30xx_cmd_update(client, CMD_ENTER_UPDATE);\r
832         param_update_next_step(ret);\r
833 \r
834         /* config */\r
835         len = (ts_data->tags.cfg_size >> 2);\r
836         ret = ist30xx_write_buf(client, CMD_UPDATE_CONFIG, param, len);\r
837         param_update_next_step(ret);\r
838         msleep(10);\r
839 \r
840         param += len;\r
841         size -= (len << 2);\r
842 \r
843         /* sensor */\r
844         len = ((ts_data->tags.sensor1_size + ts_data->tags.sensor2_size) >> 2);\r
845         ret = ist30xx_write_buf(client, CMD_UPDATE_SENSOR, param, len);\r
846         param_update_next_step(ret);\r
847         msleep(10);\r
848 \r
849         param += len;\r
850         size -= (len << 2);\r
851 \r
852         ret = ist30xx_cmd_update(client, CMD_EXIT_UPDATE);\r
853         param_update_next_step(ret);\r
854         msleep(120);\r
855 \r
856         ret = ist30xx_cmd_run_device(client);\r
857         update_next_step(ret);\r
858 \r
859         ret = ist30xx_read_cmd(client, CMD_GET_PARAM_VER, &ver);\r
860         update_next_step(ret);\r
861         fw->prev_param_ver = fw->param_ver;\r
862         fw->param_ver = ver;\r
863         tsp_info("Param version : %x\n", fw->param_ver);\r
864 \r
865 end:\r
866         if (ret) {\r
867                 if (step == 1)\r
868                         tsp_warn("Firmware update Fail!, ret=%d", ret);\r
869                 else if (step == 2)\r
870                         tsp_warn("Parameters update Fail!, ret=%d", ret);\r
871         } else if (chksum != fw->chksum) {\r
872                 tsp_warn("Error CheckSum: %08x(%08x)\n", chksum, fw->chksum);\r
873                 ret = -ENOEXEC;\r
874         }\r
875 \r
876         ist30xx_enable_irq(ts_data);\r
877         ts_data->status.update = 2;\r
878 \r
879         return ret;\r
880 }\r
881 \r
882 \r
883 #if IST30XX_INTERNAL_BIN\r
884 int ist30xx_check_fw(struct ist30xx_data *data, const u8 *buf)\r
885 {\r
886         int ret;\r
887         u32 chksum;\r
888 \r
889         ret = ist30xx_read_cmd(data->client, CMD_GET_CHECKSUM, &chksum);\r
890         if (ret) return ret;\r
891 \r
892         if (chksum != data->fw.chksum) {\r
893                 tsp_warn("Checksum compare error %08x(%08x)\n", chksum, data->fw.chksum);\r
894                 return -EPERM;\r
895         }\r
896 \r
897         return 0;\r
898 }\r
899 \r
900 bool ist30xx_check_valid_vendor(u32 tsp_vendor)\r
901 {\r
902         switch (tsp_vendor) {\r
903         case TSP_TYPE_ALPS:\r
904         case TSP_TYPE_EELY:\r
905         case TSP_TYPE_TOP:\r
906         case TSP_TYPE_DIGITECH:\r
907         case TSP_TYPE_ILJIN:\r
908         case TSP_TYPE_SYNOPEX:\r
909         case TSP_TYPE_SMAC:\r
910         case TSP_TYPE_TAEYANG:\r
911         case TSP_TYPE_TOVIS:\r
912         case TSP_TYPE_ELK:\r
913                 return true;\r
914         default:\r
915                 return false;\r
916         }\r
917 \r
918         return false;\r
919 }\r
920 #if 1     //sinjan.kumar\r
921 #if IST30XX_MULTIPLE_TSP\r
922 void ist30xx_set_tsp_fw(struct ist30xx_data *data)\r
923 {\r
924         char *str;\r
925         struct ist30xx_fw *fw = &data->fw;\r
926 \r
927         switch (data->tsp_type) {\r
928         case TSP_TYPE_ILJIN:\r
929                 str = "ILJIN";\r
930                 fw->buf = (u8 *)ist30xxb_fw;\r
931                 fw->buf_size = sizeof(ist30xxb_fw);\r
932                 break;\r
933         case TSP_TYPE_SYNOPEX:\r
934                 str = "SYNOPEX";\r
935                 fw->buf = (u8 *)ist30xxb_fw1;\r
936                 fw->buf_size = sizeof(ist30xxb_fw1);\r
937                 break;\r
938         case TSP_TYPE_UNKNOWN:\r
939         default:\r
940                 str = "Unknown";\r
941                 tsp_warn("Unknown TSP vendor(0x%x)\n", data->tsp_type);\r
942                 break;\r
943         }\r
944         tsp_info("TSP vendor : %s(%x)\n", str, data->tsp_type);\r
945 \r
946         ist30xx_get_update_info(ts_data, fw->buf, fw->buf_size);\r
947         ist30xx_fw_ver = ist30xx_parse_ver(FLAG_FW, fw->buf);\r
948         ist30xx_param_ver = ist30xx_parse_ver(FLAG_PARAM, fw->buf);\r
949 }\r
950 #endif  // IST30XX_MULTIPLE_TSP\r
951 #endif    //sinjan.kumar\r
952 \r
953 int ist30xx_check_auto_update(struct ist30xx_data *data)\r
954 {\r
955 #if 1                    //sinjan.kumar\r
956         int ret = 0;\r
957         int retry = IST30XX_FW_UPDATE_RETRY;\r
958         u32 tsp_type = TSP_TYPE_UNKNOWN;         //sinjan.kumar\r
959         u32 chksum;\r
960         bool tsp_check = false;\r
961         struct ist30xx_fw *fw = &data->fw;\r
962 \r
963         while (retry--) {\r
964                 ret = ist30xx_read_cmd(data->client,\r
965                                        CMD_GET_TSP_PANNEL_TYPE, &tsp_type);\r
966                 if (ret == 0) {\r
967                         if (ist30xx_check_valid_vendor(tsp_type) == true)\r
968                                 tsp_check = true;\r
969                         break;\r
970                 }\r
971         }\r
972 \r
973         retry = IST30XX_FW_UPDATE_RETRY;\r
974 \r
975         if (!tsp_check) {\r
976                 while (retry--) {\r
977                         /* FW recovery */\r
978                         tsp_info("tsp type: %x\n", tsp_type);\r
979                         ret = ist30xxb_isp_bootloader(data->client, fw->buf);\r
980                         if (ret == 0) {\r
981                                 ist30xx_reset();\r
982                                 ret = ist30xx_read_cmd(data->client,\r
983                                                        CMD_GET_TSP_PANNEL_TYPE, &tsp_type);\r
984                                 tsp_info("tsp type: %x\n", tsp_type);\r
985                                 if (ret == 0) // recovery OK\r
986                                         if (ist30xx_check_valid_vendor(tsp_type) == true) {\r
987                                                 data->tsp_type = tsp_type;\r
988 #if IST30XX_MULTIPLE_TSP\r
989                                                 ist30xx_set_tsp_fw(data);\r
990 #endif\r
991                                                 break;\r
992                                         }\r
993                         }\r
994 \r
995                         if (retry == 0) return 1;  /* TSP is not connected */\r
996                 }\r
997         }\r
998 \r
999         ist30xx_write_cmd(data->client, CMD_RUN_DEVICE, 0);\r
1000         msleep(10);\r
1001 \r
1002         ist30xx_get_ver_info(data);\r
1003 \r
1004         if ((fw->param_ver > 0) && (fw->param_ver < 0xFFFFFFFF) &&\r
1005             ((fw->core_ver & MASK_FW_VER) == IST30XX_FW_VER3)) {\r
1006                 tsp_info("Version compare IC: %x(%x), BIN: %x(%x)\n",\r
1007                          fw->param_ver, fw->core_ver, ist30xx_param_ver, ist30xx_fw_ver);\r
1008 \r
1009                 /* If FW version is same, check FW checksum */\r
1010                 if ((fw->core_ver == ist30xx_fw_ver) &&\r
1011                     (fw->param_ver == ist30xx_param_ver)) {\r
1012                         ret = ist30xx_read_cmd(data->client, CMD_GET_CHECKSUM, &chksum);\r
1013                         if (ret) goto fw_check_end;\r
1014 \r
1015                         if ((ret) || (chksum != fw->chksum)) {\r
1016                                 tsp_warn("Checksum error, IC: %x, Bin: %x\n",\r
1017                                          chksum, fw->chksum);\r
1018                                 goto fw_check_end;\r
1019                         }\r
1020                 }\r
1021 \r
1022                 /*\r
1023                  *  fw->core_ver : FW core version in TSP IC\r
1024                  *  fw->param_ver : FW version if TSP IC\r
1025                  *  ist30xx_fw_ver : FW core version in FW Binary\r
1026                  *  ist30xx_fw_ver : FW version in FW Binary\r
1027                  */\r
1028                 /* If the ver of binary is higher than ver of IC, FW update operate. */\r
1029 \r
1030                 if ((fw->core_ver >= ist30xx_fw_ver) &&\r
1031                     (fw->param_ver >= ist30xx_param_ver))\r
1032                         return 0;\r
1033         }\r
1034 \r
1035 fw_check_end:\r
1036         return -EAGAIN;\r
1037         #endif            return 0;   //sinjan.kumar\r
1038 }\r
1039 \r
1040 int ist30xx_auto_bin_update(struct ist30xx_data *data)\r
1041 {\r
1042 #if 1     //sinjan.kumar\r
1043         int ret = 0;\r
1044         int retry = IST30XX_FW_UPDATE_RETRY;\r
1045         struct ist30xx_fw *fw = &data->fw;\r
1046 \r
1047         fw->buf = (u8 *)ist30xxb_fw;\r
1048         fw->buf_size = sizeof(ist30xxb_fw);\r
1049 \r
1050 #if IST30XX_MULTIPLE_TSP\r
1051         ist30xx_set_tsp_fw(data);\r
1052 #else\r
1053         ist30xx_get_update_info(data, fw->buf, fw->buf_size);\r
1054         ist30xx_fw_ver = ist30xx_parse_ver(FLAG_FW, fw->buf);\r
1055         ist30xx_param_ver = ist30xx_parse_ver(FLAG_PARAM, fw->buf);\r
1056 #endif\r
1057 \r
1058         tsp_info("IC: %x, Binary ver core: %x, param: %x\n",\r
1059                  data->chip_id, ist30xx_fw_ver, ist30xx_param_ver);\r
1060 \r
1061         mutex_lock(&ist30xx_mutex);\r
1062         ret = ist30xx_check_auto_update(data);\r
1063         mutex_unlock(&ist30xx_mutex);\r
1064         //return 0;\r
1065         //printk("[TSP] %s : %d\n", __func__, __LINE__);\r
1066         if (ret >= 0)\r
1067                 return ret;\r
1068         //printk("[TSP] %s : %d\n", __func__, __LINE__);\r
1069 update_bin:   // TSP is not ready / FW update\r
1070         tsp_info("Update version. param(core): %x(%x) -> %x(%x)\n",\r
1071                  fw->param_ver, fw->core_ver, ist30xx_param_ver, ist30xx_fw_ver);\r
1072         //printk("[TSP] %s : %d\n", __func__, __LINE__);\r
1073         mutex_lock(&ist30xx_mutex);\r
1074         while (retry--) {\r
1075                 //printk("[TSP] %s : %d\n", __func__, __LINE__);\r
1076                 ret = ist30xx_fw_update(data->client, fw->buf, fw->buf_size, true);\r
1077                 if (!ret) break;\r
1078         }\r
1079         mutex_unlock(&ist30xx_mutex);\r
1080 \r
1081         if (ret)\r
1082                 return ret;\r
1083 \r
1084         if (retry > 0 && ist30xx_check_fw(data, fw->buf))\r
1085                 goto update_bin;\r
1086 \r
1087         ist30xx_calibrate(IST30XX_FW_UPDATE_RETRY);\r
1088 \r
1089         return ret;\r
1090         #endif    return 0;  //sinjan.kumar\r
1091 }\r
1092 #endif // IST30XX_INTERNAL_BIN\r
1093 \r
1094 \r
1095 /* sysfs: /sys/class/touch/firmware/boot */\r
1096 ssize_t ist30xx_boot_store(struct device *dev, struct device_attribute *attr,\r
1097                            const char *buf, size_t size)\r
1098 {\r
1099         int ret;\r
1100         int fw_size = 0;\r
1101         u8 *fw = NULL;\r
1102         char *tmp;\r
1103         const struct firmware *request_fw = NULL;\r
1104 \r
1105         unsigned long mode = simple_strtoul(buf, &tmp, 10);\r
1106 \r
1107         if (mode == MASK_UPDATE_ISP || mode == MASK_UPDATE_FW) {\r
1108                 ret = request_firmware(&request_fw, IST30XXB_FW_NAME, &ts_data->client->dev);\r
1109                 if (ret) {\r
1110                         tsp_warn("File not found, %s\n", IST30XXB_FW_NAME);\r
1111                         return size;\r
1112                 }\r
1113                 fw = (u8 *)request_fw->data;\r
1114                 fw_size = (u32)request_fw->size;\r
1115         } else {\r
1116 #if IST30XX_INTERNAL_BIN\r
1117                 fw = ts_data->fw.buf;\r
1118                 fw_size = ts_data->fw.buf_size;\r
1119 #else\r
1120                 return size;\r
1121 #endif          // IST30XX_INTERNAL_BIN\r
1122         }\r
1123 \r
1124         if (mode == 3) {\r
1125                 tsp_info("EEPROM all erase test\n");\r
1126                 ist30xx_disable_irq(ts_data);\r
1127                 mutex_lock(&ist30xx_mutex);\r
1128 \r
1129                 ist30xxb_isp_enable(true);\r
1130                 ist30xxb_isp_erase(ts_data->client, IST30XXB_ISP_ERASE_ALL, 0);\r
1131                 ist30xxb_isp_enable(false);\r
1132 \r
1133                 mutex_unlock(&ist30xx_mutex);\r
1134                 ist30xx_enable_irq(ts_data);\r
1135         } else {\r
1136                 ist30xx_get_update_info(ts_data, fw, fw_size);\r
1137                 ist30xx_fw_ver = ist30xx_parse_ver(FLAG_FW, fw);\r
1138 \r
1139                 ist30xx_disable_irq(ts_data);\r
1140 \r
1141                 mutex_lock(&ist30xx_mutex);\r
1142                 ist30xxb_isp_bootloader(ts_data->client, fw);\r
1143                 mutex_unlock(&ist30xx_mutex);\r
1144 \r
1145                 if (mode == MASK_UPDATE_ISP || mode == MASK_UPDATE_FW)\r
1146                         release_firmware(request_fw);\r
1147         }\r
1148 \r
1149         return size;\r
1150 }\r
1151 \r
1152 u32 buf32_eeprom[IST30XX_EEPROM_SIZE / IST30XX_DATA_LEN];\r
1153 ssize_t ist30xx_fw_show(struct device *dev, struct device_attribute *attr,\r
1154                         char *buf)\r
1155 {\r
1156         int i;\r
1157         u8 *buf8 = (u8 *)buf32_eeprom;;\r
1158 \r
1159         mutex_lock(&ist30xx_mutex);\r
1160         ist30xx_disable_irq(ts_data);\r
1161 \r
1162         ist30xxb_isp_fw_read(ts_data->client, buf32_eeprom);\r
1163         for (i = 0; i < IST30XX_EEPROM_SIZE; i += 16) {\r
1164                 tsp_debug("%07x: %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x\n", i,\r
1165                           buf8[i], buf8[i + 1], buf8[i + 2], buf8[i + 3],\r
1166                           buf8[i + 4], buf8[i + 5], buf8[i + 6], buf8[i + 7],\r
1167                           buf8[i + 8], buf8[i + 9], buf8[i + 10], buf8[i + 11],\r
1168                           buf8[i + 12], buf8[i + 13], buf8[i + 14], buf8[i + 15]);\r
1169         }\r
1170 \r
1171         ist30xx_enable_irq(ts_data);\r
1172         mutex_unlock(&ist30xx_mutex);\r
1173 \r
1174         return 0;\r
1175 }\r
1176 \r
1177 /* sysfs: /sys/class/touch/firmware/firmware */\r
1178 ssize_t ist30xx_fw_store(struct device *dev, struct device_attribute *attr,\r
1179                          const char *buf, size_t size)\r
1180 {\r
1181         int ret;\r
1182         bool isp_mode = false;\r
1183         int fw_size = 0;\r
1184         u8 *fw = NULL;\r
1185         char *tmp;\r
1186         const struct firmware *request_fw = NULL;\r
1187 \r
1188         unsigned long mode = simple_strtoul(buf, &tmp, 10);\r
1189 \r
1190         if (mode == MASK_UPDATE_ISP || mode == MASK_UPDATE_FW) {\r
1191                 ret = request_firmware(&request_fw, IST30XXB_FW_NAME, &ts_data->client->dev);\r
1192                 if (ret) {\r
1193                         tsp_warn("File not found, %s\n", IST30XXB_FW_NAME);\r
1194                         return size;\r
1195                 }\r
1196                 fw = (u8 *)request_fw->data;\r
1197                 fw_size = (u32)request_fw->size;\r
1198                 isp_mode = (mode == MASK_UPDATE_ISP ? true : false);\r
1199         } else {\r
1200 #if IST30XX_INTERNAL_BIN\r
1201                 fw = ts_data->fw.buf;\r
1202                 fw_size = ts_data->fw.buf_size;\r
1203 #else\r
1204                 return size;\r
1205 #endif          // IST30XX_INTERNAL_BIN\r
1206         }\r
1207 \r
1208         ist30xx_get_update_info(ts_data, fw, fw_size);\r
1209         ist30xx_fw_ver = ist30xx_parse_ver(FLAG_FW, fw);\r
1210         ist30xx_param_ver = ist30xx_parse_ver(FLAG_PARAM, fw);\r
1211 \r
1212         mutex_lock(&ist30xx_mutex);\r
1213         ist30xx_fw_update(ts_data->client, fw, fw_size, isp_mode);\r
1214         mutex_unlock(&ist30xx_mutex);\r
1215 \r
1216         ist30xx_calibrate(1);\r
1217 \r
1218         ist30xx_init_touch_driver(ts_data);\r
1219 \r
1220         if (mode == MASK_UPDATE_ISP || mode == MASK_UPDATE_FW)\r
1221                 release_firmware(request_fw);\r
1222 \r
1223         return size;\r
1224 }\r
1225 \r
1226 ssize_t ist30xx_fw_status(struct device *dev, struct device_attribute *attr,\r
1227                           char *buf)\r
1228 {\r
1229         int count;\r
1230 \r
1231         switch (ts_data->status.update) {\r
1232         case 1:\r
1233                 count = sprintf(buf, "Downloading\n");\r
1234                 break;\r
1235         case 2:\r
1236                 count = sprintf(buf, "Update success, ver %x(%x) -> %x(%x), status : %d, gap : %d\n",\r
1237                                 ts_data->fw.prev_param_ver, ts_data->fw.prev_core_ver,\r
1238                                 ts_data->fw.param_ver, ts_data->fw.core_ver,\r
1239                                 CALIB_TO_STATUS(ts_data->status.calib_msg),\r
1240                                 CALIB_TO_GAP(ts_data->status.calib_msg));\r
1241                 break;\r
1242         default:\r
1243                 count = sprintf(buf, "Pass\n");\r
1244         }\r
1245 \r
1246         return count;\r
1247 }\r
1248 \r
1249 \r
1250 /* sysfs: /sys/class/touch/firmware/fwparam */\r
1251 ssize_t ist30xx_fwparam_store(struct device *dev, struct device_attribute *attr,\r
1252                               const char *buf, size_t size)\r
1253 {\r
1254         int ret;\r
1255         int fw_size = 0;\r
1256         u8 *fw = NULL;\r
1257         char *tmp;\r
1258         const struct firmware *request_fw = NULL;\r
1259 \r
1260         unsigned long mode = simple_strtoul(buf, &tmp, 10);\r
1261 \r
1262         if (mode == MASK_UPDATE_FW) {\r
1263                 ret = request_firmware(&request_fw, IST30XXB_FW_NAME, &ts_data->client->dev);\r
1264                 if (ret) {\r
1265                         tsp_warn("File not found, %s\n", IST30XXB_FW_NAME);\r
1266                         return size;\r
1267                 }\r
1268                 fw = (u8 *)request_fw->data;\r
1269                 fw_size = (u32)request_fw->size;\r
1270         } else {\r
1271 #if IST30XX_INTERNAL_BIN\r
1272                 fw = ts_data->fw.buf;\r
1273                 fw_size = ts_data->fw.buf_size;\r
1274 #else\r
1275                 return size;\r
1276 #endif          // IST30XX_INTERNAL_BIN\r
1277         }\r
1278 \r
1279         ist30xx_get_update_info(ts_data, fw, fw_size);\r
1280         ist30xx_fw_ver = ist30xx_parse_ver(FLAG_FW, fw);\r
1281         ist30xx_param_ver = ist30xx_parse_ver(FLAG_PARAM, fw);\r
1282 \r
1283         mutex_lock(&ist30xx_mutex);\r
1284         ist30xx_fw_param_update(ts_data->client, fw);\r
1285         mutex_unlock(&ist30xx_mutex);\r
1286 \r
1287         ist30xx_calibrate(1);\r
1288 \r
1289         ist30xx_init_touch_driver(ts_data);\r
1290 \r
1291         if (mode == MASK_UPDATE_FW)\r
1292                 release_firmware(request_fw);\r
1293 \r
1294         return size;\r
1295 }\r
1296 \r
1297 \r
1298 /* sysfs: /sys/class/touch/firmware/viersion */\r
1299 ssize_t ist30xx_fw_version(struct device *dev, struct device_attribute *attr,\r
1300                            char *buf)\r
1301 {\r
1302         int count;\r
1303 \r
1304         count = sprintf(buf, "IST30XX id: 0x%x, f/w core: 0x%x, param ver: 0x%x\n",\r
1305                         ts_data->chip_id, ts_data->fw.core_ver, ts_data->fw.param_ver);\r
1306 \r
1307 #if IST30XX_INTERNAL_BIN\r
1308         {\r
1309                 char msg[128];\r
1310 \r
1311                 ist30xx_get_update_info(ts_data, ts_data->fw.buf, ts_data->fw.buf_size);\r
1312 \r
1313                 count += snprintf(msg, sizeof(msg),\r
1314                                   " Header - f/w ver: 0x%x, param ver: 0x%x\r\n",\r
1315                                   ist30xx_parse_ver(FLAG_FW, ts_data->fw.buf),\r
1316                                   ist30xx_parse_ver(FLAG_PARAM, ts_data->fw.buf));\r
1317                 strncat(buf, msg, sizeof(msg));\r
1318         }\r
1319 #endif\r
1320 \r
1321         return count;\r
1322 }\r
1323 \r
1324 \r
1325 /* sysfs  */\r
1326 static DEVICE_ATTR(firmware, 0644, ist30xx_fw_status, ist30xx_fw_store);\r
1327 static DEVICE_ATTR(fwparam, 0644, NULL, ist30xx_fwparam_store);\r
1328 static DEVICE_ATTR(boot, 0644, ist30xx_fw_show, ist30xx_boot_store);\r
1329 static DEVICE_ATTR(version, 0644, ist30xx_fw_version, NULL);\r
1330 \r
1331 struct class *ist30xx_class;\r
1332 struct device *ist30xx_fw_dev;\r
1333 \r
1334 static struct attribute *fw_attributes[] = {\r
1335         &dev_attr_firmware.attr,\r
1336         &dev_attr_fwparam.attr,\r
1337         &dev_attr_boot.attr,\r
1338         &dev_attr_version.attr,\r
1339         NULL,\r
1340 };\r
1341 \r
1342 static struct attribute_group fw_attr_group = {\r
1343         .attrs  = fw_attributes,\r
1344 };\r
1345 \r
1346 \r
1347 int ist30xx_init_update_sysfs(void)\r
1348 {\r
1349         /* /sys/class/touch */\r
1350         ist30xx_class = class_create(THIS_MODULE, "touch");\r
1351 \r
1352         /* /sys/class/touch/firmware */\r
1353         ist30xx_fw_dev = device_create(ist30xx_class, NULL, 0, NULL, "firmware");\r
1354 \r
1355         /* /sys/class/touch/firmware/... */\r
1356         if (sysfs_create_group(&ist30xx_fw_dev->kobj, &fw_attr_group))\r
1357                 tsp_err("Failed to create sysfs group(%s)!\n", "firmware");\r
1358 \r
1359         ts_data->status.update = 0;\r
1360         ts_data->status.calib = 0;\r
1361 \r
1362         return 0;\r
1363 }\r