summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jun <b47624@freescale.com>2014-06-29 12:43:02 +0800
committerLi Jun <B47624@freescale.com>2014-06-30 16:37:44 +0800
commit0b2b7c9b4005035cb7e62520c4d87a76004aea07 (patch)
tree2f8e86c30607dfe179aa2fb350f07861706d2c3f
parent91d9685df8f456cead12dda23849c2e0cbada83f (diff)
ENGR00320439-8 usb: chipidea: otg_fsm: power lost handling for otg fsm
This patch adds support for system resume from power lost in otg fsm mode. Signed-off-by: Li Jun <b47624@freescale.com>
-rw-r--r--drivers/usb/chipidea/core.c5
-rw-r--r--drivers/usb/chipidea/otg_fsm.c37
-rw-r--r--drivers/usb/chipidea/otg_fsm.h6
3 files changed, 47 insertions, 1 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index c1350e7e7553..b6c57161985c 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -649,7 +649,10 @@ static void ci_power_lost_work(struct work_struct *work)
power_lost_work);
pm_runtime_get_sync(ci->dev);
- ci_start_new_role(ci);
+ if (ci_otg_is_fsm_mode(ci))
+ ci_hdrc_otg_fsm_restart(ci);
+ else
+ ci_start_new_role(ci);
pm_runtime_put_sync(ci->dev);
enable_irq(ci->irq);
}
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index bf85469993f2..6faab2a06053 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -29,6 +29,7 @@
#include "bits.h"
#include "otg.h"
#include "otg_fsm.h"
+#include "host.h"
static struct ci_otg_fsm_timer *otg_timer_initializer
(struct ci_hdrc *ci, void (*function)(void *, unsigned long),
@@ -899,3 +900,39 @@ void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci)
sysfs_remove_group(&ci->dev->kobj, &inputs_attr_group);
del_timer_sync(&ci->hnp_polling_timer);
}
+
+/* Restart OTG fsm if resume from power lost */
+void ci_hdrc_otg_fsm_restart(struct ci_hdrc *ci)
+{
+ struct otg_fsm *fsm = &ci->fsm;
+ int id_status = fsm->id;
+
+ /* Update fsm if power lost in peripheral state */
+ if (ci->transceiver->state == OTG_STATE_B_PERIPHERAL) {
+ fsm->b_sess_vld = 0;
+ otg_statemachine(fsm);
+ }
+
+ hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
+ hw_write_otgsc(ci, OTGSC_AVVIE, OTGSC_AVVIE);
+
+ /* Update fsm variables for restart */
+ fsm->id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
+ if (fsm->id) {
+ fsm->b_ssend_srp =
+ hw_read_otgsc(ci, OTGSC_BSV) ? 0 : 1;
+ fsm->b_sess_vld =
+ hw_read_otgsc(ci, OTGSC_BSV) ? 1 : 0;
+ } else if (fsm->id != id_status) {
+ /* ID changes to be 0 */
+ fsm->a_bus_drop = 0;
+ fsm->a_bus_req = 1;
+ ci->id_event = true;
+ }
+
+ if (ci_hdrc_host_has_device(ci) &&
+ !hw_read(ci, OP_PORTSC, PORTSC_CCS))
+ fsm->b_conn = 0;
+
+ ci_otg_fsm_work(ci);
+}
diff --git a/drivers/usb/chipidea/otg_fsm.h b/drivers/usb/chipidea/otg_fsm.h
index 2cfffb7061e1..3399e901b419 100644
--- a/drivers/usb/chipidea/otg_fsm.h
+++ b/drivers/usb/chipidea/otg_fsm.h
@@ -98,6 +98,7 @@ int ci_otg_fsm_work(struct ci_hdrc *ci);
irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci);
void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci);
void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci);
+void ci_hdrc_otg_fsm_restart(struct ci_hdrc *ci);
#else
@@ -126,6 +127,11 @@ static inline void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci)
}
+static inline void ci_hdrc_otg_fsm_restart(struct ci_hdrc *ci)
+{
+
+}
+
#endif
#endif /* __DRIVERS_USB_CHIPIDEA_OTG_FSM_H */