From: Li Jun <b47...@freescale.com>

Add a dedicataed normal timer for HNP polling since it's cyclical, while
in peripheral mode, change a/b_bus_req to be 1 will make it response
to host request flag with 1, then role switch will be started.

Signed-off-by: Li Jun <jun...@freescale.com>
---
 drivers/usb/chipidea/ci.h      |    4 ++++
 drivers/usb/chipidea/otg_fsm.c |   49 +++++++++++++++++++++++++++++++++++++---
 drivers/usb/chipidea/otg_fsm.h |    2 ++
 3 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index aeec5f0..3192a44 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -166,6 +166,8 @@ struct hw_bank {
  * @hr_timeouts: time out list for active otg fsm timers
  * @enabled_otg_timer_bits: bits of enabled otg timers
  * @next_otg_timer: next nearest enabled timer to be expired
+ * @hnp_polling_timer: cyclical timer for hnp polling
+ * @hnp_polling_req: indicates there is hnp polling request
  * @work: work for role changing
  * @wq: workqueue thread
  * @qh_pool: allocation pool for queue heads
@@ -212,6 +214,8 @@ struct ci_hdrc {
        ktime_t                         hr_timeouts[NUM_OTG_FSM_TIMERS];
        unsigned                        enabled_otg_timer_bits;
        enum otg_fsm_timer              next_otg_timer;
+       struct timer_list               hnp_polling_timer;
+       bool                            hnp_polling_req;
        struct work_struct              work;
        struct workqueue_struct         *wq;
 
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index 083acf4..ed79ae7 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -66,6 +66,11 @@ set_a_bus_req(struct device *dev, struct device_attribute 
*attr,
                        return count;
                }
                ci->fsm.a_bus_req = 1;
+               if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) {
+                       ci->gadget.host_request_flag = 1;
+                       mutex_unlock(&ci->fsm.lock);
+                       return count;
+               }
        }
 
        ci_otg_queue_work(ci);
@@ -144,8 +149,14 @@ set_b_bus_req(struct device *dev, struct device_attribute 
*attr,
        mutex_lock(&ci->fsm.lock);
        if (buf[0] == '0')
                ci->fsm.b_bus_req = 0;
-       else if (buf[0] == '1')
+       else if (buf[0] == '1') {
                ci->fsm.b_bus_req = 1;
+               if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) {
+                       ci->gadget.host_request_flag = 1;
+                       mutex_unlock(&ci->fsm.lock);
+                       return count;
+               }
+       }
 
        ci_otg_queue_work(ci);
        mutex_unlock(&ci->fsm.lock);
@@ -203,6 +214,7 @@ static unsigned otg_timer_ms[] = {
        0,
        TB_DATA_PLS,
        TB_SSEND_SRP,
+       0,
 };
 
 /*
@@ -358,6 +370,7 @@ static int (*otg_timer_handlers[])(struct ci_hdrc *) = {
        NULL,                   /* A_WAIT_ENUM */
        b_data_pls_tmout,       /* B_DATA_PLS */
        b_ssend_srp_tmout,      /* B_SSEND_SRP */
+       NULL,                   /* HNP_POLLING */
 };
 
 /*
@@ -404,15 +417,32 @@ static enum hrtimer_restart ci_otg_hrtimer_func(struct 
hrtimer *t)
        return HRTIMER_NORESTART;
 }
 
+static void hnp_polling_timer_work(unsigned long arg)
+{
+       struct ci_hdrc *ci = (struct ci_hdrc *)arg;
+
+       ci->hnp_polling_req = true;
+       ci_otg_queue_work(ci);
+}
+
 /* Initialize timers */
 static int ci_otg_init_timers(struct ci_hdrc *ci)
 {
        hrtimer_init(&ci->otg_fsm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
        ci->otg_fsm_hrtimer.function = ci_otg_hrtimer_func;
 
+       setup_timer(&ci->hnp_polling_timer, hnp_polling_timer_work,
+                                                       (unsigned long)ci);
+
        return 0;
 }
 
+static void ci_otg_add_hnp_polling_timer(struct ci_hdrc *ci)
+{
+       mod_timer(&ci->hnp_polling_timer,
+                       jiffies + msecs_to_jiffies(T_HOST_REQ_POLL));
+}
+
 /* -------------------------------------------------------------*/
 /* Operations that will be called from OTG Finite State Machine */
 /* -------------------------------------------------------------*/
@@ -420,8 +450,12 @@ static void ci_otg_fsm_add_timer(struct otg_fsm *fsm, enum 
otg_fsm_timer t)
 {
        struct ci_hdrc  *ci = container_of(fsm, struct ci_hdrc, fsm);
 
-       if (t < NUM_OTG_FSM_TIMERS)
-               ci_otg_add_timer(ci, t);
+       if (t < NUM_OTG_FSM_TIMERS) {
+               if (t == HNP_POLLING)
+                       ci_otg_add_hnp_polling_timer(ci);
+               else
+                       ci_otg_add_timer(ci, t);
+       }
        return;
 }
 
@@ -569,6 +603,14 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
                return 0;
 
        pm_runtime_get_sync(ci->dev);
+       if (ci->hnp_polling_req) {
+               ci->hnp_polling_req = false;
+               if (otg_hnp_polling(&ci->fsm) != HOST_REQUEST_FLAG) {
+                       pm_runtime_put_sync(ci->dev);
+                       return 0;
+               }
+       }
+
        if (otg_statemachine(&ci->fsm)) {
                if (ci->fsm.otg->state == OTG_STATE_A_IDLE) {
                        /*
@@ -817,4 +859,5 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
 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);
 }
diff --git a/drivers/usb/chipidea/otg_fsm.h b/drivers/usb/chipidea/otg_fsm.h
index 2689375..fbd6dc7 100644
--- a/drivers/usb/chipidea/otg_fsm.h
+++ b/drivers/usb/chipidea/otg_fsm.h
@@ -62,6 +62,8 @@
 /* SSEND time before SRP */
 #define TB_SSEND_SRP         (1500)    /* minimum 1.5 sec, section:5.1.2 */
 
+#define T_HOST_REQ_POLL      (1500)    /* HNP polling interval 1s~2s */
+
 #ifdef CONFIG_USB_OTG_FSM
 
 int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci);
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to