From 31f284d67cef70eeb8b6bf1c0d489f5b34206d86 Mon Sep 17 00:00:00 2001 From: yangkai Date: Thu, 27 Jan 2011 16:53:03 +0800 Subject: [PATCH] add suspend & wake lock for usb subsys --- drivers/usb/dwc_otg/dwc_otg_driver.c | 45 ++------- drivers/usb/dwc_otg/dwc_otg_hcd.c | 133 +++++++++++++++------------ drivers/usb/dwc_otg/dwc_otg_pcd.c | 51 +++++----- drivers/usb/dwc_otg/dwc_otg_pcd.h | 4 + 4 files changed, 116 insertions(+), 117 deletions(-) diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.c b/drivers/usb/dwc_otg/dwc_otg_driver.c index 56cefcc65b6d..987794f7fe95 100755 --- a/drivers/usb/dwc_otg/dwc_otg_driver.c +++ b/drivers/usb/dwc_otg/dwc_otg_driver.c @@ -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}, diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.c b/drivers/usb/dwc_otg/dwc_otg_hcd.c index 7ff7db6ea73c..226a06ab5944 100755 --- a/drivers/usb/dwc_otg/dwc_otg_hcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_hcd.c @@ -38,6 +38,7 @@ * This file contains the implementation of the HCD. In Linux, the HCD * implements the hc_driver API. */ +#include #include #include #include @@ -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; } diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.c b/drivers/usb/dwc_otg/dwc_otg_pcd.c index c574339595bd..0451addf8dc0 100755 --- a/drivers/usb/dwc_otg/dwc_otg_pcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_pcd.c @@ -83,12 +83,7 @@ #include "dwc_otg_pcd.h" #include "dwc_otg_regs.h" -#ifdef CONFIG_ANDROID_POWER #include -#include -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 */ diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.h b/drivers/usb/dwc_otg/dwc_otg_pcd.h index 7d44d18e391a..bb055395c043 100755 --- a/drivers/usb/dwc_otg/dwc_otg_pcd.h +++ b/drivers/usb/dwc_otg/dwc_otg_pcd.h @@ -42,6 +42,7 @@ #include #include #include +#include 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; -- 2.34.1