| From a89b94b53371bbfa582787c2fa3378000ea4263d Mon Sep 17 00:00:00 2001 |
| From: Stephen Boyd <stephen.boyd@linaro.org> |
| Date: Wed, 28 Dec 2016 14:56:51 -0800 |
| Subject: [PATCH] usb: chipidea: Handle extcon events properly |
| |
| commit a89b94b53371bbfa582787c2fa3378000ea4263d upstream. |
| |
| We're currently emulating the vbus and id interrupts in the OTGSC |
| read API, but we also need to make sure that if we're handling |
| the events with extcon that we don't enable the interrupts for |
| those events in the hardware. Therefore, properly emulate this |
| register if we're using extcon, but don't enable the interrupts. |
| This allows me to get my cable connect/disconnect working |
| properly without getting spurious interrupts on my device that |
| uses an extcon for these two events. |
| |
| Acked-by: Peter Chen <peter.chen@nxp.com> |
| Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Cc: "Ivan T. Ivanov" <iivanov.xz@gmail.com> |
| Fixes: 3ecb3e09b042 ("usb: chipidea: Use extcon framework for VBUS and ID detect") |
| Signed-off-by: Stephen Boyd <stephen.boyd@linaro.org> |
| Signed-off-by: Peter Chen <peter.chen@nxp.com> |
| |
| diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c |
| index a829607c3e4d..0cf149edddd8 100644 |
| --- a/drivers/usb/chipidea/otg.c |
| +++ b/drivers/usb/chipidea/otg.c |
| @@ -44,12 +44,15 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) |
| else |
| val &= ~OTGSC_BSVIS; |
| |
| - cable->changed = false; |
| - |
| if (cable->state) |
| val |= OTGSC_BSV; |
| else |
| val &= ~OTGSC_BSV; |
| + |
| + if (cable->enabled) |
| + val |= OTGSC_BSVIE; |
| + else |
| + val &= ~OTGSC_BSVIE; |
| } |
| |
| cable = &ci->platdata->id_extcon; |
| @@ -59,15 +62,18 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) |
| else |
| val &= ~OTGSC_IDIS; |
| |
| - cable->changed = false; |
| - |
| if (cable->state) |
| val |= OTGSC_ID; |
| else |
| val &= ~OTGSC_ID; |
| + |
| + if (cable->enabled) |
| + val |= OTGSC_IDIE; |
| + else |
| + val &= ~OTGSC_IDIE; |
| } |
| |
| - return val; |
| + return val & mask; |
| } |
| |
| /** |
| @@ -77,6 +83,36 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) |
| */ |
| void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data) |
| { |
| + struct ci_hdrc_cable *cable; |
| + |
| + cable = &ci->platdata->vbus_extcon; |
| + if (!IS_ERR(cable->edev)) { |
| + if (data & mask & OTGSC_BSVIS) |
| + cable->changed = false; |
| + |
| + /* Don't enable vbus interrupt if using external notifier */ |
| + if (data & mask & OTGSC_BSVIE) { |
| + cable->enabled = true; |
| + data &= ~OTGSC_BSVIE; |
| + } else if (mask & OTGSC_BSVIE) { |
| + cable->enabled = false; |
| + } |
| + } |
| + |
| + cable = &ci->platdata->id_extcon; |
| + if (!IS_ERR(cable->edev)) { |
| + if (data & mask & OTGSC_IDIS) |
| + cable->changed = false; |
| + |
| + /* Don't enable id interrupt if using external notifier */ |
| + if (data & mask & OTGSC_IDIE) { |
| + cable->enabled = true; |
| + data &= ~OTGSC_IDIE; |
| + } else if (mask & OTGSC_IDIE) { |
| + cable->enabled = false; |
| + } |
| + } |
| + |
| hw_write(ci, OP_OTGSC, mask | OTGSC_INT_STATUS_BITS, data); |
| } |
| |
| diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h |
| index 5dd75fa47dd8..f9be467d6695 100644 |
| --- a/include/linux/usb/chipidea.h |
| +++ b/include/linux/usb/chipidea.h |
| @@ -14,6 +14,7 @@ struct ci_hdrc; |
| * struct ci_hdrc_cable - structure for external connector cable state tracking |
| * @state: current state of the line |
| * @changed: set to true when extcon event happen |
| + * @enabled: set to true if we've enabled the vbus or id interrupt |
| * @edev: device which generate events |
| * @ci: driver state of the chipidea device |
| * @nb: hold event notification callback |
| @@ -22,6 +23,7 @@ struct ci_hdrc; |
| struct ci_hdrc_cable { |
| bool state; |
| bool changed; |
| + bool enabled; |
| struct extcon_dev *edev; |
| struct ci_hdrc *ci; |
| struct notifier_block nb; |
| -- |
| 2.12.0 |
| |