add suspend & wake lock for usb subsys
authoryangkai <yangkai@ubuntu-fs>
Thu, 27 Jan 2011 08:53:03 +0000 (16:53 +0800)
committeryangkai <yangkai@ubuntu-fs>
Thu, 27 Jan 2011 08:53:03 +0000 (16:53 +0800)
drivers/usb/dwc_otg/dwc_otg_driver.c
drivers/usb/dwc_otg/dwc_otg_hcd.c
drivers/usb/dwc_otg/dwc_otg_pcd.c
drivers/usb/dwc_otg/dwc_otg_pcd.h

index 56cefcc65b6da368bbae56910d70e676cc34d715..987794f7fe95cd85b5442fc2f9743bb08fde06cb 100755 (executable)
@@ -1158,6 +1158,8 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev)
        return retval;
 }
 
+#ifndef DWC_HOST_ONLY
+extern int rk28_usb_suspend( int exitsuspend );
 static int dwc_otg_driver_suspend(struct platform_device *_dev , pm_message_t state )
 {
        struct device *dev = &_dev->dev;
@@ -1171,8 +1173,15 @@ static int dwc_otg_driver_suspend(struct platform_device *_dev , pm_message_t st
     /* Clear any pending interrupts */
     dwc_write_reg32( &core_if->core_global_regs->gintsts, 0xFFFFFFFF);
     dwc_otg_disable_global_interrupts(core_if);
+    rk28_usb_suspend(0);
     return 0;
 }
+#else
+static int dwc_otg_driver_suspend(struct platform_device *_dev , pm_message_t state )
+{
+    return 0;
+}
+#endif
 
 static int dwc_otg_driver_resume(struct platform_device *_dev )
 {
@@ -1518,27 +1527,9 @@ fail1:
        return retval;
 }
 
-static int host11_driver_suspend(struct platform_device *_dev , pm_message_t state )
-{
-       //struct device *dev = &_dev->dev;
-       //dwc_otg_device_t *otg_dev = dev->platform_data;
-    //dwc_otg_core_if_t *core_if = otg_dev->core_if;
-    return 0;
-}
-
-static int host11_driver_resume(struct platform_device *_dev )
-{
-       //struct device *dev = &_dev->dev;
-       //dwc_otg_device_t *otg_dev = dev->platform_data;
-    //dwc_otg_core_if_t *core_if = otg_dev->core_if;
-    return 0;
-}
-
 static struct platform_driver host11_driver = {
        .probe = host11_driver_probe,
        .remove = host11_driver_remove,
-       .suspend = host11_driver_suspend,
-       .resume = host11_driver_resume,
        .driver = {
                   .name = "usb11_host",
                   .owner = THIS_MODULE},
@@ -1806,27 +1797,9 @@ static __devinit int host20_driver_probe(struct platform_device *pdev)
        return retval;
 }
 
-static int host20_driver_suspend(struct platform_device *_dev , pm_message_t state )
-{
-       //struct device *dev = &_dev->dev;
-       //dwc_otg_device_t *otg_dev = dev->platform_data;
-    //dwc_otg_core_if_t *core_if = otg_dev->core_if;
-    return 0;
-}
-
-static int host20_driver_resume(struct platform_device *_dev )
-{
-       //struct device *dev = &_dev->dev;
-       //dwc_otg_device_t *otg_dev = dev->platform_data;
-    //dwc_otg_core_if_t *core_if = otg_dev->core_if;
-    return 0;
-}
-
 static struct platform_driver host20_driver = {
        .probe = host20_driver_probe,
        .remove = host20_driver_remove,
-       .suspend = host20_driver_suspend,
-       .resume = host20_driver_resume,
        .driver = {
                   .name = "usb20_host",
                   .owner = THIS_MODULE},
index 7ff7db6ea73cc2617fbcd30ebdb7fbbb07730c15..226a06ab59444f0ad619953f1df117d87d5747ec 100755 (executable)
@@ -38,6 +38,7 @@
  * This file contains the implementation of the HCD. In Linux, the HCD
  * implements the hc_driver API.
  */
+#include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -57,7 +58,6 @@
 
 static int dwc_otg_hcd_suspend(struct usb_hcd *hcd)
 {
-#if 1
     dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (hcd);
     dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
     hprt0_data_t hprt0;
@@ -69,43 +69,49 @@ static int dwc_otg_hcd_suspend(struct usb_hcd *hcd)
        return 0;
     }
     hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
-    DWC_PRINT("%s, HPRT0:0x%x\n",__func__,hprt0.d32);
-    //partial power-down
-    if(!hprt0.b.prtsusp)
+    DWC_PRINT("%s suspend, HPRT0:0x%x\n",hcd->self.bus_name,hprt0.d32);
+    if(hprt0.b.prtconnsts)  // usb device connected
     {
-        //hprt0.d32 = 0;
-        hprt0.b.prtsusp = 1;
-        hprt0.b.prtena = 0;
-        dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+        //partial power-down
+        if(!hprt0.b.prtsusp)
+        {
+            //hprt0.d32 = 0;
+            hprt0.b.prtsusp = 1;
+            hprt0.b.prtena = 0;
+            dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+        }
+        udelay(10);
+        hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
+        if(!hprt0.b.prtsusp)
+        {
+            //hprt0.d32 = 0;
+            hprt0.b.prtsusp = 1;
+            hprt0.b.prtena = 0;
+            dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+        }
+        mdelay(5);
+        pcgcctl.d32 = dwc_read_reg32(core_if->pcgcctl);
+        pcgcctl.b.pwrclmp = 1;//power clamp
+        dwc_write_reg32(core_if->pcgcctl, pcgcctl.d32);
+        udelay(1);
+        //pcgcctl.b.rstpdwnmodule = 1;//reset PDM
+        pcgcctl.b.stoppclk = 1;//stop phy clk
+        dwc_write_reg32(core_if->pcgcctl, pcgcctl.d32);
     }
-    udelay(10);
-    hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
-    DWC_PRINT("%s, HPRT0:0x%x\n",__func__,hprt0.d32);
-    if(!hprt0.b.prtsusp)
+    else    //no device connect
     {
-        //hprt0.d32 = 0;
-        hprt0.b.prtsusp = 1;
-        hprt0.b.prtena = 0;
-        dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+        if (core_if->hcd_cb && core_if->hcd_cb->suspend) {
+                core_if->hcd_cb->suspend( core_if->hcd_cb->p, 0);
+        }
     }
-    mdelay(5);
-#if 1
-    pcgcctl.d32 = dwc_read_reg32(core_if->pcgcctl);
-    pcgcctl.b.pwrclmp = 1;//power clamp
-    dwc_write_reg32(core_if->pcgcctl, pcgcctl.d32);
-    udelay(1);
-    //pcgcctl.b.rstpdwnmodule = 1;//reset PDM
-    pcgcctl.b.stoppclk = 1;//stop phy clk
-    dwc_write_reg32(core_if->pcgcctl, pcgcctl.d32);
-#endif
-#endif
+    clk_disable(core_if->otg_dev->phyclk);
+    clk_disable(core_if->otg_dev->ahbclk);
     //power off
     return 0;
 }
 
 static int dwc_otg_hcd_resume(struct usb_hcd *hcd)
 {
-#if 1
     dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (hcd);
     dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
     hprt0_data_t hprt0;
@@ -117,7 +123,9 @@ static int dwc_otg_hcd_resume(struct usb_hcd *hcd)
        DWC_PRINT("%s, usb device mode\n", __func__);
        return 0;
     }
-#if 1
+    clk_enable(core_if->otg_dev->phyclk);
+    clk_enable(core_if->otg_dev->ahbclk);
+    
     //partial power-down
     //power on
     pcgcctl.d32 = dwc_read_reg32(core_if->pcgcctl);;
@@ -127,38 +135,49 @@ static int dwc_otg_hcd_resume(struct usb_hcd *hcd)
     pcgcctl.b.pwrclmp = 0;//power clamp
     dwc_write_reg32(core_if->pcgcctl, pcgcctl.d32);
     udelay(2);
-#endif
+
     gintmsk.d32 = dwc_read_reg32(&core_if->core_global_regs->gintmsk);
     gintmsk.b.portintr = 0;
     dwc_write_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
-
+        
     hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
-    DWC_PRINT("%s, HPRT0:0x%x\n",__func__,hprt0.d32);
-    hprt0.b.prtpwr = 1;    
-    hprt0.b.prtres = 1;
-    hprt0.b.prtena = 0;
-    dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
-    mdelay(20);
-    hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);       
-    DWC_PRINT("%s, HPRT0:0x%x\n",__func__,hprt0.d32);
-    //hprt0.d32 = 0;
-    hprt0.b.prtpwr = 1;    
-    hprt0.b.prtres = 0;
-    hprt0.b.prtena = 0;
-    dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
-    hprt0.d32 = 0;
-    hprt0.b.prtpwr = 1;
-    hprt0.b.prtena = 0;
-    hprt0.b.prtconndet = 1;
-    dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
-
-    hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);       
-    DWC_PRINT("%s, HPRT0:0x%x\n",__func__,hprt0.d32);
-       
-    gintmsk.b.portintr = 1;
-    dwc_write_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
-    mdelay(10);
-#endif
+    DWC_PRINT("%s resume, HPRT0:0x%x\n",hcd->self.bus_name,hprt0.d32);
+    if(hprt0.b.prtconnsts)
+    {
+        //hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
+        //DWC_PRINT("%s, HPRT0:0x%x\n",hcd->self.bus_name,hprt0.d32);
+        hprt0.b.prtpwr = 1;    
+        hprt0.b.prtres = 1;
+        hprt0.b.prtena = 0;
+        dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+        mdelay(20);
+        hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);   
+        //DWC_PRINT("%s, HPRT0:0x%x\n",hcd->self.bus_name,hprt0.d32);
+        //hprt0.d32 = 0;
+        hprt0.b.prtpwr = 1;    
+        hprt0.b.prtres = 0;
+        hprt0.b.prtena = 0;
+        dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+        hprt0.d32 = 0;
+        hprt0.b.prtpwr = 1;
+        hprt0.b.prtena = 0;
+        hprt0.b.prtconndet = 1;
+        dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+
+        hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);   
+        //DWC_PRINT("%s, HPRT0:0x%x\n",hcd->self.bus_name,hprt0.d32);
+       
+        gintmsk.b.portintr = 1;
+        dwc_write_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
+        mdelay(10);
+    }
+    else
+    {
+        if (core_if->hcd_cb && core_if->hcd_cb->suspend) {
+                core_if->hcd_cb->suspend( core_if->hcd_cb->p, 1);
+        }
+    }
+
        return 0;
 }
 
index c574339595bdec72b1a9af859d407733ed52c81f..0451addf8dc0eb11865384492399014744f94ea2 100755 (executable)
 #include "dwc_otg_pcd.h"
 #include "dwc_otg_regs.h"
 
-#ifdef CONFIG_ANDROID_POWER
 #include <linux/usb/composite.h>
-#include <linux/android_power.h>
-android_suspend_lock_t usb_msc_lock;
-#endif
-
 
 /**
  * Static PCD pointer for use in usb_gadget_register_driver and
@@ -1094,7 +1089,7 @@ static int32_t dwc_otg_pcd_stop_cb( void *_p )
 static int32_t dwc_otg_pcd_suspend_cb( void *_p ,int suspend)
 {
        dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *)_p;
-#ifdef CONFIG_ANDROID_POWER
+//#ifdef CONFIG_ANDROID_POWER
        /* yk@rk 20100520
         * PC disconnect the USB, unlock the msc_lock and
         * system can enter level 2 sleep mode.
@@ -1106,7 +1101,7 @@ static int32_t dwc_otg_pcd_suspend_cb( void *_p ,int suspend)
                if(cdev->config)
                        pcd->conn_status = 3;
        }
-#endif         
+//#endif               
        if (pcd->driver && pcd->driver->resume) 
        {
                SPIN_UNLOCK(&pcd->lock);
@@ -1593,18 +1588,24 @@ int dwc_otg_reset( void )
     //DWC_PRINT("%s::otg reset connect!!!\n" , __func__ );
     return 0;
 }
-void dwc_otg_msc_lock(void)
+void dwc_otg_msc_lock(dwc_otg_pcd_t *pcd)
 {
-#ifdef CONFIG_ANDROID_POWER
-       android_lock_suspend(&usb_msc_lock);
-#endif
+       unsigned long           flags;
+
+       spin_lock_irqsave(&pcd->lock, flags);
+
+    wake_lock(&pcd->wake_lock);
+
+       spin_unlock_irqrestore(&pcd->lock, flags);
+
 }
 
-void dwc_otg_msc_unlock(void)
+void dwc_otg_msc_unlock(dwc_otg_pcd_t *pcd)
 {
-#ifdef CONFIG_ANDROID_POWER
-       android_unlock_suspend(&usb_msc_lock);
-#endif
+       unsigned long           flags;
+       spin_lock_irqsave(&pcd->lock, flags);
+       wake_unlock(&pcd->wake_lock);
+    spin_unlock_irqrestore(&pcd->lock, flags);
 }
 static void dwc_phy_reconnect(struct work_struct *work)
 {
@@ -1617,7 +1618,7 @@ static void dwc_phy_reconnect(struct work_struct *work)
     core_if = GET_CORE_IF(pcd); 
     gctrl.d32 = dwc_read_reg32( &core_if->core_global_regs->gotgctl );
     if( gctrl.b.bsesvld  ) {
-        dwc_otg_msc_lock();
+        dwc_otg_msc_lock(pcd);
         pcd->conn_status++;
            dwc_pcd_reset(pcd);
        /*
@@ -1662,7 +1663,7 @@ static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata )
            }
 
         } else if((_pcd->conn_status>0)&&(_pcd->conn_status <3)) {
-            dwc_otg_msc_unlock();
+            dwc_otg_msc_unlock(_pcd);
             DWC_PRINT("********soft reconnect******************************************\n");
             _pcd->vbus_status =0;
             
@@ -1682,8 +1683,10 @@ static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata )
         else if(_pcd->conn_status ==3)
         {
                        //*Á¬½Ó²»ÉÏʱÊÍ·ÅËø£¬ÔÊÐíϵͳ½øÈë¶þ¼¶Ë¯Ãߣ¬yk@rk,20100331*//
-            dwc_otg_msc_unlock();
+            dwc_otg_msc_unlock(_pcd);
             _pcd->conn_status++;
+            if((dwc_read_reg32((uint32_t*)((uint8_t *)_pcd->otg_dev->base + DWC_OTG_HOST_PORT_REGS_OFFSET))&0xc00) == 0xc00)
+                _pcd->vbus_status = 2;
         }
     } else {
         //DWC_PRINT("new vbus=%d,old vbus=%d\n" , gctrl.b.bsesvld , _pcd->vbus_status );
@@ -1691,7 +1694,7 @@ static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata )
         if(_pcd->conn_status)
         {
              _pcd->conn_status = 0;
-             dwc_otg_msc_unlock();
+             dwc_otg_msc_unlock(_pcd);
         }
         /* every 500 ms open usb phy power and start 1 jiffies timer to get vbus */
         if( _pcd->phy_suspend == 0 ) {
@@ -1718,7 +1721,7 @@ void dwc_otg_pcd_start_vbus_timer( dwc_otg_pcd_t * _pcd )
          * when receive reset int,the vbus state may not be update,so 
          * always start timer here.
          */                
-        mod_timer( vbus_timer , jiffies + (HZ+(HZ/2)));
+        mod_timer( vbus_timer , jiffies + (HZ<<2));
 }
 
 /*
@@ -1809,10 +1812,8 @@ int dwc_otg_pcd_init(struct device *dev)
                return -EBUSY;
        }
     
-#ifdef CONFIG_ANDROID_POWER
-    usb_msc_lock.name = "usb_msc";
-    android_init_suspend_lock(&usb_msc_lock);
-#endif
+       wake_lock_init(&pcd->wake_lock, WAKE_LOCK_SUSPEND,
+                          "usb_pcd");
 
        /*
         * Initialize EP structures
@@ -1865,6 +1866,8 @@ void dwc_otg_pcd_remove( struct device *dev )
        
        DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
 
+       wake_lock_destroy(&pcd->wake_lock);
+
        /*
         * Free the IRQ 
         */
index 7d44d18e391ad9480b3762c9fcd799fab4090079..bb055395c043e39712c4c2ab2c0589e72b5c18d4 100755 (executable)
@@ -42,6 +42,7 @@
 #include <linux/usb/gadget.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
+#include <linux/wakelock.h>
 
 struct dwc_otg_device;
 
@@ -201,6 +202,9 @@ typedef struct dwc_otg_pcd
         * every 500 ms. */
        struct timer_list check_vbus_timer;
     struct delayed_work        reconnect;
+
+    /** pervent device suspend while usb connected */
+    struct wake_lock wake_lock;
 } dwc_otg_pcd_t;