0078-rpi-ft5406-Add-touchscreen-driver-for-pi-LCD-display.patch 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. From e6cf054ec136973f863fb31684453c37aef9c616 Mon Sep 17 00:00:00 2001
  2. From: Gordon Hollingworth <gordon@raspberrypi.org>
  3. Date: Tue, 12 May 2015 14:47:56 +0100
  4. Subject: [PATCH] rpi-ft5406: Add touchscreen driver for pi LCD display
  5. Fix driver detection failure Check that the buffer response is non-zero meaning the touchscreen was detected
  6. rpi-ft5406: Use firmware API
  7. ---
  8. drivers/input/touchscreen/Kconfig | 7 +
  9. drivers/input/touchscreen/Makefile | 1 +
  10. drivers/input/touchscreen/rpi-ft5406.c | 246 +++++++++++++++++++++++++++++++++
  11. 3 files changed, 254 insertions(+)
  12. create mode 100644 drivers/input/touchscreen/rpi-ft5406.c
  13. --- a/drivers/input/touchscreen/Kconfig
  14. +++ b/drivers/input/touchscreen/Kconfig
  15. @@ -608,6 +608,13 @@ config TOUCHSCREEN_EDT_FT5X06
  16. To compile this driver as a module, choose M here: the
  17. module will be called edt-ft5x06.
  18. +config TOUCHSCREEN_RPI_FT5406
  19. + tristate "Raspberry Pi FT5406 driver"
  20. + depends on RASPBERRYPI_FIRMWARE
  21. + help
  22. + Say Y here to enable the Raspberry Pi memory based FT5406 device
  23. +
  24. +
  25. config TOUCHSCREEN_MIGOR
  26. tristate "Renesas MIGO-R touchscreen"
  27. depends on SH_MIGOR && I2C
  28. --- a/drivers/input/touchscreen/Makefile
  29. +++ b/drivers/input/touchscreen/Makefile
  30. @@ -29,6 +29,7 @@ obj-$(CONFIG_TOUCHSCREEN_DA9034) += da90
  31. obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o
  32. obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
  33. obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06) += edt-ft5x06.o
  34. +obj-$(CONFIG_TOUCHSCREEN_RPI_FT5406) += rpi-ft5406.o
  35. obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
  36. obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
  37. obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
  38. --- /dev/null
  39. +++ b/drivers/input/touchscreen/rpi-ft5406.c
  40. @@ -0,0 +1,246 @@
  41. +/*
  42. + * Driver for memory based ft5406 touchscreen
  43. + *
  44. + * Copyright (C) 2015 Raspberry Pi
  45. + *
  46. + *
  47. + * This program is free software; you can redistribute it and/or modify
  48. + * it under the terms of the GNU General Public License version 2 as
  49. + * published by the Free Software Foundation.
  50. + */
  51. +
  52. +
  53. +#include <linux/module.h>
  54. +#include <linux/interrupt.h>
  55. +#include <linux/input.h>
  56. +#include <linux/irq.h>
  57. +#include <linux/delay.h>
  58. +#include <linux/slab.h>
  59. +#include <linux/bitops.h>
  60. +#include <linux/input/mt.h>
  61. +#include <linux/kthread.h>
  62. +#include <linux/platform_device.h>
  63. +#include <asm/io.h>
  64. +#include <soc/bcm2835/raspberrypi-firmware.h>
  65. +
  66. +#define MAXIMUM_SUPPORTED_POINTS 10
  67. +struct ft5406_regs {
  68. + uint8_t device_mode;
  69. + uint8_t gesture_id;
  70. + uint8_t num_points;
  71. + struct ft5406_touch {
  72. + uint8_t xh;
  73. + uint8_t xl;
  74. + uint8_t yh;
  75. + uint8_t yl;
  76. + uint8_t res1;
  77. + uint8_t res2;
  78. + } point[MAXIMUM_SUPPORTED_POINTS];
  79. +};
  80. +
  81. +#define SCREEN_WIDTH 800
  82. +#define SCREEN_HEIGHT 480
  83. +
  84. +struct ft5406 {
  85. + struct platform_device * pdev;
  86. + struct input_dev * input_dev;
  87. + void __iomem * ts_base;
  88. + struct ft5406_regs * regs;
  89. + struct task_struct * thread;
  90. +};
  91. +
  92. +/* Thread to poll for touchscreen events
  93. + *
  94. + * This thread polls the memory based register copy of the ft5406 registers
  95. + * using the number of points register to know whether the copy has been
  96. + * updated (we write 99 to the memory copy, the GPU will write between
  97. + * 0 - 10 points)
  98. + */
  99. +static int ft5406_thread(void *arg)
  100. +{
  101. + struct ft5406 *ts = (struct ft5406 *) arg;
  102. + struct ft5406_regs regs;
  103. + int known_ids = 0;
  104. +
  105. + while(!kthread_should_stop())
  106. + {
  107. + // 60fps polling
  108. + msleep_interruptible(17);
  109. + memcpy_fromio(&regs, ts->regs, sizeof(*ts->regs));
  110. + writel(99, &ts->regs->num_points);
  111. + // Do not output if theres no new information (num_points is 99)
  112. + // or we have no touch points and don't need to release any
  113. + if(!(regs.num_points == 99 || (regs.num_points == 0 && known_ids == 0)))
  114. + {
  115. + int i;
  116. + int modified_ids = 0, released_ids;
  117. + for(i = 0; i < regs.num_points; i++)
  118. + {
  119. + int x = (((int) regs.point[i].xh & 0xf) << 8) + regs.point[i].xl;
  120. + int y = (((int) regs.point[i].yh & 0xf) << 8) + regs.point[i].yl;
  121. + int touchid = (regs.point[i].yh >> 4) & 0xf;
  122. +
  123. + modified_ids |= 1 << touchid;
  124. +
  125. + if(!((1 << touchid) & known_ids))
  126. + dev_dbg(&ts->pdev->dev, "x = %d, y = %d, touchid = %d\n", x, y, touchid);
  127. +
  128. + input_mt_slot(ts->input_dev, touchid);
  129. + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1);
  130. +
  131. + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
  132. + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
  133. +
  134. + }
  135. +
  136. + released_ids = known_ids & ~modified_ids;
  137. + for(i = 0; released_ids && i < MAXIMUM_SUPPORTED_POINTS; i++)
  138. + {
  139. + if(released_ids & (1<<i))
  140. + {
  141. + dev_dbg(&ts->pdev->dev, "Released %d, known = %x modified = %x\n", i, known_ids, modified_ids);
  142. + input_mt_slot(ts->input_dev, i);
  143. + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
  144. + modified_ids &= ~(1 << i);
  145. + }
  146. + }
  147. + known_ids = modified_ids;
  148. +
  149. + input_mt_report_pointer_emulation(ts->input_dev, true);
  150. + input_sync(ts->input_dev);
  151. + }
  152. +
  153. + }
  154. +
  155. + return 0;
  156. +}
  157. +
  158. +static int ft5406_probe(struct platform_device *pdev)
  159. +{
  160. + int ret;
  161. + struct input_dev * input_dev = input_allocate_device();
  162. + struct ft5406 * ts;
  163. + struct device_node *fw_node;
  164. + struct rpi_firmware *fw;
  165. + u32 touchbuf;
  166. +
  167. + dev_info(&pdev->dev, "Probing device\n");
  168. +
  169. + fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
  170. + if (!fw_node) {
  171. + dev_err(&pdev->dev, "Missing firmware node\n");
  172. + return -ENOENT;
  173. + }
  174. +
  175. + fw = rpi_firmware_get(fw_node);
  176. + if (!fw)
  177. + return -EPROBE_DEFER;
  178. +
  179. + ret = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF,
  180. + &touchbuf, sizeof(touchbuf));
  181. + if (ret) {
  182. + dev_err(&pdev->dev, "Failed to get touch buffer\n");
  183. + return ret;
  184. + }
  185. +
  186. + if (!touchbuf) {
  187. + dev_err(&pdev->dev, "Touchscreen not detected\n");
  188. + return -ENODEV;
  189. + }
  190. +
  191. + dev_dbg(&pdev->dev, "Got TS buffer 0x%x\n", touchbuf);
  192. +
  193. + ts = kzalloc(sizeof(struct ft5406), GFP_KERNEL);
  194. +
  195. + if (!ts || !input_dev) {
  196. + ret = -ENOMEM;
  197. + dev_err(&pdev->dev, "Failed to allocate memory\n");
  198. + return ret;
  199. + }
  200. + ts->input_dev = input_dev;
  201. + platform_set_drvdata(pdev, ts);
  202. + ts->pdev = pdev;
  203. +
  204. + input_dev->name = "FT5406 memory based driver";
  205. +
  206. + __set_bit(EV_KEY, input_dev->evbit);
  207. + __set_bit(EV_SYN, input_dev->evbit);
  208. + __set_bit(EV_ABS, input_dev->evbit);
  209. +
  210. + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
  211. + SCREEN_WIDTH, 0, 0);
  212. + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
  213. + SCREEN_HEIGHT, 0, 0);
  214. +
  215. + input_mt_init_slots(input_dev, MAXIMUM_SUPPORTED_POINTS, INPUT_MT_DIRECT);
  216. +
  217. + input_set_drvdata(input_dev, ts);
  218. +
  219. + ret = input_register_device(input_dev);
  220. + if (ret) {
  221. + dev_err(&pdev->dev, "could not register input device, %d\n",
  222. + ret);
  223. + return ret;
  224. + }
  225. +
  226. + // mmap the physical memory
  227. + touchbuf &= ~0xc0000000;
  228. + ts->ts_base = ioremap(touchbuf, sizeof(*ts->regs));
  229. + if(ts->ts_base == NULL)
  230. + {
  231. + dev_err(&pdev->dev, "Failed to map physical address\n");
  232. + input_unregister_device(input_dev);
  233. + kzfree(ts);
  234. + return -ENOMEM;
  235. + }
  236. +
  237. + ts->regs = (struct ft5406_regs *) ts->ts_base;
  238. +
  239. + // create thread to poll the touch events
  240. + ts->thread = kthread_run(ft5406_thread, ts, "ft5406");
  241. + if(ts->thread == NULL)
  242. + {
  243. + dev_err(&pdev->dev, "Failed to create kernel thread");
  244. + iounmap(ts->ts_base);
  245. + input_unregister_device(input_dev);
  246. + kzfree(ts);
  247. + }
  248. +
  249. + return 0;
  250. +}
  251. +
  252. +static int ft5406_remove(struct platform_device *pdev)
  253. +{
  254. + struct ft5406 *ts = (struct ft5406 *) platform_get_drvdata(pdev);
  255. +
  256. + dev_info(&pdev->dev, "Removing rpi-ft5406\n");
  257. +
  258. + kthread_stop(ts->thread);
  259. + iounmap(ts->ts_base);
  260. + input_unregister_device(ts->input_dev);
  261. + kzfree(ts);
  262. +
  263. + return 0;
  264. +}
  265. +
  266. +static const struct of_device_id ft5406_match[] = {
  267. + { .compatible = "rpi,rpi-ft5406", },
  268. + {},
  269. +};
  270. +MODULE_DEVICE_TABLE(of, ft5406_match);
  271. +
  272. +static struct platform_driver ft5406_driver = {
  273. + .driver = {
  274. + .name = "rpi-ft5406",
  275. + .owner = THIS_MODULE,
  276. + .of_match_table = ft5406_match,
  277. + },
  278. + .probe = ft5406_probe,
  279. + .remove = ft5406_remove,
  280. +};
  281. +
  282. +module_platform_driver(ft5406_driver);
  283. +
  284. +MODULE_AUTHOR("Gordon Hollingworth");
  285. +MODULE_DESCRIPTION("Touchscreen driver for memory based FT5406");
  286. +MODULE_LICENSE("GPL");