da9052_tsi.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*
  2. * TSI driver for Dialog DA9052
  3. *
  4. * Copyright(c) 2012 Dialog Semiconductor Ltd.
  5. *
  6. * Author: David Dajun Chen <dchen@diasemi.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation; either version 2 of the License, or (at your
  11. * option) any later version.
  12. *
  13. */
  14. #include <linux/module.h>
  15. #include <linux/input.h>
  16. #include <linux/delay.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/mfd/da9052/reg.h>
  20. #include <linux/mfd/da9052/da9052.h>
  21. #define TSI_PEN_DOWN_STATUS 0x40
  22. struct da9052_tsi {
  23. struct da9052 *da9052;
  24. struct input_dev *dev;
  25. struct delayed_work ts_pen_work;
  26. bool stopped;
  27. bool adc_on;
  28. };
  29. static void da9052_ts_adc_toggle(struct da9052_tsi *tsi, bool on)
  30. {
  31. da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 0, on);
  32. tsi->adc_on = on;
  33. }
  34. static irqreturn_t da9052_ts_pendwn_irq(int irq, void *data)
  35. {
  36. struct da9052_tsi *tsi = data;
  37. if (!tsi->stopped) {
  38. /* Mask PEN_DOWN event and unmask TSI_READY event */
  39. da9052_disable_irq_nosync(tsi->da9052, DA9052_IRQ_PENDOWN);
  40. da9052_enable_irq(tsi->da9052, DA9052_IRQ_TSIREADY);
  41. da9052_ts_adc_toggle(tsi, true);
  42. schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
  43. }
  44. return IRQ_HANDLED;
  45. }
  46. static void da9052_ts_read(struct da9052_tsi *tsi)
  47. {
  48. struct input_dev *input = tsi->dev;
  49. int ret;
  50. u16 x, y, z;
  51. u8 v;
  52. ret = da9052_reg_read(tsi->da9052, DA9052_TSI_X_MSB_REG);
  53. if (ret < 0)
  54. return;
  55. x = (u16) ret;
  56. ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Y_MSB_REG);
  57. if (ret < 0)
  58. return;
  59. y = (u16) ret;
  60. ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Z_MSB_REG);
  61. if (ret < 0)
  62. return;
  63. z = (u16) ret;
  64. ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
  65. if (ret < 0)
  66. return;
  67. v = (u8) ret;
  68. x = ((x << 2) & 0x3fc) | (v & 0x3);
  69. y = ((y << 2) & 0x3fc) | ((v & 0xc) >> 2);
  70. z = ((z << 2) & 0x3fc) | ((v & 0x30) >> 4);
  71. input_report_key(input, BTN_TOUCH, 1);
  72. input_report_abs(input, ABS_X, x);
  73. input_report_abs(input, ABS_Y, y);
  74. input_report_abs(input, ABS_PRESSURE, z);
  75. input_sync(input);
  76. }
  77. static irqreturn_t da9052_ts_datardy_irq(int irq, void *data)
  78. {
  79. struct da9052_tsi *tsi = data;
  80. da9052_ts_read(tsi);
  81. return IRQ_HANDLED;
  82. }
  83. static void da9052_ts_pen_work(struct work_struct *work)
  84. {
  85. struct da9052_tsi *tsi = container_of(work, struct da9052_tsi,
  86. ts_pen_work.work);
  87. if (!tsi->stopped) {
  88. int ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
  89. if (ret < 0 || (ret & TSI_PEN_DOWN_STATUS)) {
  90. /* Pen is still DOWN (or read error) */
  91. schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
  92. } else {
  93. struct input_dev *input = tsi->dev;
  94. /* Pen UP */
  95. da9052_ts_adc_toggle(tsi, false);
  96. /* Report Pen UP */
  97. input_report_key(input, BTN_TOUCH, 0);
  98. input_report_abs(input, ABS_PRESSURE, 0);
  99. input_sync(input);
  100. /*
  101. * FIXME: Fixes the unhandled irq issue when quick
  102. * pen down and pen up events occurs
  103. */
  104. ret = da9052_reg_update(tsi->da9052,
  105. DA9052_EVENT_B_REG, 0xC0, 0xC0);
  106. if (ret < 0)
  107. return;
  108. /* Mask TSI_READY event and unmask PEN_DOWN event */
  109. da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY);
  110. da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
  111. }
  112. }
  113. }
  114. static int da9052_ts_configure_gpio(struct da9052 *da9052)
  115. {
  116. int error;
  117. error = da9052_reg_update(da9052, DA9052_GPIO_2_3_REG, 0x30, 0);
  118. if (error < 0)
  119. return error;
  120. error = da9052_reg_update(da9052, DA9052_GPIO_4_5_REG, 0x33, 0);
  121. if (error < 0)
  122. return error;
  123. error = da9052_reg_update(da9052, DA9052_GPIO_6_7_REG, 0x33, 0);
  124. if (error < 0)
  125. return error;
  126. return 0;
  127. }
  128. static int da9052_configure_tsi(struct da9052_tsi *tsi)
  129. {
  130. int error;
  131. error = da9052_ts_configure_gpio(tsi->da9052);
  132. if (error)
  133. return error;
  134. /* Measure TSI sample every 1ms */
  135. error = da9052_reg_update(tsi->da9052, DA9052_ADC_CONT_REG,
  136. 1 << 6, 1 << 6);
  137. if (error < 0)
  138. return error;
  139. /* TSI_DELAY: 3 slots, TSI_SKIP: 0 slots, TSI_MODE: XYZP */
  140. error = da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 0xFC, 0xC0);
  141. if (error < 0)
  142. return error;
  143. /* Supply TSIRef through LD09 */
  144. error = da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x59);
  145. if (error < 0)
  146. return error;
  147. return 0;
  148. }
  149. static int da9052_ts_input_open(struct input_dev *input_dev)
  150. {
  151. struct da9052_tsi *tsi = input_get_drvdata(input_dev);
  152. tsi->stopped = false;
  153. mb();
  154. /* Unmask PEN_DOWN event */
  155. da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
  156. /* Enable Pen Detect Circuit */
  157. return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG,
  158. 1 << 1, 1 << 1);
  159. }
  160. static void da9052_ts_input_close(struct input_dev *input_dev)
  161. {
  162. struct da9052_tsi *tsi = input_get_drvdata(input_dev);
  163. tsi->stopped = true;
  164. mb();
  165. da9052_disable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
  166. cancel_delayed_work_sync(&tsi->ts_pen_work);
  167. if (tsi->adc_on) {
  168. da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY);
  169. da9052_ts_adc_toggle(tsi, false);
  170. /*
  171. * If ADC was on that means that pendwn IRQ was disabled
  172. * twice and we need to enable it to keep enable/disable
  173. * counter balanced. IRQ is still off though.
  174. */
  175. da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
  176. }
  177. /* Disable Pen Detect Circuit */
  178. da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
  179. }
  180. static int da9052_ts_probe(struct platform_device *pdev)
  181. {
  182. struct da9052 *da9052;
  183. struct da9052_tsi *tsi;
  184. struct input_dev *input_dev;
  185. int error;
  186. da9052 = dev_get_drvdata(pdev->dev.parent);
  187. if (!da9052)
  188. return -EINVAL;
  189. tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL);
  190. input_dev = input_allocate_device();
  191. if (!tsi || !input_dev) {
  192. error = -ENOMEM;
  193. goto err_free_mem;
  194. }
  195. tsi->da9052 = da9052;
  196. tsi->dev = input_dev;
  197. tsi->stopped = true;
  198. INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work);
  199. input_dev->id.version = 0x0101;
  200. input_dev->id.vendor = 0x15B6;
  201. input_dev->id.product = 0x9052;
  202. input_dev->name = "Dialog DA9052 TouchScreen Driver";
  203. input_dev->dev.parent = &pdev->dev;
  204. input_dev->open = da9052_ts_input_open;
  205. input_dev->close = da9052_ts_input_close;
  206. __set_bit(EV_ABS, input_dev->evbit);
  207. __set_bit(EV_KEY, input_dev->evbit);
  208. __set_bit(BTN_TOUCH, input_dev->keybit);
  209. input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
  210. input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
  211. input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1023, 0, 0);
  212. input_set_drvdata(input_dev, tsi);
  213. /* Disable Pen Detect Circuit */
  214. da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
  215. /* Disable ADC */
  216. da9052_ts_adc_toggle(tsi, false);
  217. error = da9052_request_irq(tsi->da9052, DA9052_IRQ_PENDOWN,
  218. "pendown-irq", da9052_ts_pendwn_irq, tsi);
  219. if (error) {
  220. dev_err(tsi->da9052->dev,
  221. "Failed to register PENDWN IRQ: %d\n", error);
  222. goto err_free_mem;
  223. }
  224. error = da9052_request_irq(tsi->da9052, DA9052_IRQ_TSIREADY,
  225. "tsiready-irq", da9052_ts_datardy_irq, tsi);
  226. if (error) {
  227. dev_err(tsi->da9052->dev,
  228. "Failed to register TSIRDY IRQ :%d\n", error);
  229. goto err_free_pendwn_irq;
  230. }
  231. /* Mask PEN_DOWN and TSI_READY events */
  232. da9052_disable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
  233. da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY);
  234. error = da9052_configure_tsi(tsi);
  235. if (error)
  236. goto err_free_datardy_irq;
  237. error = input_register_device(tsi->dev);
  238. if (error)
  239. goto err_free_datardy_irq;
  240. platform_set_drvdata(pdev, tsi);
  241. return 0;
  242. err_free_datardy_irq:
  243. da9052_free_irq(tsi->da9052, DA9052_IRQ_TSIREADY, tsi);
  244. err_free_pendwn_irq:
  245. da9052_free_irq(tsi->da9052, DA9052_IRQ_PENDOWN, tsi);
  246. err_free_mem:
  247. kfree(tsi);
  248. input_free_device(input_dev);
  249. return error;
  250. }
  251. static int da9052_ts_remove(struct platform_device *pdev)
  252. {
  253. struct da9052_tsi *tsi = platform_get_drvdata(pdev);
  254. da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19);
  255. da9052_free_irq(tsi->da9052, DA9052_IRQ_TSIREADY, tsi);
  256. da9052_free_irq(tsi->da9052, DA9052_IRQ_PENDOWN, tsi);
  257. input_unregister_device(tsi->dev);
  258. kfree(tsi);
  259. return 0;
  260. }
  261. static struct platform_driver da9052_tsi_driver = {
  262. .probe = da9052_ts_probe,
  263. .remove = da9052_ts_remove,
  264. .driver = {
  265. .name = "da9052-tsi",
  266. },
  267. };
  268. module_platform_driver(da9052_tsi_driver);
  269. MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9052");
  270. MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");
  271. MODULE_LICENSE("GPL");
  272. MODULE_ALIAS("platform:da9052-tsi");