xref: /OK3568_Linux_fs/kernel/drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  *
3  * FocalTech TouchScreen driver.
4  *
5  * Copyright (c) 2012-2018, FocalTech Systems, Ltd., all rights reserved.
6  *
7  * This software is licensed under the terms of the GNU General Public
8  * License version 2, as published by the Free Software Foundation, and
9  * may be copied, distributed, and modified under those terms.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17 
18 /*****************************************************************************
19 *
20 * File Name: focaltech_esdcheck.c
21 *
22 *    Author: Focaltech Driver Team
23 *
24 *   Created: 2016-08-03
25 *
26 *  Abstract: ESD check function
27 *
28 *   Version: v1.0
29 *
30 * Revision History:
31 *        v1.0:
32 *            First release. By luougojin 2016-08-03
33 *        v1.1: By luougojin 2017-02-15
34 *            1. Add LCD_ESD_PATCH to control idc_esdcheck_lcderror
35 *****************************************************************************/
36 
37 /*****************************************************************************
38 * Included header files
39 *****************************************************************************/
40 #include "focaltech_core.h"
41 
42 #if FTS_ESDCHECK_EN
43 /*****************************************************************************
44 * Private constant and macro definitions using #define
45 *****************************************************************************/
46 #define ESDCHECK_WAIT_TIME              1000    /* ms */
47 #define LCD_ESD_PATCH                   0
48 
49 /*****************************************************************************
50 * Private enumerations, structures and unions using typedef
51 *****************************************************************************/
52 struct fts_esdcheck_st {
53     u8      mode                : 1;    /* 1- need check esd 0- no esd check */
54     u8      suspend             : 1;
55     u8      proc_debug          : 1;    /* apk or adb is accessing I2C */
56     u8      intr                : 1;    /* 1- Interrupt trigger */
57     u8      unused              : 4;
58     u8      flow_work_hold_cnt;         /* Flow Work Cnt(reg0x91) keep a same value for x times. >=5 times is ESD, need reset */
59     u8      flow_work_cnt_last;         /* Save Flow Work Cnt(reg0x91) value */
60     u32     hardware_reset_cnt;
61     u32     i2c_nack_cnt;
62     u32     i2c_dataerror_cnt;
63 };
64 
65 /*****************************************************************************
66 * Static variables
67 *****************************************************************************/
68 static struct fts_esdcheck_st fts_esdcheck_data;
69 
70 /*****************************************************************************
71 * Global variable or extern global variabls/functions
72 *****************************************************************************/
73 
74 /*****************************************************************************
75 * Static function prototypes
76 *****************************************************************************/
77 
78 /*****************************************************************************
79 * functions body
80 *****************************************************************************/
81 #if LCD_ESD_PATCH
82 /*****************************************************************************
83 *  Name: lcd_esdcheck
84 *  Brief:
85 *  Input:
86 *  Output:
87 *  Return:
88 *****************************************************************************/
89 int lcd_need_reset;
90 static int tp_need_recovery; /* LCD reset cause Tp reset */
idc_esdcheck_lcderror(struct fts_ts_data * ts_data)91 int idc_esdcheck_lcderror(struct fts_ts_data *ts_data)
92 {
93     int ret = 0;
94     u8 val = 0;
95     struct i2c_client *client = ts_data->client;
96 
97     FTS_DEBUG("[ESD]Check LCD ESD");
98     if ( (tp_need_recovery == 1) && (lcd_need_reset == 0) ) {
99         tp_need_recovery = 0;
100         /* LCD reset, need recover TP state */
101         fts_tp_state_recovery(client);
102     }
103 
104     ret = fts_i2c_read_reg(client, FTS_REG_ESD_SATURATE, &val);
105     if ( ret < 0) {
106         FTS_ERROR("[ESD]: Read ESD_SATURATE(0xED) failed ret=%d!", ret);
107         return -EIO;
108     }
109 
110     if (val == 0xAA) {
111         /*
112         * 1. Set flag lcd_need_reset = 1;
113         * 2. LCD driver need reset(recovery) LCD and set lcd_need_reset to 0
114         * 3. recover TP state
115         */
116         FTS_INFO("LCD ESD, Execute LCD reset!");
117         lcd_need_reset = 1;
118         tp_need_recovery = 1;
119     }
120 
121     return 0;
122 }
123 #endif
124 
125 /*****************************************************************************
126 *  Name: fts_esdcheck_tp_reset
127 *  Brief: esd check algorithm
128 *  Input:
129 *  Output:
130 *  Return:
131 *****************************************************************************/
fts_esdcheck_tp_reset(struct fts_ts_data * ts_data)132 static int fts_esdcheck_tp_reset(struct fts_ts_data *ts_data)
133 {
134     FTS_FUNC_ENTER();
135 
136     fts_esdcheck_data.flow_work_hold_cnt = 0;
137     fts_esdcheck_data.hardware_reset_cnt++;
138 
139     fts_reset_proc(200);
140     fts_tp_state_recovery(ts_data->client);
141 
142     FTS_FUNC_EXIT();
143     return 0;
144 }
145 
146 /*****************************************************************************
147 *  Name: get_chip_id
148 *  Brief: Read Chip Id 3 times
149 *  Input:
150 *  Output:
151 *  Return:  1 - Read Chip Id 3 times failed
152 *           0 - Read Chip Id pass
153 *****************************************************************************/
get_chip_id(struct fts_ts_data * ts_data)154 static bool get_chip_id(struct fts_ts_data *ts_data)
155 {
156     int ret = 0;
157     int i = 0;
158     u8 reg_value = 0;
159     u8 reg_addr = 0;
160     struct i2c_client *client = ts_data->client;
161     u8 chip_id = ts_data->ic_info.ids.chip_idh;
162 
163     for (i = 0; i < 3; i++) {
164         reg_addr = FTS_REG_CHIP_ID;
165         ret = fts_i2c_read(client, &reg_addr, 1, &reg_value, 1);
166         if (ret < 0) {
167             FTS_ERROR("[ESD]: Read Reg 0xA3 failed ret = %d!!", ret);
168             fts_esdcheck_data.i2c_nack_cnt++;
169         } else {
170             if (reg_value == chip_id) {
171                 break;
172             } else {
173                 fts_esdcheck_data.i2c_dataerror_cnt++;
174             }
175         }
176         msleep(10);
177     }
178 
179     /* if can't get correct data in 3 times, then need hardware reset */
180     if (i >= 3) {
181         FTS_ERROR("[ESD]: Read Chip id 3 times failed, need execute TP reset!!");
182         return 1;
183     }
184 
185     return 0;
186 }
187 
188 /*****************************************************************************
189 *  Name: get_flow_cnt
190 *  Brief: Read flow cnt(0x91)
191 *  Input:
192 *  Output:
193 *  Return:  1 - Reg 0x91(flow cnt) abnormal: hold a value for 5 times
194 *           0 - Reg 0x91(flow cnt) normal
195 *****************************************************************************/
get_flow_cnt(struct fts_ts_data * ts_data)196 static bool get_flow_cnt(struct fts_ts_data *ts_data)
197 {
198     int     ret = 0;
199     u8      reg_value = 0;
200     u8      reg_addr = 0;
201     struct i2c_client *client = ts_data->client;
202 
203     reg_addr = FTS_REG_FLOW_WORK_CNT;
204     ret = fts_i2c_read(client, &reg_addr, 1, &reg_value, 1);
205     if (ret < 0) {
206         FTS_ERROR("[ESD]: Read Reg 0x91 failed ret = %d!!", ret);
207         fts_esdcheck_data.i2c_nack_cnt++;
208     } else {
209         if ( reg_value == fts_esdcheck_data.flow_work_cnt_last ) {
210             fts_esdcheck_data.flow_work_hold_cnt++;
211         } else {
212             fts_esdcheck_data.flow_work_hold_cnt = 0;
213         }
214 
215         fts_esdcheck_data.flow_work_cnt_last = reg_value;
216     }
217 
218     /* if read flow work cnt 5 times and the value are all the same, then need hardware_reset */
219     if (fts_esdcheck_data.flow_work_hold_cnt >= 5) {
220         FTS_DEBUG("[ESD]: Flow Work Cnt(reg0x91) keep a value for 5 times, need execute TP reset!!");
221         return 1;
222     }
223 
224     return 0;
225 }
226 
227 /*****************************************************************************
228 *  Name: esdcheck_algorithm
229 *  Brief: esd check algorithm
230 *  Input:
231 *  Output:
232 *  Return:
233 *****************************************************************************/
esdcheck_algorithm(struct fts_ts_data * ts_data)234 static int esdcheck_algorithm(struct fts_ts_data *ts_data)
235 {
236     int     ret = 0;
237     u8      reg_value = 0;
238     u8      reg_addr = 0;
239     bool    hardware_reset = 0;
240     struct i2c_client *client = ts_data->client;
241 
242     /* 1. esdcheck is interrupt, then return */
243     if (fts_esdcheck_data.intr == 1) {
244         FTS_DEBUG("[ESD]: In interrupt state, not check esd, return immediately!!");
245         return 0;
246     }
247 
248     /* 2. check power state, if suspend, no need check esd */
249     if (fts_esdcheck_data.suspend == 1) {
250         FTS_DEBUG("[ESD]: In suspend, not check esd, return immediately!!");
251         /* because in suspend state, adb can be used, when upgrade FW, will active ESD check(active = 1)
252         *  But in suspend, then will don't queue_delayed_work, when resume, don't check ESD again
253         */
254         return 0;
255     }
256 
257     /* 3. check fts_esdcheck_data.proc_debug state, if 1-proc busy, no need check esd*/
258     if (fts_esdcheck_data.proc_debug == 1) {
259         FTS_INFO("[ESD]: In apk or adb command mode, not check esd, return immediately!!");
260         return 0;
261     }
262 
263     /* 4. In factory mode, can't check esd */
264     reg_addr = FTS_REG_WORKMODE;
265     ret = fts_i2c_read(client, &reg_addr, 1, &reg_value, 1);
266     if ( ret < 0 ) {
267         fts_esdcheck_data.i2c_nack_cnt++;
268     } else if ( (reg_value & 0x70) !=  FTS_REG_WORKMODE_WORK_VALUE) {
269         FTS_DEBUG("[ESD]: not in work mode, no check esd, return immediately!!");
270         return 0;
271     }
272 
273     /* 5. IDC esd check lcd  default:close */
274 #if LCD_ESD_PATCH
275     idc_esdcheck_lcderror(ts_data);
276 #endif
277 
278     /* 6. Get Chip ID */
279     hardware_reset = get_chip_id(ts_data);
280 
281     /* 7. get Flow work cnt: 0x91 If no change for 5 times, then ESD and reset */
282     if (!hardware_reset) {
283         hardware_reset = get_flow_cnt(ts_data);
284     }
285 
286     /* 8. If need hardware reset, then handle it here */
287     if ( hardware_reset == 1) {
288         fts_esdcheck_tp_reset(ts_data);
289     }
290 
291     FTS_DEBUG("[ESD]: NoACK=%d, Error Data=%d, Hardware Reset=%d", fts_esdcheck_data.i2c_nack_cnt, fts_esdcheck_data.i2c_dataerror_cnt, fts_esdcheck_data.hardware_reset_cnt);
292     return 0;
293 }
294 
295 /*****************************************************************************
296 *  Name: fts_esdcheck_func
297 *  Brief: fts_esdcheck_func
298 *  Input:
299 *  Output:
300 *  Return:
301 *****************************************************************************/
esdcheck_func(struct work_struct * work)302 static void esdcheck_func(struct work_struct *work)
303 {
304     u8 val = 0;
305     struct fts_ts_data *ts_data = container_of(work,
306                                   struct fts_ts_data, esdcheck_work.work);
307 
308     FTS_FUNC_ENTER();
309     if (ENABLE == fts_esdcheck_data.mode) {
310         if (ts_data->ic_info.is_incell) {
311             fts_i2c_read_reg(ts_data->client, FTS_REG_ESDCHECK_DISABLE, &val);
312             if (0xA5 == val) {
313                 fts_esdcheck_data.mode = DISABLE;
314                 return;
315             }
316         }
317         esdcheck_algorithm(ts_data);
318         queue_delayed_work(ts_data->ts_workqueue, &ts_data->esdcheck_work,
319                            msecs_to_jiffies(ESDCHECK_WAIT_TIME));
320     }
321     FTS_FUNC_EXIT();
322 }
323 
324 /*****************************************************************************
325 *  Name: fts_esdcheck_set_intr
326 *  Brief: interrupt flag (main used in interrupt tp report)
327 *  Input:
328 *  Output:
329 *  Return:
330 *****************************************************************************/
fts_esdcheck_set_intr(bool intr)331 int fts_esdcheck_set_intr(bool intr)
332 {
333     /* interrupt don't add debug message */
334     fts_esdcheck_data.intr = intr;
335     return 0;
336 }
337 
338 /*****************************************************************************
339 *  Name: fts_esdcheck_get_status(void)
340 *  Brief: get current status
341 *  Input:
342 *  Output:
343 *  Return:
344 *****************************************************************************/
fts_esdcheck_get_status(void)345 int fts_esdcheck_get_status(void)
346 {
347     /* interrupt don't add debug message */
348     return fts_esdcheck_data.mode;
349 }
350 
351 /*****************************************************************************
352 *  Name: fts_esdcheck_proc_busy
353 *  Brief: When APK or ADB command access TP via driver, then need set proc_debug,
354 *         then will not check ESD.
355 *  Input:
356 *  Output:
357 *  Return:
358 *****************************************************************************/
fts_esdcheck_proc_busy(bool proc_debug)359 int fts_esdcheck_proc_busy(bool proc_debug)
360 {
361     fts_esdcheck_data.proc_debug = proc_debug;
362     return 0;
363 }
364 
365 /*****************************************************************************
366 *  Name: fts_esdcheck_switch
367 *  Brief: FTS esd check function switch.
368 *  Input:   enable:  1 - Enable esd check
369 *                    0 - Disable esd check
370 *  Output:
371 *  Return:
372 *****************************************************************************/
fts_esdcheck_switch(bool enable)373 int fts_esdcheck_switch(bool enable)
374 {
375     struct fts_ts_data *ts_data = fts_data;
376     FTS_FUNC_ENTER();
377     if (fts_esdcheck_data.mode == ENABLE) {
378         if (enable) {
379             FTS_DEBUG("[ESD]: ESD check start!!");
380             fts_esdcheck_data.flow_work_hold_cnt = 0;
381             fts_esdcheck_data.flow_work_cnt_last = 0;
382             queue_delayed_work(ts_data->ts_workqueue, &ts_data->esdcheck_work,
383                                msecs_to_jiffies(ESDCHECK_WAIT_TIME));
384         } else {
385             FTS_DEBUG("[ESD]: ESD check stop!!");
386             cancel_delayed_work(&ts_data->esdcheck_work);
387         }
388     } else {
389         FTS_DEBUG("[ESD]: ESD should disable!!");
390         cancel_delayed_work(&ts_data->esdcheck_work);
391     }
392 
393     FTS_FUNC_EXIT();
394     return 0;
395 }
396 
397 /*****************************************************************************
398 *  Name: fts_esdcheck_suspend
399 *  Brief: Run when tp enter into suspend
400 *  Input:
401 *  Output:
402 *  Return:
403 *****************************************************************************/
fts_esdcheck_suspend(void)404 int fts_esdcheck_suspend(void)
405 {
406     FTS_FUNC_ENTER();
407     fts_esdcheck_switch(DISABLE);
408     fts_esdcheck_data.suspend = 1;
409     FTS_FUNC_EXIT();
410     return 0;
411 }
412 
413 /*****************************************************************************
414 *  Name: fts_esdcheck_resume
415 *  Brief: Run when tp resume
416 *  Input:
417 *  Output:
418 *  Return:
419 *****************************************************************************/
fts_esdcheck_resume(void)420 int fts_esdcheck_resume( void )
421 {
422     FTS_FUNC_ENTER();
423     fts_esdcheck_switch(ENABLE);
424     fts_esdcheck_data.suspend = 0;
425     FTS_FUNC_EXIT();
426     return 0;
427 }
428 
429 /************************************************************************
430 * Name: fts_esdcheck_store
431 * Brief:  no
432 * Input: device, device attribute, char buf, char count
433 * Output: no
434 * Return: EPERM
435 ***********************************************************************/
fts_esdcheck_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)436 static ssize_t fts_esdcheck_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
437 {
438     struct input_dev *input_dev = fts_data->input_dev;
439 
440     mutex_lock(&input_dev->mutex);
441     if (FTS_SYSFS_ECHO_ON(buf)) {
442         FTS_DEBUG("enable esdcheck");
443         fts_esdcheck_data.mode = ENABLE;
444         fts_esdcheck_switch(ENABLE);
445     } else if (FTS_SYSFS_ECHO_OFF(buf)) {
446         FTS_DEBUG("disable esdcheck");
447         fts_esdcheck_data.mode = DISABLE;
448         fts_esdcheck_switch(DISABLE);
449     }
450     mutex_unlock(&input_dev->mutex);
451 
452     return count;
453 }
454 
455 /************************************************************************
456 * Name: fts_esdcheck_show
457 * Brief:  no
458 * Input: device, device attribute, char buf
459 * Output: no
460 * Return: EPERM
461 ***********************************************************************/
fts_esdcheck_show(struct device * dev,struct device_attribute * attr,char * buf)462 static ssize_t fts_esdcheck_show(struct device *dev, struct device_attribute *attr, char *buf)
463 {
464     int count;
465     struct input_dev *input_dev = fts_data->input_dev;
466 
467     mutex_lock(&input_dev->mutex);
468     count = snprintf(buf, PAGE_SIZE, "Esd check: %s\n", fts_esdcheck_get_status() ? "On" : "Off");
469     mutex_unlock(&input_dev->mutex);
470 
471     return count;
472 }
473 
474 /* sysfs esd node
475  *   read example: cat  fts_esd_mode        ---read esd mode
476  *   write example:echo 01 > fts_esd_mode   ---make esdcheck enable
477  *
478  */
479 static DEVICE_ATTR (fts_esd_mode, S_IRUGO | S_IWUSR, fts_esdcheck_show, fts_esdcheck_store);
480 
481 static struct attribute *fts_esd_mode_attrs[] = {
482 
483     &dev_attr_fts_esd_mode.attr,
484     NULL,
485 };
486 
487 static struct attribute_group fts_esd_group = {
488     .attrs = fts_esd_mode_attrs,
489 };
490 /*****************************************************************************
491 *   Name: fts_create_gesture_sysfs
492 *  Brief:
493 *  Input:
494 * Output:
495 * Return: 0-success or others-error
496 *****************************************************************************/
fts_create_esd_sysfs(struct i2c_client * client)497 int fts_create_esd_sysfs(struct i2c_client *client)
498 {
499     int ret = 0;
500 
501     ret = sysfs_create_group(&client->dev.kobj, &fts_esd_group);
502     if ( ret != 0) {
503         FTS_ERROR("fts_create_esd_sysfs(sysfs) create failed!");
504         sysfs_remove_group(&client->dev.kobj, &fts_esd_group);
505         return ret;
506     }
507     return 0;
508 }
509 
510 /*****************************************************************************
511 *  Name: fts_esdcheck_init
512 *  Brief: Init and create a queue work to check esd
513 *  Input:
514 *  Output:
515 *  Return: < 0: Fail to create esd check queue
516 *****************************************************************************/
fts_esdcheck_init(struct fts_ts_data * ts_data)517 int fts_esdcheck_init(struct fts_ts_data *ts_data)
518 {
519     FTS_FUNC_ENTER();
520 
521     if (ts_data->ts_workqueue) {
522         INIT_DELAYED_WORK(&ts_data->esdcheck_work, esdcheck_func);
523     } else {
524         FTS_ERROR("fts workqueue is NULL, can't run esd check function");
525         return -EINVAL;
526     }
527 
528     memset((u8 *)&fts_esdcheck_data, 0, sizeof(struct fts_esdcheck_st));
529 
530     fts_esdcheck_data.mode = ENABLE;
531     fts_esdcheck_switch(ENABLE);
532     fts_create_esd_sysfs(ts_data->client);
533     FTS_FUNC_EXIT();
534     return 0;
535 }
536 
537 /*****************************************************************************
538 *  Name: fts_esdcheck_exit
539 *  Brief: When FTS TP driver is removed, then call this function to destory work queue
540 *  Input:
541 *  Output:
542 *  Return:
543 *****************************************************************************/
fts_esdcheck_exit(struct fts_ts_data * ts_data)544 int fts_esdcheck_exit(struct fts_ts_data *ts_data)
545 {
546     FTS_FUNC_ENTER();
547 
548     FTS_FUNC_EXIT();
549     return 0;
550 }
551 #endif /* FTS_ESDCHECK_EN */
552 
553