diff options
author | Li Jun <b47624@freescale.com> | 2014-06-20 15:52:14 +0800 |
---|---|---|
committer | Li Jun <B47624@freescale.com> | 2014-06-26 16:51:33 +0800 |
commit | 4a0477021f03428f4d61a9be73638cbdf858dd17 (patch) | |
tree | d0b28ecdaeeb80abdca87486605547d7805dbef3 /drivers/usb | |
parent | bb7dbdf5fa721da4f496580ef8747f80174697a9 (diff) |
ENGR00320099 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>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/chipidea/ci.h | 1 | ||||
-rw-r--r-- | drivers/usb/chipidea/core.c | 2 | ||||
-rw-r--r-- | drivers/usb/chipidea/otg.c | 59 | ||||
-rw-r--r-- | drivers/usb/chipidea/otg_fsm.c | 9 |
4 files changed, 62 insertions, 9 deletions
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index a52f9d38dc89..47d81a14c025 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -183,6 +183,7 @@ struct ci_hdrc { struct dentry *debugfs; bool id_event; bool b_sess_valid_event; + bool vbus_glitch_check_event; /* imx28 needs swp instruction for writing */ bool imx28_write_fix; bool supports_runtime_pm; diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index d691dbadac58..a83e0e239691 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -457,7 +457,7 @@ static irqreturn_t ci_irq(int irq, void *data) * and disconnection events. */ if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) { - ci->b_sess_valid_event = true; + ci->vbus_glitch_check_event = true; hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS); ci_otg_queue_work(ci); return IRQ_HANDLED; diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 70ac5c4028af..15a818ae4bad 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -57,6 +57,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) { u32 otgsc; @@ -71,7 +92,7 @@ void ci_handle_vbus_connected(struct ci_hdrc *ci) otgsc = hw_read(ci, OP_OTGSC, ~0); - if (otgsc & OTGSC_BSV) + if ((otgsc & OTGSC_BSV) && !ci_is_vbus_glitch(ci)) usb_gadget_vbus_connect(&ci->gadget); } @@ -115,6 +136,33 @@ static 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 @@ -123,6 +171,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; diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index a30e2bf25ef9..bf85469993f2 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -802,13 +802,8 @@ irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci) } } else if (otg_int_src & OTGSC_BSVIS) { hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS); - ci->b_sess_valid_event = true; - if (otgsc & OTGSC_BSV) { - fsm->b_sess_vld = 1; - ci_otg_del_timer(ci, B_SSEND_SRP); - ci_otg_del_timer(ci, B_SRP_FAIL); - fsm->b_ssend_srp = 0; - } else { + ci->vbus_glitch_check_event = true; + if (!(otgsc & OTGSC_BSV) && fsm->b_sess_vld) { fsm->b_sess_vld = 0; if (fsm->id) ci_otg_add_timer(ci, B_SSEND_SRP); |