raspberrypi-ts.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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 <nsaenzjulienne@suse.de>
  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 rpi_firmware *fw;
  105. struct rpi_ts *ts;
  106. u32 touchbuf;
  107. int error;
  108. struct device_node *fw_node __free(device_node) = of_get_parent(np);
  109. if (!fw_node) {
  110. dev_err(dev, "Missing firmware node\n");
  111. return -ENOENT;
  112. }
  113. fw = devm_rpi_firmware_get(&pdev->dev, fw_node);
  114. if (!fw)
  115. return -EPROBE_DEFER;
  116. ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
  117. if (!ts)
  118. return -ENOMEM;
  119. ts->pdev = pdev;
  120. ts->fw_regs_va = dma_alloc_coherent(dev, PAGE_SIZE, &ts->fw_regs_phys,
  121. GFP_KERNEL);
  122. if (!ts->fw_regs_va) {
  123. dev_err(dev, "failed to dma_alloc_coherent\n");
  124. return -ENOMEM;
  125. }
  126. error = devm_add_action_or_reset(dev, rpi_ts_dma_cleanup, ts);
  127. if (error) {
  128. dev_err(dev, "failed to devm_add_action_or_reset, %d\n", error);
  129. return error;
  130. }
  131. touchbuf = (u32)ts->fw_regs_phys;
  132. error = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF,
  133. &touchbuf, sizeof(touchbuf));
  134. if (error || touchbuf != 0) {
  135. dev_warn(dev, "Failed to set touchbuf, %d\n", error);
  136. return error;
  137. }
  138. input = devm_input_allocate_device(dev);
  139. if (!input) {
  140. dev_err(dev, "Failed to allocate input device\n");
  141. return -ENOMEM;
  142. }
  143. ts->input = input;
  144. input_set_drvdata(input, ts);
  145. input->name = "raspberrypi-ts";
  146. input->id.bustype = BUS_HOST;
  147. input_set_abs_params(input, ABS_MT_POSITION_X, 0,
  148. RPI_TS_DEFAULT_WIDTH, 0, 0);
  149. input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
  150. RPI_TS_DEFAULT_HEIGHT, 0, 0);
  151. touchscreen_parse_properties(input, true, &ts->prop);
  152. error = input_mt_init_slots(input, RPI_TS_MAX_SUPPORTED_POINTS,
  153. INPUT_MT_DIRECT);
  154. if (error) {
  155. dev_err(dev, "could not init mt slots, %d\n", error);
  156. return error;
  157. }
  158. error = input_setup_polling(input, rpi_ts_poll);
  159. if (error) {
  160. dev_err(dev, "could not set up polling mode, %d\n", error);
  161. return error;
  162. }
  163. input_set_poll_interval(input, RPI_TS_POLL_INTERVAL);
  164. error = input_register_device(input);
  165. if (error) {
  166. dev_err(dev, "could not register input device, %d\n", error);
  167. return error;
  168. }
  169. return 0;
  170. }
  171. static const struct of_device_id rpi_ts_match[] = {
  172. { .compatible = "raspberrypi,firmware-ts", },
  173. {},
  174. };
  175. MODULE_DEVICE_TABLE(of, rpi_ts_match);
  176. static struct platform_driver rpi_ts_driver = {
  177. .driver = {
  178. .name = "raspberrypi-ts",
  179. .of_match_table = rpi_ts_match,
  180. },
  181. .probe = rpi_ts_probe,
  182. };
  183. module_platform_driver(rpi_ts_driver);
  184. MODULE_AUTHOR("Gordon Hollingworth");
  185. MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>");
  186. MODULE_DESCRIPTION("Raspberry Pi firmware based touchscreen driver");
  187. MODULE_LICENSE("GPL v2");