raspberrypi-ts.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Raspberry Pi firmware based touchscreen driver
  4. *
  5. * Copyright (C) 2015, 2017 Raspberry Pi
  6. * Copyright (C) 2018 Nicolas Saenz Julienne <[email protected]>
  7. */
  8. #include <linux/io.h>
  9. #include <linux/of.h>
  10. #include <linux/slab.h>
  11. #include <linux/device.h>
  12. #include <linux/module.h>
  13. #include <linux/bitops.h>
  14. #include <linux/dma-mapping.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/input.h>
  17. #include <linux/input/mt.h>
  18. #include <linux/input/touchscreen.h>
  19. #include <soc/bcm2835/raspberrypi-firmware.h>
  20. #define RPI_TS_DEFAULT_WIDTH 800
  21. #define RPI_TS_DEFAULT_HEIGHT 480
  22. #define RPI_TS_MAX_SUPPORTED_POINTS 10
  23. #define RPI_TS_FTS_TOUCH_DOWN 0
  24. #define RPI_TS_FTS_TOUCH_CONTACT 2
  25. #define RPI_TS_POLL_INTERVAL 17 /* 60fps */
  26. #define RPI_TS_NPOINTS_REG_INVALIDATE 99
  27. struct rpi_ts {
  28. struct platform_device *pdev;
  29. struct input_dev *input;
  30. struct touchscreen_properties prop;
  31. void __iomem *fw_regs_va;
  32. dma_addr_t fw_regs_phys;
  33. int known_ids;
  34. };
  35. struct rpi_ts_regs {
  36. u8 device_mode;
  37. u8 gesture_id;
  38. u8 num_points;
  39. struct rpi_ts_touch {
  40. u8 xh;
  41. u8 xl;
  42. u8 yh;
  43. u8 yl;
  44. u8 pressure; /* Not supported */
  45. u8 area; /* Not supported */
  46. } point[RPI_TS_MAX_SUPPORTED_POINTS];
  47. };
  48. static void rpi_ts_poll(struct input_dev *input)
  49. {
  50. struct rpi_ts *ts = input_get_drvdata(input);
  51. struct rpi_ts_regs regs;
  52. int modified_ids = 0;
  53. long released_ids;
  54. int event_type;
  55. int touchid;
  56. int x, y;
  57. int i;
  58. memcpy_fromio(&regs, ts->fw_regs_va, sizeof(regs));
  59. /*
  60. * We poll the memory based register copy of the touchscreen chip using
  61. * the number of points register to know whether the copy has been
  62. * updated (we write 99 to the memory copy, the GPU will write between
  63. * 0 - 10 points)
  64. */
  65. iowrite8(RPI_TS_NPOINTS_REG_INVALIDATE,
  66. ts->fw_regs_va + offsetof(struct rpi_ts_regs, num_points));
  67. if (regs.num_points == RPI_TS_NPOINTS_REG_INVALIDATE ||
  68. (regs.num_points == 0 && ts->known_ids == 0))
  69. return;
  70. for (i = 0; i < regs.num_points; i++) {
  71. x = (((int)regs.point[i].xh & 0xf) << 8) + regs.point[i].xl;
  72. y = (((int)regs.point[i].yh & 0xf) << 8) + regs.point[i].yl;
  73. touchid = (regs.point[i].yh >> 4) & 0xf;
  74. event_type = (regs.point[i].xh >> 6) & 0x03;
  75. modified_ids |= BIT(touchid);
  76. if (event_type == RPI_TS_FTS_TOUCH_DOWN ||
  77. event_type == RPI_TS_FTS_TOUCH_CONTACT) {
  78. input_mt_slot(input, touchid);
  79. input_mt_report_slot_state(input, MT_TOOL_FINGER, 1);
  80. touchscreen_report_pos(input, &ts->prop, x, y, true);
  81. }
  82. }
  83. released_ids = ts->known_ids & ~modified_ids;
  84. for_each_set_bit(i, &released_ids, RPI_TS_MAX_SUPPORTED_POINTS) {
  85. input_mt_slot(input, i);
  86. input_mt_report_slot_inactive(input);
  87. modified_ids &= ~(BIT(i));
  88. }
  89. ts->known_ids = modified_ids;
  90. input_mt_sync_frame(input);
  91. input_sync(input);
  92. }
  93. static void rpi_ts_dma_cleanup(void *data)
  94. {
  95. struct rpi_ts *ts = data;
  96. struct device *dev = &ts->pdev->dev;
  97. dma_free_coherent(dev, PAGE_SIZE, ts->fw_regs_va, ts->fw_regs_phys);
  98. }
  99. static int rpi_ts_probe(struct platform_device *pdev)
  100. {
  101. struct device *dev = &pdev->dev;
  102. struct device_node *np = dev->of_node;
  103. struct input_dev *input;
  104. struct device_node *fw_node;
  105. struct rpi_firmware *fw;
  106. struct rpi_ts *ts;
  107. u32 touchbuf;
  108. int error;
  109. fw_node = of_get_parent(np);
  110. if (!fw_node) {
  111. dev_err(dev, "Missing firmware node\n");
  112. return -ENOENT;
  113. }
  114. fw = devm_rpi_firmware_get(&pdev->dev, fw_node);
  115. of_node_put(fw_node);
  116. if (!fw)
  117. return -EPROBE_DEFER;
  118. ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
  119. if (!ts)
  120. return -ENOMEM;
  121. ts->pdev = pdev;
  122. ts->fw_regs_va = dma_alloc_coherent(dev, PAGE_SIZE, &ts->fw_regs_phys,
  123. GFP_KERNEL);
  124. if (!ts->fw_regs_va) {
  125. dev_err(dev, "failed to dma_alloc_coherent\n");
  126. return -ENOMEM;
  127. }
  128. error = devm_add_action_or_reset(dev, rpi_ts_dma_cleanup, ts);
  129. if (error) {
  130. dev_err(dev, "failed to devm_add_action_or_reset, %d\n", error);
  131. return error;
  132. }
  133. touchbuf = (u32)ts->fw_regs_phys;
  134. error = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF,
  135. &touchbuf, sizeof(touchbuf));
  136. if (error || touchbuf != 0) {
  137. dev_warn(dev, "Failed to set touchbuf, %d\n", error);
  138. return error;
  139. }
  140. input = devm_input_allocate_device(dev);
  141. if (!input) {
  142. dev_err(dev, "Failed to allocate input device\n");
  143. return -ENOMEM;
  144. }
  145. ts->input = input;
  146. input_set_drvdata(input, ts);
  147. input->name = "raspberrypi-ts";
  148. input->id.bustype = BUS_HOST;
  149. input_set_abs_params(input, ABS_MT_POSITION_X, 0,
  150. RPI_TS_DEFAULT_WIDTH, 0, 0);
  151. input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
  152. RPI_TS_DEFAULT_HEIGHT, 0, 0);
  153. touchscreen_parse_properties(input, true, &ts->prop);
  154. error = input_mt_init_slots(input, RPI_TS_MAX_SUPPORTED_POINTS,
  155. INPUT_MT_DIRECT);
  156. if (error) {
  157. dev_err(dev, "could not init mt slots, %d\n", error);
  158. return error;
  159. }
  160. error = input_setup_polling(input, rpi_ts_poll);
  161. if (error) {
  162. dev_err(dev, "could not set up polling mode, %d\n", error);
  163. return error;
  164. }
  165. input_set_poll_interval(input, RPI_TS_POLL_INTERVAL);
  166. error = input_register_device(input);
  167. if (error) {
  168. dev_err(dev, "could not register input device, %d\n", error);
  169. return error;
  170. }
  171. return 0;
  172. }
  173. static const struct of_device_id rpi_ts_match[] = {
  174. { .compatible = "raspberrypi,firmware-ts", },
  175. {},
  176. };
  177. MODULE_DEVICE_TABLE(of, rpi_ts_match);
  178. static struct platform_driver rpi_ts_driver = {
  179. .driver = {
  180. .name = "raspberrypi-ts",
  181. .of_match_table = rpi_ts_match,
  182. },
  183. .probe = rpi_ts_probe,
  184. };
  185. module_platform_driver(rpi_ts_driver);
  186. MODULE_AUTHOR("Gordon Hollingworth");
  187. MODULE_AUTHOR("Nicolas Saenz Julienne <[email protected]>");
  188. MODULE_DESCRIPTION("Raspberry Pi firmware based touchscreen driver");
  189. MODULE_LICENSE("GPL v2");