hcd nonper channel problem & suspend when no device connect
authoryangkai <yk@rock-chips.com>
Mon, 9 Jul 2012 02:41:30 +0000 (10:41 +0800)
committeryangkai <yk@rock-chips.com>
Mon, 9 Jul 2012 02:41:30 +0000 (10:41 +0800)
drivers/usb/dwc_otg/dwc_otg_hcd.c
drivers/usb/dwc_otg/dwc_otg_hcd_intr.c

index d42eb76e3bbd88a64020bceb2f129946d7ea3324..e85ada78ead6c841e295e274f5b6866b2cf8ef07 100755 (executable)
@@ -432,6 +432,10 @@ static void kill_all_urbs(dwc_otg_hcd_t *_hcd)
 //     kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_assigned);
 //     kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_queued);
 }
+extern void release_channel(dwc_otg_hcd_t *_hcd,
+                           dwc_hc_t *_hc,
+                           dwc_otg_qtd_t *_qtd,
+                           dwc_otg_halt_status_e _halt_status);
 
 /**
  * HCD Callback function for disconnect of the HCD.
@@ -463,7 +467,7 @@ static int32_t dwc_otg_hcd_disconnect_cb( void *_p )
     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);
+//     del_timers(dwc_otg_hcd);
 
        /*
         * Turn off the vbus power only if the core has transitioned to device
@@ -523,10 +527,13 @@ static int32_t dwc_otg_hcd_disconnect_cb( void *_p )
                                        hcchar.b.chdis = 1;
                                        dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
                                }
-
+#if 1                          
+                release_channel(dwc_otg_hcd, channel, NULL, DWC_OTG_HC_XFER_URB_DEQUEUE);
+#else
                                dwc_otg_hc_cleanup(dwc_otg_hcd->core_if, channel);
                                list_add_tail(&channel->hc_list_entry,
                                              &dwc_otg_hcd->free_hc_list);
+#endif
                        }
                }
        }
@@ -556,11 +563,11 @@ void dwc_otg_hcd_connect_timeout( unsigned long _ptr )
  */
 static void dwc_otg_hcd_start_connect_timer( dwc_otg_hcd_t *_hcd)
 {
-        init_timer( &_hcd->conn_timer );
-        _hcd->conn_timer.function = dwc_otg_hcd_connect_timeout;
-        _hcd->conn_timer.data = (unsigned long)0;
-        _hcd->conn_timer.expires = jiffies + (HZ*10);
-        add_timer( &_hcd->conn_timer );
+    init_timer( &_hcd->conn_timer );
+    _hcd->conn_timer.function = dwc_otg_hcd_connect_timeout;
+    _hcd->conn_timer.data = (unsigned long)0;
+    _hcd->conn_timer.expires = jiffies + (HZ*10);
+    add_timer( &_hcd->conn_timer );
 }
 
 /**
@@ -572,7 +579,7 @@ static int32_t dwc_otg_hcd_session_start_cb( void *_p )
 {
         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_p);
         DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p);
-        dwc_otg_hcd_start_connect_timer( dwc_otg_hcd );
+//        dwc_otg_hcd_start_connect_timer( dwc_otg_hcd );
         return 1;
 }
 
@@ -599,6 +606,18 @@ static int32_t dwc_otg_phy_suspend_cb( void *_p, int suspend)
         DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n");
     }
 #endif    
+#ifdef CONFIG_ARCH_RK30
+    unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON2);
+    if(suspend) {
+        *otg_phy_con1 = ((0x01<<2)<<16);    // exit suspend.
+        DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n");
+    }
+    else{
+        *otg_phy_con1 = 0x554|(0xfff<<16);   // enter suspend.
+        udelay(3);
+        DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n");
+    }
+#endif
     return suspend;
 }
 
@@ -661,7 +680,7 @@ static void dwc_otg_hcd_enable(struct work_struct *work)
        dwc_otg_hcd->host_enabled = dwc_otg_hcd->host_setenable;
        if(dwc_otg_hcd->host_setenable == 0)    // enable -> disable
        {
-           DWC_PRINT("disable host controller\n");
+           DWC_PRINT("%s, disable host controller\n", __func__);
            #if 1
         if (_core_if->hcd_cb && _core_if->hcd_cb->disconnect) {
                 _core_if->hcd_cb->disconnect( _core_if->hcd_cb->p );
@@ -679,7 +698,7 @@ static void dwc_otg_hcd_enable(struct work_struct *work)
        }
        else if(dwc_otg_hcd->host_setenable == 1)
        {
-           DWC_PRINT("enable host controller\n");
+           DWC_PRINT("%s, enable host controller\n", __func__);
 //        clk_enable(otg_dev->phyclk);
 //        clk_enable(otg_dev->ahbclk);
         if (_core_if->hcd_cb && _core_if->hcd_cb->suspend) {
@@ -701,7 +720,7 @@ static void dwc_otg_hcd_connect_detect(unsigned long pdata)
 
        local_irq_save(flags);
 
-//    DWC_PRINT("%s %p, grfstatus 0x%x\n", __func__, dwc_otg_hcd, usbgrf_status& (7<<22));
+//    DWC_PRINT("%s hprt %x, grfstatus 0x%x\n", __func__, dwc_read_reg32(core_if->host_if->hprt0), usbgrf_status& (7<<22));
     if(usbgrf_status & (7<<22)){
     // usb device connected
         dwc_otg_hcd->host_setenable = 1;
@@ -712,7 +731,10 @@ static void dwc_otg_hcd_connect_detect(unsigned long pdata)
             dwc_otg_hcd->host_setenable = 0;
     
     }
-    schedule_delayed_work(&dwc_otg_hcd->host_enable_work, jiffies);
+    if(dwc_otg_hcd->host_setenable != dwc_otg_hcd->host_enabled){
+    DWC_PRINT("%s schedule delaywork \n", __func__, dwc_read_reg32(core_if->host_if->hprt0), usbgrf_status& (7<<22));
+    schedule_delayed_work(&dwc_otg_hcd->host_enable_work, 8);
+    }
 //    dwc_otg_hcd->connect_detect_timer.expires = jiffies + (HZ<<1); /* 1 s */
     mod_timer(&dwc_otg_hcd->connect_detect_timer,jiffies + (HZ<<1)); 
        local_irq_restore(flags);
@@ -814,7 +836,7 @@ int __devinit dwc_otg_hcd_init(struct device *dev)
        }
        
         /* Initialize the Connection timeout timer. */
-        init_timer( &dwc_otg_hcd->conn_timer );
+//        init_timer( &dwc_otg_hcd->conn_timer );
 
        /* Initialize reset tasklet. */
        reset_tasklet.data = (unsigned long) dwc_otg_hcd;
@@ -999,7 +1021,7 @@ int __devinit host11_hcd_init(struct device *dev)
        }
        
         /* Initialize the Connection timeout timer. */
-        init_timer( &dwc_otg_hcd->conn_timer );
+//        init_timer( &dwc_otg_hcd->conn_timer );
 
        /* Initialize reset tasklet. */
        host11_reset_tasklet.data = (unsigned long) dwc_otg_hcd;
@@ -1082,6 +1104,19 @@ static int32_t host20_phy_suspend_cb( void *_p, int suspend)
     }
     *otg_phy_con1 = regval;
 #endif    
+    
+#ifdef CONFIG_ARCH_RK30
+    unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);
+    if(suspend) {
+        *otg_phy_con1 = ((0x01<<2)<<16);    // exit suspend.
+        DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n");
+    }
+    else{
+        *otg_phy_con1 = 0x554|(0xfff<<16);   // enter suspend.
+        udelay(3);
+        DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n");
+    }
+#endif
     return suspend;
 }
 
@@ -1450,7 +1485,7 @@ void dwc_otg_hcd_free(struct usb_hcd *_hcd)
 
        DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
 
-       del_timers(dwc_otg_hcd);
+//     del_timers(dwc_otg_hcd);
 
        /* Free memory for QH/QTD lists */
        qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
@@ -1683,7 +1718,6 @@ int dwc_otg_hcd_urb_dequeue(struct usb_hcd *_hcd, struct urb *_urb, int _status)
     if (urb_qtd == qh->qtd_in_process) {
            /* The QTD is in process (it has been assigned to a channel). */
            if (dwc_otg_hcd->flags.b.port_connect_status) {
-
                    /*
                     * If still connected (i.e. in host mode), halt the
                     * channel so it can be used for other transfers. If
@@ -2947,7 +2981,8 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd)
 
        /* Process entries in the periodic ready list. */
        qh_ptr = _hcd->periodic_sched_inactive.next;
-       while (qh_ptr != &_hcd->periodic_sched_inactive) {
+       while ((qh_ptr != &_hcd->periodic_sched_inactive)&&
+              !list_empty(&_hcd->free_hc_list)) {
                qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry);
                if(qh->qh_state != QH_READY){
                qh_ptr = qh_ptr->next;
index fe383025c7c31f5e8ae26feff47f938e41b0f942..175708a3079aa26a7d8ce3290eb339e5e101fbbc 100755 (executable)
@@ -359,7 +359,7 @@ int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
                hprt0_modify.b.prtconndet = 1;
 
                 /* B-Device has connected, Delete the connection timer.  */
-                del_timer( &_dwc_otg_hcd->conn_timer );
+//                del_timer( &_dwc_otg_hcd->conn_timer );
 
                /* The Hub driver asserts a reset when it sees port connect
                 * status change flag */
@@ -813,7 +813,8 @@ update_isoc_urb_state(dwc_otg_hcd_t *_hcd,
  * @param _halt_status Reason the channel is being released. This status
  * determines the actions taken by this function.
  */
-static void release_channel(dwc_otg_hcd_t *_hcd,
+/*static */
+void release_channel(dwc_otg_hcd_t *_hcd,
                            dwc_hc_t *_hc,
                            dwc_otg_qtd_t *_qtd,
                            dwc_otg_halt_status_e _halt_status)
@@ -863,6 +864,7 @@ static void release_channel(dwc_otg_hcd_t *_hcd,
                 * deactivated. Don't want to do anything except release the
                 * host channel and try to queue more transfers.
                 */
+               continue_trans = 0;
                goto cleanup;
        case DWC_OTG_HC_XFER_NO_HALT_STATUS:
                DWC_ERROR("%s: No halt_status, channel %d\n", __func__, _hc->hc_num);