usb:otg: wait for system resume before stopping host
authorjzhuan5 <jin.can.zhuang@intel.com>
Thu, 14 Jun 2012 22:24:49 +0000 (18:24 -0400)
committerbuildbot <buildbot@intel.com>
Tue, 19 Jun 2012 11:49:01 +0000 (04:49 -0700)
BZ: 38545

add a PM notifier to know whether system is resumed.
EHCI driver should not be removed until system is resumed.

Change-Id: I012d1130215f08bd4230af8adf4068d8cb588c0b
Signed-off-by: jzhuan5 <jin.can.zhuang@intel.com>
Reviewed-on: http://android.intel.com:8080/52758
Reviewed-by: Wu, Hao <hao.wu@intel.com>
Reviewed-by: Tang, Jianqiang <jianqiang.tang@intel.com>
Reviewed-by: Tang, Richard <richard.tang@intel.com>
Reviewed-by: Meng, Zhe <zhe.meng@intel.com>
Tested-by: Meng, Zhe <zhe.meng@intel.com>
Reviewed-by: Gao, Yunpeng <yunpeng.gao@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
drivers/usb/otg/penwell_otg.c

index d179dad..f1215b0 100644 (file)
@@ -71,6 +71,47 @@ static int penwell_otg_ulpi_read(struct intel_mid_otg_xceiv *iotg,
 static int penwell_otg_ulpi_write(struct intel_mid_otg_xceiv *iotg,
                                u8 reg, u8 val);
 
+#ifdef CONFIG_PM_SLEEP
+#include <linux/suspend.h>
+DECLARE_WAIT_QUEUE_HEAD(stop_host_wait);
+atomic_t pnw_sys_suspended;
+
+static int pnw_sleep_pm_callback(struct notifier_block *nfb,
+                       unsigned long action, void *ignored)
+{
+       switch (action) {
+       case PM_SUSPEND_PREPARE:
+               atomic_set(&pnw_sys_suspended, 1);
+               return NOTIFY_OK;
+       case PM_POST_SUSPEND:
+               atomic_set(&pnw_sys_suspended, 0);
+               return NOTIFY_OK;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block pnw_sleep_pm_notifier = {
+       .notifier_call = pnw_sleep_pm_callback,
+       .priority = 0
+};
+
+#define PNW_PM_RESUME_WAIT(a) \
+               while (atomic_read(&pnw_sys_suspended)) { \
+                       wait_event_timeout(a, false, HZ/100); \
+               }
+#else
+
+#define PNW_PM_RESUME_WAIT(a)
+
+#endif
+
+#define PNW_STOP_HOST(pnw) do { \
+       if ((pnw)->iotg.stop_host) { \
+               PNW_PM_RESUME_WAIT(stop_host_wait); \
+               (pnw)->iotg.stop_host(&(pnw)->iotg); \
+       } \
+       } while (0)
+
 static inline int is_clovertrail(struct pci_dev *pdev)
 {
        return (pdev->vendor == 0x8086 && pdev->device == 0xE006);
@@ -2836,11 +2877,8 @@ static void penwell_otg_work(struct work_struct *work)
                        hsm->a_srp_det = 0;
 
                        penwell_otg_HAAR(0);
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+
+                       PNW_STOP_HOST(pnw);
 
                        set_host_mode();
                        penwell_otg_phy_low_power(1);
@@ -2869,11 +2907,7 @@ static void penwell_otg_work(struct work_struct *work)
                        hsm->b_bus_req = 0;
                        penwell_otg_HAAR(0);
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+                       PNW_STOP_HOST(pnw);
 
                        set_client_mode();
                        penwell_otg_phy_low_power(1);
@@ -2901,11 +2935,7 @@ static void penwell_otg_work(struct work_struct *work)
                        penwell_otg_HAAR(0);
                        penwell_otg_nsf_msg(7);
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+                       PNW_STOP_HOST(pnw);
 
                        hsm->a_bus_suspend = 0;
                        hsm->b_bus_req = 0;
@@ -2939,11 +2969,7 @@ static void penwell_otg_work(struct work_struct *work)
                        /* Stop HNP polling */
                        iotg->stop_hnp_poll(iotg);
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+                       PNW_STOP_HOST(pnw);
 
                        set_host_mode();
                        penwell_otg_phy_low_power(1);
@@ -2971,11 +2997,7 @@ static void penwell_otg_work(struct work_struct *work)
                        /* Stop HNP polling */
                        iotg->stop_hnp_poll(iotg);
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+                       PNW_STOP_HOST(pnw);
 
                        set_client_mode();
                        penwell_otg_phy_low_power(1);
@@ -2991,12 +3013,7 @@ static void penwell_otg_work(struct work_struct *work)
                        /* Stop HNP polling */
                        iotg->stop_hnp_poll(iotg);
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
-
+                       PNW_STOP_HOST(pnw);
                        hsm->a_bus_suspend = 0;
 
                        /* Clear HNP polling flag */
@@ -3172,11 +3189,7 @@ static void penwell_otg_work(struct work_struct *work)
 
                        hsm->b_bus_req = 0;
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+                       PNW_STOP_HOST(pnw);
 
                        /* Turn off VBUS */
                        otg_set_vbus(&iotg->otg, false);
@@ -3196,11 +3209,7 @@ static void penwell_otg_work(struct work_struct *work)
                        /* Delete current timer and disable host function */
                        penwell_otg_del_timer(TA_WAIT_BCON_TMR);
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+                       PNW_STOP_HOST(pnw);
 
                        /* Turn off VBUS and enter PHY low power mode */
                        otg_set_vbus(&iotg->otg, false);
@@ -3253,11 +3262,7 @@ static void penwell_otg_work(struct work_struct *work)
 
                        penwell_otg_phy_low_power(0);
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+                       PNW_STOP_HOST(pnw);
 
                        /* Turn off VBUS */
                        otg_set_vbus(&iotg->otg, false);
@@ -3277,11 +3282,7 @@ static void penwell_otg_work(struct work_struct *work)
 
                        penwell_otg_phy_low_power(0);
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+                       PNW_STOP_HOST(pnw);
 
                        /* Turn off VBUS */
                        otg_set_vbus(&iotg->otg, false);
@@ -3309,11 +3310,7 @@ static void penwell_otg_work(struct work_struct *work)
                        /* Stop HNP polling */
                        iotg->stop_hnp_poll(iotg);
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+                       PNW_STOP_HOST(pnw);
 
                        /* Turn off VBUS */
                        otg_set_vbus(&iotg->otg, false);
@@ -3369,11 +3366,7 @@ static void penwell_otg_work(struct work_struct *work)
 
                        penwell_otg_phy_low_power(0);
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+                       PNW_STOP_HOST(pnw);
 
                        /* Turn off VBUS */
                        otg_set_vbus(&iotg->otg, false);
@@ -3425,11 +3418,7 @@ static void penwell_otg_work(struct work_struct *work)
                        /* Stop HNP polling */
                        iotg->stop_hnp_poll(iotg);
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+                       PNW_STOP_HOST(pnw);
 
                        /* Turn off VBUS */
                        otg_set_vbus(&iotg->otg, false);
@@ -3444,11 +3433,7 @@ static void penwell_otg_work(struct work_struct *work)
                        /* Delete current timer and clear flags */
                        penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+                       PNW_STOP_HOST(pnw);
 
                        /* Turn off VBUS */
                        otg_set_vbus(&iotg->otg, false);
@@ -3476,11 +3461,7 @@ static void penwell_otg_work(struct work_struct *work)
                        penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
                        penwell_otg_phy_low_power(0);
 
-                       if (iotg->stop_host)
-                               iotg->stop_host(iotg);
-                       else
-                               dev_dbg(pnw->dev,
-                                       "host driver has been removed.\n");
+                       PNW_STOP_HOST(pnw);
 
                        penwell_otg_phy_low_power(0);
                        hsm->b_bus_suspend = 0;
@@ -4210,6 +4191,11 @@ static int penwell_otg_probe(struct pci_dev *pdev,
                retval = -EBUSY;
                goto err;
        }
+       if (register_pm_notifier(&pnw_sleep_pm_notifier)) {
+               dev_dbg(pnw->dev, "Fail to register PM notifier\n");
+               retval = -EBUSY;
+               goto err;
+       }
 
 #ifdef CONFIG_BOARD_CTP
        /* Set up gpio for Clovertrail */
@@ -4435,10 +4421,7 @@ static int penwell_otg_suspend_noirq(struct device *dev)
        case OTG_STATE_A_SUSPEND:
                penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
                penwell_otg_HABA(0);
-               if (pnw->iotg.stop_host)
-                       pnw->iotg.stop_host(&pnw->iotg);
-               else
-                       dev_dbg(pnw->dev, "host driver has been removed.\n");
+               PNW_STOP_HOST(pnw);
                iotg->hsm.a_srp_det = 0;
 
                penwell_otg_phy_vbus_wakeup(false);
@@ -4464,10 +4447,7 @@ static int penwell_otg_suspend_noirq(struct device *dev)
                /* Stop HNP polling */
                iotg->stop_hnp_poll(iotg);
 
-               if (pnw->iotg.stop_host)
-                       pnw->iotg.stop_host(&pnw->iotg);
-               else
-                       dev_dbg(pnw->dev, "host driver has been stopped.\n");
+               PNW_STOP_HOST(pnw);
                iotg->hsm.b_bus_req = 0;
                iotg->otg.state = OTG_STATE_B_IDLE;
                break;
@@ -4480,10 +4460,7 @@ static int penwell_otg_suspend_noirq(struct device *dev)
 
                penwell_otg_HAAR(0);
 
-               if (pnw->iotg.stop_host)
-                       pnw->iotg.stop_host(&pnw->iotg);
-               else
-                       dev_dbg(pnw->dev, "host driver has been stopped.\n");
+               PNW_STOP_HOST(pnw);
                iotg->hsm.b_bus_req = 0;
                iotg->otg.state = OTG_STATE_B_IDLE;
                break;