xref: /linux/drivers/input/mouse/gpio_mouse.c (revision 5f5655023f2814969b744c1e07494666587243aa)
1*5f565502SHans-Christian Egtvedt /*
2*5f565502SHans-Christian Egtvedt  * Driver for simulating a mouse on GPIO lines.
3*5f565502SHans-Christian Egtvedt  *
4*5f565502SHans-Christian Egtvedt  * Copyright (C) 2007 Atmel Corporation
5*5f565502SHans-Christian Egtvedt  *
6*5f565502SHans-Christian Egtvedt  * This program is free software; you can redistribute it and/or modify
7*5f565502SHans-Christian Egtvedt  * it under the terms of the GNU General Public License version 2 as
8*5f565502SHans-Christian Egtvedt  * published by the Free Software Foundation.
9*5f565502SHans-Christian Egtvedt  */
10*5f565502SHans-Christian Egtvedt 
11*5f565502SHans-Christian Egtvedt #include <linux/init.h>
12*5f565502SHans-Christian Egtvedt #include <linux/version.h>
13*5f565502SHans-Christian Egtvedt #include <linux/module.h>
14*5f565502SHans-Christian Egtvedt #include <linux/platform_device.h>
15*5f565502SHans-Christian Egtvedt #include <linux/input-polldev.h>
16*5f565502SHans-Christian Egtvedt #include <linux/gpio_mouse.h>
17*5f565502SHans-Christian Egtvedt 
18*5f565502SHans-Christian Egtvedt #include <asm/gpio.h>
19*5f565502SHans-Christian Egtvedt 
20*5f565502SHans-Christian Egtvedt /*
21*5f565502SHans-Christian Egtvedt  * Timer function which is run every scan_ms ms when the device is opened.
22*5f565502SHans-Christian Egtvedt  * The dev input varaible is set to the the input_dev pointer.
23*5f565502SHans-Christian Egtvedt  */
24*5f565502SHans-Christian Egtvedt static void gpio_mouse_scan(struct input_polled_dev *dev)
25*5f565502SHans-Christian Egtvedt {
26*5f565502SHans-Christian Egtvedt 	struct gpio_mouse_platform_data *gpio = dev->private;
27*5f565502SHans-Christian Egtvedt 	struct input_dev *input = dev->input;
28*5f565502SHans-Christian Egtvedt 	int x, y;
29*5f565502SHans-Christian Egtvedt 
30*5f565502SHans-Christian Egtvedt 	if (gpio->bleft >= 0)
31*5f565502SHans-Christian Egtvedt 		input_report_key(input, BTN_LEFT,
32*5f565502SHans-Christian Egtvedt 				gpio_get_value(gpio->bleft) ^ gpio->polarity);
33*5f565502SHans-Christian Egtvedt 	if (gpio->bmiddle >= 0)
34*5f565502SHans-Christian Egtvedt 		input_report_key(input, BTN_MIDDLE,
35*5f565502SHans-Christian Egtvedt 				gpio_get_value(gpio->bmiddle) ^ gpio->polarity);
36*5f565502SHans-Christian Egtvedt 	if (gpio->bright >= 0)
37*5f565502SHans-Christian Egtvedt 		input_report_key(input, BTN_RIGHT,
38*5f565502SHans-Christian Egtvedt 				gpio_get_value(gpio->bright) ^ gpio->polarity);
39*5f565502SHans-Christian Egtvedt 
40*5f565502SHans-Christian Egtvedt 	x = (gpio_get_value(gpio->right) ^ gpio->polarity)
41*5f565502SHans-Christian Egtvedt 		- (gpio_get_value(gpio->left) ^ gpio->polarity);
42*5f565502SHans-Christian Egtvedt 	y = (gpio_get_value(gpio->down) ^ gpio->polarity)
43*5f565502SHans-Christian Egtvedt 		- (gpio_get_value(gpio->up) ^ gpio->polarity);
44*5f565502SHans-Christian Egtvedt 
45*5f565502SHans-Christian Egtvedt 	input_report_rel(input, REL_X, x);
46*5f565502SHans-Christian Egtvedt 	input_report_rel(input, REL_Y, y);
47*5f565502SHans-Christian Egtvedt 	input_sync(input);
48*5f565502SHans-Christian Egtvedt }
49*5f565502SHans-Christian Egtvedt 
50*5f565502SHans-Christian Egtvedt static int __init gpio_mouse_probe(struct platform_device *pdev)
51*5f565502SHans-Christian Egtvedt {
52*5f565502SHans-Christian Egtvedt 	struct gpio_mouse_platform_data *pdata = pdev->dev.platform_data;
53*5f565502SHans-Christian Egtvedt 	struct input_polled_dev *input_poll;
54*5f565502SHans-Christian Egtvedt 	struct input_dev *input;
55*5f565502SHans-Christian Egtvedt 	int pin, i;
56*5f565502SHans-Christian Egtvedt 	int error;
57*5f565502SHans-Christian Egtvedt 
58*5f565502SHans-Christian Egtvedt 	if (!pdata) {
59*5f565502SHans-Christian Egtvedt 		dev_err(&pdev->dev, "no platform data\n");
60*5f565502SHans-Christian Egtvedt 		error = -ENXIO;
61*5f565502SHans-Christian Egtvedt 		goto out;
62*5f565502SHans-Christian Egtvedt 	}
63*5f565502SHans-Christian Egtvedt 
64*5f565502SHans-Christian Egtvedt 	if (pdata->scan_ms < 0) {
65*5f565502SHans-Christian Egtvedt 		dev_err(&pdev->dev, "invalid scan time\n");
66*5f565502SHans-Christian Egtvedt 		error = -EINVAL;
67*5f565502SHans-Christian Egtvedt 		goto out;
68*5f565502SHans-Christian Egtvedt 	}
69*5f565502SHans-Christian Egtvedt 
70*5f565502SHans-Christian Egtvedt 	for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) {
71*5f565502SHans-Christian Egtvedt 		pin = pdata->pins[i];
72*5f565502SHans-Christian Egtvedt 
73*5f565502SHans-Christian Egtvedt 		if (pin < 0) {
74*5f565502SHans-Christian Egtvedt 
75*5f565502SHans-Christian Egtvedt 			if (i <= GPIO_MOUSE_PIN_RIGHT) {
76*5f565502SHans-Christian Egtvedt 				/* Mouse direction is required. */
77*5f565502SHans-Christian Egtvedt 				dev_err(&pdev->dev,
78*5f565502SHans-Christian Egtvedt 					"missing GPIO for directions\n");
79*5f565502SHans-Christian Egtvedt 				error = -EINVAL;
80*5f565502SHans-Christian Egtvedt 				goto out_free_gpios;
81*5f565502SHans-Christian Egtvedt 			}
82*5f565502SHans-Christian Egtvedt 
83*5f565502SHans-Christian Egtvedt 			if (i == GPIO_MOUSE_PIN_BLEFT)
84*5f565502SHans-Christian Egtvedt 				dev_dbg(&pdev->dev, "no left button defined\n");
85*5f565502SHans-Christian Egtvedt 
86*5f565502SHans-Christian Egtvedt 		} else {
87*5f565502SHans-Christian Egtvedt 			error = gpio_request(pin, "gpio_mouse");
88*5f565502SHans-Christian Egtvedt 			if (error) {
89*5f565502SHans-Christian Egtvedt 				dev_err(&pdev->dev, "fail %d pin (%d idx)\n",
90*5f565502SHans-Christian Egtvedt 					pin, i);
91*5f565502SHans-Christian Egtvedt 				goto out_free_gpios;
92*5f565502SHans-Christian Egtvedt 			}
93*5f565502SHans-Christian Egtvedt 
94*5f565502SHans-Christian Egtvedt 			gpio_direction_input(pin);
95*5f565502SHans-Christian Egtvedt 		}
96*5f565502SHans-Christian Egtvedt 	}
97*5f565502SHans-Christian Egtvedt 
98*5f565502SHans-Christian Egtvedt 	input_poll = input_allocate_polled_device();
99*5f565502SHans-Christian Egtvedt 	if (!input_poll) {
100*5f565502SHans-Christian Egtvedt 		dev_err(&pdev->dev, "not enough memory for input device\n");
101*5f565502SHans-Christian Egtvedt 		error = -ENOMEM;
102*5f565502SHans-Christian Egtvedt 		goto out_free_gpios;
103*5f565502SHans-Christian Egtvedt 	}
104*5f565502SHans-Christian Egtvedt 
105*5f565502SHans-Christian Egtvedt 	platform_set_drvdata(pdev, input_poll);
106*5f565502SHans-Christian Egtvedt 
107*5f565502SHans-Christian Egtvedt 	/* set input-polldev handlers */
108*5f565502SHans-Christian Egtvedt 	input_poll->private = pdata;
109*5f565502SHans-Christian Egtvedt 	input_poll->poll = gpio_mouse_scan;
110*5f565502SHans-Christian Egtvedt 	input_poll->poll_interval = pdata->scan_ms;
111*5f565502SHans-Christian Egtvedt 
112*5f565502SHans-Christian Egtvedt 	input = input_poll->input;
113*5f565502SHans-Christian Egtvedt 	input->name = pdev->name;
114*5f565502SHans-Christian Egtvedt 	input->id.bustype = BUS_HOST;
115*5f565502SHans-Christian Egtvedt 	input->dev.parent = &pdev->dev;
116*5f565502SHans-Christian Egtvedt 
117*5f565502SHans-Christian Egtvedt 	input_set_capability(input, EV_REL, REL_X);
118*5f565502SHans-Christian Egtvedt 	input_set_capability(input, EV_REL, REL_Y);
119*5f565502SHans-Christian Egtvedt 	if (pdata->bleft >= 0)
120*5f565502SHans-Christian Egtvedt 		input_set_capability(input, EV_KEY, BTN_LEFT);
121*5f565502SHans-Christian Egtvedt 	if (pdata->bmiddle >= 0)
122*5f565502SHans-Christian Egtvedt 		input_set_capability(input, EV_KEY, BTN_MIDDLE);
123*5f565502SHans-Christian Egtvedt 	if (pdata->bright >= 0)
124*5f565502SHans-Christian Egtvedt 		input_set_capability(input, EV_KEY, BTN_RIGHT);
125*5f565502SHans-Christian Egtvedt 
126*5f565502SHans-Christian Egtvedt 	error = input_register_polled_device(input_poll);
127*5f565502SHans-Christian Egtvedt 	if (error) {
128*5f565502SHans-Christian Egtvedt 		dev_err(&pdev->dev, "could not register input device\n");
129*5f565502SHans-Christian Egtvedt 		goto out_free_polldev;
130*5f565502SHans-Christian Egtvedt 	}
131*5f565502SHans-Christian Egtvedt 
132*5f565502SHans-Christian Egtvedt 	dev_dbg(&pdev->dev, "%d ms scan time, buttons: %s%s%s\n",
133*5f565502SHans-Christian Egtvedt 			pdata->scan_ms,
134*5f565502SHans-Christian Egtvedt 			pdata->bleft < 0 ? "" : "left ",
135*5f565502SHans-Christian Egtvedt 			pdata->bmiddle < 0 ? "" : "middle ",
136*5f565502SHans-Christian Egtvedt 			pdata->bright < 0 ? "" : "right");
137*5f565502SHans-Christian Egtvedt 
138*5f565502SHans-Christian Egtvedt 	return 0;
139*5f565502SHans-Christian Egtvedt 
140*5f565502SHans-Christian Egtvedt  out_free_polldev:
141*5f565502SHans-Christian Egtvedt 	input_free_polled_device(input_poll);
142*5f565502SHans-Christian Egtvedt 	platform_set_drvdata(pdev, NULL);
143*5f565502SHans-Christian Egtvedt 
144*5f565502SHans-Christian Egtvedt  out_free_gpios:
145*5f565502SHans-Christian Egtvedt 	while (--i >= 0) {
146*5f565502SHans-Christian Egtvedt 		pin = pdata->pins[i];
147*5f565502SHans-Christian Egtvedt 		if (pin)
148*5f565502SHans-Christian Egtvedt 			gpio_free(pin);
149*5f565502SHans-Christian Egtvedt 	}
150*5f565502SHans-Christian Egtvedt  out:
151*5f565502SHans-Christian Egtvedt 	return error;
152*5f565502SHans-Christian Egtvedt }
153*5f565502SHans-Christian Egtvedt 
154*5f565502SHans-Christian Egtvedt static int __devexit gpio_mouse_remove(struct platform_device *pdev)
155*5f565502SHans-Christian Egtvedt {
156*5f565502SHans-Christian Egtvedt 	struct input_polled_dev *input = platform_get_drvdata(pdev);
157*5f565502SHans-Christian Egtvedt 	struct gpio_mouse_platform_data *pdata = input->private;
158*5f565502SHans-Christian Egtvedt 	int pin, i;
159*5f565502SHans-Christian Egtvedt 
160*5f565502SHans-Christian Egtvedt 	input_unregister_polled_device(input);
161*5f565502SHans-Christian Egtvedt 	input_free_polled_device(input);
162*5f565502SHans-Christian Egtvedt 
163*5f565502SHans-Christian Egtvedt 	for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) {
164*5f565502SHans-Christian Egtvedt 		pin = pdata->pins[i];
165*5f565502SHans-Christian Egtvedt 		if (pin >= 0)
166*5f565502SHans-Christian Egtvedt 			gpio_free(pin);
167*5f565502SHans-Christian Egtvedt 	}
168*5f565502SHans-Christian Egtvedt 
169*5f565502SHans-Christian Egtvedt 	platform_set_drvdata(pdev, NULL);
170*5f565502SHans-Christian Egtvedt 
171*5f565502SHans-Christian Egtvedt 	return 0;
172*5f565502SHans-Christian Egtvedt }
173*5f565502SHans-Christian Egtvedt 
174*5f565502SHans-Christian Egtvedt struct platform_driver gpio_mouse_device_driver = {
175*5f565502SHans-Christian Egtvedt 	.remove		= __devexit_p(gpio_mouse_remove),
176*5f565502SHans-Christian Egtvedt 	.driver		= {
177*5f565502SHans-Christian Egtvedt 		.name	= "gpio_mouse",
178*5f565502SHans-Christian Egtvedt 	}
179*5f565502SHans-Christian Egtvedt };
180*5f565502SHans-Christian Egtvedt 
181*5f565502SHans-Christian Egtvedt static int __init gpio_mouse_init(void)
182*5f565502SHans-Christian Egtvedt {
183*5f565502SHans-Christian Egtvedt 	return platform_driver_probe(&gpio_mouse_device_driver,
184*5f565502SHans-Christian Egtvedt 			gpio_mouse_probe);
185*5f565502SHans-Christian Egtvedt }
186*5f565502SHans-Christian Egtvedt module_init(gpio_mouse_init);
187*5f565502SHans-Christian Egtvedt 
188*5f565502SHans-Christian Egtvedt static void __exit gpio_mouse_exit(void)
189*5f565502SHans-Christian Egtvedt {
190*5f565502SHans-Christian Egtvedt 	platform_driver_unregister(&gpio_mouse_device_driver);
191*5f565502SHans-Christian Egtvedt }
192*5f565502SHans-Christian Egtvedt module_exit(gpio_mouse_exit);
193*5f565502SHans-Christian Egtvedt 
194*5f565502SHans-Christian Egtvedt MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
195*5f565502SHans-Christian Egtvedt MODULE_DESCRIPTION("GPIO mouse driver");
196*5f565502SHans-Christian Egtvedt MODULE_LICENSE("GPL");
197