cyttsp5_mt_common.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149
  1. /*
  2. * cyttsp5_mt_common.c
  3. * Cypress TrueTouch(TM) Standard Product V5 Multi-Touch Reports Module.
  4. * For use with Cypress Txx5xx parts.
  5. * Supported parts include:
  6. * TMA5XX
  7. *
  8. * Copyright (C) 2012-2013 Cypress Semiconductor
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * version 2, and only version 2, as published by the
  13. * Free Software Foundation.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
  21. *
  22. */
  23. #include "cyttsp5_regs.h"
  24. #include <linux/input/mt.h>
  25. #define CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MT_B
  26. #define CYTTSP5_TOUCHLOG_ENABLE 0
  27. #define FORCE_SATISFY_PALMPAUSE_FOR_LARGEOBJ
  28. #if defined(TSP_BOOSTER)
  29. #include <linux/cpufreq.h>
  30. #define DVFS_STAGE_DUAL 2
  31. #define DVFS_STAGE_SINGLE 1
  32. #define DVFS_STAGE_NONE 0
  33. #define TOUCH_BOOSTER_OFF_TIME 300
  34. #define TOUCH_BOOSTER_CHG_TIME 200
  35. static void change_dvfs_lock(struct work_struct *work)
  36. {
  37. struct cyttsp5_mt_data *md = container_of(work,struct cyttsp5_mt_data, work_dvfs_chg.work);
  38. int ret = 0;
  39. mutex_lock(&md->dvfs_lock);
  40. if (md->boost_level == DVFS_STAGE_DUAL) {
  41. ret = set_freq_limit(DVFS_TOUCH_ID, MIN_TOUCH_LIMIT_SECOND);
  42. md->dvfs_freq = MIN_TOUCH_LIMIT_SECOND;
  43. } else if (md->boost_level == DVFS_STAGE_SINGLE) {
  44. ret = set_freq_limit(DVFS_TOUCH_ID, -1);
  45. md->dvfs_freq = -1;
  46. }
  47. if (ret < 0)
  48. printk(KERN_ERR "[TSP] %s: booster stop failed(%d)\n",\
  49. __func__, __LINE__);
  50. mutex_unlock(&md->dvfs_lock);
  51. }
  52. static void set_dvfs_off(struct work_struct *work)
  53. {
  54. struct cyttsp5_mt_data *md = container_of(work,struct cyttsp5_mt_data, work_dvfs_off.work);
  55. int ret;
  56. mutex_lock(&md->dvfs_lock);
  57. ret = set_freq_limit(DVFS_TOUCH_ID, -1);
  58. if (ret < 0)
  59. printk(KERN_ERR "[TSP] %s: booster stop failed(%d)\n",\
  60. __func__, __LINE__);
  61. md->dvfs_freq = -1;
  62. md->dvfs_lock_status = false;
  63. mutex_unlock(&md->dvfs_lock);
  64. }
  65. static void set_dvfs_lock(struct cyttsp5_mt_data *md, int32_t on, bool mode)
  66. {
  67. int ret = 0;
  68. if (md->boost_level == DVFS_STAGE_NONE) {
  69. printk(KERN_INFO "%s: DVFS stage is none(%d)\n", __func__, md->boost_level);
  70. return;
  71. }
  72. mutex_lock(&md->dvfs_lock);
  73. if (on == 0) {
  74. if (md->dvfs_lock_status) {
  75. schedule_delayed_work(&md->work_dvfs_off,msecs_to_jiffies(TOUCH_BOOSTER_OFF_TIME));
  76. }
  77. } else if (on == 1) {
  78. cancel_delayed_work(&md->work_dvfs_off);
  79. if (!md->dvfs_lock_status || mode) {
  80. if (md->dvfs_old_status != on) {
  81. cancel_delayed_work(&md->work_dvfs_chg);
  82. if (md->dvfs_freq != MIN_TOUCH_LIMIT) {
  83. ret = set_freq_limit(DVFS_TOUCH_ID,
  84. MIN_TOUCH_LIMIT);
  85. md->dvfs_freq = MIN_TOUCH_LIMIT;
  86. if (ret < 0)
  87. printk(KERN_ERR
  88. "%s: cpu first lock failed(%d)\n",
  89. __func__, ret);
  90. schedule_delayed_work(&md->work_dvfs_chg,
  91. msecs_to_jiffies(TOUCH_BOOSTER_CHG_TIME));
  92. md->dvfs_lock_status = true;
  93. }
  94. }
  95. }
  96. } else if (on == 2) {
  97. if (md->dvfs_lock_status) {
  98. cancel_delayed_work(&md->work_dvfs_off);
  99. cancel_delayed_work(&md->work_dvfs_chg);
  100. schedule_work(&md->work_dvfs_off.work);
  101. }
  102. }
  103. md->dvfs_old_status = on;
  104. mutex_unlock(&md->dvfs_lock);
  105. }
  106. #endif
  107. #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MT_B
  108. #ifdef SAMSUNG_PALM_MOTION
  109. static void cyttsp5_final_sync(struct input_dev *input, int max_slots,
  110. int mt_sync_count, unsigned long *ids,
  111. u16 sumsize, bool palm)
  112. {
  113. int t;
  114. for (t = 0; t < max_slots; t++) {
  115. if (test_bit(t, ids)) {
  116. input_mt_slot(input, t);
  117. input_report_abs(input, ABS_MT_PALM, palm);
  118. dev_vdbg(input->dev.parent,
  119. "%s:t=%d sumsize=%d palm=%d\n", __func__,
  120. t, sumsize, palm);
  121. continue;
  122. }
  123. input_mt_slot(input, t);
  124. input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
  125. }
  126. input_sync(input);
  127. }
  128. #else
  129. static void cyttsp5_final_sync(struct input_dev *input, int max_slots,
  130. int mt_sync_count, unsigned long *ids)
  131. {
  132. int t;
  133. for (t = 0; t < max_slots; t++) {
  134. if (test_bit(t, ids))
  135. continue;
  136. input_mt_slot(input, t);
  137. input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
  138. }
  139. input_sync(input);
  140. }
  141. #endif
  142. static inline void cyttsp5_input_sync(struct input_dev *input){}
  143. static void cyttsp5_input_report(struct input_dev *input, int sig,
  144. int t, int type)
  145. {
  146. unsigned char tool_type = MT_TOOL_FINGER;
  147. input_mt_slot(input, t);
  148. if (type == CY_OBJ_STYLUS)
  149. tool_type = MT_TOOL_PEN;
  150. input_mt_report_slot_state(input, tool_type, true);
  151. }
  152. static void cyttsp5_report_slot_liftoff(struct cyttsp5_mt_data *md,
  153. int max_slots)
  154. {
  155. int t;
  156. if (md->num_prv_tch == 0)
  157. return;
  158. for (t = 0; t < max_slots; t++) {
  159. input_mt_slot(md->input, t);
  160. input_mt_report_slot_state(md->input,
  161. MT_TOOL_FINGER, false);
  162. }
  163. }
  164. static int cyttsp5_input_register_device(struct input_dev *input,
  165. int max_slots)
  166. {
  167. input_mt_init_slots(input, max_slots);
  168. return input_register_device(input);
  169. }
  170. #endif
  171. static void cyttsp5_mt_lift_all(struct cyttsp5_mt_data *md)
  172. {
  173. int max = MAX_TOUCH_ID_NUMBER;
  174. #ifdef SAMSUNG_PALM_MOTION
  175. md->palm = false;
  176. #endif
  177. if (md->num_prv_tch != 0) {
  178. cyttsp5_report_slot_liftoff(md, max);
  179. input_sync(md->input);
  180. md->num_prv_tch = 0;
  181. }
  182. #if defined(TSP_BOOSTER)
  183. if (md->touch_pressed_num != 0) {
  184. dev_err(md->dev, "%s force dvfs off\n", __func__);
  185. md->touch_pressed_num = 0;
  186. set_dvfs_lock(md, 0, false);
  187. }
  188. #endif
  189. }
  190. static void cyttsp5_get_touch_axis(struct cyttsp5_mt_data *md,
  191. int *axis, int size, int max, u8 *xy_data, int bofs)
  192. {
  193. int nbyte;
  194. int next;
  195. for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) {
  196. dev_vdbg(md->dev,
  197. "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p"
  198. " xy_data[%d]=%02X(%d) bofs=%d\n",
  199. __func__, *axis, *axis, size, max, xy_data, next,
  200. xy_data[next], xy_data[next], bofs);
  201. *axis = *axis + ((xy_data[next] >> bofs) << (nbyte * 8));
  202. next++;
  203. }
  204. *axis &= max - 1;
  205. dev_vdbg(md->dev,
  206. "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p"
  207. " xy_data[%d]=%02X(%d)\n",
  208. __func__, *axis, *axis, size, max, xy_data, next,
  209. xy_data[next], xy_data[next]);
  210. }
  211. static void cyttsp5_get_touch_hdr(struct cyttsp5_mt_data *md,
  212. struct cyttsp5_touch *touch, u8 *xy_mode)
  213. {
  214. struct device *dev = md->dev;
  215. struct cyttsp5_sysinfo *si = md->si;
  216. enum cyttsp5_tch_hdr hdr;
  217. for (hdr = CY_TCH_TIME; hdr < CY_TCH_NUM_HDR; hdr++) {
  218. if (!si->tch_hdr[hdr].report)
  219. continue;
  220. cyttsp5_get_touch_axis(md, &touch->hdr[hdr],
  221. si->tch_hdr[hdr].size,
  222. si->tch_hdr[hdr].max,
  223. xy_mode + si->tch_hdr[hdr].ofs,
  224. si->tch_hdr[hdr].bofs);
  225. dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
  226. cyttsp5_tch_hdr_string[hdr],
  227. touch->hdr[hdr], touch->hdr[hdr]);
  228. }
  229. #if CYTTSP5_TOUCHLOG_ENABLE
  230. dev_dbg(dev,
  231. "%s: time=%X tch_num=%d lo=%d noise=%d counter=%d\n",
  232. __func__,
  233. touch->hdr[CY_TCH_TIME],
  234. touch->hdr[CY_TCH_NUM],
  235. touch->hdr[CY_TCH_LO],
  236. touch->hdr[CY_TCH_NOISE],
  237. touch->hdr[CY_TCH_COUNTER]);
  238. #endif
  239. }
  240. static void cyttsp5_get_touch(struct cyttsp5_mt_data *md,
  241. struct cyttsp5_touch *touch, u8 *xy_data)
  242. {
  243. struct device *dev = md->dev;
  244. struct cyttsp5_sysinfo *si = md->si;
  245. enum cyttsp5_tch_abs abs;
  246. int tmp;
  247. bool flipped;
  248. for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
  249. if (!si->tch_abs[abs].report)
  250. continue;
  251. cyttsp5_get_touch_axis(md, &touch->abs[abs],
  252. si->tch_abs[abs].size,
  253. si->tch_abs[abs].max,
  254. xy_data + si->tch_abs[abs].ofs,
  255. si->tch_abs[abs].bofs);
  256. dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
  257. cyttsp5_tch_abs_string[abs],
  258. touch->abs[abs], touch->abs[abs]);
  259. }
  260. if (md->pdata->flags & CY_MT_FLAG_FLIP) {
  261. tmp = touch->abs[CY_TCH_X];
  262. touch->abs[CY_TCH_X] = touch->abs[CY_TCH_Y];
  263. touch->abs[CY_TCH_Y] = tmp;
  264. flipped = true;
  265. } else
  266. flipped = false;
  267. if (md->pdata->flags & CY_MT_FLAG_INV_X) {
  268. if (flipped)
  269. touch->abs[CY_TCH_X] = si->sensing_conf_data.res_y -
  270. touch->abs[CY_TCH_X];
  271. else
  272. touch->abs[CY_TCH_X] = si->sensing_conf_data.res_x -
  273. touch->abs[CY_TCH_X];
  274. }
  275. if (md->pdata->flags & CY_MT_FLAG_INV_Y) {
  276. if (flipped)
  277. touch->abs[CY_TCH_Y] = si->sensing_conf_data.res_x -
  278. touch->abs[CY_TCH_Y];
  279. else
  280. touch->abs[CY_TCH_Y] = si->sensing_conf_data.res_y -
  281. touch->abs[CY_TCH_Y];
  282. }
  283. dev_vdbg(dev, "%s: flip=%s inv-x=%s inv-y=%s x=%04X(%d) y=%04X(%d)\n",
  284. __func__, flipped ? "true" : "false",
  285. md->pdata->flags & CY_MT_FLAG_INV_X ? "true" : "false",
  286. md->pdata->flags & CY_MT_FLAG_INV_Y ? "true" : "false",
  287. touch->abs[CY_TCH_X], touch->abs[CY_TCH_X],
  288. touch->abs[CY_TCH_Y], touch->abs[CY_TCH_Y]);
  289. }
  290. #define ABS_PARAM(_abs, _param) md->pdata->frmwrk->abs[((_abs) * CY_NUM_ABS_SET) + (_param)]
  291. static inline void print_log(struct device *dev,
  292. struct cyttsp5_touch *tch, int t)
  293. {
  294. #if CYTTSP5_TOUCHLOG_ENABLE
  295. if (tch->abs[CY_TCH_E] == CY_EV_LIFTOFF)
  296. dev_dbg(dev, "%s: t=%d e=%d lift-off\n",
  297. __func__, t, tch->abs[CY_TCH_E]);
  298. dev_dbg(dev,
  299. "%s: t=%d x=%d y=%d z=%d M=%d m=%d o=%d e=%d obj=%d tip=%d\n",
  300. __func__, t,
  301. tch->abs[CY_TCH_X],
  302. tch->abs[CY_TCH_Y],
  303. tch->abs[CY_TCH_P],
  304. tch->abs[CY_TCH_MAJ],
  305. tch->abs[CY_TCH_MIN],
  306. tch->abs[CY_TCH_OR],
  307. tch->abs[CY_TCH_E],
  308. tch->abs[CY_TCH_O],
  309. tch->abs[CY_TCH_TIP]);
  310. #else//CYTTSP5_TOUCHLOG_ENABLE
  311. #ifdef CONFIG_SAMSUNG_PRODUCT_SHIP
  312. if ((tch->abs[CY_TCH_E] == CY_EV_TOUCHDOWN) &&
  313. (tch->abs[CY_TCH_O] != CY_OBJ_HOVER))
  314. dev_info(dev, "P [%d]\n", t);
  315. else if ((tch->abs[CY_TCH_E] == CY_EV_LIFTOFF) &&
  316. (tch->abs[CY_TCH_O] != CY_OBJ_HOVER))
  317. dev_info(dev, "R [%d]\n", t);
  318. #else
  319. if ((tch->abs[CY_TCH_E] == CY_EV_TOUCHDOWN) &&
  320. (tch->abs[CY_TCH_O] != CY_OBJ_HOVER))
  321. dev_err(dev, "P [%d] x=%d y=%d z=%d M=%d m=%d\n",
  322. t, tch->abs[CY_TCH_X],
  323. tch->abs[CY_TCH_Y],
  324. tch->abs[CY_TCH_P],
  325. tch->abs[CY_TCH_MAJ],
  326. tch->abs[CY_TCH_MIN]);
  327. else if ((tch->abs[CY_TCH_E] == CY_EV_LIFTOFF) &&
  328. (tch->abs[CY_TCH_O] != CY_OBJ_HOVER))
  329. dev_err(dev, "R [%d] x=%d y=%d z=%d M=%d m=%d\n",
  330. t, tch->abs[CY_TCH_X],
  331. tch->abs[CY_TCH_Y],
  332. tch->abs[CY_TCH_P],
  333. tch->abs[CY_TCH_MAJ],
  334. tch->abs[CY_TCH_MIN]);
  335. #endif
  336. #endif//CYTTSP5_TOUCHLOG_ENABLE
  337. }
  338. #ifdef SAMSUNG_TOUCH_MODE
  339. static inline void manage_touch_mode(struct cyttsp5_mt_data *md,
  340. struct cyttsp5_touch *tch)
  341. {
  342. if (tch->abs[CY_TCH_O] == CY_OBJ_HOVER) {
  343. if (tch->abs[CY_TCH_E] == CY_EV_TOUCHDOWN) {
  344. /*
  345. * First hover touch event.
  346. * F/W should send hover information in the first touch buffer
  347. */
  348. input_mt_slot(md->input, 0);
  349. input_mt_report_slot_state(md->input, MT_TOOL_FINGER, 1);
  350. input_report_key(md->input, BTN_TOUCH, 0);
  351. input_report_key(md->input, BTN_TOOL_FINGER, 1);
  352. input_report_abs(md->input, ABS_MT_DISTANCE, tch->abs[CY_TCH_P]);
  353. } else if (tch->abs[CY_TCH_E] == CY_EV_LIFTOFF) {
  354. /*
  355. * Release hover slot by force.
  356. * This will change event from hover to normal finger immediately
  357. */
  358. input_mt_slot(md->input, 0);
  359. input_mt_report_slot_state(md->input, MT_TOOL_FINGER, 0);
  360. input_sync(md->input);
  361. }
  362. } else {
  363. if (tch->abs[CY_TCH_E] == CY_EV_TOUCHDOWN) {
  364. input_report_key(md->input, BTN_TOUCH, 1);
  365. input_report_key(md->input, BTN_TOOL_FINGER, 1);
  366. }
  367. }
  368. if (md->glove_switch &&
  369. tch->abs[CY_TCH_E] == CY_EV_TOUCHDOWN) {
  370. input_report_switch(md->input,
  371. SW_GLOVE, md->glove_enable);
  372. md->glove_switch = false;
  373. dev_dbg(md->dev, "%s: glove switch %d\n", __func__,
  374. md->glove_enable);
  375. }
  376. if (tch->abs[CY_TCH_E] == CY_EV_TOUCHDOWN) {
  377. if (
  378. (!md->glove_enable &&
  379. tch->abs[CY_TCH_O] == CY_OBJ_GLOVE
  380. ) ||
  381. (md->glove_enable &&
  382. (tch->abs[CY_TCH_O] == CY_OBJ_STANDARD_FINGER ||
  383. tch->abs[CY_TCH_O] == CY_OBJ_STYLUS)
  384. )
  385. ) {
  386. md->glove_enable = !md->glove_enable;
  387. dev_dbg(md->dev, "%s: ****** glove mode %s\n",
  388. __func__, md->glove_enable ? "on " : "off");
  389. input_report_switch(md->input,
  390. SW_GLOVE, md->glove_enable);
  391. }
  392. }
  393. }
  394. void cyttsp5_mt_glove_enable(struct device *dev, bool enable)
  395. {
  396. struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
  397. struct cyttsp5_mt_data *md;
  398. if (cd == NULL)
  399. return;
  400. md = &cd->md;
  401. if (md == NULL)
  402. return;
  403. dev_dbg(dev, "%s: %d\n", __func__, enable);
  404. md->glove_enable = enable;
  405. md->glove_switch = true;
  406. }
  407. #endif
  408. #ifdef SAMSUNG_PALM_MOTION
  409. static void inline scale_sum_size(struct cyttsp5_mt_data *md,
  410. u16 *sumsize)
  411. {
  412. // struct device *dev = md->dev;
  413. //*sumsize /= 2.5;
  414. *sumsize *= 2;
  415. *sumsize /= 5;
  416. if (*sumsize > 255)
  417. *sumsize = 255;
  418. // dev_dbg(dev, "%s: sumsize=%d\n", __func__, *sumsize);
  419. }
  420. #endif//SAMSUNG_PALM_MOTION
  421. #ifdef FORCE_SATISFY_PALMPAUSE_FOR_LARGEOBJ
  422. static void forceSatisfyPalmPause(struct cyttsp5_mt_data *md,
  423. struct cyttsp5_touch *tch, int t)
  424. {
  425. int x, y;
  426. dev_dbg(md->dev, "%s: \n", __func__);
  427. switch (t) {
  428. case 0: x = 10;y = 10; break;
  429. case 1: x = 700;y = 10; break;
  430. case 2: x = 700;y = 1200; break;
  431. case 3: x = 10;y = 1200; break;
  432. default: x = 10;y = 10; break;
  433. }
  434. tch->abs[CY_TCH_T] = t;
  435. tch->abs[CY_TCH_X] = x;
  436. tch->abs[CY_TCH_Y] = y;
  437. tch->abs[CY_TCH_P] = 10;
  438. tch->abs[CY_TCH_E] = CY_EV_TOUCHDOWN;
  439. tch->abs[CY_TCH_O] = CY_OBJ_STANDARD_FINGER;
  440. tch->abs[CY_TCH_MAJ] = 30;
  441. tch->abs[CY_TCH_MIN] = 30;
  442. tch->abs[CY_TCH_OR] = 0;
  443. }
  444. #endif//FORCE_SATISFY_PALMPAUSE_FOR_LARGEOBJ
  445. static void cyttsp5_get_mt_touches(struct cyttsp5_mt_data *md,
  446. struct cyttsp5_touch *tch, int num_cur_tch)
  447. {
  448. struct device *dev = md->dev;
  449. struct cyttsp5_sysinfo *si = md->si;
  450. int sig, value;
  451. int i, j, t = 0;
  452. DECLARE_BITMAP(ids, MAX_TOUCH_ID_NUMBER);
  453. int mt_sync_count = 0;
  454. #ifdef SAMSUNG_PALM_MOTION
  455. u16 sumsize = 0;
  456. u16 sum_maj_mnr;
  457. bool hover = 0;
  458. #endif
  459. #if defined(TSP_BOOSTER)
  460. u8 touch_num = 0;
  461. bool booster_status = false;
  462. #endif
  463. bitmap_zero(ids, MAX_TOUCH_ID_NUMBER);
  464. memset(tch->abs, 0, sizeof(tch->abs));
  465. for (i = 0; i < num_cur_tch; i++) {
  466. #ifdef FORCE_SATISFY_PALMPAUSE_FOR_LARGEOBJ
  467. if (md->largeobj)
  468. forceSatisfyPalmPause(md, tch, i);
  469. else
  470. #endif
  471. cyttsp5_get_touch(md, tch, si->xy_data +
  472. (i * si->desc.tch_record_size));
  473. /* Discard proximity event */
  474. if (tch->abs[CY_TCH_O] == CY_OBJ_PROXIMITY) {
  475. dev_vdbg(dev, "%s: Discarding proximity event\n",
  476. __func__);
  477. continue;
  478. } else if (tch->abs[CY_TCH_O] == CY_OBJ_HOVER) {
  479. tch->abs[CY_TCH_P] = 0;
  480. }
  481. if (tch->abs[CY_TCH_T] < ABS_PARAM(CY_ABS_ID_OST, CY_MIN_OST) ||
  482. tch->abs[CY_TCH_T] > ABS_PARAM(CY_ABS_ID_OST, CY_MAX_OST)) {
  483. dev_err(dev, "%s: tch=%d -> bad trk_id=%d max_id=%d\n",
  484. __func__, i, tch->abs[CY_TCH_T],
  485. ABS_PARAM(CY_ABS_ID_OST, CY_MAX_OST));
  486. cyttsp5_input_sync(md->input);
  487. mt_sync_count++;
  488. continue;
  489. }
  490. /* use 0 based track id's */
  491. sig = ABS_PARAM(CY_ABS_ID_OST, CY_SIGNAL_OST);
  492. if (sig != CY_IGNORE_VALUE) {
  493. t = tch->abs[CY_TCH_T] - ABS_PARAM(CY_ABS_ID_OST, CY_MIN_OST);
  494. if (t >= MAX_TOUCH_NUMBER) {
  495. dev_dbg(dev, "%s: t=%d exceeds max touch num\n",
  496. __func__, t);
  497. goto cyttsp5_get_mt_touches_pr_tch; // means continue for()
  498. }
  499. #ifdef SAMSUNG_TOUCH_MODE
  500. manage_touch_mode(md, tch);
  501. #endif
  502. #if defined(TSP_BOOSTER)
  503. if ((tch->abs[CY_TCH_O] != CY_OBJ_HOVER) &&
  504. (tch->abs[CY_TCH_E] == CY_EV_TOUCHDOWN))
  505. booster_status = true;
  506. #endif
  507. if (tch->abs[CY_TCH_E] == CY_EV_LIFTOFF)
  508. goto cyttsp5_get_mt_touches_pr_tch;
  509. #ifdef SAMSUNG_TOUCH_MODE
  510. cyttsp5_input_report(md->input, sig, t,
  511. ((tch->abs[CY_TCH_O] == CY_OBJ_STYLUS)
  512. && !md->stylus_enable) ? CY_OBJ_STANDARD_FINGER :
  513. tch->abs[CY_TCH_O]);
  514. #else
  515. cyttsp5_input_report(md->input, sig,
  516. t, tch->abs[CY_TCH_O]);
  517. #endif
  518. __set_bit(t, ids);
  519. }
  520. #if defined(TSP_BOOSTER)
  521. if (tch->abs[CY_TCH_O] != CY_OBJ_HOVER)
  522. touch_num++;
  523. #endif
  524. /* all devices: position and pressure fields */
  525. for (j = 0; j <= CY_ABS_W_OST; j++) {
  526. if (!si->tch_abs[j].report)
  527. continue;
  528. sig = ABS_PARAM(CY_ABS_X_OST + j, CY_SIGNAL_OST);
  529. if (sig == CY_IGNORE_VALUE)
  530. continue;
  531. value = tch->abs[CY_TCH_X + j];
  532. input_report_abs(md->input, sig, value);
  533. }
  534. /* Get the extended touch fields */
  535. #ifdef SAMSUNG_TOUCH_MODE
  536. if (tch->abs[CY_TCH_O] == CY_OBJ_HOVER) {
  537. mt_sync_count++;
  538. hover = 1;
  539. goto cyttsp5_get_mt_touches_pr_tch;
  540. }
  541. #endif
  542. #ifdef SAMSUNG_PALM_MOTION
  543. sum_maj_mnr = 0;
  544. #endif
  545. for (j = 0; j < CY_NUM_EXT_TCH_FIELDS; j++) {
  546. if (!si->tch_abs[j].report)
  547. continue;
  548. sig = ABS_PARAM((CY_ABS_MAJ_OST + j), CY_SIGNAL_OST);
  549. if (sig == CY_IGNORE_VALUE)
  550. continue;
  551. value = tch->abs[CY_TCH_MAJ + j];
  552. input_report_abs(md->input, sig, value);
  553. #ifdef SAMSUNG_PALM_MOTION
  554. if (sig == ABS_MT_TOUCH_MAJOR || sig == ABS_MT_TOUCH_MINOR) {
  555. sumsize += value;
  556. sum_maj_mnr += value;
  557. }
  558. #endif
  559. }
  560. cyttsp5_input_sync(md->input);
  561. mt_sync_count++;
  562. cyttsp5_get_mt_touches_pr_tch:
  563. print_log(dev, tch, t);
  564. }//for (i = 0; i < num_cur_tch; i++)
  565. #ifdef SAMSUNG_PALM_MOTION
  566. if (hover)
  567. sumsize = 1;
  568. else
  569. scale_sum_size(md, &sumsize);
  570. cyttsp5_final_sync(md->input, MAX_TOUCH_ID_NUMBER,
  571. mt_sync_count, ids,
  572. sumsize, md->palm);
  573. #else
  574. cyttsp5_final_sync(md->input, MAX_TOUCH_ID_NUMBER,
  575. mt_sync_count, ids); // slot state for MTB
  576. #endif
  577. #if defined(TSP_BOOSTER)
  578. if (touch_num != md->touch_pressed_num) {
  579. // dev_dbg(dev, "%s: touch num = (%d -> %d)\n",
  580. // __func__, md->touch_pressed_num, touch_num);
  581. md->touch_pressed_num = touch_num;
  582. }
  583. if (!!md->touch_pressed_num)
  584. set_dvfs_lock(md, 1, booster_status);
  585. else
  586. set_dvfs_lock(md, 0, false);
  587. #endif
  588. md->num_prv_tch = num_cur_tch;
  589. return;
  590. }
  591. /* read xy_data for all current touches */
  592. static int cyttsp5_xy_worker(struct cyttsp5_mt_data *md)
  593. {
  594. struct device *dev = md->dev;
  595. struct cyttsp5_sysinfo *si = md->si;
  596. struct cyttsp5_touch tch;
  597. u8 num_cur_tch;
  598. cyttsp5_get_touch_hdr(md, &tch, si->xy_mode + 3);
  599. num_cur_tch = tch.hdr[CY_TCH_NUM];
  600. if (num_cur_tch > MAX_TOUCH_ID_NUMBER) {
  601. dev_err(dev, "%s: Num touch err detected (n=%d)\n",
  602. __func__, num_cur_tch);
  603. num_cur_tch = MAX_TOUCH_ID_NUMBER;
  604. }
  605. if (tch.hdr[CY_TCH_LO]) {
  606. dev_dbg(dev, "%s: Large area detected\n", __func__);
  607. if (md->pdata->flags & CY_MT_FLAG_NO_TOUCH_ON_LO)
  608. num_cur_tch = 0;
  609. #ifdef SAMSUNG_PALM_MOTION
  610. md->palm = true;
  611. #endif
  612. }
  613. #ifdef FORCE_SATISFY_PALMPAUSE_FOR_LARGEOBJ
  614. if (!md->largeobj) {
  615. if (tch.hdr[CY_TCH_LO]) {
  616. md->largeobj = true;
  617. cyttsp5_get_mt_touches(md, &tch, 4);
  618. goto skip_num_cur_tch;
  619. }
  620. } else {
  621. if (!num_cur_tch && !tch.hdr[CY_TCH_LO]) {
  622. md->largeobj = false;
  623. cyttsp5_mt_lift_all(md);
  624. }
  625. goto skip_num_cur_tch;
  626. }
  627. #endif
  628. /* extract xy_data for all currently reported touches */
  629. dev_vdbg(dev, "%s: extract data num_cur_tch=%d\n", __func__,
  630. num_cur_tch);
  631. if (num_cur_tch)
  632. cyttsp5_get_mt_touches(md, &tch, num_cur_tch);
  633. else
  634. cyttsp5_mt_lift_all(md);
  635. #ifdef FORCE_SATISFY_PALMPAUSE_FOR_LARGEOBJ
  636. skip_num_cur_tch:
  637. #endif
  638. return 0;
  639. }
  640. static void cyttsp5_mt_send_dummy_event(struct cyttsp5_mt_data *md)
  641. {
  642. unsigned long ids = 0;
  643. /* for easy wakeup */
  644. cyttsp5_input_report(md->input, ABS_MT_TRACKING_ID,
  645. 0, CY_OBJ_STANDARD_FINGER);
  646. cyttsp5_input_sync(md->input);
  647. #ifdef SAMSUNG_PALM_MOTION
  648. cyttsp5_final_sync(md->input, 0, 1, &ids, 1, 0);
  649. cyttsp5_report_slot_liftoff(md, 1);
  650. cyttsp5_final_sync(md->input, 1, 1, &ids, 1, 0);
  651. #else
  652. cyttsp5_final_sync(md->input, 0, 1, &ids);
  653. cyttsp5_report_slot_liftoff(md, 1);
  654. cyttsp5_final_sync(md->input, 1, 1, &ids);
  655. #endif
  656. }
  657. static int cyttsp5_mt_attention(struct device *dev)
  658. {
  659. struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
  660. struct cyttsp5_mt_data *md = &cd->md;
  661. int rc;
  662. if (md->si->xy_mode[2] != md->si->desc.tch_report_id)
  663. return 0;
  664. mutex_lock(&md->mt_lock);
  665. if (md->prevent_touch) {
  666. mutex_unlock(&md->mt_lock);
  667. dev_dbg(dev, "%s: touch is now prevented\n", __func__);
  668. return 0;
  669. }
  670. /* core handles handshake */
  671. rc = cyttsp5_xy_worker(md);
  672. mutex_unlock(&md->mt_lock);
  673. if (rc < 0)
  674. dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
  675. return rc;
  676. }
  677. static int cyttsp5_mt_wake_attention(struct device *dev)
  678. {
  679. struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
  680. struct cyttsp5_mt_data *md = &cd->md;
  681. mutex_lock(&md->mt_lock);
  682. cyttsp5_mt_send_dummy_event(md);
  683. mutex_unlock(&md->mt_lock);
  684. return 0;
  685. }
  686. static int cyttsp5_startup_attention(struct device *dev)
  687. {
  688. struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
  689. struct cyttsp5_mt_data *md = &cd->md;
  690. mutex_lock(&md->mt_lock);
  691. cyttsp5_mt_lift_all(md);
  692. mutex_unlock(&md->mt_lock);
  693. return 0;
  694. }
  695. void cyttsp5_mt_prevent_touch(struct device *dev, bool prevent)
  696. {
  697. struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
  698. struct cyttsp5_mt_data *md;
  699. if (cd == NULL)
  700. return;
  701. md = &cd->md;
  702. if (md == NULL)
  703. return;
  704. dev_dbg(dev, "%s: %d\n", __func__, prevent);
  705. mutex_lock(&md->mt_lock);
  706. md->prevent_touch = prevent;
  707. if (prevent)
  708. cyttsp5_mt_lift_all(md);
  709. mutex_unlock(&md->mt_lock);
  710. }
  711. void cyttsp5_mt_stylus_enable(struct device *dev, bool enable)
  712. {
  713. struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
  714. struct cyttsp5_mt_data *md;
  715. if (cd == NULL)
  716. return;
  717. md = &cd->md;
  718. if (md == NULL)
  719. return;
  720. dev_dbg(dev, "%s: %d\n", __func__, enable);
  721. mutex_lock(&md->mt_lock);
  722. if (md->stylus_enable != enable) {
  723. md->stylus_enable = enable;
  724. cyttsp5_mt_lift_all(md);
  725. }
  726. mutex_unlock(&md->mt_lock);
  727. }
  728. static int cyttsp5_mt_open(struct input_dev *input)
  729. {
  730. struct device *dev = input->dev.parent;
  731. dev_dbg(dev, "%s:\n", __func__);
  732. /* pm_runtime_get_sync(dev); */
  733. dev_vdbg(dev, "%s: setup subscriptions\n", __func__);
  734. /* set up touch call back */
  735. _cyttsp5_subscribe_attention(dev, CY_ATTEN_IRQ, CY_MODULE_MT,
  736. cyttsp5_mt_attention, CY_MODE_OPERATIONAL);
  737. /* set up startup call back */
  738. _cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP, CY_MODULE_MT,
  739. cyttsp5_startup_attention, 0);
  740. /* set up wakeup call back */
  741. _cyttsp5_subscribe_attention(dev, CY_ATTEN_WAKE, CY_MODULE_MT,
  742. cyttsp5_mt_wake_attention, 0);
  743. cyttsp5_core_resume(dev);
  744. return 0;
  745. }
  746. static void cyttsp5_mt_close(struct input_dev *input)
  747. {
  748. struct device *dev = input->dev.parent;
  749. struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
  750. struct cyttsp5_mt_data *md = &cd->md;
  751. dev_dbg(dev, "%s:\n", __func__);
  752. #if defined(TSP_BOOSTER)
  753. //if (md->touch_pressed_num != 0) {
  754. dev_err(md->dev, "%s force dvfs off\n", __func__);
  755. md->touch_pressed_num = 0;
  756. set_dvfs_lock(md, 2, false);
  757. //}
  758. #endif
  759. #ifdef SAMSUNG_TOUCH_MODE
  760. input_report_switch(md->input,
  761. SW_GLOVE, false);
  762. md->glove_switch = true;
  763. #endif
  764. _cyttsp5_unsubscribe_attention(dev, CY_ATTEN_IRQ, CY_MODULE_MT,
  765. cyttsp5_mt_attention, CY_MODE_OPERATIONAL);
  766. _cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP, CY_MODULE_MT,
  767. cyttsp5_startup_attention, 0);
  768. mutex_lock(&md->mt_lock);
  769. md->prevent_touch = 0;
  770. mutex_unlock(&md->mt_lock);
  771. /* pm_runtime_put(dev); */
  772. cyttsp5_core_suspend(dev);
  773. }
  774. #ifdef CONFIG_HAS_EARLYSUSPEND
  775. static void cyttsp5_mt_early_suspend(struct early_suspend *h)
  776. {
  777. struct cyttsp5_mt_data *md =
  778. container_of(h, struct cyttsp5_mt_data, es);
  779. struct device *dev = md->dev;
  780. /* pm_runtime_put_sync(dev); */
  781. cyttsp5_core_suspend(dev);
  782. mutex_lock(&md->mt_lock);
  783. md->is_suspended = true;
  784. mutex_unlock(&md->mt_lock);
  785. }
  786. static void cyttsp5_mt_late_resume(struct early_suspend *h)
  787. {
  788. struct cyttsp5_mt_data *md =
  789. container_of(h, struct cyttsp5_mt_data, es);
  790. struct device *dev = md->dev;
  791. /*pm_runtime_get(dev); */
  792. cyttsp5_core_resume(dev);
  793. mutex_lock(&md->mt_lock);
  794. md->is_suspended = false;
  795. mutex_unlock(&md->mt_lock);
  796. }
  797. static void cyttsp5_setup_early_suspend(struct cyttsp5_mt_data *md)
  798. {
  799. md->es.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
  800. md->es.suspend = cyttsp5_mt_early_suspend;
  801. md->es.resume = cyttsp5_mt_late_resume;
  802. register_early_suspend(&md->es);
  803. }
  804. #endif
  805. static int cyttsp5_setup_input_device(struct device *dev)
  806. {
  807. struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
  808. struct cyttsp5_mt_data *md = &cd->md;
  809. int signal = CY_IGNORE_VALUE;
  810. int max_x, max_y, max_p, min, max;
  811. int max_x_tmp, max_y_tmp;
  812. int i;
  813. int rc;
  814. dev_vdbg(dev, "%s: Initialize event signals\n", __func__);
  815. set_bit(EV_SYN, md->input->evbit);
  816. set_bit(EV_ABS, md->input->evbit);
  817. set_bit(EV_KEY, md->input->evbit);
  818. #ifdef INPUT_PROP_DIRECT
  819. set_bit(INPUT_PROP_DIRECT, md->input->propbit);
  820. #endif
  821. #ifdef SAMSUNG_TOUCH_MODE
  822. set_bit(BTN_TOUCH, md->input->keybit);
  823. set_bit(BTN_TOOL_FINGER, md->input->keybit);
  824. input_set_capability(md->input, EV_SW, SW_GLOVE);
  825. #endif
  826. /* If virtualkeys enabled, don't use all screen */
  827. if (md->pdata->flags & CY_MT_FLAG_VKEYS) {
  828. max_x_tmp = md->pdata->vkeys_x;
  829. max_y_tmp = md->pdata->vkeys_y;
  830. } else {
  831. max_x_tmp = md->si->sensing_conf_data.res_x;
  832. max_y_tmp = md->si->sensing_conf_data.res_y;
  833. }
  834. /* get maximum values from the sysinfo data */
  835. if (md->pdata->flags & CY_MT_FLAG_FLIP) {
  836. max_x = max_y_tmp - 1;
  837. max_y = max_x_tmp - 1;
  838. } else {
  839. max_x = max_x_tmp - 1;
  840. max_y = max_y_tmp - 1;
  841. }
  842. max_p = md->si->sensing_conf_data.max_z;
  843. /* set event signal capabilities */
  844. for (i = 0; i < (md->pdata->frmwrk->size / CY_NUM_ABS_SET); i++) {
  845. signal = ABS_PARAM(i, CY_SIGNAL_OST);
  846. if (signal != CY_IGNORE_VALUE) {
  847. set_bit(signal, md->input->absbit);
  848. min = ABS_PARAM(i, CY_MIN_OST);
  849. max = ABS_PARAM(i, CY_MAX_OST);
  850. if (i == CY_ABS_ID_OST) {
  851. /* shift track ids down to start at 0 */
  852. max = max - min;
  853. /*min = min - min;*/
  854. min = 0;
  855. } else if (i == CY_ABS_X_OST)
  856. max = max_x;
  857. else if (i == CY_ABS_Y_OST)
  858. max = max_y;
  859. else if (i == CY_ABS_P_OST)
  860. max = max_p;
  861. input_set_abs_params(md->input, signal, min, max,
  862. ABS_PARAM(i, CY_FUZZ_OST),
  863. ABS_PARAM(i, CY_FLAT_OST));
  864. dev_dbg(dev, "%s: register signal=%02X min=%d max=%d\n",
  865. __func__, signal, min, max);
  866. }
  867. }
  868. #if defined(SAMSUNG_TOUCH_MODE)
  869. input_set_abs_params(md->input, ABS_MT_DISTANCE, 0, 255, 0, 0);
  870. #endif
  871. #if defined(SAMSUNG_PALM_MOTION)
  872. input_set_abs_params(md->input, signal = ABS_MT_PALM,
  873. min = 0, max = 1, 0, 0);
  874. dev_dbg(dev, "%s: register signal=%02X min=%d max=%d\n",
  875. __func__, signal, min, max);
  876. dev_dbg(dev, "%s: register signal=%02X min=%d max=%d\n",
  877. __func__, signal, min, max);
  878. #endif
  879. rc = cyttsp5_input_register_device(md->input,
  880. MAX_TOUCH_ID_NUMBER);
  881. if (rc < 0)
  882. dev_err(dev, "%s: Error, failed register input device r=%d\n",
  883. __func__, rc);
  884. else
  885. md->input_device_registered = true;
  886. return rc;
  887. }
  888. static int cyttsp5_setup_input_attention(struct device *dev)
  889. {
  890. struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
  891. struct cyttsp5_mt_data *md = &cd->md;
  892. int rc;
  893. md->si = _cyttsp5_request_sysinfo(dev);
  894. if (!md->si)
  895. return -EINVAL;
  896. rc = cyttsp5_setup_input_device(dev);
  897. _cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP, CY_MODULE_MT,
  898. cyttsp5_setup_input_attention, 0);
  899. return rc;
  900. }
  901. int cyttsp5_mt_probe(struct device *dev)
  902. {
  903. struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
  904. struct cyttsp5_mt_data *md = &cd->md;
  905. struct cyttsp5_platform_data *pdata = dev_get_platdata(dev);
  906. struct cyttsp5_mt_platform_data *mt_pdata;
  907. int rc = 0;
  908. dev_dbg(dev, "%s:\n", __func__);
  909. if (!pdata || !pdata->mt_pdata) {
  910. dev_err(dev, "%s: Missing platform data\n", __func__);
  911. rc = -ENODEV;
  912. goto error_no_pdata;
  913. }
  914. mt_pdata = pdata->mt_pdata;
  915. mutex_init(&md->mt_lock);
  916. md->dev = dev;
  917. md->pdata = mt_pdata;
  918. #if defined(TSP_BOOSTER)
  919. mutex_init(&md->dvfs_lock);
  920. md->touch_pressed_num = 0;
  921. md->dvfs_lock_status = false;
  922. md->boost_level = DVFS_STAGE_DUAL;
  923. INIT_DELAYED_WORK(&md->work_dvfs_off, set_dvfs_off);
  924. INIT_DELAYED_WORK(&md->work_dvfs_chg, change_dvfs_lock);
  925. #endif
  926. /* Create the input device and register it. */
  927. dev_vdbg(dev, "%s: Create the input device and register it\n",
  928. __func__);
  929. md->input = input_allocate_device();
  930. if (!md->input) {
  931. dev_err(dev, "%s: Error, failed to allocate input device\n",
  932. __func__);
  933. rc = -ENOSYS;
  934. goto error_alloc_failed;
  935. }
  936. if (md->pdata->inp_dev_name)
  937. md->input->name = md->pdata->inp_dev_name;
  938. else
  939. md->input->name = CYTTSP5_MT_NAME;
  940. scnprintf(md->phys, sizeof(md->phys)-1, "%s", CYTTSP5_MT_NAME);
  941. md->input->phys = md->phys;
  942. md->input->dev.parent = md->dev;
  943. md->input->open = cyttsp5_mt_open;
  944. md->input->close = cyttsp5_mt_close;
  945. input_set_drvdata(md->input, md);
  946. /* get sysinfo */
  947. md->si = _cyttsp5_request_sysinfo(dev);
  948. if (md->si) {
  949. rc = cyttsp5_setup_input_device(dev);
  950. if (rc)
  951. goto error_init_input;
  952. } else {
  953. dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n",
  954. __func__, md->si);
  955. _cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP,
  956. CY_MODULE_MT, cyttsp5_setup_input_attention, 0);
  957. }
  958. #ifdef CONFIG_HAS_EARLYSUSPEND
  959. cyttsp5_setup_early_suspend(md);
  960. #endif
  961. dev_dbg(dev, "%s:done\n", __func__);
  962. return 0;
  963. error_init_input:
  964. input_free_device(md->input);
  965. error_alloc_failed:
  966. error_no_pdata:
  967. dev_err(dev, "%s failed.\n", __func__);
  968. return rc;
  969. }
  970. EXPORT_SYMBOL(cyttsp5_mt_probe);
  971. int cyttsp5_mt_release(struct device *dev)
  972. {
  973. struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
  974. struct cyttsp5_mt_data *md = &cd->md;
  975. #ifdef CONFIG_HAS_EARLYSUSPEND
  976. /*
  977. * This check is to prevent pm_runtime usage_count drop below zero
  978. * because of removing the module while in suspended state
  979. */
  980. /*if (md->is_suspended)
  981. pm_runtime_get_noresume(dev);*/
  982. unregister_early_suspend(&md->es);
  983. #endif
  984. if (md->input_device_registered) {
  985. input_unregister_device(md->input);
  986. } else {
  987. input_free_device(md->input);
  988. _cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP,
  989. CY_MODULE_MT, cyttsp5_setup_input_attention, 0);
  990. }
  991. return 0;
  992. }
  993. EXPORT_SYMBOL(cyttsp5_mt_release);