From 24ecfd64c77d6f8ffbfac6d2ba784382dd7745e7 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Mon, 11 Dec 2017 14:09:17 +0530 Subject: [PATCH] gpio: usbdetect: Avoid threaded IRQ handling if no change in ID It is observed that the hard ID IRQ is enabled when the threaded IRQ handler for the same is still running. In that case, there are two issues. The ID LOW IRQ can come consecutively which will increase the disable count of vbus_irq. Then ID HIGH IRQ will not enable the vbus_irq and peripheral mode detection will not work anymore. The second issue is that ID HIGH IRQ is fired just before ID LOW IRQ. This will mark usb->id_state from HIGH to LOW even while threaded IRQ is running which will lead to host not getting stopped and peripheral mode not working. Fix both issues by maintaning a local copy of ID IRQ in threaded IRQ handler and comparing it with previous ID state. If same, then bail out. Change-Id: If5da1f91ece9d1751d7002e64bab0e145623a92e Signed-off-by: Ajay Agarwal --- drivers/platform/msm/gpio-usbdetect.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/gpio-usbdetect.c b/drivers/platform/msm/gpio-usbdetect.c index 1628253fb545..97682436f92c 100644 --- a/drivers/platform/msm/gpio-usbdetect.c +++ b/drivers/platform/msm/gpio-usbdetect.c @@ -77,8 +77,16 @@ static irqreturn_t gpio_usbdetect_id_irq(int irq, void *data) static irqreturn_t gpio_usbdetect_id_irq_thread(int irq, void *data) { struct gpio_usbdetect *usb = data; + bool curr_id_state; + static int prev_id_state = -EINVAL; - if (usb->id_state) { + curr_id_state = usb->id_state; + if (curr_id_state == prev_id_state) { + dev_dbg(&usb->pdev->dev, "no change in ID state\n"); + return IRQ_HANDLED; + } + + if (curr_id_state) { dev_dbg(&usb->pdev->dev, "stopping usb host\n"); extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 0); enable_irq(usb->vbus_det_irq); @@ -88,6 +96,8 @@ static irqreturn_t gpio_usbdetect_id_irq_thread(int irq, void *data) extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_SPEED, 1); extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 1); } + + prev_id_state = curr_id_state; return IRQ_HANDLED; }