From fd34558b5f1fa711f2daccc36c1dcd000ef28525 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 15 Jan 2015 21:00:34 +0800 Subject: [PATCH] MLK-10102-8 usb: chipidea: support role change after power lost This patch is to complete support usb resume from power lost in non-otg fsm mode: - Re-init usb phy. - Support role changes during system sleep with power lost. Acked-by: Peter Chen Signed-off-by: Li Jun (cherry picked from commit b15794487c32a6c9317f12b6bca5d2d752c9d76c) (cherry picked from commit 3e5d97cfd2f3b350dd5b5012cf7af73ce11531ac) --- drivers/usb/chipidea/ci.h | 1 + drivers/usb/chipidea/core.c | 78 ++++++++++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 19 deletions(-) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 9e14d753b3b1..b125a653c497 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -263,6 +263,7 @@ struct ci_hdrc { u32 pm_configured_flag; u32 pm_portsc; u32 pm_usbmode; + struct work_struct power_lost_work; }; static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index d907dd7e4e22..284830db3d2a 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -859,6 +859,50 @@ static void ci_get_otg_capable(struct ci_hdrc *ci) } } +static enum ci_role ci_get_role(struct ci_hdrc *ci) +{ + if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { + if (ci->is_otg) { + hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE); + return ci_otg_role(ci); + } else { + /* + * If the controller is not OTG capable, but support + * role switch, the defalt role is gadget, and the + * user can switch it through debugfs. + */ + return CI_ROLE_GADGET; + } + } else { + return ci->roles[CI_ROLE_HOST] + ? CI_ROLE_HOST + : CI_ROLE_GADGET; + } +} + +static void ci_start_new_role(struct ci_hdrc *ci) +{ + enum ci_role role = ci_get_role(ci); + + if (ci->role != role) + ci_handle_id_switch(ci); + + if (role == CI_ROLE_GADGET) + ci_handle_vbus_connected(ci); +} + +static void ci_power_lost_work(struct work_struct *work) +{ + struct ci_hdrc *ci = container_of(work, struct ci_hdrc, + power_lost_work); + + pm_runtime_get_sync(ci->dev); + if (!ci_otg_is_fsm_mode(ci)) + ci_start_new_role(ci); + pm_runtime_put_sync(ci->dev); + enable_irq(ci->irq); +} + static int ci_hdrc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -963,25 +1007,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) } } - if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { - if (ci->is_otg) { - ci->role = ci_otg_role(ci); - /* Enable ID change irq */ - hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE); - } else { - /* - * If the controller is not OTG capable, but support - * role switch, the defalt role is gadget, and the - * user can switch it through debugfs. - */ - ci->role = CI_ROLE_GADGET; - } - } else { - ci->role = ci->roles[CI_ROLE_HOST] - ? CI_ROLE_HOST - : CI_ROLE_GADGET; - } - + ci->role = ci_get_role(ci); /* only update vbus status for peripheral */ if (ci->role == CI_ROLE_GADGET) ci_handle_vbus_connected(ci); @@ -1018,6 +1044,9 @@ static int ci_hdrc_probe(struct platform_device *pdev) device_set_wakeup_capable(&pdev->dev, true); + /* Init workqueue for controller power lost handling */ + INIT_WORK(&ci->power_lost_work, ci_power_lost_work); + ret = dbg_create_files(ci); if (!ret) return 0; @@ -1181,10 +1210,21 @@ static int ci_resume(struct device *dev) if (ret) return ret; + if (power_lost) { + /* shutdown and re-init for phy */ + ci_usb_phy_exit(ci); + ci_usb_phy_init(ci); + } + /* Extra routine per role after system resume */ if (ci->role != CI_ROLE_END && ci_role(ci)->resume) ci_role(ci)->resume(ci, power_lost); + if (power_lost) { + disable_irq_nosync(ci->irq); + schedule_work(&ci->power_lost_work); + } + if (ci->supports_runtime_pm) { pm_runtime_disable(dev); pm_runtime_set_active(dev); -- 2.17.1