usb:add usb host1.1 for 3G modem
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc_otg / dwc_otg_hcd_intr.c
index 7a646272b9f216a599f0fe07638d19c654438bb6..8e24b6173e055a4172664c371b96452dcb3d2ea5 100755 (executable)
@@ -55,6 +55,7 @@ int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
         if (dwc_otg_is_host_mode(core_if)) {
                gintsts.d32 = dwc_otg_read_core_intr(core_if);
                if (!gintsts.d32) {
+                       DWC_PRINT("%s,GINTSTS = 0\n",__func__);
                        return 0;
                }
 
@@ -467,17 +468,23 @@ int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
  * host channel interrupt and handles them appropriately. */
 int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
 {
-       int hcnum;
+       int i;
        int retval = 0;
-       struct list_head        *qh_entry;
-       dwc_otg_qh_t            *qh;
        haint_data_t haint;
 
        /* Clear appropriate bits in HCINTn to clear the interrupt bit in
         * GINTSTS */
 
        haint.d32 = dwc_otg_read_host_all_channels_intr(_dwc_otg_hcd->core_if);
-
+#if 1
+       for (i = 0; i < _dwc_otg_hcd->core_if->core_params->host_channels; i++) {
+               if (haint.b2.chint & (1 << i))
+                       retval |= dwc_otg_hcd_handle_hc_n_intr(_dwc_otg_hcd, i);
+       }
+#else
+       int hcnum;
+       struct list_head        *qh_entry;
+       dwc_otg_qh_t            *qh;
        /* yk@rk 20100511
         * USB Spec2.0 11.18.4
         * for all periodic endpoints that have split transactions scheduled within 
@@ -505,6 +512,7 @@ int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
                        retval |= dwc_otg_hcd_handle_hc_n_intr (_dwc_otg_hcd, hcnum);
                }
        }
+#endif
        return retval;
 }
 
@@ -784,9 +792,19 @@ static void release_channel(dwc_otg_hcd_t *_hcd,
        dwc_otg_transaction_type_e tr_type;
        int free_qtd;
 
+       int continue_trans = 0;
+
        DWC_DEBUGPL(DBG_HCDV, "  %s: channel %d, halt_status %d\n",
                    __func__, _hc->hc_num, _halt_status);
-
+       if((!_hc->halt_pending)||
+//             (!list_empty(&_hcd->non_periodic_sched_inactive))
+               (_hcd->core_if->core_params->host_channels > 2)||
+               (!_hc->ep_is_in)||
+               (_hc->ep_type != DWC_OTG_EP_TYPE_BULK)
+               )
+       {
+               continue_trans = 1;
+       }
        switch (_halt_status) {
        case DWC_OTG_HC_XFER_URB_COMPLETE:
                free_qtd = 1;
@@ -848,12 +866,23 @@ static void release_channel(dwc_otg_hcd_t *_hcd,
                 */
                break;
        }
-
-       /* Try to queue more transfers now that there's a free channel. */
-       tr_type = dwc_otg_hcd_select_transactions(_hcd);
-       if (tr_type != DWC_OTG_TRANSACTION_NONE) {
-               dwc_otg_hcd_queue_transactions(_hcd, tr_type);
+       if(continue_trans)
+       {
+               /* Try to queue more transfers now that there's a free channel. */
+               tr_type = dwc_otg_hcd_select_transactions(_hcd);
+               if (tr_type != DWC_OTG_TRANSACTION_NONE) {
+                       dwc_otg_hcd_queue_transactions(_hcd, tr_type);
+               }
        }
+       /*
+        * Make sure the start of frame interrupt is enabled now that
+        * we know we should have queued data. The SOF interrupt
+        * handler automatically disables itself when idle to reduce
+        * the number of interrupts. See dwc_otg_hcd_handle_sof_intr()
+        * for the disable
+        */
+       dwc_modify_reg32(&_hcd->core_if->core_global_regs->gintmsk, 0,
+                        DWC_SOF_INTR_MASK);
 }
 
 /**
@@ -1201,6 +1230,12 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t *_hcd,
                         * occurs. The core will continue transferring data.
                         */
                        _qtd->error_count = 0;
+                       //yk@rk 20100714
+                       #if 1
+                       if((_hcd->core_if->core_params->host_channels <= 2)
+                               &&(!_hc->halt_pending))
+                       dwc_otg_hc_halt(_hcd->core_if, _hc, DWC_OTG_HC_XFER_NAK);
+                       #endif
                        goto handle_nak_done;
                }
 
@@ -1238,6 +1273,8 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t *_hcd,
        }
 
  handle_nak_done:
+       clear_hc_int(_hc_regs,nak);
+       if(_hcd->core_if->core_params->host_channels > 2)
        disable_hc_int(_hc_regs,nak);
 
        return 1;
@@ -1697,6 +1734,23 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t *_hcd,
        hcint.d32 = dwc_read_reg32(&_hc_regs->hcint);
        hcintmsk.d32 = dwc_read_reg32(&_hc_regs->hcintmsk);
 
+       if((!hcint.b.xfercomp)&&
+               (_hcd->core_if->core_params->host_channels <= 2)&&
+               (_hc->halt_pending)&&
+               (_hc->ep_is_in)&&
+               (_hc->ep_type == DWC_OTG_EP_TYPE_BULK))
+       {
+               if(hcint.b.ack && !hcintmsk.b.ack)
+               {
+                       //DWC_PRINT("Halt pending, ack!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+                       handle_hc_xfercomp_intr(_hcd, _hc, _hc_regs, _qtd);
+                       return;
+               }
+               release_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK);
+               clear_hc_int(_hc_regs,chhltd);  
+               return;
+       }
+       
        if (hcint.b.xfercomp) {
                /** @todo This is here because of a possible hardware bug.  Spec
                 * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
@@ -1745,6 +1799,10 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t *_hcd,
                 * split transfers. Start splits halt on ACK.
                 */
                handle_hc_ack_intr(_hcd, _hc, _hc_regs, _qtd);
+       } else if(hcint.b.datatglerr){
+            DWC_PRINT("%s, DATA toggle error\n");
+            dwc_debug(1);
+                               clear_hc_int(_hc_regs,chhltd);
        } else {
                if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
                    _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
@@ -1764,6 +1822,7 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t *_hcd,
                                  "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n",
                                  __func__, _hc->hc_num, hcint.d32,
                                  dwc_read_reg32(&_hcd->core_if->core_global_regs->gintsts));
+                               clear_hc_int(_hc_regs,chhltd);
                }
        }
 }