summaryrefslogtreecommitdiff
path: root/drivers/usb/chipidea/core.c
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@nxp.com>2016-12-06 09:34:58 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:25:24 +0800
commit0b6420f9cbe7dfd28321fa1dcb3d63bf1064ccc1 (patch)
tree65d836f25c7512adff40e4ad7da58ab0b21f9174 /drivers/usb/chipidea/core.c
parent2b516b2477468c77035ea730bf0bba6bce065c1a (diff)
MLK-13570-3 usb: chipidea: core: change extcon usage for imx_4.1.y
At v4.1 kernel, we can't get cable type at notifier, but at extcon-usb-gpio.c notifies both VBUS and ID event, we had to do special handling for ID event, and omit VBUS event. Current implementation only supports ID extcon event. If wakeup event occurs by extcon, it needs to call ci_irq again since the first ci_irq calling at extcon notifier only wakes up controller, but do noop for event handling. Signed-off-by: Peter Chen <peter.chen@nxp.com>
Diffstat (limited to 'drivers/usb/chipidea/core.c')
-rw-r--r--drivers/usb/chipidea/core.c41
1 files changed, 38 insertions, 3 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 381ea120cd82..e500a07bc780 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -593,11 +593,22 @@ static int ci_cable_notifier(struct notifier_block *nb, unsigned long event,
{
struct ci_hdrc_cable *cbl = container_of(nb, struct ci_hdrc_cable, nb);
struct ci_hdrc *ci = cbl->ci;
+ struct extcon_dev *dev = ptr;
+ int ret;
- cbl->connected = event;
- cbl->changed = true;
+ /* Only support ID extcon now */
+
+ ret = extcon_get_state(dev, EXTCON_USB_HOST);
+ if (ret && !cbl->connected) {
+ cbl->connected = true;
+ cbl->changed = true;
+ ci_irq(ci->irq, ci);
+ } else if (!ret && cbl->connected) {
+ cbl->connected = false;
+ cbl->changed = true;
+ ci_irq(ci->irq, ci);
+ }
- ci_irq(ci->irq, ci);
return NOTIFY_DONE;
}
@@ -1210,6 +1221,29 @@ static void ci_controller_suspend(struct ci_hdrc *ci)
enable_irq(ci->irq);
}
+/*
+ * Handle the wakeup interrupt triggered by extcon connector
+ * We need to call ci_irq again for extcon since the first
+ * interrupt (wakeup int) only let the controller be out of
+ * low power mode, but not handle any interrupts.
+ */
+static void ci_extcon_wakeup_int(struct ci_hdrc *ci)
+{
+ struct ci_hdrc_cable *cable_id, *cable_vbus;
+ u32 otgsc = hw_read_otgsc(ci, ~0);
+
+ cable_id = &ci->platdata->id_extcon;
+ cable_vbus = &ci->platdata->vbus_extcon;
+
+ if (!IS_ERR(cable_id->edev) && ci->is_otg &&
+ (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS))
+ ci_irq(ci->irq, ci);
+
+ if (!IS_ERR(cable_vbus->edev) && ci->is_otg &&
+ (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS))
+ ci_irq(ci->irq, ci);
+}
+
static int ci_controller_resume(struct device *dev)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
@@ -1242,6 +1276,7 @@ static int ci_controller_resume(struct device *dev)
enable_irq(ci->irq);
if (ci_otg_is_fsm_mode(ci))
ci_otg_fsm_wakeup_by_srp(ci);
+ ci_extcon_wakeup_int(ci);
}
return 0;