mfd: cpcap-3mm5: Fix for missing key event on resume
authorGreg Meiste <w30289@motorola.com>
Mon, 29 Nov 2010 21:52:46 +0000 (15:52 -0600)
committerColin Cross <ccross@android.com>
Wed, 1 Dec 2010 00:25:27 +0000 (16:25 -0800)
The key_handler was checking the sense bits to see whether a press
or release occurred.  The problem with this is it takes so long to
resume from LP0/LP1, that the key state could have changed again
before the handler has even ran.  The driver would see the key was
currently released, which was the same state it last reported, and
not send a new event.

This patch changes the handler so it does not check the sense bits.
It simply sends a press when the MB2 interrupt occurs and a release
when the MACRO_5 interrupt occurs.

This fixes the kernel portion of bug 3225781.

Change-Id: I38a89417a0053315c93dc6c696a34a8974252d2a
Signed-off-by: Greg Meiste <w30289@motorola.com>
drivers/mfd/cpcap-3mm5.c

index 29e39749d62367e1633a534425402b0d8e2b906f..709e415ede7c274a08b2d8ee31eaf874a8ddbe7e 100644 (file)
@@ -153,11 +153,11 @@ static void hs_handler(enum cpcap_irqs irq, void *data)
                 new_state);
 }
 
-static void key_handler(enum cpcap_irqs irq, void *data)
+static void mb2_handler(enum cpcap_irqs irq, void *data)
 {
        struct cpcap_3mm5_data *data_3mm5 = data;
 
-       if ((irq != CPCAP_IRQ_MB2) && (irq != CPCAP_IRQ_UC_PRIMACRO_5))
+       if (irq != CPCAP_IRQ_MB2)
                return;
 
        if ((cpcap_irq_sense(data_3mm5->cpcap, CPCAP_IRQ_HS, 1) == 1) ||
@@ -166,21 +166,24 @@ static void key_handler(enum cpcap_irqs irq, void *data)
                return;
        }
 
-       if ((cpcap_irq_sense(data_3mm5->cpcap, CPCAP_IRQ_MB2, 0) == 0) ||
-           (cpcap_irq_sense(data_3mm5->cpcap, CPCAP_IRQ_PTT, 0) == 0)) {
-               send_key_event(data_3mm5, 1);
+       send_key_event(data_3mm5, 1);
+       cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_MB2);
+}
 
-               /* If macro not available, only short presses are supported */
-               if (!cpcap_uc_status(data_3mm5->cpcap, CPCAP_MACRO_5)) {
-                       send_key_event(data_3mm5, 0);
+static void mac5_handler(enum cpcap_irqs irq, void *data)
+{
+       struct cpcap_3mm5_data *data_3mm5 = data;
 
-                       /* Attempt to restart the macro for next time. */
-                       cpcap_uc_start(data_3mm5->cpcap, CPCAP_MACRO_5);
-               }
-       } else
-               send_key_event(data_3mm5, 0);
+       if (irq != CPCAP_IRQ_UC_PRIMACRO_5)
+               return;
 
-       cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_MB2);
+       if ((cpcap_irq_sense(data_3mm5->cpcap, CPCAP_IRQ_HS, 1) == 1) ||
+           (switch_get_state(&data_3mm5->sdev) != HEADSET_WITH_MIC)) {
+               hs_handler(CPCAP_IRQ_HS, data_3mm5);
+               return;
+       }
+
+       send_key_event(data_3mm5, 0);
        cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_UC_PRIMACRO_5);
 }
 
@@ -248,13 +251,13 @@ static int cpcap_3mm5_probe(struct platform_device *pdev)
        if (retval)
                goto reg_put;
 
-       retval = cpcap_irq_register(data->cpcap, CPCAP_IRQ_MB2, key_handler,
+       retval = cpcap_irq_register(data->cpcap, CPCAP_IRQ_MB2, mb2_handler,
                                    data);
        if (retval)
                goto free_hs;
 
        retval = cpcap_irq_register(data->cpcap, CPCAP_IRQ_UC_PRIMACRO_5,
-                                   key_handler, data);
+                                   mac5_handler, data);
        if (retval)
                goto free_mb2;