xref: /OK3568_Linux_fs/kernel/drivers/input/touchscreen/focaltech_touch_ft5436/focaltech_esdcheck.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  *
3  * FocalTech TouchScreen driver.
4  *
5  * Copyright (c) 2012-2019, 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 #define ESDCHECK_INTRCNT_MAX            2
49 
50 /*****************************************************************************
51 * Private enumerations, structures and unions using typedef
52 *****************************************************************************/
53 struct fts_esdcheck_st {
54     u8      mode                : 1;    /* 1- need check esd 0- no esd check */
55     u8      suspend             : 1;
56     u8      proc_debug          : 1;    /* apk or adb use */
57     u8      intr                : 1;    /* 1- Interrupt trigger */
58     u8      unused              : 4;
59     u8      intr_cnt;
60     u8      flow_work_hold_cnt;         /* Flow Work Cnt(reg0x91) keep a same value for x times. >=5 times is ESD, need reset */
61     u8      flow_work_cnt_last;         /* Save Flow Work Cnt(reg0x91) value */
62     u32     hardware_reset_cnt;
63     u32     nack_cnt;
64     u32     dataerror_cnt;
65 };
66 
67 /*****************************************************************************
68 * Static variables
69 *****************************************************************************/
70 static struct fts_esdcheck_st fts_esdcheck_data;
71 
72 /*****************************************************************************
73 * Global variable or extern global variabls/functions
74 *****************************************************************************/
75 
76 /*****************************************************************************
77 * Static function prototypes
78 *****************************************************************************/
79 
80 /*****************************************************************************
81 * functions body
82 *****************************************************************************/
83 #if LCD_ESD_PATCH
84 int lcd_need_reset;
85 static int tp_need_recovery; /* LCD reset cause Tp reset */
idc_esdcheck_lcderror(struct fts_ts_data * ts_data)86 int idc_esdcheck_lcderror(struct fts_ts_data *ts_data)
87 {
88     int ret = 0;
89     u8 val = 0;
90 
91     FTS_DEBUG("check LCD ESD");
92     if ( (tp_need_recovery == 1) && (lcd_need_reset == 0) ) {
93         tp_need_recovery = 0;
94         /* LCD reset, need recover TP state */
95         fts_release_all_finger();
96         fts_tp_state_recovery(ts_data);
97     }
98 
99     ret = fts_read_reg(FTS_REG_ESD_SATURATE, &val);
100     if ( ret < 0) {
101         FTS_ERROR("read reg0xED fail,ret:%d", ret);
102         return -EIO;
103     }
104 
105     if (val == 0xAA) {
106         /*
107         * 1. Set flag lcd_need_reset = 1;
108         * 2. LCD driver need reset(recovery) LCD and set lcd_need_reset to 0
109         * 3. recover TP state
110         */
111         FTS_INFO("LCD ESD, need execute LCD reset");
112         lcd_need_reset = 1;
113         tp_need_recovery = 1;
114     }
115 
116     return 0;
117 }
118 #endif
119 
fts_esdcheck_tp_reset(struct fts_ts_data * ts_data)120 static int fts_esdcheck_tp_reset(struct fts_ts_data *ts_data)
121 {
122     FTS_FUNC_ENTER();
123 
124     fts_esdcheck_data.flow_work_hold_cnt = 0;
125     fts_esdcheck_data.hardware_reset_cnt++;
126 
127     fts_reset_proc(200);
128     fts_release_all_finger();
129     fts_tp_state_recovery(ts_data);
130 
131     FTS_FUNC_EXIT();
132     return 0;
133 }
134 
get_chip_id(struct fts_ts_data * ts_data)135 static bool get_chip_id(struct fts_ts_data *ts_data)
136 {
137     int ret = 0;
138     int i = 0;
139     u8 reg_value = 0;
140     u8 reg_addr = 0;
141     u8 chip_id = ts_data->ic_info.ids.chip_idh;
142 
143     for (i = 0; i < 3; i++) {
144         reg_addr = FTS_REG_CHIP_ID;
145         ret = fts_read(&reg_addr, 1, &reg_value, 1);
146         if (ret < 0) {
147             FTS_ERROR("read chip id fail,ret:%d", ret);
148             fts_esdcheck_data.nack_cnt++;
149         } else {
150             if (reg_value == chip_id) {
151                 break;
152             } else {
153                 FTS_DEBUG("read chip_id:%x,retry:%d", reg_value, i);
154                 fts_esdcheck_data.dataerror_cnt++;
155             }
156         }
157         msleep(10);
158     }
159 
160     /* if can't get correct data in 3 times, then need hardware reset */
161     if (i >= 3) {
162         FTS_ERROR("read chip id 3 times fail, need execute TP reset");
163         return true;
164     }
165 
166     return false;
167 }
168 
169 /*****************************************************************************
170 *  Name: get_flow_cnt
171 *  Brief: Read flow cnt(0x91)
172 *  Input:
173 *  Output:
174 *  Return:  1(true) - Reg 0x91(flow cnt) abnormal: hold a value for 5 times
175 *           0(false) - Reg 0x91(flow cnt) normal
176 *****************************************************************************/
get_flow_cnt(struct fts_ts_data * ts_data)177 static bool get_flow_cnt(struct fts_ts_data *ts_data)
178 {
179     int     ret = 0;
180     u8      reg_value = 0;
181     u8      reg_addr = 0;
182 
183     reg_addr = FTS_REG_FLOW_WORK_CNT;
184     ret = fts_read(&reg_addr, 1, &reg_value, 1);
185     if (ret < 0) {
186         FTS_ERROR("read reg0x91 fail,ret:%d", ret);
187         fts_esdcheck_data.nack_cnt++;
188     } else {
189         if ( reg_value == fts_esdcheck_data.flow_work_cnt_last ) {
190             FTS_DEBUG("reg0x91,val:%x,last:%x", reg_value,
191                       fts_esdcheck_data.flow_work_cnt_last);
192             fts_esdcheck_data.flow_work_hold_cnt++;
193         } else {
194             fts_esdcheck_data.flow_work_hold_cnt = 0;
195         }
196 
197         fts_esdcheck_data.flow_work_cnt_last = reg_value;
198     }
199 
200     /* Flow Work Cnt keep a value for 5 times, need execute TP reset */
201     if (fts_esdcheck_data.flow_work_hold_cnt >= 5) {
202         FTS_DEBUG("reg0x91 keep a value for 5 times, need execute TP reset");
203         return true;
204     }
205 
206     return false;
207 }
208 
esdcheck_algorithm(struct fts_ts_data * ts_data)209 static int esdcheck_algorithm(struct fts_ts_data *ts_data)
210 {
211     int     ret = 0;
212     u8      reg_value = 0;
213     u8      reg_addr = 0;
214     bool    hardware_reset = 0;
215 
216     /* 1. esdcheck is interrupt, then return */
217     if (fts_esdcheck_data.intr == 1) {
218         fts_esdcheck_data.intr_cnt++;
219         if (fts_esdcheck_data.intr_cnt > ESDCHECK_INTRCNT_MAX)
220             fts_esdcheck_data.intr = 0;
221         else
222             return 0;
223     }
224 
225     /* 2. check power state, if suspend, no need check esd */
226     if (fts_esdcheck_data.suspend == 1) {
227         FTS_DEBUG("In suspend, not check esd");
228         /* because in suspend state, adb can be used, when upgrade FW, will
229          * active ESD check(active = 1); But in suspend, then will don't
230          * queue_delayed_work, when resume, don't check ESD again
231          */
232         return 0;
233     }
234 
235     /* 3. check fts_esdcheck_data.proc_debug state, if 1-proc busy, no need check esd*/
236     if (fts_esdcheck_data.proc_debug == 1) {
237         FTS_INFO("In apk/adb command mode, not check esd");
238         return 0;
239     }
240 
241     /* 4. In factory mode, can't check esd */
242     reg_addr = FTS_REG_WORKMODE;
243     ret = fts_read_reg(reg_addr, &reg_value);
244     if ( ret < 0 ) {
245         fts_esdcheck_data.nack_cnt++;
246     } else if ( (reg_value & 0x70) !=  FTS_REG_WORKMODE_WORK_VALUE) {
247         FTS_DEBUG("not in work mode(%x), no check esd", reg_value);
248         return 0;
249     }
250 
251     /* 5. IDC esd check lcd  default:close */
252 #if LCD_ESD_PATCH
253     idc_esdcheck_lcderror(ts_data);
254 #endif
255 
256     /* 6. Get Chip ID */
257     hardware_reset = get_chip_id(ts_data);
258 
259     /* 7. get Flow work cnt: 0x91 If no change for 5 times, then ESD and reset */
260     if (!hardware_reset) {
261         hardware_reset = get_flow_cnt(ts_data);
262     }
263 
264     /* 8. If need hardware reset, then handle it here */
265     if (hardware_reset == 1) {
266         FTS_DEBUG("NoACK=%d, Error Data=%d, Hardware Reset=%d",
267                   fts_esdcheck_data.nack_cnt,
268                   fts_esdcheck_data.dataerror_cnt,
269                   fts_esdcheck_data.hardware_reset_cnt);
270         fts_esdcheck_tp_reset(ts_data);
271     }
272 
273     return 0;
274 }
275 
esdcheck_func(struct work_struct * work)276 static void esdcheck_func(struct work_struct *work)
277 {
278     struct fts_ts_data *ts_data = container_of(work,
279                                   struct fts_ts_data, esdcheck_work.work);
280 
281     if (ENABLE == fts_esdcheck_data.mode) {
282         esdcheck_algorithm(ts_data);
283         queue_delayed_work(ts_data->ts_workqueue, &ts_data->esdcheck_work,
284                            msecs_to_jiffies(ESDCHECK_WAIT_TIME));
285     }
286 
287 }
288 
fts_esdcheck_set_intr(bool intr)289 int fts_esdcheck_set_intr(bool intr)
290 {
291     /* interrupt don't add debug message */
292     fts_esdcheck_data.intr = intr;
293     fts_esdcheck_data.intr_cnt = (u8)intr;
294     return 0;
295 }
296 
fts_esdcheck_get_status(void)297 static int fts_esdcheck_get_status(void)
298 {
299     /* interrupt don't add debug message */
300     return fts_esdcheck_data.mode;
301 }
302 
303 /*****************************************************************************
304 *  Name: fts_esdcheck_proc_busy
305 *  Brief: When APK or ADB command access TP via driver, then need set proc_debug,
306 *         then will not check ESD.
307 *  Input:
308 *  Output:
309 *  Return:
310 *****************************************************************************/
fts_esdcheck_proc_busy(bool proc_debug)311 int fts_esdcheck_proc_busy(bool proc_debug)
312 {
313     fts_esdcheck_data.proc_debug = proc_debug;
314     return 0;
315 }
316 
317 /*****************************************************************************
318 *  Name: fts_esdcheck_switch
319 *  Brief: FTS esd check function switch.
320 *  Input:   enable:  1 - Enable esd check
321 *                    0 - Disable esd check
322 *  Output:
323 *  Return:
324 *****************************************************************************/
fts_esdcheck_switch(bool enable)325 int fts_esdcheck_switch(bool enable)
326 {
327     struct fts_ts_data *ts_data = fts_data;
328     FTS_FUNC_ENTER();
329     if (fts_esdcheck_data.mode == ENABLE) {
330         if (enable) {
331             FTS_DEBUG("ESD check start");
332             fts_esdcheck_data.flow_work_hold_cnt = 0;
333             fts_esdcheck_data.flow_work_cnt_last = 0;
334             fts_esdcheck_data.intr = 0;
335             fts_esdcheck_data.intr_cnt = 0;
336             queue_delayed_work(ts_data->ts_workqueue,
337                                &ts_data->esdcheck_work,
338                                msecs_to_jiffies(ESDCHECK_WAIT_TIME));
339         } else {
340             FTS_DEBUG("ESD check stop");
341             cancel_delayed_work_sync(&ts_data->esdcheck_work);
342         }
343     }
344 
345     FTS_FUNC_EXIT();
346     return 0;
347 }
348 
fts_esdcheck_suspend(void)349 int fts_esdcheck_suspend(void)
350 {
351     FTS_FUNC_ENTER();
352     fts_esdcheck_switch(DISABLE);
353     fts_esdcheck_data.suspend = 1;
354     fts_esdcheck_data.intr = 0;
355     fts_esdcheck_data.intr_cnt = 0;
356     FTS_FUNC_EXIT();
357     return 0;
358 }
359 
fts_esdcheck_resume(void)360 int fts_esdcheck_resume( void )
361 {
362     FTS_FUNC_ENTER();
363     fts_esdcheck_switch(ENABLE);
364     fts_esdcheck_data.suspend = 0;
365     fts_esdcheck_data.intr = 0;
366     fts_esdcheck_data.intr_cnt = 0;
367     FTS_FUNC_EXIT();
368     return 0;
369 }
370 
fts_esdcheck_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)371 static ssize_t fts_esdcheck_store(
372     struct device *dev,
373     struct device_attribute *attr, const char *buf, size_t count)
374 {
375     struct input_dev *input_dev = fts_data->input_dev;
376 
377     mutex_lock(&input_dev->mutex);
378     if (FTS_SYSFS_ECHO_ON(buf)) {
379         FTS_DEBUG("enable esdcheck");
380         fts_esdcheck_data.mode = ENABLE;
381         fts_esdcheck_switch(ENABLE);
382     } else if (FTS_SYSFS_ECHO_OFF(buf)) {
383         FTS_DEBUG("disable esdcheck");
384         fts_esdcheck_switch(DISABLE);
385         fts_esdcheck_data.mode = DISABLE;
386     }
387     mutex_unlock(&input_dev->mutex);
388 
389     return count;
390 }
391 
fts_esdcheck_show(struct device * dev,struct device_attribute * attr,char * buf)392 static ssize_t fts_esdcheck_show(
393     struct device *dev, struct device_attribute *attr, char *buf)
394 {
395     int count;
396     struct input_dev *input_dev = fts_data->input_dev;
397 
398     mutex_lock(&input_dev->mutex);
399     count = snprintf(buf, PAGE_SIZE, "Esd check: %s\n", \
400                      fts_esdcheck_get_status() ? "On" : "Off");
401     mutex_unlock(&input_dev->mutex);
402 
403     return count;
404 }
405 
406 /* sysfs esd node
407  *   read example: cat  fts_esd_mode        ---read esd mode
408  *   write example:echo 01 > fts_esd_mode   ---make esdcheck enable
409  *
410  */
411 static DEVICE_ATTR (fts_esd_mode, S_IRUGO | S_IWUSR, fts_esdcheck_show, fts_esdcheck_store);
412 
413 static struct attribute *fts_esd_mode_attrs[] = {
414 
415     &dev_attr_fts_esd_mode.attr,
416     NULL,
417 };
418 
419 static struct attribute_group fts_esd_group = {
420     .attrs = fts_esd_mode_attrs,
421 };
422 
fts_create_esd_sysfs(struct device * dev)423 int fts_create_esd_sysfs(struct device *dev)
424 {
425     int ret = 0;
426 
427     ret = sysfs_create_group(&dev->kobj, &fts_esd_group);
428     if ( ret != 0) {
429         FTS_ERROR("fts_create_esd_sysfs(sysfs) create fail");
430         sysfs_remove_group(&dev->kobj, &fts_esd_group);
431         return ret;
432     }
433     return 0;
434 }
435 
fts_esdcheck_init(struct fts_ts_data * ts_data)436 int fts_esdcheck_init(struct fts_ts_data *ts_data)
437 {
438     FTS_FUNC_ENTER();
439 
440     if (ts_data->ts_workqueue) {
441         INIT_DELAYED_WORK(&ts_data->esdcheck_work, esdcheck_func);
442     } else {
443         FTS_ERROR("fts workqueue is NULL, can't run esd check function");
444         return -EINVAL;
445     }
446 
447     memset((u8 *)&fts_esdcheck_data, 0, sizeof(struct fts_esdcheck_st));
448 
449     fts_esdcheck_data.mode = ENABLE;
450     fts_esdcheck_data.intr = 0;
451     fts_esdcheck_data.intr_cnt = 0;
452     fts_esdcheck_switch(ENABLE);
453     fts_create_esd_sysfs(ts_data->dev);
454     FTS_FUNC_EXIT();
455     return 0;
456 }
457 
fts_esdcheck_exit(struct fts_ts_data * ts_data)458 int fts_esdcheck_exit(struct fts_ts_data *ts_data)
459 {
460     sysfs_remove_group(&ts_data->dev->kobj, &fts_esd_group);
461     return 0;
462 }
463 #endif /* FTS_ESDCHECK_EN */
464 
465