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-polldev.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 */ 31 struct 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 */ 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 52 if (gpio->bleft) 53 input_report_key(input, BTN_LEFT, 54 gpiod_get_value(gpio->bleft)); 55 if (gpio->bmiddle) 56 input_report_key(input, BTN_MIDDLE, 57 gpiod_get_value(gpio->bmiddle)); 58 if (gpio->bright) 59 input_report_key(input, BTN_RIGHT, 60 gpiod_get_value(gpio->bright)); 61 62 x = gpiod_get_value(gpio->right) - gpiod_get_value(gpio->left); 63 y = gpiod_get_value(gpio->down) - gpiod_get_value(gpio->up); 64 65 input_report_rel(input, REL_X, x); 66 input_report_rel(input, REL_Y, y); 67 input_sync(input); 68 } 69 70 static int gpio_mouse_probe(struct platform_device *pdev) 71 { 72 struct device *dev = &pdev->dev; 73 struct gpio_mouse *gmouse; 74 struct input_polled_dev *input_poll; 75 struct input_dev *input; 76 int ret; 77 78 gmouse = devm_kzalloc(dev, sizeof(*gmouse), GFP_KERNEL); 79 if (!gmouse) 80 return -ENOMEM; 81 82 /* Assign some default scanning time */ 83 ret = device_property_read_u32(dev, "scan-interval-ms", 84 &gmouse->scan_ms); 85 if (ret || gmouse->scan_ms == 0) { 86 dev_warn(dev, "invalid scan time, set to 50 ms\n"); 87 gmouse->scan_ms = 50; 88 } 89 90 gmouse->up = devm_gpiod_get(dev, "up", GPIOD_IN); 91 if (IS_ERR(gmouse->up)) 92 return PTR_ERR(gmouse->up); 93 gmouse->down = devm_gpiod_get(dev, "down", GPIOD_IN); 94 if (IS_ERR(gmouse->down)) 95 return PTR_ERR(gmouse->down); 96 gmouse->left = devm_gpiod_get(dev, "left", GPIOD_IN); 97 if (IS_ERR(gmouse->left)) 98 return PTR_ERR(gmouse->left); 99 gmouse->right = devm_gpiod_get(dev, "right", GPIOD_IN); 100 if (IS_ERR(gmouse->right)) 101 return PTR_ERR(gmouse->right); 102 103 gmouse->bleft = devm_gpiod_get_optional(dev, "button-left", GPIOD_IN); 104 if (IS_ERR(gmouse->bleft)) 105 return PTR_ERR(gmouse->bleft); 106 gmouse->bmiddle = devm_gpiod_get_optional(dev, "button-middle", 107 GPIOD_IN); 108 if (IS_ERR(gmouse->bmiddle)) 109 return PTR_ERR(gmouse->bmiddle); 110 gmouse->bright = devm_gpiod_get_optional(dev, "button-right", 111 GPIOD_IN); 112 if (IS_ERR(gmouse->bright)) 113 return PTR_ERR(gmouse->bright); 114 115 input_poll = devm_input_allocate_polled_device(dev); 116 if (!input_poll) { 117 dev_err(dev, "not enough memory for input device\n"); 118 return -ENOMEM; 119 } 120 121 platform_set_drvdata(pdev, input_poll); 122 123 /* set input-polldev handlers */ 124 input_poll->private = gmouse; 125 input_poll->poll = gpio_mouse_scan; 126 input_poll->poll_interval = gmouse->scan_ms; 127 128 input = input_poll->input; 129 input->name = pdev->name; 130 input->id.bustype = BUS_HOST; 131 input->dev.parent = &pdev->dev; 132 133 input_set_capability(input, EV_REL, REL_X); 134 input_set_capability(input, EV_REL, REL_Y); 135 if (gmouse->bleft) 136 input_set_capability(input, EV_KEY, BTN_LEFT); 137 if (gmouse->bmiddle) 138 input_set_capability(input, EV_KEY, BTN_MIDDLE); 139 if (gmouse->bright) 140 input_set_capability(input, EV_KEY, BTN_RIGHT); 141 142 ret = input_register_polled_device(input_poll); 143 if (ret) { 144 dev_err(dev, "could not register input device\n"); 145 return ret; 146 } 147 148 dev_dbg(dev, "%d ms scan time, buttons: %s%s%s\n", 149 gmouse->scan_ms, 150 gmouse->bleft ? "" : "left ", 151 gmouse->bmiddle ? "" : "middle ", 152 gmouse->bright ? "" : "right"); 153 154 return 0; 155 } 156 157 static const struct of_device_id gpio_mouse_of_match[] = { 158 { .compatible = "gpio-mouse", }, 159 { }, 160 }; 161 MODULE_DEVICE_TABLE(of, gpio_mouse_of_match); 162 163 static struct platform_driver gpio_mouse_device_driver = { 164 .probe = gpio_mouse_probe, 165 .driver = { 166 .name = "gpio_mouse", 167 .of_match_table = gpio_mouse_of_match, 168 } 169 }; 170 module_platform_driver(gpio_mouse_device_driver); 171 172 MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>"); 173 MODULE_DESCRIPTION("GPIO mouse driver"); 174 MODULE_LICENSE("GPL"); 175 MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */ 176