diff options
author | Li Jun <b47624@freescale.com> | 2014-06-20 15:52:14 +0800 |
---|---|---|
committer | Octavian Purdila <octavian.purdila@nxp.com> | 2017-02-23 14:21:42 +0200 |
commit | 20847c772c54c43cf097dbc128e35855036e8fb1 (patch) | |
tree | 7576e3c5e615d9ffbbcca9ede64e3e3205440d29 /drivers/usb/chipidea/otg.c | |
parent | d87b1afa8a5c261cf5efae085bc9e096eb9207f6 (diff) |
MLK-11340-41 usb: chipidea: add vbus glitch handling
We add vbus glitch handling for both BSV rise and drop interruptes.
If it is a vbus glitch (higher than BSV but cannot reach AVV), ignore it.
Signed-off-by: Peter Chen <peter.chen@freescale.com>
Signed-off-by: Li Jun <b47624@freescale.com>
(cherry picked from commit 827f2fe71e6222882930db7e89460087cb3bce5b)
(cherry picked from commit 4f9cefe4cf4bb093c8c1766409320dc86dd9a596)
Diffstat (limited to 'drivers/usb/chipidea/otg.c')
-rw-r--r-- | drivers/usb/chipidea/otg.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 8af573d58c41..ddf2622f7425 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -94,6 +94,27 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci) return role; } +#define CI_VBUS_CONNECT_TIMEOUT_MS 500 +static int ci_is_vbus_glitch(struct ci_hdrc *ci) +{ + /* + * Handling vbus glitch + * + * We only need to consider glitch for without usb connection, + * With usb connection, we consider it as real disconnection. + * + * If the vbus can't higher than AVV in timeout value, we think + * it is a vbus glitch + */ + if (hw_wait_reg(ci, OP_OTGSC, OTGSC_AVV, OTGSC_AVV, + CI_VBUS_CONNECT_TIMEOUT_MS)) { + dev_warn(ci->dev, "there is a vbus glitch\n"); + return 1; + } + + return 0; +} + void ci_handle_vbus_connected(struct ci_hdrc *ci) { /* @@ -104,7 +125,7 @@ void ci_handle_vbus_connected(struct ci_hdrc *ci) if (!ci->is_otg) return; - if (hw_read_otgsc(ci, OTGSC_BSV)) + if (hw_read_otgsc(ci, OTGSC_BSV) && !ci_is_vbus_glitch(ci)) usb_gadget_vbus_connect(&ci->gadget); } @@ -144,6 +165,33 @@ void ci_handle_id_switch(struct ci_hdrc *ci) ci_role_start(ci, role); } } + +static void ci_handle_vbus_glitch(struct ci_hdrc *ci) +{ + bool valid_vbus_change = false; + + if (hw_read_otgsc(ci, OTGSC_BSV)) { + if (!ci_is_vbus_glitch(ci)) { + if (ci_otg_is_fsm_mode(ci)) { + ci->fsm.b_sess_vld = 1; + ci->fsm.b_ssend_srp = 0; + otg_del_timer(&ci->fsm, B_SSEND_SRP); + otg_del_timer(&ci->fsm, B_SRP_FAIL); + } + valid_vbus_change = true; + } + } else { + if (ci->vbus_active || (ci_otg_is_fsm_mode(ci) && + ci->fsm.b_sess_vld)) + valid_vbus_change = true; + } + + if (valid_vbus_change) { + ci->b_sess_valid_event = true; + ci_otg_queue_work(ci); + } +} + /** * ci_otg_work - perform otg (vbus/id) event handle * @work: work struct @@ -152,6 +200,15 @@ static void ci_otg_work(struct work_struct *work) { struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); + if (ci->vbus_glitch_check_event) { + ci->vbus_glitch_check_event = false; + pm_runtime_get_sync(ci->dev); + ci_handle_vbus_glitch(ci); + pm_runtime_put_sync(ci->dev); + enable_irq(ci->irq); + return; + } + if (ci_otg_is_fsm_mode(ci) && !ci_otg_fsm_work(ci)) { enable_irq(ci->irq); return; |