From adb6ec9aaa875545c492b09c95791f90ad83f7c0 Mon Sep 17 00:00:00 2001 From: yangkai Date: Tue, 21 Dec 2010 17:25:22 +0800 Subject: [PATCH] add clock gate in usb module --- drivers/usb/dwc_otg/Kconfig | 1 + drivers/usb/dwc_otg/dwc_otg_cil.c | 3 +- drivers/usb/dwc_otg/dwc_otg_driver.c | 55 +++++++- drivers/usb/dwc_otg/dwc_otg_driver.h | 24 ++-- drivers/usb/dwc_otg/dwc_otg_pcd.c | 194 +++++++++++++-------------- 5 files changed, 165 insertions(+), 112 deletions(-) diff --git a/drivers/usb/dwc_otg/Kconfig b/drivers/usb/dwc_otg/Kconfig index e5573885b786..24267cd81b1a 100755 --- a/drivers/usb/dwc_otg/Kconfig +++ b/drivers/usb/dwc_otg/Kconfig @@ -14,6 +14,7 @@ config USB20_HOST config USB20_OTG tristate "RockChip USB 2.0 OTG controller" + depends on USB||USB_GADGET ---help--- This driver supports Rockchip USB2.0 DWC_OTG controller. diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.c b/drivers/usb/dwc_otg/dwc_otg_cil.c index a5f2c07dda45..853777fea799 100755 --- a/drivers/usb/dwc_otg/dwc_otg_cil.c +++ b/drivers/usb/dwc_otg/dwc_otg_cil.c @@ -614,7 +614,7 @@ void dwc_otg_core_init(dwc_otg_core_if_t *_core_if) case DWC_INT_DMA_ARCH: /* rockchip dwc_otg */ DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n"); - ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR; + ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR16; // yk@20101221 _core_if->dma_enable = (_core_if->core_params->dma_enable != 0); break; @@ -812,6 +812,7 @@ void dwc_otg_core_dev_init(dwc_otg_core_if_t *_core_if) gahbcfg.d32 = 0; gahbcfg.b.glblintrmsk = 1; gahbcfg.b.dmaenable = 1; + gahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR16; // yk@20101221 dwc_write_reg32( &global_regs->gahbcfg, gahbcfg.d32 ); } diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.c b/drivers/usb/dwc_otg/dwc_otg_driver.c index 6b6361d59673..e5aa34a1648b 100755 --- a/drivers/usb/dwc_otg/dwc_otg_driver.c +++ b/drivers/usb/dwc_otg/dwc_otg_driver.c @@ -824,6 +824,8 @@ static int dwc_otg_driver_remove(struct platform_device *pdev) { iounmap(otg_dev->base); } + clk_put(otg_dev->clk); + clk_disable(otg_dev->clk); kfree(otg_dev); /* @@ -853,8 +855,8 @@ static int dwc_otg_driver_remove(struct platform_device *pdev) */ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) { - struct resource *res_base; int retval = 0; + struct resource *res_base; struct device *dev = &pdev->dev; dwc_otg_device_t *dwc_otg_device; int32_t snpsid; @@ -864,7 +866,16 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) *Enable usb phy */ unsigned int * otg_phy_con1 = (unsigned int*)(USB_GRF_CON); + struct clk* clk; + clk = clk_get(NULL, "otgphy0"); + if (IS_ERR(clk)) { + retval = PTR_ERR(clk); + DWC_ERROR("can't get USB clock of otgphy0\n"); + goto fail; + } + clk_enable(clk); + regval = * otg_phy_con1; regval |= (0x01<<2); regval |= (0x01<<3); // exit suspend. @@ -896,6 +907,7 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) memset(dwc_otg_device, 0, sizeof(*dwc_otg_device)); dwc_otg_device->reg_offset = 0xFFFFFFFF; + dwc_otg_device->clk = clk; /* * Map the DWC_otg Core memory into virtual address space. */ @@ -1046,7 +1058,6 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) dwc_otg_enable_global_interrupts( dwc_otg_device->core_if ); DWC_PRINT("dwc_otg_driver_probe end, everest\n"); return 0; - fail: devm_kfree(&pdev->dev, dwc_otg_device); DWC_PRINT("dwc_otg_driver_probe fail,everest\n"); @@ -1191,6 +1202,8 @@ static int host11_driver_remove(struct platform_device *pdev) { iounmap(otg_dev->base); } + clk_put(otg_dev->clk); + clk_disable(otg_dev->clk); kfree(otg_dev); /* @@ -1224,6 +1237,25 @@ static __devinit int host11_driver_probe(struct platform_device *pdev) *Enable usb phy */ unsigned int * otg_phy_con1 = (unsigned int*)(USB_GRF_CON); + struct clk* clk; + + clk = clk_get(NULL, "uhost"); + if (IS_ERR(clk)) { + retval = PTR_ERR(clk); + DWC_ERROR("can't get USB clock of uhost\n"); + goto fail; + } + clk_enable(clk); + if (clk_get_rate(clk) != 48000000) { + DWC_PRINT("Bad USB clock (%d Hz), changing to 48000000 Hz\n", + (int)clk_get_rate(clk)); + if (clk_set_rate(clk, 48000000)) { + DWC_ERROR("Unable to set correct USB clock (48MHz)\n"); + retval = -EIO; + goto fail1; + } + } + *otg_phy_con1 &= ~(0x01<<28); // exit suspend. #if 0 *otg_phy_con1 |= (0x01<<2); @@ -1246,6 +1278,7 @@ static __devinit int host11_driver_probe(struct platform_device *pdev) memset(dwc_otg_device, 0, sizeof(*dwc_otg_device)); dwc_otg_device->reg_offset = 0xFFFFFFFF; + dwc_otg_device->clk = clk; /* * Map the DWC_otg Core memory into virtual address space. */ @@ -1358,6 +1391,10 @@ static __devinit int host11_driver_probe(struct platform_device *pdev) dwc_otg_enable_global_interrupts( dwc_otg_device->core_if ); DWC_PRINT("host11_driver_probe end, everest\n"); return 0; + +fail1: + clk_put(clk); + clk_disable(clk); fail: devm_kfree(&pdev->dev, dwc_otg_device); @@ -1439,12 +1476,15 @@ static int host20_driver_remove(struct platform_device *pdev) { iounmap(otg_dev->base); } + clk_put(otg_dev->clk); + clk_disable(otg_dev->clk); kfree(otg_dev); /* * Clear the drvdata pointer. */ dev->platform_data = 0; + return 0; } @@ -1473,6 +1513,16 @@ static __devinit int host20_driver_probe(struct platform_device *pdev) *Enable usb phy */ unsigned int * otg_phy_con1 = (unsigned int*)(USB_GRF_CON); + struct clk* clk; + + clk = clk_get(NULL, "otgphy1"); + if (IS_ERR(clk)) { + retval = PTR_ERR(clk); + DWC_ERROR(&"can't get USB clock of otgphy1\n"); + goto fail; + } + clk_enable(clk); + otgreg = * otg_phy_con1; otgreg |= (0x01<<13); // software control otgreg |= (0x01<<14); // exit suspend. @@ -1499,6 +1549,7 @@ static __devinit int host20_driver_probe(struct platform_device *pdev) memset(dwc_otg_device, 0, sizeof(*dwc_otg_device)); dwc_otg_device->reg_offset = 0xFFFFFFFF; + dwc_otg_device->clk = clk; /* * Map the DWC_otg Core memory into virtual address space. */ diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.h b/drivers/usb/dwc_otg/dwc_otg_driver.h index fa104e0fdcbf..702b9744b6ab 100755 --- a/drivers/usb/dwc_otg/dwc_otg_driver.h +++ b/drivers/usb/dwc_otg/dwc_otg_driver.h @@ -49,21 +49,23 @@ struct dwc_otg_hcd; */ typedef struct dwc_otg_device { - /** Base address returned from ioremap() */ - void *base; + /** Base address returned from ioremap() */ + void *base; - /** Pointer to the core interface structure. */ - dwc_otg_core_if_t *core_if; + /** Pointer to the core interface structure. */ + dwc_otg_core_if_t *core_if; - /** Register offset for Diagnostic API.*/ - uint32_t reg_offset; - - /** Pointer to the PCD structure. */ - struct dwc_otg_pcd *pcd; + /** Register offset for Diagnostic API.*/ + uint32_t reg_offset; + + /** Pointer to the PCD structure. */ + struct dwc_otg_pcd *pcd; - /** Pointer to the HCD structure. */ - struct dwc_otg_hcd *hcd; + /** Pointer to the HCD structure. */ + struct dwc_otg_hcd *hcd; + struct clk* clk; + /** Flag to indicate whether the common IRQ handler is installed. */ uint8_t common_irq_installed; diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.c b/drivers/usb/dwc_otg/dwc_otg_pcd.c index c1fe4382d428..42efcdf41fbc 100755 --- a/drivers/usb/dwc_otg/dwc_otg_pcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_pcd.c @@ -1540,30 +1540,29 @@ int rk28_usb_suspend( int exitsuspend ) { dwc_otg_pcd_t *pcd = s_pcd; - unsigned int * otg_phy_con1 = (unsigned int*)(USB_GRF_CON); -// unsigned int * usb_core_ctrl_reg = (unsigned int*)(USB_OTG_BASE_ADDR_VA); - if(exitsuspend && (pcd->phy_suspend == 1)) { - pcd->phy_suspend = 0; - *otg_phy_con1 |= (0x01<<2); - *otg_phy_con1 |= (0x01<<3); // exit suspend. - *otg_phy_con1 &= ~(0x01<<2); - - /* 20091011,reenable usb phy ,will raise reset intr */ - //debug_print("enable usb phy\n"); - DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n"); - } - if( !exitsuspend && (pcd->phy_suspend == 0)) { - if(1) {//!__rkusb_debug_mod() - pcd->phy_suspend = 1; - *otg_phy_con1 |= (0x01<<2); - *otg_phy_con1 &= ~(0x01<<3); // enter suspend. - //*otg_phy_con1 &= ~(0x01<<2); - //debug_print("disable usb phy\n"); - } - DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); - } + unsigned int * otg_phy_con1 = (unsigned int*)(USB_GRF_CON); + if(exitsuspend && (pcd->phy_suspend == 1)) { + clk_enable(pcd->otg_dev->clk); + pcd->phy_suspend = 0; + *otg_phy_con1 |= (0x01<<2); + *otg_phy_con1 |= (0x01<<3); // exit suspend. + *otg_phy_con1 &= ~(0x01<<2); - return pcd->phy_suspend; + /* 20091011,reenable usb phy ,will raise reset intr */ + //debug_print("enable usb phy\n"); + DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n"); + } + if( !exitsuspend && (pcd->phy_suspend == 0)) { + pcd->phy_suspend = 1; + *otg_phy_con1 |= (0x01<<2); + *otg_phy_con1 &= ~(0x01<<3); // enter suspend. + clk_disable(pcd->otg_dev->clk); + //*otg_phy_con1 &= ~(0x01<<2); + //debug_print("disable usb phy\n"); + DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); + } + + return pcd->phy_suspend; } void rk28_usb_force_resume( void ) { @@ -1607,28 +1606,27 @@ void dwc_otg_msc_unlock(void) } static void dwc_phy_reconnect(struct work_struct *work) { - dwc_otg_pcd_t *pcd; - dwc_otg_core_if_t *core_if; - gotgctl_data_t gctrl; - dctl_data_t dctl = {.d32=0}; - - pcd = container_of(work, dwc_otg_pcd_t, reconnect.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(); -// pcd->vbus_status = 1; /* set after softconnect */ - pcd->conn_status++; - dwc_pcd_reset(pcd); - /* - * Enable the global interrupt after all the interrupt - * handlers are installed. - */ + dwc_otg_pcd_t *pcd; + dwc_otg_core_if_t *core_if; + gotgctl_data_t gctrl; + dctl_data_t dctl = {.d32=0}; + + pcd = container_of(work, dwc_otg_pcd_t, reconnect.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(); + pcd->conn_status++; + dwc_pcd_reset(pcd); + /* + * Enable the global interrupt after all the interrupt + * handlers are installed. + */ dctl.d32 = dwc_read_reg32( &core_if->dev_if->dev_global_regs->dctl ); dctl.b.sftdiscon = 0; dwc_write_reg32( &core_if->dev_if->dev_global_regs->dctl, dctl.d32 ); DWC_PRINT("********soft connect!!!*****************************************\n"); - } + } } static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata ) @@ -1645,66 +1643,65 @@ static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata ) _pcd->check_vbus_timer.expires = jiffies + (HZ); /* 1 s */ if( gctrl.b.bsesvld ) { - /* if usb not connect before ,then start connect */ - if( _pcd->vbus_status == 0 ) { - DWC_PRINT("********vbus detect*********************************************\n"); -// _pcd->conn_status = - _pcd->vbus_status = 1; - /* soft disconnect */ - dctl.d32 = dwc_read_reg32( &core_if->dev_if->dev_global_regs->dctl ); - dctl.b.sftdiscon = 1; - dwc_write_reg32( &core_if->dev_if->dev_global_regs->dctl, dctl.d32 ); - /* Clear any pending interrupts */ - dwc_write_reg32( &core_if->core_global_regs->gintsts, 0xFFFFFFFF); - if(_pcd->conn_en) - { - schedule_delayed_work( &_pcd->reconnect , 8 ); /* delay 1 jiffies */ - _pcd->check_vbus_timer.expires = jiffies + (HZ<<1); /* 1 s */ - } - - } else if((_pcd->conn_status>0)&&(_pcd->conn_status <3)) { - dwc_otg_msc_unlock(); - DWC_PRINT("********soft reconnect******************************************\n"); - _pcd->vbus_status =0; - - /* soft disconnect */ - dctl.d32 = dwc_read_reg32( &core_if->dev_if->dev_global_regs->dctl ); - dctl.b.sftdiscon = 1; - dwc_write_reg32( &core_if->dev_if->dev_global_regs->dctl, dctl.d32 ); - /* Clear any pending interrupts */ - dwc_write_reg32( &core_if->core_global_regs->gintsts, 0xFFFFFFFF); - } - else if((_pcd->conn_en)&&(_pcd->conn_status == 0)) + /* if usb not connect before ,then start connect */ + if( _pcd->vbus_status == 0 ) { + DWC_PRINT("********vbus detect*********************************************\n"); + _pcd->vbus_status = 1; + /* soft disconnect */ + dctl.d32 = dwc_read_reg32( &core_if->dev_if->dev_global_regs->dctl ); + dctl.b.sftdiscon = 1; + dwc_write_reg32( &core_if->dev_if->dev_global_regs->dctl, dctl.d32 ); + /* Clear any pending interrupts */ + dwc_write_reg32( &core_if->core_global_regs->gintsts, 0xFFFFFFFF); + if(_pcd->conn_en) { - - schedule_delayed_work( &_pcd->reconnect , 8 ); /* delay 1 jiffies */ - _pcd->check_vbus_timer.expires = jiffies + (HZ<<1); /* 1 s */ + schedule_delayed_work( &_pcd->reconnect , 8 ); /* delay 1 jiffies */ + _pcd->check_vbus_timer.expires = jiffies + (HZ<<1); /* 1 s */ } - else if(_pcd->conn_status ==3) - { - //*Á¬½Ó²»ÉÏʱÊÍ·ÅËø£¬ÔÊÐíϵͳ½øÈë¶þ¼¶Ë¯Ãߣ¬yk@rk,20100331*// - dwc_otg_msc_unlock(); - _pcd->conn_status++; - } + + } else if((_pcd->conn_status>0)&&(_pcd->conn_status <3)) { + dwc_otg_msc_unlock(); + DWC_PRINT("********soft reconnect******************************************\n"); + _pcd->vbus_status =0; + + /* soft disconnect */ + dctl.d32 = dwc_read_reg32( &core_if->dev_if->dev_global_regs->dctl ); + dctl.b.sftdiscon = 1; + dwc_write_reg32( &core_if->dev_if->dev_global_regs->dctl, dctl.d32 ); + /* Clear any pending interrupts */ + dwc_write_reg32( &core_if->core_global_regs->gintsts, 0xFFFFFFFF); + } + else if((_pcd->conn_en)&&(_pcd->conn_status == 0)) + { + + schedule_delayed_work( &_pcd->reconnect , 8 ); /* delay 1 jiffies */ + _pcd->check_vbus_timer.expires = jiffies + (HZ<<1); /* 1 s */ + } + else if(_pcd->conn_status ==3) + { + //*Á¬½Ó²»ÉÏʱÊÍ·ÅËø£¬ÔÊÐíϵͳ½øÈë¶þ¼¶Ë¯Ãߣ¬yk@rk,20100331*// + dwc_otg_msc_unlock(); + _pcd->conn_status++; + } } else { - //DWC_PRINT("new vbus=%d,old vbus=%d\n" , gctrl.b.bsesvld , _pcd->vbus_status ); - _pcd->vbus_status = 0; - if(_pcd->conn_status) - { - _pcd->conn_status = 0; - dwc_otg_msc_unlock(); - } - /* every 500 ms open usb phy power and start 1 jiffies timer to get vbus */ - if( _pcd->phy_suspend == 0 ) { - /* no vbus detect here , close usb phy for 500ms */ - rk28_usb_suspend( 0 ); - _pcd->check_vbus_timer.expires = jiffies + (HZ/2); /* 500 ms */ - } else if( _pcd->phy_suspend == 1 ) { - rk28_usb_suspend( 1 ); - /*20100325 yk@rk,delay 2-->8,for host connect id detect*/ - _pcd->check_vbus_timer.expires = jiffies + 8; /* 20091127,HSL@RK,1-->2 */ - - } + //DWC_PRINT("new vbus=%d,old vbus=%d\n" , gctrl.b.bsesvld , _pcd->vbus_status ); + _pcd->vbus_status = 0; + if(_pcd->conn_status) + { + _pcd->conn_status = 0; + dwc_otg_msc_unlock(); + } + /* every 500 ms open usb phy power and start 1 jiffies timer to get vbus */ + if( _pcd->phy_suspend == 0 ) { + /* no vbus detect here , close usb phy for 500ms */ + rk28_usb_suspend( 0 ); + _pcd->check_vbus_timer.expires = jiffies + (HZ/2); /* 500 ms */ + } else if( _pcd->phy_suspend == 1 ) { + rk28_usb_suspend( 1 ); + /*20100325 yk@rk,delay 2-->8,for host connect id detect*/ + _pcd->check_vbus_timer.expires = jiffies + 8; /* 20091127,HSL@RK,1-->2 */ + + } } //DWC_PRINT("%s:restart check vbus timer\n" , __func__ ); add_timer(&_pcd->check_vbus_timer); @@ -1851,6 +1848,7 @@ int dwc_otg_pcd_init(struct device *dev) INIT_DELAYED_WORK(&pcd->reconnect , dwc_phy_reconnect); pcd->vbus_status = 0; + pcd->phy_suspend = 0; if(dwc_otg_is_device_mode(core_if)) dwc_otg_pcd_start_vbus_timer( pcd ); return 0; -- 2.34.1