pt_proximity.c 21 KB

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