gpio_mouse.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Driver for simulating a mouse on GPIO lines.
  3. *
  4. * Copyright (C) 2007 Atmel Corporation
  5. * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. */
  11. #include <linux/module.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/input-polldev.h>
  14. #include <linux/gpio/consumer.h>
  15. #include <linux/property.h>
  16. #include <linux/of.h>
  17. /**
  18. * struct gpio_mouse
  19. * @scan_ms: the scan interval in milliseconds.
  20. * @up: GPIO line for up value.
  21. * @down: GPIO line for down value.
  22. * @left: GPIO line for left value.
  23. * @right: GPIO line for right value.
  24. * @bleft: GPIO line for left button.
  25. * @bmiddle: GPIO line for middle button.
  26. * @bright: GPIO line for right button.
  27. *
  28. * This struct must be added to the platform_device in the board code.
  29. * It is used by the gpio_mouse driver to setup GPIO lines and to
  30. * calculate mouse movement.
  31. */
  32. struct gpio_mouse {
  33. u32 scan_ms;
  34. struct gpio_desc *up;
  35. struct gpio_desc *down;
  36. struct gpio_desc *left;
  37. struct gpio_desc *right;
  38. struct gpio_desc *bleft;
  39. struct gpio_desc *bmiddle;
  40. struct gpio_desc *bright;
  41. };
  42. /*
  43. * Timer function which is run every scan_ms ms when the device is opened.
  44. * The dev input variable is set to the the input_dev pointer.
  45. */
  46. static void gpio_mouse_scan(struct input_polled_dev *dev)
  47. {
  48. struct gpio_mouse *gpio = dev->private;
  49. struct input_dev *input = dev->input;
  50. int x, y;
  51. if (gpio->bleft)
  52. input_report_key(input, BTN_LEFT,
  53. gpiod_get_value(gpio->bleft));
  54. if (gpio->bmiddle)
  55. input_report_key(input, BTN_MIDDLE,
  56. gpiod_get_value(gpio->bmiddle));
  57. if (gpio->bright)
  58. input_report_key(input, BTN_RIGHT,
  59. gpiod_get_value(gpio->bright));
  60. x = gpiod_get_value(gpio->right) - gpiod_get_value(gpio->left);
  61. y = gpiod_get_value(gpio->down) - gpiod_get_value(gpio->up);
  62. input_report_rel(input, REL_X, x);
  63. input_report_rel(input, REL_Y, y);
  64. input_sync(input);
  65. }
  66. static int gpio_mouse_probe(struct platform_device *pdev)
  67. {
  68. struct device *dev = &pdev->dev;
  69. struct gpio_mouse *gmouse;
  70. struct input_polled_dev *input_poll;
  71. struct input_dev *input;
  72. int ret;
  73. gmouse = devm_kzalloc(dev, sizeof(*gmouse), GFP_KERNEL);
  74. if (!gmouse)
  75. return -ENOMEM;
  76. /* Assign some default scanning time */
  77. ret = device_property_read_u32(dev, "scan-interval-ms",
  78. &gmouse->scan_ms);
  79. if (ret || gmouse->scan_ms == 0) {
  80. dev_warn(dev, "invalid scan time, set to 50 ms\n");
  81. gmouse->scan_ms = 50;
  82. }
  83. gmouse->up = devm_gpiod_get(dev, "up", GPIOD_IN);
  84. if (IS_ERR(gmouse->up))
  85. return PTR_ERR(gmouse->up);
  86. gmouse->down = devm_gpiod_get(dev, "down", GPIOD_IN);
  87. if (IS_ERR(gmouse->down))
  88. return PTR_ERR(gmouse->down);
  89. gmouse->left = devm_gpiod_get(dev, "left", GPIOD_IN);
  90. if (IS_ERR(gmouse->left))
  91. return PTR_ERR(gmouse->left);
  92. gmouse->right = devm_gpiod_get(dev, "right", GPIOD_IN);
  93. if (IS_ERR(gmouse->right))
  94. return PTR_ERR(gmouse->right);
  95. gmouse->bleft = devm_gpiod_get_optional(dev, "button-left", GPIOD_IN);
  96. if (IS_ERR(gmouse->bleft))
  97. return PTR_ERR(gmouse->bleft);
  98. gmouse->bmiddle = devm_gpiod_get_optional(dev, "button-middle",
  99. GPIOD_IN);
  100. if (IS_ERR(gmouse->bmiddle))
  101. return PTR_ERR(gmouse->bmiddle);
  102. gmouse->bright = devm_gpiod_get_optional(dev, "button-right",
  103. GPIOD_IN);
  104. if (IS_ERR(gmouse->bright))
  105. return PTR_ERR(gmouse->bright);
  106. input_poll = devm_input_allocate_polled_device(dev);
  107. if (!input_poll) {
  108. dev_err(dev, "not enough memory for input device\n");
  109. return -ENOMEM;
  110. }
  111. platform_set_drvdata(pdev, input_poll);
  112. /* set input-polldev handlers */
  113. input_poll->private = gmouse;
  114. input_poll->poll = gpio_mouse_scan;
  115. input_poll->poll_interval = gmouse->scan_ms;
  116. input = input_poll->input;
  117. input->name = pdev->name;
  118. input->id.bustype = BUS_HOST;
  119. input->dev.parent = &pdev->dev;
  120. input_set_capability(input, EV_REL, REL_X);
  121. input_set_capability(input, EV_REL, REL_Y);
  122. if (gmouse->bleft)
  123. input_set_capability(input, EV_KEY, BTN_LEFT);
  124. if (gmouse->bmiddle)
  125. input_set_capability(input, EV_KEY, BTN_MIDDLE);
  126. if (gmouse->bright)
  127. input_set_capability(input, EV_KEY, BTN_RIGHT);
  128. ret = input_register_polled_device(input_poll);
  129. if (ret) {
  130. dev_err(dev, "could not register input device\n");
  131. return ret;
  132. }
  133. dev_dbg(dev, "%d ms scan time, buttons: %s%s%s\n",
  134. gmouse->scan_ms,
  135. gmouse->bleft ? "" : "left ",
  136. gmouse->bmiddle ? "" : "middle ",
  137. gmouse->bright ? "" : "right");
  138. return 0;
  139. }
  140. static const struct of_device_id gpio_mouse_of_match[] = {
  141. { .compatible = "gpio-mouse", },
  142. { },
  143. };
  144. MODULE_DEVICE_TABLE(of, gpio_mouse_of_match);
  145. static struct platform_driver gpio_mouse_device_driver = {
  146. .probe = gpio_mouse_probe,
  147. .driver = {
  148. .name = "gpio_mouse",
  149. .of_match_table = gpio_mouse_of_match,
  150. }
  151. };
  152. module_platform_driver(gpio_mouse_device_driver);
  153. MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
  154. MODULE_DESCRIPTION("GPIO mouse driver");
  155. MODULE_LICENSE("GPL");
  156. MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */