synaptics_dsx_proximity.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. /*
  2. * Synaptics DSX touchscreen driver
  3. *
  4. * Copyright (C) 2012-2016 Synaptics Incorporated. All rights reserved.
  5. *
  6. * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
  7. * Copyright (C) 2012 Alexandra Chin <[email protected]>
  8. * Copyright (C) 2012 Scott Lin <[email protected]>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  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. * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
  21. * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
  22. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
  23. * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
  24. * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
  26. * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
  27. * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  28. * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
  29. * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
  30. * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
  31. * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
  32. * DOLLARS.
  33. */
  34. #include <linux/kernel.h>
  35. #include <linux/module.h>
  36. #include <linux/slab.h>
  37. #include <linux/interrupt.h>
  38. #include <linux/delay.h>
  39. #include <linux/input.h>
  40. #include <linux/platform_device.h>
  41. #include <linux/input/synaptics_dsx.h>
  42. #include "synaptics_dsx_core.h"
  43. #define PROX_PHYS_NAME "synaptics_dsx/proximity"
  44. #define HOVER_Z_MAX (255)
  45. #define HOVERING_FINGER_EN (1 << 4)
  46. static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev,
  47. struct device_attribute *attr, char *buf);
  48. static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev,
  49. struct device_attribute *attr, const char *buf, size_t count);
  50. static struct device_attribute attrs[] = {
  51. __ATTR(hover_finger_en, 0664,
  52. synaptics_rmi4_hover_finger_en_show,
  53. synaptics_rmi4_hover_finger_en_store),
  54. };
  55. struct synaptics_rmi4_f12_query_5 {
  56. union {
  57. struct {
  58. unsigned char size_of_query6;
  59. struct {
  60. unsigned char ctrl0_is_present:1;
  61. unsigned char ctrl1_is_present:1;
  62. unsigned char ctrl2_is_present:1;
  63. unsigned char ctrl3_is_present:1;
  64. unsigned char ctrl4_is_present:1;
  65. unsigned char ctrl5_is_present:1;
  66. unsigned char ctrl6_is_present:1;
  67. unsigned char ctrl7_is_present:1;
  68. } __packed;
  69. struct {
  70. unsigned char ctrl8_is_present:1;
  71. unsigned char ctrl9_is_present:1;
  72. unsigned char ctrl10_is_present:1;
  73. unsigned char ctrl11_is_present:1;
  74. unsigned char ctrl12_is_present:1;
  75. unsigned char ctrl13_is_present:1;
  76. unsigned char ctrl14_is_present:1;
  77. unsigned char ctrl15_is_present:1;
  78. } __packed;
  79. struct {
  80. unsigned char ctrl16_is_present:1;
  81. unsigned char ctrl17_is_present:1;
  82. unsigned char ctrl18_is_present:1;
  83. unsigned char ctrl19_is_present:1;
  84. unsigned char ctrl20_is_present:1;
  85. unsigned char ctrl21_is_present:1;
  86. unsigned char ctrl22_is_present:1;
  87. unsigned char ctrl23_is_present:1;
  88. } __packed;
  89. };
  90. unsigned char data[4];
  91. };
  92. };
  93. struct synaptics_rmi4_f12_query_8 {
  94. union {
  95. struct {
  96. unsigned char size_of_query9;
  97. struct {
  98. unsigned char data0_is_present:1;
  99. unsigned char data1_is_present:1;
  100. unsigned char data2_is_present:1;
  101. unsigned char data3_is_present:1;
  102. unsigned char data4_is_present:1;
  103. unsigned char data5_is_present:1;
  104. unsigned char data6_is_present:1;
  105. unsigned char data7_is_present:1;
  106. } __packed;
  107. };
  108. unsigned char data[2];
  109. };
  110. };
  111. struct prox_finger_data {
  112. union {
  113. struct {
  114. unsigned char object_type_and_status;
  115. unsigned char x_lsb;
  116. unsigned char x_msb;
  117. unsigned char y_lsb;
  118. unsigned char y_msb;
  119. unsigned char z;
  120. } __packed;
  121. unsigned char proximity_data[6];
  122. };
  123. };
  124. struct synaptics_rmi4_prox_handle {
  125. bool hover_finger_present;
  126. bool hover_finger_en;
  127. unsigned char intr_mask;
  128. unsigned short query_base_addr;
  129. unsigned short control_base_addr;
  130. unsigned short data_base_addr;
  131. unsigned short command_base_addr;
  132. unsigned short hover_finger_en_addr;
  133. unsigned short hover_finger_data_addr;
  134. struct input_dev *prox_dev;
  135. struct prox_finger_data *finger_data;
  136. struct synaptics_rmi4_data *rmi4_data;
  137. };
  138. static struct synaptics_rmi4_prox_handle *prox;
  139. DECLARE_COMPLETION(prox_remove_complete);
  140. static void prox_hover_finger_lift(void)
  141. {
  142. input_report_key(prox->prox_dev, BTN_TOUCH, 0);
  143. input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 0);
  144. input_sync(prox->prox_dev);
  145. prox->hover_finger_present = false;
  146. }
  147. static void prox_hover_finger_report(void)
  148. {
  149. int retval;
  150. int x;
  151. int y;
  152. int z;
  153. struct prox_finger_data *data;
  154. struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
  155. data = prox->finger_data;
  156. retval = synaptics_rmi4_reg_read(rmi4_data,
  157. prox->hover_finger_data_addr,
  158. data->proximity_data,
  159. sizeof(data->proximity_data));
  160. if (retval < 0) {
  161. dev_err(rmi4_data->pdev->dev.parent,
  162. "%s: Failed to read hovering finger data\n",
  163. __func__);
  164. return;
  165. }
  166. if (data->object_type_and_status != F12_HOVERING_FINGER_STATUS) {
  167. if (prox->hover_finger_present)
  168. prox_hover_finger_lift();
  169. return;
  170. }
  171. x = (data->x_msb << 8) | (data->x_lsb);
  172. y = (data->y_msb << 8) | (data->y_lsb);
  173. z = HOVER_Z_MAX - data->z;
  174. input_report_key(prox->prox_dev, BTN_TOUCH, 0);
  175. input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 1);
  176. input_report_abs(prox->prox_dev, ABS_X, x);
  177. input_report_abs(prox->prox_dev, ABS_Y, y);
  178. input_report_abs(prox->prox_dev, ABS_DISTANCE, z);
  179. input_sync(prox->prox_dev);
  180. dev_dbg(rmi4_data->pdev->dev.parent,
  181. "%s: x = %d y = %d z = %d\n",
  182. __func__, x, y, z);
  183. prox->hover_finger_present = true;
  184. }
  185. static int prox_set_hover_finger_en(void)
  186. {
  187. int retval;
  188. unsigned char object_report_enable;
  189. struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
  190. retval = synaptics_rmi4_reg_read(rmi4_data,
  191. prox->hover_finger_en_addr,
  192. &object_report_enable,
  193. sizeof(object_report_enable));
  194. if (retval < 0) {
  195. dev_err(rmi4_data->pdev->dev.parent,
  196. "%s: Failed to read from object report enable register\n",
  197. __func__);
  198. return retval;
  199. }
  200. if (prox->hover_finger_en)
  201. object_report_enable |= HOVERING_FINGER_EN;
  202. else
  203. object_report_enable &= ~HOVERING_FINGER_EN;
  204. retval = synaptics_rmi4_reg_write(rmi4_data,
  205. prox->hover_finger_en_addr,
  206. &object_report_enable,
  207. sizeof(object_report_enable));
  208. if (retval < 0) {
  209. dev_err(rmi4_data->pdev->dev.parent,
  210. "%s: Failed to write to object report enable register\n",
  211. __func__);
  212. return retval;
  213. }
  214. return 0;
  215. }
  216. static void prox_set_params(void)
  217. {
  218. input_set_abs_params(prox->prox_dev, ABS_X, 0,
  219. prox->rmi4_data->sensor_max_x, 0, 0);
  220. input_set_abs_params(prox->prox_dev, ABS_Y, 0,
  221. prox->rmi4_data->sensor_max_y, 0, 0);
  222. input_set_abs_params(prox->prox_dev, ABS_DISTANCE, 0,
  223. HOVER_Z_MAX, 0, 0);
  224. }
  225. static int prox_reg_init(void)
  226. {
  227. int retval;
  228. unsigned char ctrl_23_offset;
  229. unsigned char data_1_offset;
  230. struct synaptics_rmi4_f12_query_5 query_5;
  231. struct synaptics_rmi4_f12_query_8 query_8;
  232. struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
  233. retval = synaptics_rmi4_reg_read(rmi4_data,
  234. prox->query_base_addr + 5,
  235. query_5.data,
  236. sizeof(query_5.data));
  237. if (retval < 0)
  238. return retval;
  239. ctrl_23_offset = query_5.ctrl0_is_present +
  240. query_5.ctrl1_is_present +
  241. query_5.ctrl2_is_present +
  242. query_5.ctrl3_is_present +
  243. query_5.ctrl4_is_present +
  244. query_5.ctrl5_is_present +
  245. query_5.ctrl6_is_present +
  246. query_5.ctrl7_is_present +
  247. query_5.ctrl8_is_present +
  248. query_5.ctrl9_is_present +
  249. query_5.ctrl10_is_present +
  250. query_5.ctrl11_is_present +
  251. query_5.ctrl12_is_present +
  252. query_5.ctrl13_is_present +
  253. query_5.ctrl14_is_present +
  254. query_5.ctrl15_is_present +
  255. query_5.ctrl16_is_present +
  256. query_5.ctrl17_is_present +
  257. query_5.ctrl18_is_present +
  258. query_5.ctrl19_is_present +
  259. query_5.ctrl20_is_present +
  260. query_5.ctrl21_is_present +
  261. query_5.ctrl22_is_present;
  262. prox->hover_finger_en_addr = prox->control_base_addr + ctrl_23_offset;
  263. retval = synaptics_rmi4_reg_read(rmi4_data,
  264. prox->query_base_addr + 8,
  265. query_8.data,
  266. sizeof(query_8.data));
  267. if (retval < 0)
  268. return retval;
  269. data_1_offset = query_8.data0_is_present;
  270. prox->hover_finger_data_addr = prox->data_base_addr + data_1_offset;
  271. return retval;
  272. }
  273. static int prox_scan_pdt(void)
  274. {
  275. int retval;
  276. unsigned char ii;
  277. unsigned char page;
  278. unsigned char intr_count = 0;
  279. unsigned char intr_off;
  280. unsigned char intr_src;
  281. unsigned short addr;
  282. struct synaptics_rmi4_fn_desc fd;
  283. struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
  284. for (page = 0; page < PAGES_TO_SERVICE; page++) {
  285. for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
  286. addr |= (page << 8);
  287. retval = synaptics_rmi4_reg_read(rmi4_data,
  288. addr,
  289. (unsigned char *)&fd,
  290. sizeof(fd));
  291. if (retval < 0)
  292. return retval;
  293. addr &= ~(MASK_8BIT << 8);
  294. if (fd.fn_number) {
  295. dev_dbg(rmi4_data->pdev->dev.parent,
  296. "%s: Found F%02x\n",
  297. __func__, fd.fn_number);
  298. switch (fd.fn_number) {
  299. case SYNAPTICS_RMI4_F12:
  300. goto f12_found;
  301. break;
  302. }
  303. } else {
  304. break;
  305. }
  306. intr_count += fd.intr_src_count;
  307. }
  308. }
  309. dev_err(rmi4_data->pdev->dev.parent,
  310. "%s: Failed to find F12\n",
  311. __func__);
  312. return -EINVAL;
  313. f12_found:
  314. prox->query_base_addr = fd.query_base_addr | (page << 8);
  315. prox->control_base_addr = fd.ctrl_base_addr | (page << 8);
  316. prox->data_base_addr = fd.data_base_addr | (page << 8);
  317. prox->command_base_addr = fd.cmd_base_addr | (page << 8);
  318. retval = prox_reg_init();
  319. if (retval < 0) {
  320. dev_err(rmi4_data->pdev->dev.parent,
  321. "%s: Failed to initialize proximity registers\n",
  322. __func__);
  323. return retval;
  324. }
  325. prox->intr_mask = 0;
  326. intr_src = fd.intr_src_count;
  327. intr_off = intr_count % 8;
  328. for (ii = intr_off;
  329. ii < (intr_src + intr_off);
  330. ii++) {
  331. prox->intr_mask |= 1 << ii;
  332. }
  333. rmi4_data->intr_mask[0] |= prox->intr_mask;
  334. addr = rmi4_data->f01_ctrl_base_addr + 1;
  335. retval = synaptics_rmi4_reg_write(rmi4_data,
  336. addr,
  337. &(rmi4_data->intr_mask[0]),
  338. sizeof(rmi4_data->intr_mask[0]));
  339. if (retval < 0) {
  340. dev_err(rmi4_data->pdev->dev.parent,
  341. "%s: Failed to set interrupt enable bit\n",
  342. __func__);
  343. return retval;
  344. }
  345. return 0;
  346. }
  347. static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev,
  348. struct device_attribute *attr, char *buf)
  349. {
  350. if (!prox)
  351. return -ENODEV;
  352. return snprintf(buf, PAGE_SIZE, "%u\n",
  353. prox->hover_finger_en);
  354. }
  355. static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev,
  356. struct device_attribute *attr, const char *buf, size_t count)
  357. {
  358. int retval;
  359. unsigned int input;
  360. struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
  361. if (!prox)
  362. return -ENODEV;
  363. if (kstrtouint(buf, 16, &input) != 1)
  364. return -EINVAL;
  365. if (input == 1)
  366. prox->hover_finger_en = true;
  367. else if (input == 0)
  368. prox->hover_finger_en = false;
  369. else
  370. return -EINVAL;
  371. retval = prox_set_hover_finger_en();
  372. if (retval < 0) {
  373. dev_err(rmi4_data->pdev->dev.parent,
  374. "%s: Failed to change hovering finger enable setting\n",
  375. __func__);
  376. return retval;
  377. }
  378. return count;
  379. }
  380. int synaptics_rmi4_prox_hover_finger_en(bool enable)
  381. {
  382. int retval;
  383. if (!prox)
  384. return -ENODEV;
  385. prox->hover_finger_en = enable;
  386. retval = prox_set_hover_finger_en();
  387. if (retval < 0)
  388. return retval;
  389. return 0;
  390. }
  391. EXPORT_SYMBOL(synaptics_rmi4_prox_hover_finger_en);
  392. static void synaptics_rmi4_prox_attn(struct synaptics_rmi4_data *rmi4_data,
  393. unsigned char intr_mask)
  394. {
  395. if (!prox)
  396. return;
  397. if (prox->intr_mask & intr_mask)
  398. prox_hover_finger_report();
  399. }
  400. static int synaptics_rmi4_prox_init(struct synaptics_rmi4_data *rmi4_data)
  401. {
  402. int retval;
  403. unsigned char attr_count;
  404. if (prox) {
  405. dev_dbg(rmi4_data->pdev->dev.parent,
  406. "%s: Handle already exists\n",
  407. __func__);
  408. return 0;
  409. }
  410. prox = kzalloc(sizeof(*prox), GFP_KERNEL);
  411. if (!prox) {
  412. dev_err(rmi4_data->pdev->dev.parent,
  413. "%s: Failed to alloc mem for prox\n",
  414. __func__);
  415. retval = -ENOMEM;
  416. goto exit;
  417. }
  418. prox->finger_data = kzalloc(sizeof(*(prox->finger_data)), GFP_KERNEL);
  419. if (!prox->finger_data) {
  420. dev_err(rmi4_data->pdev->dev.parent,
  421. "%s: Failed to alloc mem for finger_data\n",
  422. __func__);
  423. retval = -ENOMEM;
  424. goto exit_free_prox;
  425. }
  426. prox->rmi4_data = rmi4_data;
  427. retval = prox_scan_pdt();
  428. if (retval < 0)
  429. goto exit_free_finger_data;
  430. prox->hover_finger_en = true;
  431. retval = prox_set_hover_finger_en();
  432. if (retval < 0)
  433. return retval;
  434. prox->prox_dev = input_allocate_device();
  435. if (prox->prox_dev == NULL) {
  436. dev_err(rmi4_data->pdev->dev.parent,
  437. "%s: Failed to allocate proximity device\n",
  438. __func__);
  439. retval = -ENOMEM;
  440. goto exit_free_finger_data;
  441. }
  442. prox->prox_dev->name = PROXIMITY_DRIVER_NAME;
  443. prox->prox_dev->phys = PROX_PHYS_NAME;
  444. prox->prox_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
  445. prox->prox_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
  446. prox->prox_dev->dev.parent = rmi4_data->pdev->dev.parent;
  447. input_set_drvdata(prox->prox_dev, rmi4_data);
  448. set_bit(EV_KEY, prox->prox_dev->evbit);
  449. set_bit(EV_ABS, prox->prox_dev->evbit);
  450. set_bit(BTN_TOUCH, prox->prox_dev->keybit);
  451. set_bit(BTN_TOOL_FINGER, prox->prox_dev->keybit);
  452. #ifdef INPUT_PROP_DIRECT
  453. set_bit(INPUT_PROP_DIRECT, prox->prox_dev->propbit);
  454. #endif
  455. prox_set_params();
  456. retval = input_register_device(prox->prox_dev);
  457. if (retval) {
  458. dev_err(rmi4_data->pdev->dev.parent,
  459. "%s: Failed to register proximity device\n",
  460. __func__);
  461. goto exit_free_input_device;
  462. }
  463. for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
  464. retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
  465. &attrs[attr_count].attr);
  466. if (retval < 0) {
  467. dev_err(rmi4_data->pdev->dev.parent,
  468. "%s: Failed to create sysfs attributes\n",
  469. __func__);
  470. goto exit_free_sysfs;
  471. }
  472. }
  473. return 0;
  474. exit_free_sysfs:
  475. for (attr_count--; attr_count >= 0; attr_count--) {
  476. sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
  477. &attrs[attr_count].attr);
  478. }
  479. input_unregister_device(prox->prox_dev);
  480. prox->prox_dev = NULL;
  481. exit_free_input_device:
  482. if (prox->prox_dev)
  483. input_free_device(prox->prox_dev);
  484. exit_free_finger_data:
  485. kfree(prox->finger_data);
  486. exit_free_prox:
  487. kfree(prox);
  488. prox = NULL;
  489. exit:
  490. return retval;
  491. }
  492. static void synaptics_rmi4_prox_remove(struct synaptics_rmi4_data *rmi4_data)
  493. {
  494. unsigned char attr_count;
  495. if (!prox)
  496. goto exit;
  497. for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
  498. sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
  499. &attrs[attr_count].attr);
  500. }
  501. input_unregister_device(prox->prox_dev);
  502. kfree(prox->finger_data);
  503. kfree(prox);
  504. prox = NULL;
  505. exit:
  506. complete(&prox_remove_complete);
  507. }
  508. static void synaptics_rmi4_prox_reset(struct synaptics_rmi4_data *rmi4_data)
  509. {
  510. if (!prox) {
  511. synaptics_rmi4_prox_init(rmi4_data);
  512. return;
  513. }
  514. prox_hover_finger_lift();
  515. prox_scan_pdt();
  516. prox_set_hover_finger_en();
  517. }
  518. static void synaptics_rmi4_prox_reinit(struct synaptics_rmi4_data *rmi4_data)
  519. {
  520. if (!prox)
  521. return;
  522. prox_hover_finger_lift();
  523. prox_set_hover_finger_en();
  524. }
  525. static void synaptics_rmi4_prox_e_suspend(struct synaptics_rmi4_data *rmi4_data)
  526. {
  527. if (!prox)
  528. return;
  529. prox_hover_finger_lift();
  530. }
  531. static void synaptics_rmi4_prox_suspend(struct synaptics_rmi4_data *rmi4_data)
  532. {
  533. if (!prox)
  534. return;
  535. prox_hover_finger_lift();
  536. }
  537. static struct synaptics_rmi4_exp_fn proximity_module = {
  538. .fn_type = RMI_PROXIMITY,
  539. .init = synaptics_rmi4_prox_init,
  540. .remove = synaptics_rmi4_prox_remove,
  541. .reset = synaptics_rmi4_prox_reset,
  542. .reinit = synaptics_rmi4_prox_reinit,
  543. .early_suspend = synaptics_rmi4_prox_e_suspend,
  544. .suspend = synaptics_rmi4_prox_suspend,
  545. .resume = NULL,
  546. .late_resume = NULL,
  547. .attn = synaptics_rmi4_prox_attn,
  548. };
  549. static int __init rmi4_proximity_module_init(void)
  550. {
  551. synaptics_rmi4_new_function(&proximity_module, true);
  552. return 0;
  553. }
  554. static void __exit rmi4_proximity_module_exit(void)
  555. {
  556. synaptics_rmi4_new_function(&proximity_module, false);
  557. wait_for_completion(&prox_remove_complete);
  558. }
  559. module_init(rmi4_proximity_module_init);
  560. module_exit(rmi4_proximity_module_exit);
  561. MODULE_AUTHOR("Synaptics, Inc.");
  562. MODULE_DESCRIPTION("Synaptics DSX Proximity Module");
  563. MODULE_LICENSE("GPL v2");