aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamu Onkalo <samu.p.onkalo@nokia.com>2010-05-24 17:33:37 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-25 11:07:07 -0400
commit6d94d4081048756df78444a07201156f4930fe48 (patch)
tree7bfecedff2b04284ab45764d0ce6ec183a6594b3
parent92ba4fe4b53b4fa5ac71ec4d80572348fca85796 (diff)
lis3: interrupt handlers for 8bit wakeup and click events
Content for the 8bit device threaded interrupt handlers. Depending on the interrupt line and chip configuration, either click or wakeup / freefall handler is called. In case of click, BTN_ event is sent via input device. In case of wakeup or freefall, input device ABS_ events are updated immediatelly. It is still possible to configure interrupt line 1 for fast freefall detection and use the second line either for click or threshold based interrupts. Or both lines can be used for click / threshold interrupts. Polled input device can be set to stopped state and still get coordinate updates via input device using interrupt based method. Polled mode and interrupt mode can also be used parallel. BTN_ events are remapped based on existing axis remapping information. Signed-off-by: Samu Onkalo <samu.p.onkalo@nokia.com> Acked-by: Eric Piel <eric.piel@tremplin-utc.net> Cc: Daniel Mack <daniel@caiaq.de> Cc: Pavel Machek <pavel@ucw.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/hwmon/lis3lv02d.c98
-rw-r--r--drivers/hwmon/lis3lv02d.h1
-rw-r--r--include/linux/lis3lv02d.h2
3 files changed, 88 insertions, 13 deletions
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c
index 3c06350bae3a..56a1d34d3670 100644
--- a/drivers/hwmon/lis3lv02d.c
+++ b/drivers/hwmon/lis3lv02d.c
@@ -121,11 +121,9 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
121 int position[3]; 121 int position[3];
122 int i; 122 int i;
123 123
124 mutex_lock(&lis3->mutex);
125 position[0] = lis3->read_data(lis3, OUTX); 124 position[0] = lis3->read_data(lis3, OUTX);
126 position[1] = lis3->read_data(lis3, OUTY); 125 position[1] = lis3->read_data(lis3, OUTY);
127 position[2] = lis3->read_data(lis3, OUTZ); 126 position[2] = lis3->read_data(lis3, OUTZ);
128 mutex_unlock(&lis3->mutex);
129 127
130 for (i = 0; i < 3; i++) 128 for (i = 0; i < 3; i++)
131 position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY; 129 position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY;
@@ -249,6 +247,19 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3)
249EXPORT_SYMBOL_GPL(lis3lv02d_poweron); 247EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
250 248
251 249
250static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
251{
252 int x, y, z;
253
254 mutex_lock(&lis3_dev.mutex);
255 lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
256 input_report_abs(pidev->input, ABS_X, x);
257 input_report_abs(pidev->input, ABS_Y, y);
258 input_report_abs(pidev->input, ABS_Z, z);
259 input_sync(pidev->input);
260 mutex_unlock(&lis3_dev.mutex);
261}
262
252static irqreturn_t lis302dl_interrupt(int irq, void *dummy) 263static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
253{ 264{
254 if (!test_bit(0, &lis3_dev.misc_opened)) 265 if (!test_bit(0, &lis3_dev.misc_opened))
@@ -270,13 +281,71 @@ out:
270 return IRQ_HANDLED; 281 return IRQ_HANDLED;
271} 282}
272 283
284static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3)
285{
286 struct input_dev *dev = lis3->idev->input;
287 u8 click_src;
288
289 mutex_lock(&lis3->mutex);
290 lis3->read(lis3, CLICK_SRC, &click_src);
291
292 if (click_src & CLICK_SINGLE_X) {
293 input_report_key(dev, lis3->mapped_btns[0], 1);
294 input_report_key(dev, lis3->mapped_btns[0], 0);
295 }
296
297 if (click_src & CLICK_SINGLE_Y) {
298 input_report_key(dev, lis3->mapped_btns[1], 1);
299 input_report_key(dev, lis3->mapped_btns[1], 0);
300 }
301
302 if (click_src & CLICK_SINGLE_Z) {
303 input_report_key(dev, lis3->mapped_btns[2], 1);
304 input_report_key(dev, lis3->mapped_btns[2], 0);
305 }
306 input_sync(dev);
307 mutex_unlock(&lis3->mutex);
308}
309
310static void lis302dl_interrupt_handle_ff_wu(struct lis3lv02d *lis3)
311{
312 u8 wu1_src;
313 u8 wu2_src;
314
315 lis3->read(lis3, FF_WU_SRC_1, &wu1_src);
316 lis3->read(lis3, FF_WU_SRC_2, &wu2_src);
317
318 wu1_src = wu1_src & FF_WU_SRC_IA ? wu1_src : 0;
319 wu2_src = wu2_src & FF_WU_SRC_IA ? wu2_src : 0;
320
321 /* joystick poll is internally protected by the lis3->mutex. */
322 if (wu1_src || wu2_src)
323 lis3lv02d_joystick_poll(lis3_dev.idev);
324}
325
273static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data) 326static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
274{ 327{
328
329 struct lis3lv02d *lis3 = data;
330
331 if ((lis3->pdata->irq_cfg & LIS3_IRQ1_MASK) == LIS3_IRQ1_CLICK)
332 lis302dl_interrupt_handle_click(lis3);
333 else
334 lis302dl_interrupt_handle_ff_wu(lis3);
335
275 return IRQ_HANDLED; 336 return IRQ_HANDLED;
276} 337}
277 338
278static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data) 339static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
279{ 340{
341
342 struct lis3lv02d *lis3 = data;
343
344 if ((lis3->pdata->irq_cfg & LIS3_IRQ2_MASK) == LIS3_IRQ2_CLICK)
345 lis302dl_interrupt_handle_click(lis3);
346 else
347 lis302dl_interrupt_handle_ff_wu(lis3);
348
280 return IRQ_HANDLED; 349 return IRQ_HANDLED;
281} 350}
282 351
@@ -374,22 +443,12 @@ static struct miscdevice lis3lv02d_misc_device = {
374 .fops = &lis3lv02d_misc_fops, 443 .fops = &lis3lv02d_misc_fops,
375}; 444};
376 445
377static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
378{
379 int x, y, z;
380
381 lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
382 input_report_abs(pidev->input, ABS_X, x);
383 input_report_abs(pidev->input, ABS_Y, y);
384 input_report_abs(pidev->input, ABS_Z, z);
385 input_sync(pidev->input);
386}
387
388int lis3lv02d_joystick_enable(void) 446int lis3lv02d_joystick_enable(void)
389{ 447{
390 struct input_dev *input_dev; 448 struct input_dev *input_dev;
391 int err; 449 int err;
392 int max_val, fuzz, flat; 450 int max_val, fuzz, flat;
451 int btns[] = {BTN_X, BTN_Y, BTN_Z};
393 452
394 if (lis3_dev.idev) 453 if (lis3_dev.idev)
395 return -EINVAL; 454 return -EINVAL;
@@ -416,6 +475,10 @@ int lis3lv02d_joystick_enable(void)
416 input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat); 475 input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
417 input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat); 476 input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
418 477
478 lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns);
479 lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns);
480 lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns);
481
419 err = input_register_polled_device(lis3_dev.idev); 482 err = input_register_polled_device(lis3_dev.idev);
420 if (err) { 483 if (err) {
421 input_free_polled_device(lis3_dev.idev); 484 input_free_polled_device(lis3_dev.idev);
@@ -461,7 +524,9 @@ static ssize_t lis3lv02d_position_show(struct device *dev,
461{ 524{
462 int x, y, z; 525 int x, y, z;
463 526
527 mutex_lock(&lis3_dev.mutex);
464 lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); 528 lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
529 mutex_unlock(&lis3_dev.mutex);
465 return sprintf(buf, "(%d,%d,%d)\n", x, y, z); 530 return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
466} 531}
467 532
@@ -535,6 +600,13 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
535 dev->write(dev, CLICK_THSY_X, 600 dev->write(dev, CLICK_THSY_X,
536 (p->click_thresh_x & 0xf) | 601 (p->click_thresh_x & 0xf) |
537 (p->click_thresh_y << 4)); 602 (p->click_thresh_y << 4));
603
604 if (dev->idev) {
605 struct input_dev *input_dev = lis3_dev.idev->input;
606 input_set_capability(input_dev, EV_KEY, BTN_X);
607 input_set_capability(input_dev, EV_KEY, BTN_Y);
608 input_set_capability(input_dev, EV_KEY, BTN_Z);
609 }
538 } 610 }
539 611
540 if (p->wakeup_flags) { 612 if (p->wakeup_flags) {
diff --git a/drivers/hwmon/lis3lv02d.h b/drivers/hwmon/lis3lv02d.h
index 692e2442ce08..854091380e33 100644
--- a/drivers/hwmon/lis3lv02d.h
+++ b/drivers/hwmon/lis3lv02d.h
@@ -233,6 +233,7 @@ struct lis3lv02d {
233 struct platform_device *pdev; /* platform device */ 233 struct platform_device *pdev; /* platform device */
234 atomic_t count; /* interrupt count after last read */ 234 atomic_t count; /* interrupt count after last read */
235 struct axis_conversion ac; /* hw -> logical axis */ 235 struct axis_conversion ac; /* hw -> logical axis */
236 int mapped_btns[3];
236 237
237 u32 irq; /* IRQ number */ 238 u32 irq; /* IRQ number */
238 struct fasync_struct *async_queue; /* queue for the misc device */ 239 struct fasync_struct *async_queue; /* queue for the misc device */
diff --git a/include/linux/lis3lv02d.h b/include/linux/lis3lv02d.h
index fd289b1e1ec1..0e8a346424bb 100644
--- a/include/linux/lis3lv02d.h
+++ b/include/linux/lis3lv02d.h
@@ -25,12 +25,14 @@ struct lis3lv02d_platform_data {
25#define LIS3_IRQ1_FF_WU_12 (3 << 0) 25#define LIS3_IRQ1_FF_WU_12 (3 << 0)
26#define LIS3_IRQ1_DATA_READY (4 << 0) 26#define LIS3_IRQ1_DATA_READY (4 << 0)
27#define LIS3_IRQ1_CLICK (7 << 0) 27#define LIS3_IRQ1_CLICK (7 << 0)
28#define LIS3_IRQ1_MASK (7 << 0)
28#define LIS3_IRQ2_DISABLE (0 << 3) 29#define LIS3_IRQ2_DISABLE (0 << 3)
29#define LIS3_IRQ2_FF_WU_1 (1 << 3) 30#define LIS3_IRQ2_FF_WU_1 (1 << 3)
30#define LIS3_IRQ2_FF_WU_2 (2 << 3) 31#define LIS3_IRQ2_FF_WU_2 (2 << 3)
31#define LIS3_IRQ2_FF_WU_12 (3 << 3) 32#define LIS3_IRQ2_FF_WU_12 (3 << 3)
32#define LIS3_IRQ2_DATA_READY (4 << 3) 33#define LIS3_IRQ2_DATA_READY (4 << 3)
33#define LIS3_IRQ2_CLICK (7 << 3) 34#define LIS3_IRQ2_CLICK (7 << 3)
35#define LIS3_IRQ2_MASK (7 << 3)
34#define LIS3_IRQ_OPEN_DRAIN (1 << 6) 36#define LIS3_IRQ_OPEN_DRAIN (1 << 6)
35#define LIS3_IRQ_ACTIVE_LOW (1 << 7) 37#define LIS3_IRQ_ACTIVE_LOW (1 << 7)
36 unsigned char irq_cfg; 38 unsigned char irq_cfg;