gpio_mouse.c (4740B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Driver for simulating a mouse on GPIO lines. 4 * 5 * Copyright (C) 2007 Atmel Corporation 6 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> 7 */ 8 9#include <linux/module.h> 10#include <linux/platform_device.h> 11#include <linux/input.h> 12#include <linux/gpio/consumer.h> 13#include <linux/property.h> 14#include <linux/of.h> 15 16/** 17 * struct gpio_mouse 18 * @scan_ms: the scan interval in milliseconds. 19 * @up: GPIO line for up value. 20 * @down: GPIO line for down value. 21 * @left: GPIO line for left value. 22 * @right: GPIO line for right value. 23 * @bleft: GPIO line for left button. 24 * @bmiddle: GPIO line for middle button. 25 * @bright: GPIO line for right button. 26 * 27 * This struct must be added to the platform_device in the board code. 28 * It is used by the gpio_mouse driver to setup GPIO lines and to 29 * calculate mouse movement. 30 */ 31struct gpio_mouse { 32 u32 scan_ms; 33 struct gpio_desc *up; 34 struct gpio_desc *down; 35 struct gpio_desc *left; 36 struct gpio_desc *right; 37 struct gpio_desc *bleft; 38 struct gpio_desc *bmiddle; 39 struct gpio_desc *bright; 40}; 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 */ 46static void gpio_mouse_scan(struct input_dev *input) 47{ 48 struct gpio_mouse *gpio = input_get_drvdata(input); 49 int x, y; 50 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 61 x = gpiod_get_value(gpio->right) - gpiod_get_value(gpio->left); 62 y = gpiod_get_value(gpio->down) - gpiod_get_value(gpio->up); 63 64 input_report_rel(input, REL_X, x); 65 input_report_rel(input, REL_Y, y); 66 input_sync(input); 67} 68 69static int gpio_mouse_probe(struct platform_device *pdev) 70{ 71 struct device *dev = &pdev->dev; 72 struct gpio_mouse *gmouse; 73 struct input_dev *input; 74 int error; 75 76 gmouse = devm_kzalloc(dev, sizeof(*gmouse), GFP_KERNEL); 77 if (!gmouse) 78 return -ENOMEM; 79 80 /* Assign some default scanning time */ 81 error = device_property_read_u32(dev, "scan-interval-ms", 82 &gmouse->scan_ms); 83 if (error || gmouse->scan_ms == 0) { 84 dev_warn(dev, "invalid scan time, set to 50 ms\n"); 85 gmouse->scan_ms = 50; 86 } 87 88 gmouse->up = devm_gpiod_get(dev, "up", GPIOD_IN); 89 if (IS_ERR(gmouse->up)) 90 return PTR_ERR(gmouse->up); 91 gmouse->down = devm_gpiod_get(dev, "down", GPIOD_IN); 92 if (IS_ERR(gmouse->down)) 93 return PTR_ERR(gmouse->down); 94 gmouse->left = devm_gpiod_get(dev, "left", GPIOD_IN); 95 if (IS_ERR(gmouse->left)) 96 return PTR_ERR(gmouse->left); 97 gmouse->right = devm_gpiod_get(dev, "right", GPIOD_IN); 98 if (IS_ERR(gmouse->right)) 99 return PTR_ERR(gmouse->right); 100 101 gmouse->bleft = devm_gpiod_get_optional(dev, "button-left", GPIOD_IN); 102 if (IS_ERR(gmouse->bleft)) 103 return PTR_ERR(gmouse->bleft); 104 gmouse->bmiddle = devm_gpiod_get_optional(dev, "button-middle", 105 GPIOD_IN); 106 if (IS_ERR(gmouse->bmiddle)) 107 return PTR_ERR(gmouse->bmiddle); 108 gmouse->bright = devm_gpiod_get_optional(dev, "button-right", 109 GPIOD_IN); 110 if (IS_ERR(gmouse->bright)) 111 return PTR_ERR(gmouse->bright); 112 113 input = devm_input_allocate_device(dev); 114 if (!input) 115 return -ENOMEM; 116 117 input->name = pdev->name; 118 input->id.bustype = BUS_HOST; 119 120 input_set_drvdata(input, gmouse); 121 122 input_set_capability(input, EV_REL, REL_X); 123 input_set_capability(input, EV_REL, REL_Y); 124 if (gmouse->bleft) 125 input_set_capability(input, EV_KEY, BTN_LEFT); 126 if (gmouse->bmiddle) 127 input_set_capability(input, EV_KEY, BTN_MIDDLE); 128 if (gmouse->bright) 129 input_set_capability(input, EV_KEY, BTN_RIGHT); 130 131 error = input_setup_polling(input, gpio_mouse_scan); 132 if (error) 133 return error; 134 135 input_set_poll_interval(input, gmouse->scan_ms); 136 137 error = input_register_device(input); 138 if (error) { 139 dev_err(dev, "could not register input device\n"); 140 return error; 141 } 142 143 dev_dbg(dev, "%d ms scan time, buttons: %s%s%s\n", 144 gmouse->scan_ms, 145 gmouse->bleft ? "" : "left ", 146 gmouse->bmiddle ? "" : "middle ", 147 gmouse->bright ? "" : "right"); 148 149 return 0; 150} 151 152static const struct of_device_id gpio_mouse_of_match[] = { 153 { .compatible = "gpio-mouse", }, 154 { }, 155}; 156MODULE_DEVICE_TABLE(of, gpio_mouse_of_match); 157 158static struct platform_driver gpio_mouse_device_driver = { 159 .probe = gpio_mouse_probe, 160 .driver = { 161 .name = "gpio_mouse", 162 .of_match_table = gpio_mouse_of_match, 163 } 164}; 165module_platform_driver(gpio_mouse_device_driver); 166 167MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>"); 168MODULE_DESCRIPTION("GPIO mouse driver"); 169MODULE_LICENSE("GPL"); 170MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */