focaltech_esdcheck.c 13 KB

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