tsc40.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * TSC-40 serial touchscreen driver. It should be compatible with
  3. * TSC-10 and 25.
  4. *
  5. * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  6. * License: GPLv2 as published by the FSF.
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/module.h>
  10. #include <linux/slab.h>
  11. #include <linux/input.h>
  12. #include <linux/serio.h>
  13. #include <linux/init.h>
  14. #define PACKET_LENGTH 5
  15. struct tsc_ser {
  16. struct input_dev *dev;
  17. struct serio *serio;
  18. u32 idx;
  19. unsigned char data[PACKET_LENGTH];
  20. char phys[32];
  21. };
  22. static void tsc_process_data(struct tsc_ser *ptsc)
  23. {
  24. struct input_dev *dev = ptsc->dev;
  25. u8 *data = ptsc->data;
  26. u32 x;
  27. u32 y;
  28. x = ((data[1] & 0x03) << 8) | data[2];
  29. y = ((data[3] & 0x03) << 8) | data[4];
  30. input_report_abs(dev, ABS_X, x);
  31. input_report_abs(dev, ABS_Y, y);
  32. input_report_key(dev, BTN_TOUCH, 1);
  33. input_sync(dev);
  34. }
  35. static irqreturn_t tsc_interrupt(struct serio *serio,
  36. unsigned char data, unsigned int flags)
  37. {
  38. struct tsc_ser *ptsc = serio_get_drvdata(serio);
  39. struct input_dev *dev = ptsc->dev;
  40. ptsc->data[ptsc->idx] = data;
  41. switch (ptsc->idx++) {
  42. case 0:
  43. if (unlikely((data & 0x3e) != 0x10)) {
  44. dev_dbg(&serio->dev,
  45. "unsynchronized packet start (0x%02x)\n", data);
  46. ptsc->idx = 0;
  47. } else if (!(data & 0x01)) {
  48. input_report_key(dev, BTN_TOUCH, 0);
  49. input_sync(dev);
  50. ptsc->idx = 0;
  51. }
  52. break;
  53. case 1:
  54. case 3:
  55. if (unlikely(data & 0xfc)) {
  56. dev_dbg(&serio->dev,
  57. "unsynchronized data 0x%02x at offset %d\n",
  58. data, ptsc->idx - 1);
  59. ptsc->idx = 0;
  60. }
  61. break;
  62. case 4:
  63. tsc_process_data(ptsc);
  64. ptsc->idx = 0;
  65. break;
  66. }
  67. return IRQ_HANDLED;
  68. }
  69. static int tsc_connect(struct serio *serio, struct serio_driver *drv)
  70. {
  71. struct tsc_ser *ptsc;
  72. struct input_dev *input_dev;
  73. int error;
  74. ptsc = kzalloc(sizeof(struct tsc_ser), GFP_KERNEL);
  75. input_dev = input_allocate_device();
  76. if (!ptsc || !input_dev) {
  77. error = -ENOMEM;
  78. goto fail1;
  79. }
  80. ptsc->serio = serio;
  81. ptsc->dev = input_dev;
  82. snprintf(ptsc->phys, sizeof(ptsc->phys), "%s/input0", serio->phys);
  83. input_dev->name = "TSC-10/25/40 Serial TouchScreen";
  84. input_dev->phys = ptsc->phys;
  85. input_dev->id.bustype = BUS_RS232;
  86. input_dev->id.vendor = SERIO_TSC40;
  87. input_dev->id.product = 40;
  88. input_dev->id.version = 0x0001;
  89. input_dev->dev.parent = &serio->dev;
  90. input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
  91. __set_bit(BTN_TOUCH, input_dev->keybit);
  92. input_set_abs_params(ptsc->dev, ABS_X, 0, 0x3ff, 0, 0);
  93. input_set_abs_params(ptsc->dev, ABS_Y, 0, 0x3ff, 0, 0);
  94. serio_set_drvdata(serio, ptsc);
  95. error = serio_open(serio, drv);
  96. if (error)
  97. goto fail2;
  98. error = input_register_device(ptsc->dev);
  99. if (error)
  100. goto fail3;
  101. return 0;
  102. fail3:
  103. serio_close(serio);
  104. fail2:
  105. serio_set_drvdata(serio, NULL);
  106. fail1:
  107. input_free_device(input_dev);
  108. kfree(ptsc);
  109. return error;
  110. }
  111. static void tsc_disconnect(struct serio *serio)
  112. {
  113. struct tsc_ser *ptsc = serio_get_drvdata(serio);
  114. serio_close(serio);
  115. input_unregister_device(ptsc->dev);
  116. kfree(ptsc);
  117. serio_set_drvdata(serio, NULL);
  118. }
  119. static struct serio_device_id tsc_serio_ids[] = {
  120. {
  121. .type = SERIO_RS232,
  122. .proto = SERIO_TSC40,
  123. .id = SERIO_ANY,
  124. .extra = SERIO_ANY,
  125. },
  126. { 0 }
  127. };
  128. MODULE_DEVICE_TABLE(serio, tsc_serio_ids);
  129. #define DRIVER_DESC "TSC-10/25/40 serial touchscreen driver"
  130. static struct serio_driver tsc_drv = {
  131. .driver = {
  132. .name = "tsc40",
  133. },
  134. .description = DRIVER_DESC,
  135. .id_table = tsc_serio_ids,
  136. .interrupt = tsc_interrupt,
  137. .connect = tsc_connect,
  138. .disconnect = tsc_disconnect,
  139. };
  140. static int __init tsc_ser_init(void)
  141. {
  142. return serio_register_driver(&tsc_drv);
  143. }
  144. module_init(tsc_ser_init);
  145. static void __exit tsc_exit(void)
  146. {
  147. serio_unregister_driver(&tsc_drv);
  148. }
  149. module_exit(tsc_exit);
  150. MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
  151. MODULE_DESCRIPTION(DRIVER_DESC);
  152. MODULE_LICENSE("GPL v2");