2 * Driver for simulating a mouse on GPIO lines.
4 * Copyright (C) 2007 Atmel Corporation
5 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
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.
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>
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.
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.
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
;
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.
49 static void gpio_mouse_scan(struct input_polled_dev
*dev
)
51 struct gpio_mouse
*gpio
= dev
->private;
52 struct input_dev
*input
= dev
->input
;
56 input_report_key(input
, BTN_LEFT
,
57 gpiod_get_value(gpio
->bleft
));
59 input_report_key(input
, BTN_MIDDLE
,
60 gpiod_get_value(gpio
->bmiddle
));
62 input_report_key(input
, BTN_RIGHT
,
63 gpiod_get_value(gpio
->bright
));
65 x
= gpiod_get_value(gpio
->right
) - gpiod_get_value(gpio
->left
);
66 y
= gpiod_get_value(gpio
->down
) - gpiod_get_value(gpio
->up
);
68 input_report_rel(input
, REL_X
, x
);
69 input_report_rel(input
, REL_Y
, y
);
73 static int gpio_mouse_probe(struct platform_device
*pdev
)
75 struct device
*dev
= &pdev
->dev
;
76 struct gpio_mouse
*gmouse
;
77 struct input_polled_dev
*input_poll
;
78 struct input_dev
*input
;
81 gmouse
= devm_kzalloc(dev
, sizeof(*gmouse
), GFP_KERNEL
);
85 /* Assign some default scanning time */
86 ret
= device_property_read_u32(dev
, "scan-interval-ms",
88 if (ret
|| gmouse
->scan_ms
== 0) {
89 dev_warn(dev
, "invalid scan time, set to 50 ms\n");
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
);
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",
111 if (IS_ERR(gmouse
->bmiddle
))
112 return PTR_ERR(gmouse
->bmiddle
);
113 gmouse
->bright
= devm_gpiod_get_optional(dev
, "button-right",
115 if (IS_ERR(gmouse
->bright
))
116 return PTR_ERR(gmouse
->bright
);
118 input_poll
= devm_input_allocate_polled_device(dev
);
120 dev_err(dev
, "not enough memory for input device\n");
124 platform_set_drvdata(pdev
, input_poll
);
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
;
131 input
= input_poll
->input
;
132 input
->name
= pdev
->name
;
133 input
->id
.bustype
= BUS_HOST
;
134 input
->dev
.parent
= &pdev
->dev
;
136 input_set_capability(input
, EV_REL
, REL_X
);
137 input_set_capability(input
, EV_REL
, REL_Y
);
139 input_set_capability(input
, EV_KEY
, BTN_LEFT
);
141 input_set_capability(input
, EV_KEY
, BTN_MIDDLE
);
143 input_set_capability(input
, EV_KEY
, BTN_RIGHT
);
145 ret
= input_register_polled_device(input_poll
);
147 dev_err(dev
, "could not register input device\n");
151 dev_dbg(dev
, "%d ms scan time, buttons: %s%s%s\n",
153 gmouse
->bleft
? "" : "left ",
154 gmouse
->bmiddle
? "" : "middle ",
155 gmouse
->bright
? "" : "right");
160 static const struct of_device_id gpio_mouse_of_match
[] = {
161 { .compatible
= "gpio-mouse", },
164 MODULE_DEVICE_TABLE(of
, gpio_mouse_of_match
);
166 static struct platform_driver gpio_mouse_device_driver
= {
167 .probe
= gpio_mouse_probe
,
169 .name
= "gpio_mouse",
170 .of_match_table
= gpio_mouse_of_match
,
173 module_platform_driver(gpio_mouse_device_driver
);
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 */