78ecb21c75c2e59587d9300e30c06a541eaad5a0
[pandora-kernel.git] / drivers / input / misc / vsense.c
1 /*
2         vsense.c
3
4         Written by GraÅžvydas Ignotas <notasas@gmail.com>
5
6         This program is free software; you can redistribute it and/or modify
7         it under the terms of the GNU General Public License as published by
8         the Free Software Foundation; version 2 of the License.
9 */
10
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/i2c.h>
15 #include <linux/input.h>
16 #include <linux/interrupt.h>
17 #include <linux/timer.h>
18 #include <linux/i2c/vsense.h>
19 #include <asm/gpio.h>
20
21 /* hack for Pandora: keep track of usage to prevent reset
22  * while other nub is in use
23  */
24 static int reference_count;
25
26 struct vsense_drvdata {
27         struct input_dev *input;
28         struct i2c_client *client;
29         struct delayed_work work;
30         int reset_gpio;
31         int irq_gpio;
32 };
33
34 static void vsense_work(struct work_struct *work)
35 {
36         struct vsense_drvdata *ddata;
37         signed char buff[8];
38         int ret, x = 0, y = 0;
39
40         ddata = container_of(work, struct vsense_drvdata, work.work);
41
42 //      dev_dbg(&ddata->client->dev, "!!! work, gpio val %i\n",
43 //              gpio_get_value(ddata->irq_gpio));
44
45         if (unlikely(gpio_get_value(ddata->irq_gpio)))
46         {
47                 goto dosync;
48         }
49
50         ret = i2c_master_recv(ddata->client, buff, 8);
51         if (unlikely(ret != 8)) {
52                 dev_err(&ddata->client->dev, "read failed with %i\n", ret);
53                 goto dosync;
54         }
55
56         x = (signed int)buff[2] * 8;
57         y = (signed int)buff[3] * 8;
58
59         schedule_delayed_work(&ddata->work, msecs_to_jiffies(25));
60
61 dosync:
62         input_report_abs(ddata->input, ABS_X, x);
63         input_report_abs(ddata->input, ABS_Y, y);
64         input_sync(ddata->input);
65 }
66
67 static irqreturn_t vsense_isr(int irq, void *dev_id)
68 {
69         struct vsense_drvdata *ddata = dev_id;
70
71 //      dev_dbg(dev, "!!! irq %i\n", irq);
72
73         schedule_delayed_work(&ddata->work, 0);
74
75         return IRQ_HANDLED;
76 }
77
78 static int vsense_reset(struct input_dev *dev, int val)
79 {
80         struct vsense_drvdata *ddata;
81         int ret;
82
83         ddata = input_get_drvdata(dev);
84
85         dev_dbg(&dev->dev, "vsense_reset: %i\n", val);
86
87         ret = gpio_request(ddata->reset_gpio, "vsense reset");
88         if (ret < 0) {
89                 dev_err(&dev->dev, "failed to request GPIO %d,"
90                                 " error %d\n", ddata->reset_gpio, ret);
91                 return ret;
92         }
93
94         ret = gpio_direction_output(ddata->reset_gpio, val);
95         if (ret < 0) {
96                 dev_err(&dev->dev, "failed to configure input direction "
97                         "for GPIO %d, error %d\n", ddata->reset_gpio, ret);
98         }
99
100         gpio_free(ddata->reset_gpio);
101         return ret;
102 }
103
104 static int vsense_open(struct input_dev *dev)
105 {
106         dev_dbg(&dev->dev, "vsense_open\n");
107
108         if (reference_count++ == 0)
109                 vsense_reset(dev, 0);
110         
111         return 0;
112 }
113
114 static void vsense_close(struct input_dev *dev)
115 {
116         dev_dbg(&dev->dev, "vsense_close\n");
117
118         if (--reference_count == 0)
119                 vsense_reset(dev, 1);
120         BUG_ON(reference_count < 0);
121 }
122
123 static int vsense_probe(struct i2c_client *client,
124                          const struct i2c_device_id *id)
125 {
126         struct vsense_platform_data *pdata = client->dev.platform_data;
127         struct vsense_drvdata *ddata;
128         struct input_dev *input;
129         int ret;
130
131         if (!pdata) {
132                 dev_err(&client->dev, "no platform data?\n");
133                 return -EINVAL;
134         }
135
136         if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
137                 dev_err(&client->dev, "can't talk I2C?\n");
138                 return -EIO;
139         }
140
141         input = input_allocate_device();
142         if (input == NULL)
143                 return -ENOMEM;
144
145         ddata = kzalloc(sizeof(struct vsense_drvdata), GFP_KERNEL);
146         if (ddata == NULL)
147         {
148                 ret = -ENOMEM;
149                 goto fail1;
150         }
151
152         input->evbit[0] = BIT_MASK(EV_ABS);
153         input_set_abs_params(input, ABS_X, -256, 256, 0, 0);
154         input_set_abs_params(input, ABS_Y, -256, 256, 0, 0);
155
156         input->name = client->name;
157         input->dev.parent = &client->dev;
158
159         input->id.bustype = BUS_I2C;
160         input->id.product = client->addr;
161         input->id.version = 0x0090;
162
163         input->open = vsense_open;
164         input->close = vsense_close;
165
166         ret = gpio_request(pdata->gpio_irq, client->name);
167         if (ret < 0) {
168                 dev_err(&client->dev, "failed to request GPIO %d,"
169                         " error %d\n", pdata->gpio_irq, ret);
170                 goto fail2;
171         }
172
173         ret = gpio_direction_input(pdata->gpio_irq);
174         if (ret < 0) {
175                 dev_err(&client->dev, "failed to configure input direction "
176                         "for GPIO %d, error %d\n", pdata->gpio_irq, ret);
177                 goto fail3;
178         }
179
180         ret = gpio_to_irq(pdata->gpio_irq);
181         if (ret < 0) {
182                 dev_err(&client->dev, "unable to get irq number for GPIO %d, "
183                         "error %d\n", pdata->gpio_irq, ret);
184                 goto fail3;
185         }
186         client->irq = ret;
187
188         ret = request_irq(client->irq, vsense_isr,
189                         IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING,
190                         client->name, ddata);
191         if (ret) {
192                 dev_err(&client->dev, "unable to claim irq %d, error %d\n",
193                         client->irq, ret);
194                 goto fail3;
195         }
196
197         INIT_DELAYED_WORK(&ddata->work, vsense_work);
198         
199         ret = input_register_device(input);
200         if (ret) {
201                 dev_err(&client->dev, "failed to register input device, "
202                         "error %d\n", ret);
203                 goto fail4;
204         }
205
206         ddata->input = input;
207         ddata->client = client;
208         ddata->reset_gpio = pdata->gpio_reset;
209         ddata->irq_gpio = pdata->gpio_irq;
210         i2c_set_clientdata(client, ddata);
211         input_set_drvdata(input, ddata);
212
213         dev_dbg(&client->dev, "probe %02x, gpio %i, irq %i, \"%s\"\n",
214                 client->addr, pdata->gpio_irq, client->irq, client->name);
215
216         return 0;
217
218 fail4:
219         free_irq(client->irq, ddata);
220 fail3:
221         gpio_free(pdata->gpio_irq);
222 fail2:
223         kfree(ddata);
224 fail1:
225         input_free_device(input);
226         return ret;
227 }
228
229 static int __devexit vsense_remove(struct i2c_client *client)
230 {
231         struct vsense_drvdata *ddata;
232
233         dev_dbg(&client->dev, "remove\n");
234
235         ddata = i2c_get_clientdata(client);
236
237         free_irq(client->irq, ddata);
238         cancel_delayed_work_sync(&ddata->work);
239         input_unregister_device(ddata->input);
240         gpio_free(ddata->irq_gpio);
241         kfree(ddata);
242
243         return 0;
244 }
245
246 static const struct i2c_device_id vsense_id[] = {
247         { "vsense", 0 },
248         { }
249 };
250
251 static struct i2c_driver vsense_driver = {
252         .driver = {
253                 .name   = "vsense",
254         },
255         .probe          = vsense_probe,
256         .remove         = __devexit_p(vsense_remove),
257         .id_table       = vsense_id,
258 };
259
260 static int __init vsense_init(void)
261 {
262         return i2c_add_driver(&vsense_driver);
263 }
264
265 static void __exit vsense_exit(void)
266 {
267         i2c_del_driver(&vsense_driver);
268 }
269
270
271 MODULE_AUTHOR("Grazvydas Ignotas");
272 MODULE_DESCRIPTION("VSense navigation device driver");
273 MODULE_LICENSE("GPL");
274
275 module_init(vsense_init);
276 module_exit(vsense_exit);