4 Written by GraÅžvydas Ignotas <notasas@gmail.com>
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.
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/uaccess.h>
19 #include <linux/ctype.h>
20 #include <linux/proc_fs.h>
21 #include <linux/i2c/vsense.h>
22 #include <linux/gpio.h>
24 #define VSENSE_MODE_ABS 0
25 #define VSENSE_MODE_MOUSE 1
26 #define VSENSE_MODE_SCROLL 2
28 /* hack for Pandora: keep track of usage to prevent reset
29 * while other nub is in use
31 static int reference_count;
33 struct vsense_drvdata {
34 struct input_dev *input;
35 struct i2c_client *client;
36 struct delayed_work work;
44 static void vsense_work(struct work_struct *work)
46 struct vsense_drvdata *ddata;
47 int ax = 0, ay = 0, rx = 0, ry = 0;
51 ddata = container_of(work, struct vsense_drvdata, work.work);
53 if (unlikely(gpio_get_value(ddata->irq_gpio)))
56 ret = i2c_master_recv(ddata->client, buff, 8);
57 if (unlikely(ret != 8)) {
58 dev_err(&ddata->client->dev, "read failed with %i\n", ret);
62 rx = (signed int)buff[0];
63 ry = (signed int)buff[1];
64 ax = (signed int)buff[2];
65 ay = (signed int)buff[3];
67 schedule_delayed_work(&ddata->work, msecs_to_jiffies(25));
70 switch (ddata->mode) {
71 case VSENSE_MODE_MOUSE:
72 input_report_rel(ddata->input, REL_X, rx);
73 input_report_rel(ddata->input, REL_Y, -ry);
75 case VSENSE_MODE_SCROLL:
76 if (ddata->scroll_counter++ % 16 != 0)
79 ax = ax < -8 ? ax / 8 : -1;
81 ax = ax > 8 ? ax / 8 : 1;
83 ay = ay < -8 ? ay / 8 : -1;
85 ay = ay > 8 ? ay / 8 : 1;
86 input_report_rel(ddata->input, REL_HWHEEL, ax);
87 input_report_rel(ddata->input, REL_WHEEL, -ay);
90 input_report_abs(ddata->input, ABS_X, ax * 8);
91 input_report_abs(ddata->input, ABS_Y, ay * 8);
94 input_sync(ddata->input);
97 static irqreturn_t vsense_isr(int irq, void *dev_id)
99 struct vsense_drvdata *ddata = dev_id;
101 schedule_delayed_work(&ddata->work, 0);
106 static int vsense_reset(struct input_dev *dev, int val)
108 struct vsense_drvdata *ddata;
111 ddata = input_get_drvdata(dev);
113 dev_dbg(&dev->dev, "vsense_reset: %i\n", val);
115 ret = gpio_request(ddata->reset_gpio, "vsense reset");
117 dev_err(&dev->dev, "failed to request GPIO %d,"
118 " error %d\n", ddata->reset_gpio, ret);
122 ret = gpio_direction_output(ddata->reset_gpio, val);
124 dev_err(&dev->dev, "failed to configure input direction "
125 "for GPIO %d, error %d\n", ddata->reset_gpio, ret);
128 gpio_free(ddata->reset_gpio);
132 static int vsense_open(struct input_dev *dev)
134 dev_dbg(&dev->dev, "vsense_open\n");
136 if (reference_count++ == 0)
137 vsense_reset(dev, 0);
142 static void vsense_close(struct input_dev *dev)
144 dev_dbg(&dev->dev, "vsense_close\n");
146 if (--reference_count == 0)
147 vsense_reset(dev, 1);
148 BUG_ON(reference_count < 0);
151 static int vsense_input_register(struct vsense_drvdata *ddata, int mode)
153 struct input_dev *input;
156 input = input_allocate_device();
160 if (mode != VSENSE_MODE_ABS) {
161 /* pretend to be a mouse */
162 input_set_capability(input, EV_REL, REL_X);
163 input_set_capability(input, EV_REL, REL_Y);
164 input_set_capability(input, EV_REL, REL_WHEEL);
165 input_set_capability(input, EV_REL, REL_HWHEEL);
166 /* add fake buttons to fool X that this is a mouse */
167 input_set_capability(input, EV_KEY, BTN_LEFT);
168 input_set_capability(input, EV_KEY, BTN_RIGHT);
170 input->evbit[BIT_WORD(EV_ABS)] = BIT_MASK(EV_ABS);
171 input_set_abs_params(input, ABS_X, -256, 256, 0, 0);
172 input_set_abs_params(input, ABS_Y, -256, 256, 0, 0);
175 input->name = ddata->dev_name;
176 input->dev.parent = &ddata->client->dev;
178 input->id.bustype = BUS_I2C;
179 input->id.version = 0x0091;
181 input->open = vsense_open;
182 input->close = vsense_close;
184 ddata->input = input;
185 input_set_drvdata(input, ddata);
187 ret = input_register_device(input);
189 dev_err(&ddata->client->dev, "failed to register input device,"
191 input_free_device(input);
199 static void vsense_input_unregister(struct vsense_drvdata *ddata)
201 cancel_delayed_work_sync(&ddata->work);
202 input_unregister_device(ddata->input);
205 static int vsense_proc_read(char *page, char **start, off_t off, int count,
206 int *eof, void *data)
208 struct vsense_drvdata *ddata = data;
212 switch (ddata->mode) {
213 case VSENSE_MODE_MOUSE:
214 len = sprintf(p, "mouse\n");
216 case VSENSE_MODE_SCROLL:
217 len = sprintf(p, "scroll\n");
220 len = sprintf(p, "absolute\n");
228 static int vsense_proc_write(struct file *file, const char __user *buffer,
229 unsigned long count, void *data)
231 struct vsense_drvdata *ddata = data;
232 int mode = ddata->mode;
236 count = strncpy_from_user(buff, buffer,
237 count < sizeof(buff) ? count : sizeof(buff) - 1);
240 p = buff + strlen(buff) - 1;
241 while (p > buff && isspace(*p))
245 if (strcasecmp(buff, "mouse") == 0)
246 mode = VSENSE_MODE_MOUSE;
247 else if (strcasecmp(buff, "scroll") == 0)
248 mode = VSENSE_MODE_SCROLL;
249 else if (strcasecmp(buff, "absolute") == 0)
250 mode = VSENSE_MODE_ABS;
252 dev_err(&ddata->client->dev, "unknown mode: %s\n", buff);
254 if (mode != ddata->mode) {
255 disable_irq(ddata->client->irq);
256 vsense_input_unregister(ddata);
257 ret = vsense_input_register(ddata, mode);
259 dev_err(&ddata->client->dev, "failed to re-register "
260 "input as %d, code %d\n", mode, ret);
262 enable_irq(ddata->client->irq);
268 static int vsense_probe(struct i2c_client *client,
269 const struct i2c_device_id *id)
271 struct vsense_platform_data *pdata = client->dev.platform_data;
272 struct vsense_drvdata *ddata;
273 struct proc_dir_entry *pret;
278 dev_err(&client->dev, "no platform data?\n");
282 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
283 dev_err(&client->dev, "can't talk I2C?\n");
287 ddata = kzalloc(sizeof(struct vsense_drvdata), GFP_KERNEL);
291 snprintf(ddata->dev_name, sizeof(ddata->dev_name),
292 "vsense%02x", client->addr);
294 ret = gpio_request(pdata->gpio_irq, client->name);
296 dev_err(&client->dev, "failed to request GPIO %d,"
297 " error %d\n", pdata->gpio_irq, ret);
301 ret = gpio_direction_input(pdata->gpio_irq);
303 dev_err(&client->dev, "failed to configure input direction "
304 "for GPIO %d, error %d\n", pdata->gpio_irq, ret);
308 ret = gpio_to_irq(pdata->gpio_irq);
310 dev_err(&client->dev, "unable to get irq number for GPIO %d, "
311 "error %d\n", pdata->gpio_irq, ret);
316 INIT_DELAYED_WORK(&ddata->work, vsense_work);
317 ddata->mode = VSENSE_MODE_ABS;
318 ddata->client = client;
319 ddata->reset_gpio = pdata->gpio_reset;
320 ddata->irq_gpio = pdata->gpio_irq;
321 i2c_set_clientdata(client, ddata);
323 ret = vsense_input_register(ddata, ddata->mode);
325 dev_err(&client->dev, "failed to register input device, "
330 ret = request_irq(client->irq, vsense_isr,
331 IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING,
332 client->name, ddata);
334 dev_err(&client->dev, "unable to claim irq %d, error %d\n",
339 dev_dbg(&client->dev, "probe %02x, gpio %i, irq %i, \"%s\"\n",
340 client->addr, pdata->gpio_irq, client->irq, client->name);
342 snprintf(buff, sizeof(buff), "pandora/vsense%02x", client->addr);
343 pret = create_proc_entry(buff, S_IWUGO | S_IRUGO, NULL);
345 proc_mkdir("pandora", NULL);
346 pret = create_proc_entry(buff, S_IWUSR | S_IRUGO, NULL);
348 dev_err(&client->dev, "can't create proc file");
352 pret->read_proc = vsense_proc_read;
353 pret->write_proc = vsense_proc_write;
358 gpio_free(pdata->gpio_irq);
364 static int __devexit vsense_remove(struct i2c_client *client)
366 struct vsense_drvdata *ddata;
369 dev_dbg(&client->dev, "remove\n");
371 ddata = i2c_get_clientdata(client);
373 snprintf(buff, sizeof(buff), "pandora/vsense%02x", client->addr);
374 remove_proc_entry(buff, NULL);
375 free_irq(client->irq, ddata);
376 vsense_input_unregister(ddata);
377 gpio_free(ddata->irq_gpio);
383 static const struct i2c_device_id vsense_id[] = {
388 static struct i2c_driver vsense_driver = {
392 .probe = vsense_probe,
393 .remove = __devexit_p(vsense_remove),
394 .id_table = vsense_id,
397 static int __init vsense_init(void)
399 return i2c_add_driver(&vsense_driver);
402 static void __exit vsense_exit(void)
404 i2c_del_driver(&vsense_driver);
408 MODULE_AUTHOR("Grazvydas Ignotas");
409 MODULE_DESCRIPTION("VSense navigation device driver");
410 MODULE_LICENSE("GPL");
412 module_init(vsense_init);
413 module_exit(vsense_exit);