diff options
Diffstat (limited to 'drivers/usb/chipidea/core.c')
-rw-r--r-- | drivers/usb/chipidea/core.c | 75 |
1 files changed, 58 insertions, 17 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 965d0e240dcb..037ee27759d7 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -609,14 +609,26 @@ static int ci_vbus_notifier(struct notifier_block *nb, unsigned long event, struct ci_hdrc_cable *vbus = container_of(nb, struct ci_hdrc_cable, nb); struct ci_hdrc *ci = vbus->ci; - if (event) - vbus->state = true; - else - vbus->state = false; + if (ci->platdata->flags & CI_HDRC_DUAL_ROLE_NOT_OTG) { + pm_runtime_get_sync(ci->dev); + + if (event) + usb_gadget_vbus_connect(&ci->gadget); + else + usb_gadget_vbus_disconnect(&ci->gadget); + + pm_runtime_put_sync(ci->dev); + } else { + if (event) + vbus->state = true; + else + vbus->state = false; + + vbus->changed = true; - vbus->changed = true; + ci_irq(ci->irq, ci); + } - ci_irq(ci->irq, ci); return NOTIFY_DONE; } @@ -626,14 +638,29 @@ static int ci_id_notifier(struct notifier_block *nb, unsigned long event, struct ci_hdrc_cable *id = container_of(nb, struct ci_hdrc_cable, nb); struct ci_hdrc *ci = id->ci; - if (event) - id->state = false; - else - id->state = true; + if (ci->platdata->flags & CI_HDRC_DUAL_ROLE_NOT_OTG) { + pm_runtime_get_sync(ci->dev); + + ci_role_stop(ci); + + hw_wait_phy_stable(); + + if (ci_role_start(ci, event ? CI_ROLE_HOST : CI_ROLE_GADGET)) + dev_err(ci->dev, + "Can't start %s role\n", ci_role(ci)->name); + + pm_runtime_put_sync(ci->dev); + } else { + if (event) + id->state = false; + else + id->state = true; - id->changed = true; + id->changed = true; + + ci_irq(ci->irq, ci); + } - ci_irq(ci->irq, ci); return NOTIFY_DONE; } @@ -911,6 +938,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) void __iomem *base; int ret; enum usb_dr_mode dr_mode; + struct ci_hdrc_cable *cable; if (!dev_get_platdata(dev)) { dev_err(dev, "platform data missing\n"); @@ -978,6 +1006,10 @@ static int ci_hdrc_probe(struct platform_device *pdev) ci_get_otg_capable(ci); + ret = ci_extcon_register(ci); + if (ret) + goto deinit_phy; + dr_mode = ci->platdata->dr_mode; /* initialize role(s) before the interrupt is requested */ if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { @@ -1017,7 +1049,14 @@ static int ci_hdrc_probe(struct platform_device *pdev) * role switch, the defalt role is gadget, and the * user can switch it through debugfs. */ - ci->role = CI_ROLE_GADGET; + cable = &ci->platdata->id_extcon; + if (!IS_ERR(cable->edev)) { + if (extcon_get_cable_state(cable->edev, + "USB-HOST") == true) + ci->role = CI_ROLE_HOST; + else + ci->role = CI_ROLE_GADGET; + } } } else { ci->role = ci->roles[CI_ROLE_HOST] @@ -1036,6 +1075,12 @@ static int ci_hdrc_probe(struct platform_device *pdev) ci_role(ci)->name); goto stop; } + cable = &ci->platdata->vbus_extcon; + if (!IS_ERR(cable->edev)) { + if ((ci->role == CI_ROLE_GADGET) && + (extcon_get_cable_state(cable->edev, "USB") == true)) + usb_gadget_vbus_connect(&ci->gadget); + } } platform_set_drvdata(pdev, ci); @@ -1044,10 +1089,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ret) goto stop; - ret = ci_extcon_register(ci); - if (ret) - goto stop; - if (ci->supports_runtime_pm) { pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); |