Merge remote-tracking branch 'kernel-2.6.32/develop' into develop-2.6.36
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc_otg / dwc_otg_hcd.c
index 79502141b6f194e84284ff460f7b38340f5bf890..69bbadf593987d06c315d40fc0bb182c80b73dba 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>
 
 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;
     pcgcctl_data_t pcgcctl;
-    //dwc_debug(1);
     
     if(core_if->op_state == B_PERIPHERAL)
     {
-       printk("%s, usb device mode\n", __func__);
+       DWC_PRINT("%s, usb device mode\n", __func__);
        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
+    udelay(3);
+    #ifndef CONFIG_DWC_REMOTE_WAKEUP
+    clk_disable(core_if->otg_dev->phyclk);
+    clk_disable(core_if->otg_dev->ahbclk);
+    #endif
     //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;
@@ -115,10 +123,13 @@ static int dwc_otg_hcd_resume(struct usb_hcd *hcd)
        
     if(core_if->op_state == B_PERIPHERAL)
     {
-       printk("%s, usb device mode\n", __func__);
+       DWC_PRINT("%s, usb device mode\n", __func__);
        return 0;
     }
-#if 1
+    #ifndef CONFIG_DWC_REMOTE_WAKEUP
+    clk_enable(core_if->otg_dev->phyclk);
+    clk_enable(core_if->otg_dev->ahbclk);
+    #endif
     //partial power-down
     //power on
     pcgcctl.d32 = dwc_read_reg32(core_if->pcgcctl);;
@@ -128,40 +139,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
-    //dwc_debug(3);
-    //dwc_debug(1);
+
     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);
-       
+    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);
+       
+        mdelay(10);
+    }
+    else
+    {
+        if (core_if->hcd_cb && core_if->hcd_cb->suspend) {
+                core_if->hcd_cb->suspend( core_if->hcd_cb->p, 1);
+        }
+    }
     gintmsk.b.portintr = 1;
     dwc_write_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
-    mdelay(10);
-#endif
+
        return 0;
 }
 
@@ -204,10 +224,48 @@ static const struct hc_driver dwc_otg_hc_driver = {
        //.hub_resume =         
 };
 
-#ifdef CONFIG_RK2818_HOST11
-static const struct hc_driver rk28_host11_hc_driver = {
+#ifdef CONFIG_USB11_HOST
+static const struct hc_driver host11_hc_driver = {
+
+       .description =          "host11_hcd",
+       .product_desc =         "DWC OTG Controller",
+       .hcd_priv_size =        sizeof(dwc_otg_hcd_t),
+
+       .irq =                  dwc_otg_hcd_irq,
+
+       .flags =                HCD_MEMORY | HCD_USB2,
+
+       //.reset =
+       .start =                dwc_otg_hcd_start,
+       //.suspend =    
+       //.resume =     
+       
+       /* yk@rk 20100625
+        * core/hcd.c call hcd->driver->bus_suspend
+        * otherwise system can not be suspended
+        */
+#ifdef CONFIG_PM
+       .bus_suspend =          dwc_otg_hcd_suspend,
+       .bus_resume =           dwc_otg_hcd_resume,
+#endif
+       .stop =                 dwc_otg_hcd_stop,
+
+       .urb_enqueue =          dwc_otg_hcd_urb_enqueue,
+       .urb_dequeue =          dwc_otg_hcd_urb_dequeue,
+       .endpoint_disable =     dwc_otg_hcd_endpoint_disable,
+
+       .get_frame_number =     dwc_otg_hcd_get_frame_number,
+
+       .hub_status_data =      dwc_otg_hcd_hub_status_data,
+       .hub_control =          dwc_otg_hcd_hub_control,
+       //.hub_suspend =        
+       //.hub_resume =         
+};
+#endif
+#ifdef CONFIG_USB20_HOST
+static const struct hc_driver host20_hc_driver = {
 
-       .description =          "rk28_host11_hcd",
+       .description =          "host20_hcd",
        .product_desc =         "DWC OTG Controller",
        .hcd_priv_size =        sizeof(dwc_otg_hcd_t),
 
@@ -247,7 +305,6 @@ static const struct hc_driver rk28_host11_hc_driver = {
  * Work queue function for starting the HCD when A-Cable is connected.
  * The dwc_otg_hcd_start() must be called in a process context.
  */
-// cmy
 static void hcd_start_func(struct work_struct *work)
 {
     dwc_otg_hcd_t *dwc_otg_hcd = container_of(work, dwc_otg_hcd_t, start_work);
@@ -334,6 +391,8 @@ static void kill_urbs_in_qh_list(dwc_otg_hcd_t *_hcd, struct list_head *_qh_list
        dwc_otg_qh_t            *qh;
        struct list_head        *qtd_item;
        dwc_otg_qtd_t           *qtd;
+       struct urb              *urb;
+       struct usb_host_endpoint *ep;
 
        list_for_each(qh_item, _qh_list) {
                qh = list_entry(qh_item, dwc_otg_qh_t, qh_list_entry);
@@ -342,8 +401,22 @@ static void kill_urbs_in_qh_list(dwc_otg_hcd_t *_hcd, struct list_head *_qh_list
                     qtd_item = qh->qtd_list.next) {
                        qtd = list_entry(qtd_item, dwc_otg_qtd_t, qtd_list_entry);
                        if (qtd->urb != NULL) {
+                       urb = qtd->urb;
+                       ep = qtd->urb->ep;
+                           // 20110415 yk 
+                           // urb will be re entry to ep->urb_list if use ETIMEOUT
                                dwc_otg_hcd_complete_urb(_hcd, qtd->urb,
-                                                        -ETIMEDOUT);
+                                                        -ETIMEDOUT);//ESHUTDOWN
+                                                        
+                       //if(!list_empty(&ep->urb_list))
+               DWC_PRINT("%s: urb %p, device %d, ep %d %s, status=%d\n",
+                         __func__, urb, usb_pipedevice(urb->pipe),
+                         usb_pipeendpoint(urb->pipe),
+                         usb_pipein(urb->pipe) ? "IN" : "OUT", urb->unlinked);
+                         
+               if (!urb->unlinked)
+                   urb->unlinked = -ESHUTDOWN;
+                   
                        }
                        dwc_otg_hcd_qtd_remove_and_free(qtd);
                }
@@ -374,28 +447,27 @@ static void kill_all_urbs(dwc_otg_hcd_t *_hcd)
 static int32_t dwc_otg_hcd_disconnect_cb( void *_p )
 {
        gintsts_data_t  intr;
-        dwc_otg_hcd_t  *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_p);
+    dwc_otg_hcd_t      *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_p);
 
-        //DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p);
+    //DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p);
 
-        /* 
-         * Set status flags for the hub driver.
-         */
-     printk("dwc_otg_hcd_disconnect_cb");
-        dwc_otg_hcd->flags.b.port_connect_status_change = 1;
+    /* 
+     * Set status flags for the hub driver.
+     */
+    dwc_otg_hcd->flags.b.port_connect_status_change = 1;
        dwc_otg_hcd->flags.b.port_connect_status = 0;
 
-        /*
-         * Shutdown any transfers in process by clearing the Tx FIFO Empty
-         * interrupt mask and status bits and disabling subsequent host
-         * channel interrupts.
-         */
-        intr.d32 = 0;
-        intr.b.nptxfempty = 1;
-        intr.b.ptxfempty = 1;
+    /*
+     * Shutdown any transfers in process by clearing the Tx FIFO Empty
+     * interrupt mask and status bits and disabling subsequent host
+     * channel interrupts.
+     */
+    intr.d32 = 0;
+    intr.b.nptxfempty = 1;
+    intr.b.ptxfempty = 1;
        intr.b.hcintr = 1;
-        dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintmsk, intr.d32, 0);
-        dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintsts, intr.d32, 0);
+    dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintmsk, intr.d32, 0);
+    dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintsts, intr.d32, 0);
 
        del_timers(dwc_otg_hcd);
 
@@ -463,10 +535,10 @@ static int32_t dwc_otg_hcd_disconnect_cb( void *_p )
                }
        }
 
-        /* A disconnect will end the session so the B-Device is no
-         * longer a B-host. */
-        ((struct usb_hcd *)_p)->self.is_b_host = 0;  
-        return 1;
+    /* A disconnect will end the session so the B-Device is no
+     * longer a B-host. */
+    ((struct usb_hcd *)_p)->self.is_b_host = 0;  
+    return 1;
 }
 
 /**
@@ -508,6 +580,31 @@ static int32_t dwc_otg_hcd_session_start_cb( void *_p )
         return 1;
 }
 
+/*
+ * suspend: 0 usb phy enable
+ *          1 usb phy suspend
+ */
+static int32_t dwc_otg_phy_suspend_cb( void *_p, int suspend)
+{
+    unsigned int * otg_phy_con1 = (unsigned int*)(USB_GRF_CON);
+    
+    if(suspend) {
+        *otg_phy_con1 |= (0x01<<2);
+        *otg_phy_con1 |= (0x01<<3);    // exit suspend.
+        *otg_phy_con1 &= ~(0x01<<2);
+        
+        DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n");
+    }
+    else
+    {
+        *otg_phy_con1 |= (0x01<<2);
+        *otg_phy_con1 &= ~(0x01<<3);    // enter suspend.
+        DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n");
+    }
+    
+    return suspend;
+}
+
 /**
  * HCD Callback structure for handling mode switching.
  */
@@ -516,6 +613,7 @@ static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
         .stop = dwc_otg_hcd_stop_cb,
         .disconnect = dwc_otg_hcd_disconnect_cb,
         .session_start = dwc_otg_hcd_session_start_cb,
+        .suspend = dwc_otg_phy_suspend_cb,
         .p = 0,//hcd
 };
 
@@ -527,7 +625,7 @@ static void reset_tasklet_func (unsigned long data)
        dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t*)data;
        dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
        hprt0_data_t hprt0;
-
+    
        DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
 
        hprt0.d32 = dwc_otg_read_hprt0 (core_if);
@@ -572,20 +670,15 @@ int __devinit dwc_otg_hcd_init(struct device *dev)
        /* Set device flags indicating whether the HCD supports DMA. */
        static u64 usb_dmamask = 0xffffffffUL;
        if (otg_dev->core_if->dma_enable) {
-//             DWC_PRINT("Using DMA mode\n");
                dev->dma_mask = &usb_dmamask;
                dev->coherent_dma_mask = ~0;
        } else {
-//             DWC_PRINT("Using Slave mode\n");
                dev->dma_mask = (void *)0;
                dev->coherent_dma_mask = 0;
        }
 #endif
-       printk("dwc_otg_hcd_init everest\n");
 //     g_dbg_lvl = 0xff;
        
-       DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n");
-
        /*
         * Allocate memory for the base HCD plus the DWC OTG HCD.
         * Initialize the base HCD.
@@ -605,6 +698,12 @@ int __devinit dwc_otg_hcd_init(struct device *dev)
 
        dwc_otg_hcd->core_if = otg_dev->core_if;
        otg_dev->hcd = dwc_otg_hcd;
+    
+#ifdef CONFIG_USB20_OTG_EN
+    dwc_otg_hcd->host_enabled = 1;
+#else
+    dwc_otg_hcd->host_enabled = 0;
+#endif
 
         /* Register the HCD CIL Callbacks */
         dwc_otg_cil_register_hcd_callbacks(otg_dev->core_if, 
@@ -681,8 +780,7 @@ int __devinit dwc_otg_hcd_init(struct device *dev)
                DWC_ERROR("%s: status_buf allocation failed\n", __func__);
                goto error3;
        }
-
-       DWC_PRINT("%s end,everest\n",__func__);
+    
 //     DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Initialized HCD, bus=%s, usbbus=%d\n", 
 //                 dev->bus_id, hcd->self.busnum);
         
@@ -696,20 +794,41 @@ int __devinit dwc_otg_hcd_init(struct device *dev)
        usb_put_hcd(hcd);
 
  error1:
-       printk("dwc_otg_hcd_init error,everest\n");
+       DWC_PRINT("dwc_otg_hcd_init error,everest\n");
        return retval;
 }
 
-#ifdef CONFIG_RK2818_HOST11
-static dwc_otg_cil_callbacks_t rk28_host11_cil_callbacks = {
+#ifdef CONFIG_USB11_HOST
+/*
+ * suspend: 0 usb phy enable
+ *          1 usb phy suspend
+ */
+static int32_t host11_phy_suspend_cb( void *_p, int suspend)
+{
+    unsigned int * otg_phy_con1 = (unsigned int*)(USB_GRF_CON);
+    
+    if(suspend) {
+        *otg_phy_con1 &= ~(0x01<<28);
+        DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n");
+    }
+    else
+    {
+        *otg_phy_con1 |= (0x01<<28);
+        DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n");
+    }
+    
+    return suspend;
+}
+static dwc_otg_cil_callbacks_t host11_cil_callbacks = {
         .start = dwc_otg_hcd_start_cb,
         .stop = dwc_otg_hcd_stop_cb,
         .disconnect = dwc_otg_hcd_disconnect_cb,
         .session_start = dwc_otg_hcd_session_start_cb,
+        .suspend = host11_phy_suspend_cb,
         .p = 0,//hcd
 };
 
-static struct tasklet_struct rk28_host11_reset_tasklet = { 
+static struct tasklet_struct host11_reset_tasklet = { 
        .next = NULL,
        .state = 0,
        .count = ATOMIC_INIT(0),
@@ -717,7 +836,7 @@ static struct tasklet_struct rk28_host11_reset_tasklet = {
        .data = 0,
 };
 
-int __devinit rk28_host11_hcd_init(struct device *dev)
+int __devinit host11_hcd_init(struct device *dev)
 {
        struct usb_hcd *hcd = NULL;
        dwc_otg_hcd_t *dwc_otg_hcd = NULL;
@@ -741,7 +860,6 @@ int __devinit rk28_host11_hcd_init(struct device *dev)
                dev->coherent_dma_mask = 0;
        }
 #endif
-       printk("%s everest\n",__func__);
 //     g_dbg_lvl = 0xff;
        
        DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n");
@@ -750,7 +868,7 @@ int __devinit rk28_host11_hcd_init(struct device *dev)
         * Allocate memory for the base HCD plus the DWC OTG HCD.
         * Initialize the base HCD.
         */
-       hcd = usb_create_hcd(&rk28_host11_hc_driver, dev, dev_name(dev));
+       hcd = usb_create_hcd(&host11_hc_driver, dev, dev_name(dev));
        if (hcd == NULL) {
                retval = -ENOMEM;
                goto error1;
@@ -762,13 +880,19 @@ int __devinit rk28_host11_hcd_init(struct device *dev)
        dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
        dwc_otg_hcd->core_if = otg_dev->core_if;
        otg_dev->hcd = dwc_otg_hcd;
+    
+#ifdef CONFIG_USB11_HOST_EN
+        dwc_otg_hcd->host_enabled = 1;
+#else
+        dwc_otg_hcd->host_enabled = 0;
+#endif
 
        spin_lock_init(&dwc_otg_hcd->global_lock);
 
 
         /* Register the HCD CIL Callbacks */
         dwc_otg_cil_register_hcd_callbacks(otg_dev->core_if, 
-                                          &rk28_host11_cil_callbacks, hcd);
+                                          &host11_cil_callbacks, hcd);
 
        /* Initialize the non-periodic schedule. */
        INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_inactive);
@@ -807,8 +931,8 @@ int __devinit rk28_host11_hcd_init(struct device *dev)
         init_timer( &dwc_otg_hcd->conn_timer );
 
        /* Initialize reset tasklet. */
-       rk28_host11_reset_tasklet.data = (unsigned long) dwc_otg_hcd;
-       dwc_otg_hcd->reset_tasklet = &rk28_host11_reset_tasklet;
+       host11_reset_tasklet.data = (unsigned long) dwc_otg_hcd;
+       dwc_otg_hcd->reset_tasklet = &host11_reset_tasklet;
        /*
         * Finish generic HCD initialization and start the HCD. This function
         * allocates the DMA buffer pool, registers the USB bus, requests the
@@ -842,7 +966,6 @@ int __devinit rk28_host11_hcd_init(struct device *dev)
                goto error3;
        }
 
-       DWC_PRINT("%s end,everest\n",__func__);
 //     DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Initialized HCD, bus=%s, usbbus=%d\n", 
 //                 dev->bus_id, hcd->self.busnum);
         
@@ -856,10 +979,203 @@ int __devinit rk28_host11_hcd_init(struct device *dev)
        usb_put_hcd(hcd);
 
  error1:
-       printk("dwc_otg_hcd_init error,everest\n");
+       DWC_PRINT("dwc_otg_hcd_init error,everest\n");
+       return retval;
+}
+#endif
+#ifdef CONFIG_USB20_HOST
+
+/*
+ * suspend: 0 usb phy enable
+ *          1 usb phy suspend
+ */
+static int32_t host20_phy_suspend_cb( void *_p, int suspend)
+{
+    unsigned int * otg_phy_con1 = (unsigned int*)(USB_GRF_CON);
+    uint32_t regval;
+
+    regval = *otg_phy_con1;
+    
+    if(suspend) {
+        regval |= (0x01<<14);    // exit suspend.
+        regval &= ~(0x01<<13);
+        
+        DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n");
+    }
+    else
+    {
+        regval &= ~(0x01<<14);    // exit suspend.
+        regval |= (0x01<<13);    // software control
+        DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n");
+    }
+    *otg_phy_con1 = regval;
+    
+    return suspend;
+}
+
+static dwc_otg_cil_callbacks_t host20_cil_callbacks = {
+        .start = dwc_otg_hcd_start_cb,
+        .stop = dwc_otg_hcd_stop_cb,
+        .disconnect = dwc_otg_hcd_disconnect_cb,
+        .session_start = dwc_otg_hcd_session_start_cb,
+        .suspend = host20_phy_suspend_cb,
+        .p = 0,//hcd
+};
+
+static struct tasklet_struct host20_reset_tasklet = { 
+       .next = NULL,
+       .state = 0,
+       .count = ATOMIC_INIT(0),
+       .func = reset_tasklet_func,
+       .data = 0,
+};
+
+int __devinit host20_hcd_init(struct device *dev)
+{
+       struct usb_hcd *hcd = NULL;
+       dwc_otg_hcd_t *dwc_otg_hcd = NULL;
+    dwc_otg_device_t *otg_dev = dev->platform_data;
+
+       int             num_channels;
+       int             i;
+       dwc_hc_t        *channel;
+
+       int retval = 0;
+#if 1  //kaiker .these code must execute before usb_create_hcd
+       /* Set device flags indicating whether the HCD supports DMA. */
+       static u64 usb_dmamask = 0xffffffffUL;
+       if (otg_dev->core_if->dma_enable) {
+//             DWC_PRINT("Using DMA mode\n");
+               dev->dma_mask = &usb_dmamask;
+               dev->coherent_dma_mask = ~0;
+       } else {
+//             DWC_PRINT("Using Slave mode\n");
+               dev->dma_mask = (void *)0;
+               dev->coherent_dma_mask = 0;
+       }
+#endif
+//     g_dbg_lvl = 0xff;
+       
+       DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n");
+
+       /*
+        * Allocate memory for the base HCD plus the DWC OTG HCD.
+        * Initialize the base HCD.
+        */
+       hcd = usb_create_hcd(&host20_hc_driver, dev, dev_name(dev));
+       if (hcd == NULL) {
+               retval = -ENOMEM;
+               goto error1;
+       }
+       hcd->regs = otg_dev->base;
+       hcd->self.otg_port = 1;  
+
+       /* Initialize the DWC OTG HCD. */
+       dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+       dwc_otg_hcd->core_if = otg_dev->core_if;
+       otg_dev->hcd = dwc_otg_hcd;
+    
+#ifdef CONFIG_USB20_HOST_EN
+        dwc_otg_hcd->host_enabled = 1;
+#else
+        dwc_otg_hcd->host_enabled = 0;
+#endif
+
+       spin_lock_init(&dwc_otg_hcd->global_lock);
+
+
+        /* Register the HCD CIL Callbacks */
+        dwc_otg_cil_register_hcd_callbacks(otg_dev->core_if, 
+                                          &host20_cil_callbacks, hcd);
+
+       /* Initialize the non-periodic schedule. */
+       INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_inactive);
+       INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_active);
+
+       /* Initialize the periodic schedule. */
+       INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_inactive);
+       INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_ready);
+       INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_assigned);
+       INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_queued);
+
+       /*
+        * Create a host channel descriptor for each host channel implemented
+        * in the controller. Initialize the channel descriptor array.
+        */
+       INIT_LIST_HEAD(&dwc_otg_hcd->free_hc_list);
+       num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
+       for (i = 0; i < num_channels; i++) {
+               channel = kmalloc(sizeof(dwc_hc_t), GFP_KERNEL);
+               if (channel == NULL) {
+                       retval = -ENOMEM;
+                       DWC_ERROR("%s: host channel allocation failed\n", __func__);
+                       goto error2;
+               }
+               memset(channel, 0, sizeof(dwc_hc_t));
+               channel->hc_num = i;
+               dwc_otg_hcd->hc_ptr_array[i] = channel;
+#ifdef DEBUG
+               init_timer(&dwc_otg_hcd->core_if->hc_xfer_timer[i]);
+#endif         
+
+               DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i, channel);
+       }
+       
+        /* Initialize the Connection timeout timer. */
+        init_timer( &dwc_otg_hcd->conn_timer );
+
+       /* Initialize reset tasklet. */
+       host20_reset_tasklet.data = (unsigned long) dwc_otg_hcd;
+       dwc_otg_hcd->reset_tasklet = &host20_reset_tasklet;
+       /*
+        * Finish generic HCD initialization and start the HCD. This function
+        * allocates the DMA buffer pool, registers the USB bus, requests the
+        * IRQ line, and calls dwc_otg_hcd_start method.
+        */
+       retval = usb_add_hcd(hcd, platform_get_irq(to_platform_device(dev), 0), 
+                                       IRQF_SHARED);
+       if (retval < 0) {
+               DWC_ERROR("usb_add_hcd fail,everest\n");
+               goto error2;
+       }
+       /*
+        * Allocate space for storing data on status transactions. Normally no
+        * data is sent, but this space acts as a bit bucket. This must be
+        * done after usb_add_hcd since that function allocates the DMA buffer
+        * pool.
+        */
+       if (otg_dev->core_if->dma_enable) {
+               dwc_otg_hcd->status_buf =
+                       dma_alloc_coherent(dev,
+                                          DWC_OTG_HCD_STATUS_BUF_SIZE,
+                                          &dwc_otg_hcd->status_buf_dma,
+                                          GFP_KERNEL | GFP_DMA);
+       } else {
+               dwc_otg_hcd->status_buf = kmalloc(DWC_OTG_HCD_STATUS_BUF_SIZE,
+                                                 GFP_KERNEL);
+       }
+       if (dwc_otg_hcd->status_buf == NULL) {
+               retval = -ENOMEM;
+               DWC_ERROR("%s: status_buf allocation failed\n", __func__);
+               goto error3;
+       }
+    
+        
+       return 0;
+
+       /* Error conditions */
+ error3:
+       usb_remove_hcd(hcd);
+ error2:
+       dwc_otg_hcd_free(hcd);
+       usb_put_hcd(hcd);
+
+ error1:
+       DWC_PRINT("dwc_otg_hcd_init error,everest\n");
        return retval;
 }
 #endif
+
 /**
  * Removes the HCD.
  * Frees memory and resources associated with the HCD and deregisters the bus.
@@ -934,33 +1250,11 @@ int dwc_otg_hcd_start(struct usb_hcd *_hcd)
     dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
        unsigned long flags;
        
-       struct usb_device *udev;
        struct usb_bus *bus;
 
        DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
        spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
-#if 0
-       unsigned int regvalue;
-       printk("__________________________________________________________________\n");
-       regvalue = dwc_read_reg32(&dwc_otg_hcd->core_if->core_global_regs->gotgctl);
-       printk("gotgctl is %08x\n",regvalue);
-        regvalue = dwc_read_reg32(&dwc_otg_hcd->core_if->core_global_regs->gotgint);
-        printk("gotgint is %08x\n",regvalue);
-        regvalue = dwc_read_reg32(&dwc_otg_hcd->core_if->core_global_regs->gahbcfg);
-        printk("gahbcfg is %08x\n",regvalue);
-        regvalue = dwc_read_reg32(&dwc_otg_hcd->core_if->core_global_regs->gusbcfg);
-        printk("gusbcfg is %08x\n",regvalue);
-        regvalue = dwc_read_reg32(&dwc_otg_hcd->core_if->core_global_regs->grstctl);
-        printk("grstctl is %08x\n",regvalue);
-        regvalue = dwc_read_reg32(&dwc_otg_hcd->core_if->core_global_regs->gintsts);
-        printk("gintsts is %08x\n",regvalue);
-        regvalue = dwc_read_reg32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk);
-        printk("gintmsk is %08x\n",regvalue);
-        regvalue = dwc_read_reg32(&dwc_otg_hcd->core_if->core_global_regs->gotgctl);
-        printk("gotgctl is %08x\n",regvalue);  
-       printk("__________________________________________________________________\n");
-#endif 
-       DWC_PRINT("dwc_otg_hcd_start! everest\n");
+
        bus = hcd_to_bus(_hcd);
        _hcd->state = HC_STATE_RUNNING;
 
@@ -971,13 +1265,17 @@ int dwc_otg_hcd_start(struct usb_hcd *_hcd)
                usb_hcd_resume_root_hub(_hcd);
         }
        else {
+           /*
+            * no use 
+            * yk@rk 2010121
+           struct usb_device *udev;6
                udev = usb_alloc_dev(NULL, bus, 0);
                udev->speed = USB_SPEED_HIGH;
                if (!udev) {
                        DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Error udev alloc\n");
                        return -ENODEV;
                }
-
+        */
            /* Not needed - VJ
               if ((retval = usb_hcd_register_root_hub(udev, _hcd)) != 0) {
                   DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Error registering %d\n", retval);
@@ -987,8 +1285,8 @@ int dwc_otg_hcd_start(struct usb_hcd *_hcd)
        }
        /* Initialize the bus state.  If the core is in Device Mode
         * HALT the USB bus and return. */
-       if (dwc_otg_is_device_mode (core_if)) {
-               printk("dwc_otg_hcd_start controller in device mode,everest\n");
+       if (!dwc_otg_hcd->host_enabled || dwc_otg_is_device_mode (core_if)) {
+               DWC_PRINT("dwc_otg_hcd_start controller in device mode,everest\n");
                //_hcd->state = HC_STATE_HALT;
                goto out;
        }
@@ -1110,7 +1408,6 @@ void dwc_otg_hcd_free(struct usb_hcd *_hcd)
 #ifdef DEBUG
 static void dump_urb_info(struct urb *_urb, char* _fn_name)
 {
-       DWC_PRINT("%s, urb %p,%x\n", _fn_name, _urb,_urb);
        DWC_PRINT("  Device address: %d\n", usb_pipedevice(_urb->pipe));
        DWC_PRINT("  Endpoint: %d, %s\n", usb_pipeendpoint(_urb->pipe),
                  (usb_pipein(_urb->pipe) ? "IN" : "OUT"));
@@ -1215,13 +1512,14 @@ int dwc_otg_hcd_urb_enqueue(struct usb_hcd *_hcd,
        dwc_otg_hcd_t * dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);
        dwc_otg_qtd_t * qtd;
        unsigned long flags;
-
+#if 0
        retval = usb_hcd_link_urb_to_ep(_hcd, _urb);
        if (retval)
        {
-               printk("%s, usb_hcd_link_urb_to_ep error\n", __func__);
+               DWC_PRINT("%s, usb_hcd_link_urb_to_ep error\n", __func__);
                return retval;
        }
+#endif
        spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
 #if 1
        /*
@@ -1271,24 +1569,31 @@ int dwc_otg_hcd_urb_dequeue(struct usb_hcd *_hcd, struct urb *_urb, int _status)
        dwc_otg_qtd_t * urb_qtd;
        dwc_otg_qh_t * qh;
        struct usb_host_endpoint *_ep = _urb->ep;//dwc_urb_to_endpoint(_urb);
-       int retval;
+       //int retval;
 
        DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
        urb_qtd = (dwc_otg_qtd_t *) _urb->hcpriv;
        if(_ep==NULL)
        {
-               printk("%s=====================================================\n",__func__);
-               printk("urb->ep is null\n");
+               DWC_PRINT("%s=====================================================\n",__func__);
+               DWC_PRINT("urb->ep is null\n");
                return -1;
        }
        qh = (dwc_otg_qh_t *) _ep->hcpriv;
        spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
+       #if 0
        retval = usb_hcd_check_unlink_urb(_hcd, _urb, _status);
        if (retval) {
                spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
                return retval;
        }
-
+       #endif
+       if(urb_qtd == NULL)
+       {
+               DWC_PRINT("%s,urb_qtd is null\n",__func__);
+               goto urb_qtd_null;
+               //return -1;
+       }
        dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);
 
 #ifdef DEBUG
@@ -1330,9 +1635,11 @@ int dwc_otg_hcd_urb_dequeue(struct usb_hcd *_hcd, struct urb *_urb, int _status)
                dwc_otg_hcd_qh_remove(dwc_otg_hcd, qh);
        }
 #endif
+       
+urb_qtd_null:
        spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
        _urb->hcpriv = NULL;
-       usb_hcd_unlink_urb_from_ep(_hcd, _urb);
+       //usb_hcd_unlink_urb_from_ep(_hcd, _urb);
     /* Higher layer software sets URB status. */
        usb_hcd_giveback_urb(_hcd, _urb, _status);
        if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
@@ -2134,10 +2441,10 @@ int dwc_otg_hcd_hub_control(struct usb_hcd *_hcd,
                        port_status |= (1 << USB_PORT_FEAT_POWER);
 
                if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
-                       port_status |= (1 << USB_PORT_FEAT_HIGHSPEED);
+                       port_status |= USB_PORT_STAT_HIGH_SPEED;
 
                else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
-                       port_status |= (1 << USB_PORT_FEAT_LOWSPEED);
+                       port_status |= USB_PORT_STAT_LOW_SPEED;
 
                if (hprt0.b.prttstctl)
                        port_status |= (1 << USB_PORT_FEAT_TEST);
@@ -2215,8 +2522,13 @@ int dwc_otg_hcd_hub_control(struct usb_hcd *_hcd,
                                 hprt0.b.prtrst = 1;
                                 dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
                         }
+            spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
                        /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
-                       MDELAY (60);
+                       // kever @rk 20110712
+                       // can not use mdelay(60) while irq disable
+                       //MDELAY (60);
+                       msleep(60);
+            spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
                        hprt0.b.prtrst = 0;
                        dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
                        break;
@@ -2389,8 +2701,18 @@ static void assign_and_init_hc(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh)
 
        if (urb->dev->speed == USB_SPEED_LOW) {
                hc->speed = DWC_OTG_EP_SPEED_LOW;
+               /*
+                * yk@rk 20101216 fix bandwidth check error when full/low speed
+                * device connected.
+                */
+        _hcd->core_if->core_params->speed = DWC_SPEED_PARAM_FULL;
        } else if (urb->dev->speed == USB_SPEED_FULL) {
                hc->speed = DWC_OTG_EP_SPEED_FULL;
+               /*
+                * yk@rk 20101216 fix bandwidth check error when full/low speed
+                * device connected. warning: only support 1 device at root hub.
+                */
+        _hcd->core_if->core_params->speed = DWC_SPEED_PARAM_FULL;
        } else {
                hc->speed = DWC_OTG_EP_SPEED_HIGH;
        }
@@ -2556,7 +2878,7 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd)
                 * periodic assigned schedule.
                 */
                qh_ptr = qh_ptr->next;
-               list_move(&qh->qh_list_entry, &_hcd->periodic_sched_assigned);
+               list_move_tail(&qh->qh_list_entry, &_hcd->periodic_sched_assigned);
 
                ret_val = DWC_OTG_TRANSACTION_PERIODIC;
        }
@@ -2574,10 +2896,6 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd)
                num_channels - _hcd->periodic_channels) &&
                */
               !list_empty(&_hcd->free_hc_list)) {
-              
-           if((num_channels > 2)&&(_hcd->non_periodic_channels >=
-               num_channels - _hcd->periodic_channels))
-                       break;
 
                qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry);
                assign_and_init_hc(_hcd, qh);
@@ -2587,7 +2905,7 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd)
                 * non-periodic active schedule.
                 */
                qh_ptr = qh_ptr->next;
-               list_move(&qh->qh_list_entry, &_hcd->non_periodic_sched_active);
+               list_move_tail(&qh->qh_list_entry, &_hcd->non_periodic_sched_active);
 
                if (ret_val == DWC_OTG_TRANSACTION_NONE) {
                        ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
@@ -2834,7 +3152,7 @@ static void process_periodic_channels(dwc_otg_hcd_t *_hcd)
                         * Move the QH from the periodic assigned schedule to
                         * the periodic queued schedule.
                         */
-                       list_move(&qh->qh_list_entry, &_hcd->periodic_sched_queued);
+                       list_move_tail(&qh->qh_list_entry, &_hcd->periodic_sched_queued);
 
                        /* done queuing high bandwidth */
                        _hcd->core_if->queuing_high_bandwidth = 0;
@@ -2946,13 +3264,22 @@ __acquires(_hcd->lock)
 
 
        _urb->hcpriv = NULL;
-       usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(_hcd), _urb);
+       //usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(_hcd), _urb);
        spin_unlock(&_hcd->lock);
        usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(_hcd), _urb, _status);
        spin_lock(&_hcd->lock);
 }
 
-
+void dwc_otg_clear_halt(struct urb *_urb)
+{
+       struct dwc_otg_qh *_qh;
+       struct usb_host_endpoint *ep = dwc_urb_to_endpoint(_urb);
+       if((ep)&&(ep->hcpriv))
+       {
+               _qh =  (dwc_otg_qh_t *) ep->hcpriv;
+               _qh->data_toggle = 0;
+       }
+}
 /*
  * Returns the Queue Head for an URB.
  */