2 * Driver for simulating a mouse on GPIO lines.
4 * Copyright (C) 2007 Atmel Corporation
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/input-polldev.h>
14 #include <linux/gpio.h>
15 #include <linux/gpio_mouse.h>
19 * Timer function which is run every scan_ms ms when the device is opened.
20 * The dev input variable is set to the the input_dev pointer.
22 static void gpio_mouse_scan(struct input_polled_dev
*dev
)
24 struct gpio_mouse_platform_data
*gpio
= dev
->private;
25 struct input_dev
*input
= dev
->input
;
29 input_report_key(input
, BTN_LEFT
,
30 gpio_get_value(gpio
->bleft
) ^ gpio
->polarity
);
31 if (gpio
->bmiddle
>= 0)
32 input_report_key(input
, BTN_MIDDLE
,
33 gpio_get_value(gpio
->bmiddle
) ^ gpio
->polarity
);
34 if (gpio
->bright
>= 0)
35 input_report_key(input
, BTN_RIGHT
,
36 gpio_get_value(gpio
->bright
) ^ gpio
->polarity
);
38 x
= (gpio_get_value(gpio
->right
) ^ gpio
->polarity
)
39 - (gpio_get_value(gpio
->left
) ^ gpio
->polarity
);
40 y
= (gpio_get_value(gpio
->down
) ^ gpio
->polarity
)
41 - (gpio_get_value(gpio
->up
) ^ gpio
->polarity
);
43 input_report_rel(input
, REL_X
, x
);
44 input_report_rel(input
, REL_Y
, y
);
48 static int gpio_mouse_probe(struct platform_device
*pdev
)
50 struct gpio_mouse_platform_data
*pdata
= dev_get_platdata(&pdev
->dev
);
51 struct input_polled_dev
*input_poll
;
52 struct input_dev
*input
;
57 dev_err(&pdev
->dev
, "no platform data\n");
62 if (pdata
->scan_ms
< 0) {
63 dev_err(&pdev
->dev
, "invalid scan time\n");
68 for (i
= 0; i
< GPIO_MOUSE_PIN_MAX
; i
++) {
73 if (i
<= GPIO_MOUSE_PIN_RIGHT
) {
74 /* Mouse direction is required. */
76 "missing GPIO for directions\n");
81 if (i
== GPIO_MOUSE_PIN_BLEFT
)
82 dev_dbg(&pdev
->dev
, "no left button defined\n");
85 error
= gpio_request(pin
, "gpio_mouse");
87 dev_err(&pdev
->dev
, "fail %d pin (%d idx)\n",
92 gpio_direction_input(pin
);
96 input_poll
= input_allocate_polled_device();
98 dev_err(&pdev
->dev
, "not enough memory for input device\n");
103 platform_set_drvdata(pdev
, input_poll
);
105 /* set input-polldev handlers */
106 input_poll
->private = pdata
;
107 input_poll
->poll
= gpio_mouse_scan
;
108 input_poll
->poll_interval
= pdata
->scan_ms
;
110 input
= input_poll
->input
;
111 input
->name
= pdev
->name
;
112 input
->id
.bustype
= BUS_HOST
;
113 input
->dev
.parent
= &pdev
->dev
;
115 input_set_capability(input
, EV_REL
, REL_X
);
116 input_set_capability(input
, EV_REL
, REL_Y
);
117 if (pdata
->bleft
>= 0)
118 input_set_capability(input
, EV_KEY
, BTN_LEFT
);
119 if (pdata
->bmiddle
>= 0)
120 input_set_capability(input
, EV_KEY
, BTN_MIDDLE
);
121 if (pdata
->bright
>= 0)
122 input_set_capability(input
, EV_KEY
, BTN_RIGHT
);
124 error
= input_register_polled_device(input_poll
);
126 dev_err(&pdev
->dev
, "could not register input device\n");
127 goto out_free_polldev
;
130 dev_dbg(&pdev
->dev
, "%d ms scan time, buttons: %s%s%s\n",
132 pdata
->bleft
< 0 ? "" : "left ",
133 pdata
->bmiddle
< 0 ? "" : "middle ",
134 pdata
->bright
< 0 ? "" : "right");
139 input_free_polled_device(input_poll
);
143 pin
= pdata
->pins
[i
];
151 static int gpio_mouse_remove(struct platform_device
*pdev
)
153 struct input_polled_dev
*input
= platform_get_drvdata(pdev
);
154 struct gpio_mouse_platform_data
*pdata
= input
->private;
157 input_unregister_polled_device(input
);
158 input_free_polled_device(input
);
160 for (i
= 0; i
< GPIO_MOUSE_PIN_MAX
; i
++) {
161 pin
= pdata
->pins
[i
];
169 static struct platform_driver gpio_mouse_device_driver
= {
170 .probe
= gpio_mouse_probe
,
171 .remove
= gpio_mouse_remove
,
173 .name
= "gpio_mouse",
176 module_platform_driver(gpio_mouse_device_driver
);
178 MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
179 MODULE_DESCRIPTION("GPIO mouse driver");
180 MODULE_LICENSE("GPL");
181 MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */