pt_proximity.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. /*
  2. * pt_proximity.c
  3. * Parade TrueTouch(TM) Standard Product Proximity Module.
  4. * For use with Parade touchscreen controllers.
  5. * Supported parts include:
  6. * TMA5XX
  7. * TMA448
  8. * TMA445A
  9. * TT21XXX
  10. * TT31XXX
  11. * TT4XXXX
  12. * TT7XXX
  13. * TC3XXX
  14. *
  15. * Copyright (C) 2015-2020 Parade Technologies
  16. *
  17. * This program is free software; you can redistribute it and/or
  18. * modify it under the terms of the GNU General Public License
  19. * version 2, and only version 2, as published by the
  20. * Free Software Foundation.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU General Public License for more details.
  26. *
  27. * Contact Parade Technologies at www.paradetech.com <[email protected]>
  28. *
  29. */
  30. #include "pt_regs.h"
  31. #define PT_PROXIMITY_NAME "pt_proximity"
  32. /* Timeout value in ms. */
  33. #define PT_PROXIMITY_REQUEST_EXCLUSIVE_TIMEOUT 1000
  34. #define PT_PROXIMITY_ON 0
  35. #define PT_PROXIMITY_OFF 1
  36. /*******************************************************************************
  37. * FUNCTION: get_prox_data
  38. *
  39. * SUMMARY: Gets pointer of proximity data from core data structure
  40. *
  41. * RETURN:
  42. * pointer of pt_proximity_data structure in core data structure
  43. *
  44. * PARAMETERS:
  45. * *dev - pointer to device structure
  46. ******************************************************************************/
  47. static inline struct pt_proximity_data *get_prox_data(struct device *dev)
  48. {
  49. struct pt_core_data *cd = dev_get_drvdata(dev);
  50. return &cd->pd;
  51. }
  52. /*******************************************************************************
  53. * FUNCTION: pt_report_proximity
  54. *
  55. * SUMMARY: Reports proximity event
  56. *
  57. * PARAMETERS:
  58. * *pd - pointer to proximity data structure
  59. * on - state of proximity(true:on; false:off)
  60. ******************************************************************************/
  61. static void pt_report_proximity(struct pt_proximity_data *pd,
  62. bool on)
  63. {
  64. int val = on ? PT_PROXIMITY_ON : PT_PROXIMITY_OFF;
  65. input_report_abs(pd->input, ABS_DISTANCE, val);
  66. input_sync(pd->input);
  67. }
  68. /*******************************************************************************
  69. * FUNCTION: pt_get_touch_axis
  70. *
  71. * SUMMARY: Calculates touch axis
  72. *
  73. * PARAMETERS:
  74. * *pd - pointer to proximity data structure
  75. * *axis - pointer to axis calculation result
  76. * size - size in bytes
  77. * max - max value of result
  78. * *xy_data - pointer to input data to be parsed
  79. * bofs - bit offset
  80. ******************************************************************************/
  81. static void pt_get_touch_axis(struct pt_proximity_data *pd,
  82. int *axis, int size, int max, u8 *xy_data, int bofs)
  83. {
  84. int nbyte;
  85. int next;
  86. for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) {
  87. pt_debug(pd->dev, DL_INFO,
  88. "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p xy_data[%d]=%02X(%d) bofs=%d\n",
  89. __func__, *axis, *axis, size, max, xy_data, next,
  90. xy_data[next], xy_data[next], bofs);
  91. *axis = *axis + ((xy_data[next] >> bofs) << (nbyte * 8));
  92. next++;
  93. }
  94. *axis &= max - 1;
  95. pt_debug(pd->dev, DL_INFO,
  96. "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p xy_data[%d]=%02X(%d)\n",
  97. __func__, *axis, *axis, size, max, xy_data, next,
  98. xy_data[next], xy_data[next]);
  99. }
  100. /*******************************************************************************
  101. * FUNCTION: pt_get_touch_hdr
  102. *
  103. * SUMMARY: Gets header of touch report
  104. *
  105. * PARAMETERS:
  106. * *pd - pointer to proximity data structure
  107. * *touch - pointer to pt_touch structure
  108. * *xy_mode - pointer to input mode data
  109. ******************************************************************************/
  110. static void pt_get_touch_hdr(struct pt_proximity_data *pd,
  111. struct pt_touch *touch, u8 *xy_mode)
  112. {
  113. struct device *dev = pd->dev;
  114. struct pt_sysinfo *si = pd->si;
  115. enum pt_tch_hdr hdr;
  116. for (hdr = PT_TCH_TIME; hdr < PT_TCH_NUM_HDR; hdr++) {
  117. if (!si->tch_hdr[hdr].report)
  118. continue;
  119. pt_get_touch_axis(pd, &touch->hdr[hdr],
  120. si->tch_hdr[hdr].size,
  121. si->tch_hdr[hdr].max,
  122. xy_mode + si->tch_hdr[hdr].ofs,
  123. si->tch_hdr[hdr].bofs);
  124. pt_debug(dev, DL_INFO, "%s: get %s=%04X(%d)\n",
  125. __func__, pt_tch_hdr_string[hdr],
  126. touch->hdr[hdr], touch->hdr[hdr]);
  127. }
  128. }
  129. /*******************************************************************************
  130. * FUNCTION: pt_get_touch
  131. *
  132. * SUMMARY: Parse proximity touch event
  133. *
  134. * PARAMETERS:
  135. * *pd - pointer to proximity data structure
  136. * *touch - pointer to touch structure
  137. * xy_data - pointer to touch data
  138. ******************************************************************************/
  139. static void pt_get_touch(struct pt_proximity_data *pd,
  140. struct pt_touch *touch, u8 *xy_data)
  141. {
  142. struct device *dev = pd->dev;
  143. struct pt_sysinfo *si = pd->si;
  144. enum pt_tch_abs abs;
  145. for (abs = PT_TCH_X; abs < PT_TCH_NUM_ABS; abs++) {
  146. if (!si->tch_abs[abs].report)
  147. continue;
  148. pt_get_touch_axis(pd, &touch->abs[abs],
  149. si->tch_abs[abs].size,
  150. si->tch_abs[abs].max,
  151. xy_data + si->tch_abs[abs].ofs,
  152. si->tch_abs[abs].bofs);
  153. pt_debug(dev, DL_INFO, "%s: get %s=%04X(%d)\n",
  154. __func__, pt_tch_abs_string[abs],
  155. touch->abs[abs], touch->abs[abs]);
  156. }
  157. pt_debug(dev, DL_INFO, "%s: x=%04X(%d) y=%04X(%d)\n",
  158. __func__, touch->abs[PT_TCH_X], touch->abs[PT_TCH_X],
  159. touch->abs[PT_TCH_Y], touch->abs[PT_TCH_Y]);
  160. }
  161. /*******************************************************************************
  162. * FUNCTION: pt_get_proximity_touch
  163. *
  164. * SUMMARY: Parse and report proximity touch event
  165. *
  166. * PARAMETERS:
  167. * *pd - pointer to proximity data structure
  168. * *touch - pointer to pt_touch structure
  169. ******************************************************************************/
  170. static void pt_get_proximity_touch(struct pt_proximity_data *pd,
  171. struct pt_touch *tch, int num_cur_tch)
  172. {
  173. struct pt_sysinfo *si = pd->si;
  174. int i;
  175. for (i = 0; i < num_cur_tch; i++) {
  176. pt_get_touch(pd, tch, si->xy_data +
  177. (i * si->desc.tch_record_size));
  178. /* Check for proximity event */
  179. if (tch->abs[PT_TCH_O] == PT_OBJ_PROXIMITY) {
  180. if (tch->abs[PT_TCH_E] == PT_EV_TOUCHDOWN)
  181. pt_report_proximity(pd, true);
  182. else if (tch->abs[PT_TCH_E] == PT_EV_LIFTOFF)
  183. pt_report_proximity(pd, false);
  184. break;
  185. }
  186. }
  187. }
  188. /*******************************************************************************
  189. * FUNCTION: pt_xy_worker
  190. *
  191. * SUMMARY: Read xy_data for all current touches
  192. *
  193. * RETURN:
  194. * 0 = success
  195. * !0 = failure
  196. *
  197. * PARAMETERS:
  198. * *pd - pointer to proximity data structure
  199. ******************************************************************************/
  200. static int pt_xy_worker(struct pt_proximity_data *pd)
  201. {
  202. struct device *dev = pd->dev;
  203. struct pt_sysinfo *si = pd->si;
  204. struct pt_touch tch;
  205. u8 num_cur_tch;
  206. pt_get_touch_hdr(pd, &tch, si->xy_mode + 3);
  207. num_cur_tch = tch.hdr[PT_TCH_NUM];
  208. if (num_cur_tch > si->sensing_conf_data.max_tch) {
  209. pt_debug(dev, DL_ERROR, "%s: Num touch err detected (n=%d)\n",
  210. __func__, num_cur_tch);
  211. num_cur_tch = si->sensing_conf_data.max_tch;
  212. }
  213. if (tch.hdr[PT_TCH_LO])
  214. pt_debug(dev, DL_WARN, "%s: Large area detected\n",
  215. __func__);
  216. /* extract xy_data for all currently reported touches */
  217. pt_debug(dev, DL_INFO, "%s: extract data num_cur_rec=%d\n",
  218. __func__, num_cur_tch);
  219. if (num_cur_tch)
  220. pt_get_proximity_touch(pd, &tch, num_cur_tch);
  221. else
  222. pt_report_proximity(pd, false);
  223. return 0;
  224. }
  225. /*******************************************************************************
  226. * FUNCTION: pt_mt_attention
  227. *
  228. * SUMMARY: Wrapper function for pt_xy_worker() that subscribe into the TTDL
  229. * attention list.
  230. *
  231. * RETURN:
  232. * 0 = success
  233. * !0 = failure
  234. *
  235. * PARAMETERS:
  236. * *dev - pointer to device structure
  237. ******************************************************************************/
  238. static int pt_proximity_attention(struct device *dev)
  239. {
  240. struct pt_proximity_data *pd = get_prox_data(dev);
  241. int rc = 0;
  242. if (pd->si->xy_mode[2] != pd->si->desc.tch_report_id)
  243. return 0;
  244. mutex_lock(&pd->prox_lock);
  245. rc = pt_xy_worker(pd);
  246. mutex_unlock(&pd->prox_lock);
  247. if (rc < 0)
  248. pt_debug(dev, DL_ERROR, "%s: xy_worker error r=%d\n",
  249. __func__, rc);
  250. return rc;
  251. }
  252. /*******************************************************************************
  253. * FUNCTION: pt_startup_attention
  254. *
  255. * SUMMARY: Wrapper function for pt_report_proximity() that subcribe into the
  256. * TTDL attention list.
  257. *
  258. * RETURN:
  259. * 0 = success
  260. *
  261. * PARAMETERS:
  262. * *dev - pointer to device structure
  263. ******************************************************************************/
  264. static int pt_startup_attention(struct device *dev)
  265. {
  266. struct pt_proximity_data *pd = get_prox_data(dev);
  267. mutex_lock(&pd->prox_lock);
  268. pt_report_proximity(pd, false);
  269. mutex_unlock(&pd->prox_lock);
  270. return 0;
  271. }
  272. /*******************************************************************************
  273. * FUNCTION: _pt_set_proximity_via_touchmode_enabled
  274. *
  275. * SUMMARY: Enable/Disable proximity via touchmode parameter
  276. *
  277. * RETURN:
  278. * 0 = success
  279. * !0 = failure
  280. *
  281. * PARAMETERS:
  282. * *pd - pointer to proximity data structure
  283. * enable - enable or disable proximity(true:enable; false:disable)
  284. ******************************************************************************/
  285. static int _pt_set_proximity_via_touchmode_enabled(
  286. struct pt_proximity_data *pd, bool enable)
  287. {
  288. struct device *dev = pd->dev;
  289. u32 touchmode_enabled;
  290. int rc;
  291. rc = _pt_request_pip_get_param(dev, 0,
  292. PT_RAM_ID_TOUCHMODE_ENABLED, &touchmode_enabled);
  293. if (rc)
  294. return rc;
  295. if (enable)
  296. touchmode_enabled |= 0x80;
  297. else
  298. touchmode_enabled &= 0x7F;
  299. rc = _pt_request_pip_set_param(dev, 0,
  300. PT_RAM_ID_TOUCHMODE_ENABLED, touchmode_enabled,
  301. PT_RAM_ID_TOUCHMODE_ENABLED_SIZE);
  302. return rc;
  303. }
  304. /*******************************************************************************
  305. * FUNCTION: _pt_set_proximity_via_proximity_enable
  306. *
  307. * SUMMARY: Enable/Disable proximity via proximity parameter
  308. *
  309. * RETURN:
  310. * 0 = success
  311. * !0 = failure
  312. *
  313. * PARAMETERS:
  314. * *pd - pointer to proximity data structure
  315. * enable - enable or disable proximity(true:enable; false:disable)
  316. ******************************************************************************/
  317. static int _pt_set_proximity_via_proximity_enable(
  318. struct pt_proximity_data *pd, bool enable)
  319. {
  320. struct device *dev = pd->dev;
  321. u32 proximity_enable;
  322. int rc;
  323. rc = _pt_request_pip_get_param(dev, 0,
  324. PT_RAM_ID_PROXIMITY_ENABLE, &proximity_enable);
  325. if (rc)
  326. return rc;
  327. if (enable)
  328. proximity_enable |= 0x01;
  329. else
  330. proximity_enable &= 0xFE;
  331. rc = _pt_request_pip_set_param(dev, 0,
  332. PT_RAM_ID_PROXIMITY_ENABLE, proximity_enable,
  333. PT_RAM_ID_PROXIMITY_ENABLE_SIZE);
  334. return rc;
  335. }
  336. /*******************************************************************************
  337. * FUNCTION: _pt_set_proximity
  338. *
  339. * SUMMARY: Set proximity mode via touchmode parameter or proximity parameter.
  340. *
  341. * RETURN:
  342. * 0 = success
  343. * !0 = failure
  344. *
  345. * PARAMETERS:
  346. * *pd - pointer to proximity data structure
  347. * enable - enable or disable proximity(true:enable; false:disable)
  348. ******************************************************************************/
  349. static int _pt_set_proximity(struct pt_proximity_data *pd,
  350. bool enable)
  351. {
  352. if (!IS_PIP_VER_GE(pd->si, 1, 4))
  353. return _pt_set_proximity_via_touchmode_enabled(pd,
  354. enable);
  355. return _pt_set_proximity_via_proximity_enable(pd, enable);
  356. }
  357. /*******************************************************************************
  358. * FUNCTION: _pt_set_proximity
  359. *
  360. * SUMMARY: Enable proximity mode and subscribe into IRQ and STARTUP TTDL
  361. * attention list.
  362. *
  363. * RETURN:
  364. * 0 = success
  365. * !0 = failure
  366. *
  367. * PARAMETERS:
  368. * *pd - pointer to proximity data structure
  369. ******************************************************************************/
  370. static int _pt_proximity_enable(struct pt_proximity_data *pd)
  371. {
  372. struct device *dev = pd->dev;
  373. int rc = 0;
  374. pm_runtime_get_sync(dev);
  375. rc = pt_request_exclusive(dev,
  376. PT_PROXIMITY_REQUEST_EXCLUSIVE_TIMEOUT);
  377. if (rc < 0) {
  378. pt_debug(dev, DL_ERROR, "%s: Error on request exclusive r=%d\n",
  379. __func__, rc);
  380. goto exit;
  381. }
  382. rc = _pt_set_proximity(pd, true);
  383. if (rc < 0) {
  384. pt_debug(dev, DL_ERROR, "%s: Error on request enable proximity scantype r=%d\n",
  385. __func__, rc);
  386. goto exit_release;
  387. }
  388. pt_debug(dev, DL_INFO, "%s: setup subscriptions\n", __func__);
  389. /* set up touch call back */
  390. _pt_subscribe_attention(dev, PT_ATTEN_IRQ, PT_PROXIMITY_NAME,
  391. pt_proximity_attention, PT_MODE_OPERATIONAL);
  392. /* set up startup call back */
  393. _pt_subscribe_attention(dev, PT_ATTEN_STARTUP,
  394. PT_PROXIMITY_NAME, pt_startup_attention, 0);
  395. exit_release:
  396. pt_release_exclusive(dev);
  397. exit:
  398. return rc;
  399. }
  400. /*******************************************************************************
  401. * FUNCTION: _pt_proximity_disable
  402. *
  403. * SUMMARY: Disable proximity mode and unsubscribe from IRQ and STARTUP TTDL
  404. * attention list.
  405. *
  406. * RETURN:
  407. * 0 = success
  408. * !0 = failure
  409. *
  410. * PARAMETERS:
  411. * *pd - pointer to proximity data structure
  412. ******************************************************************************/
  413. static int _pt_proximity_disable(struct pt_proximity_data *pd,
  414. bool force)
  415. {
  416. struct device *dev = pd->dev;
  417. int rc = 0;
  418. rc = pt_request_exclusive(dev,
  419. PT_PROXIMITY_REQUEST_EXCLUSIVE_TIMEOUT);
  420. if (rc < 0) {
  421. pt_debug(dev, DL_ERROR, "%s: Error on request exclusive r=%d\n",
  422. __func__, rc);
  423. goto exit;
  424. }
  425. rc = _pt_set_proximity(pd, false);
  426. if (rc < 0) {
  427. pt_debug(dev, DL_ERROR, "%s: Error on request disable proximity scan r=%d\n",
  428. __func__, rc);
  429. goto exit_release;
  430. }
  431. exit_release:
  432. pt_release_exclusive(dev);
  433. exit:
  434. if (!rc || force) {
  435. _pt_unsubscribe_attention(dev, PT_ATTEN_IRQ,
  436. PT_PROXIMITY_NAME, pt_proximity_attention,
  437. PT_MODE_OPERATIONAL);
  438. _pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP,
  439. PT_PROXIMITY_NAME, pt_startup_attention, 0);
  440. }
  441. pm_runtime_put(dev);
  442. return rc;
  443. }
  444. /*******************************************************************************
  445. * FUNCTION: pt_proximity_enable_show
  446. *
  447. * SUMMARY: Show method for the prox_enable sysfs node that will show the
  448. * enable_count of proximity
  449. *
  450. * RETURN: Size of printed buffer
  451. *
  452. * PARAMETERS:
  453. * *dev - pointer to device structure
  454. * *attr - pointer to device attributes
  455. * *buf - pointer to output buffer
  456. ******************************************************************************/
  457. static ssize_t pt_proximity_enable_show(struct device *dev,
  458. struct device_attribute *attr, char *buf)
  459. {
  460. struct pt_proximity_data *pd = get_prox_data(dev);
  461. int val = 0;
  462. mutex_lock(&pd->sysfs_lock);
  463. val = pd->enable_count;
  464. mutex_unlock(&pd->sysfs_lock);
  465. return scnprintf(buf, PT_MAX_PRBUF_SIZE, "%d\n", val);
  466. }
  467. /*******************************************************************************
  468. * FUNCTION: pt_proximity_enable_store
  469. *
  470. * SUMMARY: The store method for the prox_enable sysfs node that allows to
  471. * enable or disable proxmity mode.
  472. *
  473. * RETURN: Size of passed in buffer
  474. *
  475. * PARAMETERS:
  476. * *dev - pointer to device structure
  477. * *attr - pointer to device attributes
  478. * *buf - pointer to buffer that hold the command parameters
  479. * size - size of buf
  480. ******************************************************************************/
  481. static ssize_t pt_proximity_enable_store(struct device *dev,
  482. struct device_attribute *attr, const char *buf, size_t size)
  483. {
  484. struct pt_proximity_data *pd = get_prox_data(dev);
  485. unsigned long value;
  486. int rc;
  487. rc = kstrtoul(buf, 10, &value);
  488. if (rc < 0 || (value != 0 && value != 1)) {
  489. pt_debug(dev, DL_ERROR, "%s: Invalid value\n", __func__);
  490. return -EINVAL;
  491. }
  492. mutex_lock(&pd->sysfs_lock);
  493. if (value) {
  494. if (pd->enable_count++) {
  495. pt_debug(dev, DL_WARN, "%s: '%s' already enabled\n",
  496. __func__, pd->input->name);
  497. } else {
  498. rc = _pt_proximity_enable(pd);
  499. if (rc)
  500. pd->enable_count--;
  501. }
  502. } else {
  503. if (--pd->enable_count) {
  504. if (pd->enable_count < 0) {
  505. pt_debug(dev, DL_ERROR, "%s: '%s' unbalanced disable\n",
  506. __func__, pd->input->name);
  507. pd->enable_count = 0;
  508. }
  509. } else {
  510. rc = _pt_proximity_disable(pd, false);
  511. if (rc)
  512. pd->enable_count++;
  513. }
  514. }
  515. mutex_unlock(&pd->sysfs_lock);
  516. if (rc)
  517. return rc;
  518. return size;
  519. }
  520. static DEVICE_ATTR(prox_enable, 0600,
  521. pt_proximity_enable_show,
  522. pt_proximity_enable_store);
  523. /*******************************************************************************
  524. * FUNCTION: pt_setup_input_device_and_sysfs
  525. *
  526. * SUMMARY: Create sysnode, set event signal capabilities and register input
  527. * device for proximity.
  528. *
  529. * RETURN:
  530. * 0 = success
  531. * !0 = failure
  532. *
  533. * PARAMETERS:
  534. * *dev - pointer to device structure
  535. ******************************************************************************/
  536. static int pt_setup_input_device_and_sysfs(struct device *dev)
  537. {
  538. struct pt_proximity_data *pd = get_prox_data(dev);
  539. int signal = PT_IGNORE_VALUE;
  540. int i;
  541. int rc;
  542. rc = device_create_file(dev, &dev_attr_prox_enable);
  543. if (rc) {
  544. pt_debug(dev, DL_ERROR, "%s: Error, could not create enable\n",
  545. __func__);
  546. goto exit;
  547. }
  548. pt_debug(dev, DL_INFO, "%s: Initialize event signals\n",
  549. __func__);
  550. __set_bit(EV_ABS, pd->input->evbit);
  551. /* set event signal capabilities */
  552. for (i = 0; i < NUM_SIGNALS(pd->pdata->frmwrk); i++) {
  553. signal = PARAM_SIGNAL(pd->pdata->frmwrk, i);
  554. if (signal != PT_IGNORE_VALUE) {
  555. input_set_abs_params(pd->input, signal,
  556. PARAM_MIN(pd->pdata->frmwrk, i),
  557. PARAM_MAX(pd->pdata->frmwrk, i),
  558. PARAM_FUZZ(pd->pdata->frmwrk, i),
  559. PARAM_FLAT(pd->pdata->frmwrk, i));
  560. }
  561. }
  562. rc = input_register_device(pd->input);
  563. if (rc) {
  564. pt_debug(dev, DL_ERROR, "%s: Error, failed register input device r=%d\n",
  565. __func__, rc);
  566. goto unregister_enable;
  567. }
  568. pd->input_device_registered = true;
  569. return rc;
  570. unregister_enable:
  571. device_remove_file(dev, &dev_attr_prox_enable);
  572. exit:
  573. return rc;
  574. }
  575. /*******************************************************************************
  576. * FUNCTION: pt_setup_input_attention
  577. *
  578. * SUMMARY: Wrapper function for pt_setup_input_device_and_sysfs() that
  579. * subscribe into TTDL attention list.
  580. *
  581. * RETURN:
  582. * 0 = success
  583. * !0 = failure
  584. *
  585. * PARAMETERS:
  586. * *dev - pointer to device structure
  587. ******************************************************************************/
  588. static int pt_setup_input_attention(struct device *dev)
  589. {
  590. struct pt_proximity_data *pd = get_prox_data(dev);
  591. int rc;
  592. pd->si = _pt_request_sysinfo(dev);
  593. if (!pd->si)
  594. return -EINVAL;
  595. rc = pt_setup_input_device_and_sysfs(dev);
  596. if (!rc)
  597. rc = _pt_set_proximity(pd, false);
  598. _pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP,
  599. PT_PROXIMITY_NAME, pt_setup_input_attention, 0);
  600. return rc;
  601. }
  602. /*******************************************************************************
  603. * FUNCTION: pt_proximity_probe
  604. *
  605. * SUMMARY: The probe function for proximity input device
  606. *
  607. * RETURN:
  608. * 0 = success
  609. * !0 = failure
  610. *
  611. * PARAMETERS:
  612. * *dev - pointer to device structure
  613. ******************************************************************************/
  614. int pt_proximity_probe(struct device *dev)
  615. {
  616. struct pt_core_data *cd = dev_get_drvdata(dev);
  617. struct pt_proximity_data *pd = &cd->pd;
  618. struct pt_platform_data *pdata = dev_get_platdata(dev);
  619. struct pt_proximity_platform_data *prox_pdata;
  620. int rc = 0;
  621. if (!pdata || !pdata->prox_pdata) {
  622. pt_debug(dev, DL_ERROR,
  623. "%s: Missing platform data\n", __func__);
  624. rc = -ENODEV;
  625. goto error_no_pdata;
  626. }
  627. prox_pdata = pdata->prox_pdata;
  628. mutex_init(&pd->prox_lock);
  629. mutex_init(&pd->sysfs_lock);
  630. pd->dev = dev;
  631. pd->pdata = prox_pdata;
  632. /* Create the input device and register it. */
  633. pt_debug(dev, DL_INFO,
  634. "%s: Create the input device and register it\n", __func__);
  635. pd->input = input_allocate_device();
  636. if (!pd->input) {
  637. pt_debug(dev, DL_ERROR, "%s: Error, failed to allocate input device\n",
  638. __func__);
  639. rc = -ENODEV;
  640. goto error_alloc_failed;
  641. } else
  642. pd->input_device_allocated = true;
  643. if (pd->pdata->inp_dev_name)
  644. pd->input->name = pd->pdata->inp_dev_name;
  645. else
  646. pd->input->name = PT_PROXIMITY_NAME;
  647. scnprintf(pd->phys, sizeof(pd->phys), "%s/input%d", dev_name(dev),
  648. cd->phys_num++);
  649. pd->input->phys = pd->phys;
  650. pd->input->dev.parent = pd->dev;
  651. input_set_drvdata(pd->input, pd);
  652. /* get sysinfo */
  653. pd->si = _pt_request_sysinfo(dev);
  654. if (pd->si) {
  655. rc = pt_setup_input_device_and_sysfs(dev);
  656. if (rc)
  657. goto error_init_input;
  658. rc = _pt_set_proximity(pd, false);
  659. } else {
  660. pt_debug(dev, DL_ERROR, "%s: Fail get sysinfo pointer from core p=%p\n",
  661. __func__, pd->si);
  662. _pt_subscribe_attention(dev, PT_ATTEN_STARTUP,
  663. PT_PROXIMITY_NAME, pt_setup_input_attention,
  664. 0);
  665. }
  666. return 0;
  667. error_init_input:
  668. input_free_device(pd->input);
  669. pd->input_device_allocated = false;
  670. error_alloc_failed:
  671. error_no_pdata:
  672. pt_debug(dev, DL_ERROR, "%s failed.\n", __func__);
  673. return rc;
  674. }
  675. /*******************************************************************************
  676. * FUNCTION: pt_proximity_release
  677. *
  678. * SUMMARY: The release function for proximity input device
  679. *
  680. * RETURN:
  681. * 0 = success
  682. *
  683. * PARAMETERS:
  684. * *dev - pointer to device structure
  685. ******************************************************************************/
  686. int pt_proximity_release(struct device *dev)
  687. {
  688. struct pt_proximity_data *pd;
  689. /* Ensure valid pointers before de-referencing them */
  690. if (dev)
  691. pd = get_prox_data(dev);
  692. else
  693. return 0;
  694. /*
  695. * Second call this function may cause kernel panic if probe fail.
  696. * Use input_device_registered & input_device_allocated variable to
  697. * avoid unregister or free unavailable devive.
  698. */
  699. if (pd && pd->input_device_registered) {
  700. /* Disable proximity sensing */
  701. pd->input_device_registered = false;
  702. mutex_lock(&pd->sysfs_lock);
  703. if (pd->enable_count)
  704. _pt_proximity_disable(pd, true);
  705. mutex_unlock(&pd->sysfs_lock);
  706. device_remove_file(dev, &dev_attr_prox_enable);
  707. input_unregister_device(pd->input);
  708. /* Unregistering device will free the device too */
  709. pd->input_device_allocated = false;
  710. } else if (pd && pd->input_device_allocated) {
  711. pd->input_device_allocated = false;
  712. input_free_device(pd->input);
  713. _pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP,
  714. PT_PROXIMITY_NAME, pt_setup_input_attention,
  715. 0);
  716. }
  717. return 0;
  718. }