1 // SPDX-License-Identifier: GPL-2.0-only
3 * Driver for simulating a mouse on GPIO lines.
5 * Copyright (C) 2007 Atmel Corporation
6 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
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>
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.
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.
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
;
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.
46 static void gpio_mouse_scan(struct input_dev
*input
)
48 struct gpio_mouse
*gpio
= input_get_drvdata(input
);
52 input_report_key(input
, BTN_LEFT
,
53 gpiod_get_value(gpio
->bleft
));
55 input_report_key(input
, BTN_MIDDLE
,
56 gpiod_get_value(gpio
->bmiddle
));
58 input_report_key(input
, BTN_RIGHT
,
59 gpiod_get_value(gpio
->bright
));
61 x
= gpiod_get_value(gpio
->right
) - gpiod_get_value(gpio
->left
);
62 y
= gpiod_get_value(gpio
->down
) - gpiod_get_value(gpio
->up
);
64 input_report_rel(input
, REL_X
, x
);
65 input_report_rel(input
, REL_Y
, y
);
69 static int gpio_mouse_probe(struct platform_device
*pdev
)
71 struct device
*dev
= &pdev
->dev
;
72 struct gpio_mouse
*gmouse
;
73 struct input_dev
*input
;
76 gmouse
= devm_kzalloc(dev
, sizeof(*gmouse
), GFP_KERNEL
);
80 /* Assign some default scanning time */
81 error
= device_property_read_u32(dev
, "scan-interval-ms",
83 if (error
|| gmouse
->scan_ms
== 0) {
84 dev_warn(dev
, "invalid scan time, set to 50 ms\n");
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
);
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",
106 if (IS_ERR(gmouse
->bmiddle
))
107 return PTR_ERR(gmouse
->bmiddle
);
108 gmouse
->bright
= devm_gpiod_get_optional(dev
, "button-right",
110 if (IS_ERR(gmouse
->bright
))
111 return PTR_ERR(gmouse
->bright
);
113 input
= devm_input_allocate_device(dev
);
117 input
->name
= pdev
->name
;
118 input
->id
.bustype
= BUS_HOST
;
120 input_set_drvdata(input
, gmouse
);
122 input_set_capability(input
, EV_REL
, REL_X
);
123 input_set_capability(input
, EV_REL
, REL_Y
);
125 input_set_capability(input
, EV_KEY
, BTN_LEFT
);
127 input_set_capability(input
, EV_KEY
, BTN_MIDDLE
);
129 input_set_capability(input
, EV_KEY
, BTN_RIGHT
);
131 error
= input_setup_polling(input
, gpio_mouse_scan
);
135 input_set_poll_interval(input
, gmouse
->scan_ms
);
137 error
= input_register_device(input
);
139 dev_err(dev
, "could not register input device\n");
143 dev_dbg(dev
, "%d ms scan time, buttons: %s%s%s\n",
145 gmouse
->bleft
? "" : "left ",
146 gmouse
->bmiddle
? "" : "middle ",
147 gmouse
->bright
? "" : "right");
152 static const struct of_device_id gpio_mouse_of_match
[] = {
153 { .compatible
= "gpio-mouse", },
156 MODULE_DEVICE_TABLE(of
, gpio_mouse_of_match
);
158 static struct platform_driver gpio_mouse_device_driver
= {
159 .probe
= gpio_mouse_probe
,
161 .name
= "gpio_mouse",
162 .of_match_table
= gpio_mouse_of_match
,
165 module_platform_driver(gpio_mouse_device_driver
);
167 MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
168 MODULE_DESCRIPTION("GPIO mouse driver");
169 MODULE_LICENSE("GPL");
170 MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */