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