@@ -251,6 +251,9 @@ EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
251
251
252
252
static irqreturn_t lis302dl_interrupt (int irq , void * dummy )
253
253
{
254
+ if (!test_bit (0 , & lis3_dev .misc_opened ))
255
+ goto out ;
256
+
254
257
/*
255
258
* Be careful: on some HP laptops the bios force DD when on battery and
256
259
* the lid is closed. This leads to interrupts as soon as a little move
@@ -260,44 +263,35 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
260
263
261
264
wake_up_interruptible (& lis3_dev .misc_wait );
262
265
kill_fasync (& lis3_dev .async_queue , SIGIO , POLL_IN );
266
+ out :
267
+ if (lis3_dev .whoami == WAI_8B && lis3_dev .idev &&
268
+ lis3_dev .idev -> input -> users )
269
+ return IRQ_WAKE_THREAD ;
263
270
return IRQ_HANDLED ;
264
271
}
265
272
266
- static int lis3lv02d_misc_open ( struct inode * inode , struct file * file )
273
+ static irqreturn_t lis302dl_interrupt_thread1_8b ( int irq , void * data )
267
274
{
268
- int ret ;
275
+ return IRQ_HANDLED ;
276
+ }
269
277
278
+ static irqreturn_t lis302dl_interrupt_thread2_8b (int irq , void * data )
279
+ {
280
+ return IRQ_HANDLED ;
281
+ }
282
+
283
+ static int lis3lv02d_misc_open (struct inode * inode , struct file * file )
284
+ {
270
285
if (test_and_set_bit (0 , & lis3_dev .misc_opened ))
271
286
return - EBUSY ; /* already open */
272
287
273
288
atomic_set (& lis3_dev .count , 0 );
274
-
275
- /*
276
- * The sensor can generate interrupts for free-fall and direction
277
- * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep
278
- * the things simple and _fast_ we activate it only for free-fall, so
279
- * no need to read register (very slow with ACPI). For the same reason,
280
- * we forbid shared interrupts.
281
- *
282
- * IRQF_TRIGGER_RISING seems pointless on HP laptops because the
283
- * io-apic is not configurable (and generates a warning) but I keep it
284
- * in case of support for other hardware.
285
- */
286
- ret = request_irq (lis3_dev .irq , lis302dl_interrupt , IRQF_TRIGGER_RISING ,
287
- DRIVER_NAME , & lis3_dev );
288
-
289
- if (ret ) {
290
- clear_bit (0 , & lis3_dev .misc_opened );
291
- printk (KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n" , lis3_dev .irq );
292
- return - EBUSY ;
293
- }
294
289
return 0 ;
295
290
}
296
291
297
292
static int lis3lv02d_misc_release (struct inode * inode , struct file * file )
298
293
{
299
294
fasync_helper (-1 , file , 0 , & lis3_dev .async_queue );
300
- free_irq (lis3_dev .irq , & lis3_dev );
301
295
clear_bit (0 , & lis3_dev .misc_opened ); /* release the device */
302
296
return 0 ;
303
297
}
@@ -434,6 +428,11 @@ EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
434
428
435
429
void lis3lv02d_joystick_disable (void )
436
430
{
431
+ if (lis3_dev .irq )
432
+ free_irq (lis3_dev .irq , & lis3_dev );
433
+ if (lis3_dev .pdata && lis3_dev .pdata -> irq2 )
434
+ free_irq (lis3_dev .pdata -> irq2 , & lis3_dev );
435
+
437
436
if (!lis3_dev .idev )
438
437
return ;
439
438
@@ -524,6 +523,7 @@ EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
524
523
static void lis3lv02d_8b_configure (struct lis3lv02d * dev ,
525
524
struct lis3lv02d_platform_data * p )
526
525
{
526
+ int err ;
527
527
int ctrl2 = p -> hipass_ctrl ;
528
528
529
529
if (p -> click_flags ) {
@@ -554,6 +554,18 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
554
554
}
555
555
/* Configure hipass filters */
556
556
dev -> write (dev , CTRL_REG2 , ctrl2 );
557
+
558
+ if (p -> irq2 ) {
559
+ err = request_threaded_irq (p -> irq2 ,
560
+ NULL ,
561
+ lis302dl_interrupt_thread2_8b ,
562
+ IRQF_TRIGGER_RISING |
563
+ IRQF_ONESHOT ,
564
+ DRIVER_NAME , & lis3_dev );
565
+ if (err < 0 )
566
+ printk (KERN_ERR DRIVER_NAME
567
+ "No second IRQ. Limited functionality\n" );
568
+ }
557
569
}
558
570
559
571
/*
@@ -562,6 +574,9 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
562
574
*/
563
575
int lis3lv02d_init_device (struct lis3lv02d * dev )
564
576
{
577
+ int err ;
578
+ irq_handler_t thread_fn ;
579
+
565
580
dev -> whoami = lis3lv02d_read_8 (dev , WHO_AM_I );
566
581
567
582
switch (dev -> whoami ) {
@@ -616,6 +631,32 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
616
631
goto out ;
617
632
}
618
633
634
+ /*
635
+ * The sensor can generate interrupts for free-fall and direction
636
+ * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep
637
+ * the things simple and _fast_ we activate it only for free-fall, so
638
+ * no need to read register (very slow with ACPI). For the same reason,
639
+ * we forbid shared interrupts.
640
+ *
641
+ * IRQF_TRIGGER_RISING seems pointless on HP laptops because the
642
+ * io-apic is not configurable (and generates a warning) but I keep it
643
+ * in case of support for other hardware.
644
+ */
645
+ if (dev -> whoami == WAI_8B )
646
+ thread_fn = lis302dl_interrupt_thread1_8b ;
647
+ else
648
+ thread_fn = NULL ;
649
+
650
+ err = request_threaded_irq (dev -> irq , lis302dl_interrupt ,
651
+ thread_fn ,
652
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT ,
653
+ DRIVER_NAME , & lis3_dev );
654
+
655
+ if (err < 0 ) {
656
+ printk (KERN_ERR DRIVER_NAME "Cannot get IRQ\n" );
657
+ goto out ;
658
+ }
659
+
619
660
if (misc_register (& lis3lv02d_misc_device ))
620
661
printk (KERN_ERR DRIVER_NAME ": misc_register failed\n" );
621
662
out :
0 commit comments