hidg: support boot protocol
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc_otg / dwc_otg_pcd.c
index 8eb9face90966b2bad5704308c33651a277abda0..50ec2d87860509fbae80633c766faedea2442d18 100755 (executable)
@@ -61,7 +61,6 @@
  *
  */
 
-#include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
 #include <linux/irq.h>
 #include <linux/kallsyms.h>
+#include <linux/device.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/platform_device.h>
 
+#include <linux/usb/composite.h>
+
 #include "dwc_otg_driver.h"
 #include "dwc_otg_pcd.h"
 #include "dwc_otg_regs.h"
 
-#include <linux/usb/composite.h>
-#include <mach/cru.h>
-
+#include "usbdev_rk.h"
 /**
  * Static PCD pointer for use in usb_gadget_register_driver and
  * usb_gadget_unregister_driver.  Initialized in dwc_otg_pcd_init.
@@ -105,10 +105,10 @@ void request_done(dwc_otg_pcd_ep_t *_ep, dwc_otg_pcd_request_t *_req,
                                  int _status)
 {
        unsigned stopped = _ep->stopped;
-
+    
        DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _ep);
        list_del_init(&_req->queue);
-             
+
        if (_req->req.status == -EINPROGRESS) 
        {
                _req->req.status = _status;
@@ -117,22 +117,23 @@ void request_done(dwc_otg_pcd_ep_t *_ep, dwc_otg_pcd_request_t *_req,
        {       
                _status = _req->req.status;
        }
-#if 0
-
-               if (_req->mapped) {
-                       dma_unmap_single(_ep->pcd->gadget.dev.parent,
-                               _req->req.dma, _req->req.length,
-                               _ep->dwc_ep.is_in
-                                       ? DMA_TO_DEVICE
-                                       : DMA_FROM_DEVICE);
-                       _req->req.dma = DMA_ADDR_INVALID;
-                       _req->mapped = 0;
-               } else
-                       dma_sync_single_for_cpu(_ep->pcd->gadget.dev.parent,
-                               _req->req.dma, _req->req.length,
-                               _ep->dwc_ep.is_in
-                                       ? DMA_TO_DEVICE
-                                       : DMA_FROM_DEVICE);
+#if 1
+    if (_req->req.dma != DMA_ADDR_INVALID){
+       if (_req->mapped) {
+               dma_unmap_single(_ep->pcd->gadget.dev.parent,
+                       _req->req.dma, _req->req.length,
+                       _ep->dwc_ep.is_in
+                               ? DMA_TO_DEVICE
+                               : DMA_FROM_DEVICE);
+               _req->req.dma = DMA_ADDR_INVALID;
+               _req->mapped = 0;
+       } else
+               dma_sync_single_for_cpu(_ep->pcd->gadget.dev.parent,
+                       _req->req.dma, _req->req.length,
+                       _ep->dwc_ep.is_in
+                               ? DMA_TO_DEVICE
+                               : DMA_FROM_DEVICE);
+       }
 #endif
        /* don't modify queue heads during completion callback */
        _ep->stopped = 1;
@@ -187,7 +188,7 @@ void request_nuke( dwc_otg_pcd_ep_t *_ep )
  * This function assigns periodic Tx FIFO to an periodic EP
  * in shared Tx FIFO mode
  */
- #if 0
+#ifndef CONFIG_ARCH_RK29
 static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t *core_if)
 {
        uint32_t PerTxMsk = 1;
@@ -214,9 +215,9 @@ static void release_perio_tx_fifo(dwc_otg_core_if_t *core_if, uint32_t fifo_num)
 }
 /**
  * This function assigns periodic Tx FIFO to an periodic EP
- * in shared Tx FIFO mode
+ * in Dedicated FIFOs mode
  */
-#if 0
+#ifndef CONFIG_ARCH_RK29
 static uint32_t assign_tx_fifo(dwc_otg_core_if_t *core_if)
 {
        uint32_t TxMsk = 1;
@@ -236,7 +237,7 @@ static uint32_t assign_tx_fifo(dwc_otg_core_if_t *core_if)
 #endif
 /**
  * This function releases periodic Tx FIFO 
- * in shared Tx FIFO mode
+ * in Dedicated FIFOs mode
  */
 static void release_tx_fifo(dwc_otg_core_if_t  *core_if, uint32_t fifo_num)
 {
@@ -302,7 +303,7 @@ static int dwc_otg_pcd_ep_enable(struct usb_ep *_ep,
 
        if(ep->dwc_ep.is_in)
        {
-               #if 0
+#ifndef CONFIG_ARCH_RK29
                if(!pcd->otg_dev->core_if->en_multiple_tx_fifo)
                {
                        ep->dwc_ep.tx_fifo_num = 0;
@@ -323,12 +324,12 @@ static int dwc_otg_pcd_ep_enable(struct usb_ep *_ep,
                         */
                        ep->dwc_ep.tx_fifo_num = assign_tx_fifo(pcd->otg_dev->core_if);
                }
-                        #endif 
+#else
         /* yk@rk
          * ep0 -- tx fifo 0
          * ep1 -- tx fifo 1
-         * ep3 -- tx fifo 2
-         * ep5 -- tx fifo 3
+         * ep3 -- tx fifo 3
+         * ep5 -- tx fifo 2
          */
         if(ep->dwc_ep.num == 0)
                ep->dwc_ep.tx_fifo_num = 0;
@@ -336,8 +337,11 @@ static int dwc_otg_pcd_ep_enable(struct usb_ep *_ep,
                 ep->dwc_ep.tx_fifo_num = 1;
         else if(ep->dwc_ep.num == 3)
                 ep->dwc_ep.tx_fifo_num = 3;
+        else if(ep->dwc_ep.num == 5)
+                ep->dwc_ep.tx_fifo_num = 2;
         else
            ep->dwc_ep.tx_fifo_num = (ep->dwc_ep.num>>1)+1 ; /* 1,3,5 */
+#endif
        }                
        /* Set initial data PID. */
        if ((_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == 
@@ -564,11 +568,9 @@ static int dwc_otg_pcd_ep_queue(struct usb_ep *_ep,
        /* 20091226,HSL@RK */
        if ( !list_empty(&req->queue) ) 
        {
-        while(!list_empty(&req->queue) ) {
-                ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);
-                request_done(ep, req, -ECONNABORTED);
-        DWC_PRINT("%s::ep %s req not empty,done it error!\n" , __func__, _ep->name);
-        }
+               list_del_init(&req->queue);
+               ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);
+               DWC_PRINT("%s::ep %s req not empty,done it error!\n" , __func__, _ep->name);
                return -EINVAL;
        }
        
@@ -599,7 +601,6 @@ static int dwc_otg_pcd_ep_queue(struct usb_ep *_ep,
                }
        }
 
-       SPIN_LOCK_IRQSAVE(&ep->pcd->lock, flags);
 
 #if defined(DEBUG) & defined(VERBOSE)
        dump_msg(_req->buf, _req->length);
@@ -620,6 +621,8 @@ static int dwc_otg_pcd_ep_queue(struct usb_ep *_ep,
                                                : DMA_FROM_DEVICE);
                req->mapped = 0;
        }
+       SPIN_LOCK_IRQSAVE(&pcd->lock, flags);
+       
        _req->status = -EINPROGRESS;
        _req->actual = 0;
 
@@ -644,6 +647,10 @@ static int dwc_otg_pcd_ep_queue(struct usb_ep *_ep,
                                DWC_DEBUGPL(DBG_PCD, 
                                                                "%s ep0: EP0_IN_DATA_PHASE\n", 
                                                                __func__);
+                           if((_req->length % MAX_EP0_SIZE) == 0){
+                               if(_req->zero)
+                                   ep->dwc_ep.sent_zlp = 1;
+                               }
                                break;
 
                        case EP0_OUT_DATA_PHASE:
@@ -657,7 +664,13 @@ static int dwc_otg_pcd_ep_queue(struct usb_ep *_ep,
                                        pcd->ep0state = EP0_STATUS;
                                }
                                break;
-                                               
+                               
+                       case EP0_STATUS:
+                               DWC_DEBUGPL(DBG_PCD,
+                                           "%s ep0: EP0_IN_STATUS_PHASE\n",
+                                           __func__);
+                               break;
+                               
                        default:
                                DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n", 
                                                                                        pcd->ep0state);
@@ -670,7 +683,6 @@ static int dwc_otg_pcd_ep_queue(struct usb_ep *_ep,
                        ep->dwc_ep.xfer_buff = _req->buf;
                        ep->dwc_ep.xfer_len = _req->length;
                        ep->dwc_ep.xfer_count = 0;
-                       ep->dwc_ep.sent_zlp = 0;
                        ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
                        dwc_otg_ep0_start_transfer( GET_CORE_IF(pcd), 
                                                                                &ep->dwc_ep );
@@ -717,6 +729,9 @@ static int dwc_otg_pcd_ep_dequeue(struct usb_ep *_ep,
        dwc_otg_pcd_ep_t *ep;
        dwc_otg_pcd_t   *pcd;
        unsigned long flags;
+    volatile depctl_data_t depctl = {.d32 = 0};
+    
+    dwc_otg_dev_out_ep_regs_t *out_regs;
 
        DWC_DEBUGPL(DBG_PCDV,"%s(%p,%p)\n", __func__, _ep, _req);
                
@@ -729,7 +744,7 @@ static int dwc_otg_pcd_ep_dequeue(struct usb_ep *_ep,
        pcd = ep->pcd;
        if (!pcd->driver || pcd->gadget.speed == USB_SPEED_UNKNOWN) 
        {
-               DWC_WARN("%s, bogus device state\n", __func__);
+               DWC_WARN("%s, bogus device state, %p, speed %d\n", __func__, pcd->driver, pcd->gadget.speed);
                return -ESHUTDOWN;
        }
 
@@ -761,7 +776,14 @@ static int dwc_otg_pcd_ep_dequeue(struct usb_ep *_ep,
        {
                req = 0;
        }
-               
+
+       // kevery@20120602 NAK out request before new queue request
+       if(!ep->dwc_ep.is_in){
+        out_regs = GET_CORE_IF(pcd)->dev_if->out_ep_regs[ep->dwc_ep.num];
+        depctl.d32 = dwc_read_reg32(&(out_regs->doepctl));
+       depctl.b.snak = 1;
+        dwc_write_reg32( &(out_regs->doepctl), depctl.d32 );
+    }
        SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);
 
        return req ? 0 : -EOPNOTSUPP;
@@ -1019,15 +1041,19 @@ static int dwc_otg_pcd_pullup(struct usb_gadget *_gadget, int is_on)
        }
        if(is_on)   //connect
        {
-        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 );
+#ifdef CONFIG_DWC_CONN_EN
+        pcd->conn_en = 1;
+#else
+        pcd->conn_en = 0;
+#endif
+        pcd->conn_status = 0;
     }
     else        //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 );
+        pcd->conn_status = 3;
     }
     return 0;
 }
@@ -1140,9 +1166,7 @@ static int32_t dwc_otg_pcd_suspend_cb( void *_p ,int suspend)
 //#endif               
        if (pcd->driver && pcd->driver->resume) 
        {
-               SPIN_UNLOCK(&pcd->lock);
                pcd->driver->suspend(&pcd->gadget);
-               SPIN_LOCK(&pcd->lock);
        }
        return 1;
 }
@@ -1160,9 +1184,7 @@ static int32_t dwc_otg_pcd_resume_cb( void *_p )
        
        if (pcd->driver && pcd->driver->resume) 
        {
-                       SPIN_UNLOCK(&pcd->lock);
                        pcd->driver->resume(&pcd->gadget);
-                       SPIN_LOCK(&pcd->lock);
        }
        
        /* Stop the SRP timeout timer. */
@@ -1337,7 +1359,11 @@ void dwc_otg_pcd_reinit(dwc_otg_pcd_t *_pcd)
                        "ep2in",        
                        "ep3in",        
                        "ep4in",        
+#ifdef CONFIG_ARCH_RK29
+                       "ep5in-int",    
+#else
                        "ep5in",        
+#endif
                        "ep6in",        
                        "ep7in",        
                        "ep8in",        
@@ -1469,10 +1495,19 @@ void dwc_otg_pcd_reinit(dwc_otg_pcd_t *_pcd)
                         * here?  Before EP type is set?
                         */
                        ep->ep.maxpacket = MAX_PACKET_SIZE;
-       
+                       
+                       INIT_LIST_HEAD (&ep->queue);
+
+                       /**
+                        * @yk@rk 20120329
+                        * EP8&EP9 of rk30 are IN&OUT ep, we use ep8 as OUT EP default
+                        */
+              #ifndef CONFIG_ARCH_RK29
+               if(i == 8)
+                   continue;
+               #endif
                        list_add_tail (&ep->ep.ep_list, &_pcd->gadget.ep_list);
                                
-                       INIT_LIST_HEAD (&ep->queue);
                }
                hwcfg1 >>= 2;
        }
@@ -1522,9 +1557,18 @@ void dwc_otg_pcd_reinit(dwc_otg_pcd_t *_pcd)
                         */
                        ep->ep.maxpacket = MAX_PACKET_SIZE;
        
+                       INIT_LIST_HEAD (&ep->queue);
+                       
+                       /**
+                        * @yk@rk 20120329
+                        * EP8&EP9 of rk30 are IN&OUT ep, we use ep9 as IN EP default
+                        */
+               #ifndef CONFIG_ARCH_RK29
+               if(i == 9)
+                   continue;
+               #endif
                        list_add_tail (&ep->ep.ep_list, &_pcd->gadget.ep_list);
                                
-                       INIT_LIST_HEAD (&ep->queue);
                }
                hwcfg1 >>= 2;
        }
@@ -1553,8 +1597,7 @@ int dwc_pcd_reset(dwc_otg_pcd_t *pcd)
 {
     dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
     dwc_otg_disable_global_interrupts( core_if );
-    //
-
+#ifdef CONFIG_ARCH_RK29
     cru_set_soft_reset(SOFT_RST_USB_OTG_2_0_AHB_BUS, true);
     cru_set_soft_reset(SOFT_RST_USB_OTG_2_0_PHY, true);
     cru_set_soft_reset(SOFT_RST_USB_OTG_2_0_CONTROLLER, true);
@@ -1563,7 +1606,8 @@ int dwc_pcd_reset(dwc_otg_pcd_t *pcd)
     cru_set_soft_reset(SOFT_RST_USB_OTG_2_0_AHB_BUS, false);
     cru_set_soft_reset(SOFT_RST_USB_OTG_2_0_PHY, false);
     cru_set_soft_reset(SOFT_RST_USB_OTG_2_0_CONTROLLER, false);
-    
+    mdelay(1);
+#endif    
     //rockchip_scu_reset_unit(12);
     dwc_otg_pcd_reinit( pcd );
     dwc_otg_core_dev_init(core_if);
@@ -1572,55 +1616,6 @@ int dwc_pcd_reset(dwc_otg_pcd_t *pcd)
     return 0;
 }
 
-/*
- * close usb phy , about 7ma--2.5v
- * 20090925,add vbus test code.500ms ¼ä¸ô.
- * 20100122,HSL@RK,hard reset usb controller and phy.
-*/
-int rk28_usb_suspend( int exitsuspend )
-{
-       dwc_otg_pcd_t *pcd = s_pcd;
-
-    unsigned int * otg_phy_con1 = (unsigned int*)(USB_GRF_CON);
-    if(exitsuspend && (pcd->phy_suspend == 1)) {
-        clk_enable(pcd->otg_dev->ahbclk);
-        clk_enable(pcd->otg_dev->phyclk);
-        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)) {
-        pcd->phy_suspend = 1;
-        *otg_phy_con1 |= (0x01<<2);
-        *otg_phy_con1 &= ~(0x01<<3);    // enter suspend.
-        udelay(3);
-        clk_disable(pcd->otg_dev->phyclk);
-        clk_disable(pcd->otg_dev->ahbclk);
-        //*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 )
-{
-       dwc_otg_pcd_t *pcd = s_pcd;
-    if( pcd ) {
-        del_timer(&pcd->check_vbus_timer); 
-    }
-    mdelay( 10 );
-    if( pcd ) {
-        pcd->phy_suspend = 1;
-        pcd->vbus_status = 0;
-       dwc_otg_pcd_start_vbus_timer(pcd);
-    }
-}
 
 
 int dwc_otg_reset( void ) 
@@ -1639,20 +1634,18 @@ void dwc_otg_msc_lock(dwc_otg_pcd_t *pcd)
 {
        unsigned long           flags;
 
-       spin_lock_irqsave(&pcd->lock, flags);
-
+       local_irq_save(flags);
     wake_lock(&pcd->wake_lock);
-
-       spin_unlock_irqrestore(&pcd->lock, flags);
+    local_irq_restore(flags);
 
 }
 
 void dwc_otg_msc_unlock(dwc_otg_pcd_t *pcd)
 {
        unsigned long           flags;
-       spin_lock_irqsave(&pcd->lock, flags);
+       local_irq_save(flags);
        wake_unlock(&pcd->wake_lock);
-    spin_unlock_irqrestore(&pcd->lock, flags);
+       local_irq_restore(flags);
 }
 static void dwc_phy_reconnect(struct work_struct *work)
 {
@@ -1677,16 +1670,19 @@ static void dwc_phy_reconnect(struct work_struct *work)
         DWC_PRINT("********soft connect!!!*****************************************\n");
     } 
 }
-
+#if defined(CONFIG_ARCH_RK29)
 static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata )
 {
-    dwc_otg_pcd_t * _pcd = (dwc_otg_pcd_t *)pdata;
+    struct device *_dev = (struct device *)pdata;
+       struct dwc_otg_platform_data *pldata = _dev->platform_data;
+       dwc_otg_device_t *otg_dev = (dwc_otg_device_t *)(*((uint32_t *)_dev->platform_data));
+    dwc_otg_pcd_t * _pcd = otg_dev->pcd;
     dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
     gotgctl_data_t    gctrl;
     dctl_data_t dctl = {.d32=0};
     //dsts_data_t           gsts;
-       unsigned long flags;
-       local_irq_save(flags);
+        unsigned long flags;
+        local_irq_save(flags);
     gctrl.d32 = dwc_read_reg32( &core_if->core_global_regs->gotgctl );
     //gsts.d32 = dwc_read_reg32( &core_if->dev_if->dev_global_regs->dsts);
 
@@ -1696,48 +1692,45 @@ static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata )
          if( _pcd->vbus_status == 0 ) {
             dwc_otg_msc_lock(_pcd);
             DWC_PRINT("********vbus detect*********************************************\n");
-           _pcd->vbus_status = 1;
+            _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>0)&&(_pcd->conn_status <3)) {
             //dwc_otg_msc_unlock(_pcd);
             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 );
+                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); 
+            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_en)&&(_pcd->conn_status == 0))
         {
-       
-           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*//
+                        //*????????,??????????,yk@rk,20100331*//
             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 {
@@ -1749,22 +1742,124 @@ static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata )
              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 ) {
+        if( pldata->phy_status == 0 ) {
                 /* no vbus detect here , close usb phy for 500ms */
-             rk28_usb_suspend( 0 );
+            pldata->phy_suspend(pldata, USB_PHY_SUSPEND);
+            //dwc_otg20phy_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  */
-             
+        } else if( pldata->phy_status  == 1 ) {
+            pldata->phy_suspend(pldata, USB_PHY_ENABLED);
+           // dwc_otg20phy_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);
+        local_irq_restore(flags);
+}
+#else
+
+static void dwc_otg_pcd_check_vbus_timer( unsigned long data )
+{
+    struct device *_dev = (struct device *)data;
+       struct dwc_otg_platform_data *pldata = _dev->platform_data;
+       dwc_otg_device_t *otg_dev = (dwc_otg_device_t *)(*((uint32_t *)_dev->platform_data));
+    dwc_otg_pcd_t * _pcd = otg_dev->pcd;
+    unsigned long flags;
+    local_irq_save(flags);
+    _pcd->check_vbus_timer.expires = jiffies + (HZ); /* 1 s */
+    if(!pldata->get_status(USB_STATUS_ID))
+    {  // id low
+        if( pldata->dwc_otg_uart_mode != NULL )
+        {//exit phy bypass to uart & enable usb phy
+            pldata->dwc_otg_uart_mode( pldata, PHY_USB_MODE);
+        }
+        if( pldata->phy_status)
+        { 
+            pldata->clock_enable( pldata, 1);          
+            pldata->phy_suspend(pldata, USB_PHY_ENABLED);
+        } 
+    }
+       else if(pldata->get_status(USB_STATUS_BVABLID))
+       {  // bvalid
+        /* if usb not connect before ,then start connect */
+         if( _pcd->vbus_status == 0 ) 
+         {
+            DWC_PRINT("********vbus detect*********************************************\n");
+           _pcd->vbus_status = 1;
+            if(_pcd->conn_en)
+                goto connect;
+            else if( pldata->phy_status == USB_PHY_ENABLED )
+            {
+                // not connect, suspend phy
+                pldata->phy_suspend(pldata, USB_PHY_SUSPEND);
+                udelay(3);
+                pldata->clock_enable( pldata, 0);
+            }
+        } 
+        else if((_pcd->conn_en)&&(_pcd->conn_status>=0)&&(_pcd->conn_status <3))
+        {
+            DWC_PRINT("********soft reconnect******************************************\n");
+           goto connect;
+        }
+        else if(_pcd->conn_status ==3)
+        {
+                       //*Á¬½Ó²»ÉÏʱÊÍ·ÅËø£¬ÔÊÐíϵͳ½øÈë¶þ¼¶Ë¯Ãߣ¬yk@rk,20100331*//
+            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;
+                
+            // not connect, suspend phy
+            if( pldata->phy_status == USB_PHY_ENABLED )
+            {
+                pldata->phy_suspend(pldata, USB_PHY_SUSPEND);
+                udelay(3);
+                pldata->clock_enable( pldata, 0);
+            }
+        }
+       }
+    else 
+    {
+        _pcd->vbus_status = 0;
+        if(_pcd->conn_status)
+        {
+             _pcd->conn_status = 0;
+        }
+        else if( pldata->phy_status == USB_PHY_ENABLED )
+        { 
+            /* no vbus detect here , close usb phy  */
+            pldata->phy_suspend(pldata, USB_PHY_SUSPEND);
+            udelay(3);
+            pldata->clock_enable( pldata, 0);
+            /* usb phy bypass to uart mode  */
+            if( pldata->dwc_otg_uart_mode != NULL )
+                pldata->dwc_otg_uart_mode( pldata, PHY_UART_MODE);    
+            /* release wake lock */
+            dwc_otg_msc_unlock(_pcd);
+        }  
+    }
     add_timer(&_pcd->check_vbus_timer); 
        local_irq_restore(flags);
-}
+    return;
 
+connect:
+    if(_pcd->conn_status==0)
+        dwc_otg_msc_lock(_pcd);
+    if( pldata->phy_status)
+    {
+        pldata->clock_enable( pldata, 1);      
+        pldata->phy_suspend(pldata, USB_PHY_ENABLED);
+    }
+    schedule_delayed_work( &_pcd->reconnect , 8 ); /* delay 1 jiffies */
+    _pcd->check_vbus_timer.expires = jiffies + (HZ<<1); /* 1 s */
+    add_timer(&_pcd->check_vbus_timer); 
+       local_irq_restore(flags);
+    return;
+}
+#endif
 void dwc_otg_pcd_start_vbus_timer( dwc_otg_pcd_t * _pcd )
 {
         struct timer_list *vbus_timer = &_pcd->check_vbus_timer;
@@ -1782,7 +1877,10 @@ void dwc_otg_pcd_start_vbus_timer( dwc_otg_pcd_t * _pcd )
 int dwc_vbus_status( void )
 {
     dwc_otg_pcd_t *pcd = s_pcd;
-    return pcd->vbus_status ;
+    if(!pcd)
+       return 0;
+    else
+        return pcd->vbus_status ;
 }
 EXPORT_SYMBOL(dwc_vbus_status);
 
@@ -1800,8 +1898,9 @@ int dwc_otg_pcd_init(struct device *dev)
 {
        static char pcd_name[] = "dwc_otg_pcd";
        dwc_otg_pcd_t *pcd;
-       dwc_otg_device_t *otg_dev = dev->platform_data;
-    dwc_otg_core_if_t *core_if = otg_dev->core_if;
+       dwc_otg_device_t *otg_dev = (dwc_otg_device_t *)(*((uint32_t *)dev->platform_data));
+    dwc_otg_core_if_t *core_if = otg_dev->core_if; 
+       struct dwc_otg_platform_data *pldata = dev->platform_data;
        int retval = 0;
        int irq;
         /*
@@ -1816,7 +1915,6 @@ int dwc_otg_pcd_init(struct device *dev)
        
        memset( pcd, 0, sizeof(dwc_otg_pcd_t));
        spin_lock_init( &pcd->lock );
-       
        otg_dev->pcd = pcd;
        s_pcd = pcd;
        pcd->gadget.name = pcd_name;
@@ -1832,11 +1930,7 @@ int dwc_otg_pcd_init(struct device *dev)
        pcd->gadget.is_dualspeed = 0;
        pcd->gadget.is_otg = 0;
        pcd->driver = 0;
-#ifdef CONFIG_DWC_CONN_EN
-    pcd->conn_en = 1;
-#else
     pcd->conn_en = 0;
-#endif
        /* Register the gadget device */
        retval = device_register( &pcd->gadget.dev );
        if(retval != 0)
@@ -1899,14 +1993,30 @@ int dwc_otg_pcd_init(struct device *dev)
 
     init_timer( &pcd->check_vbus_timer );
     pcd->check_vbus_timer.function = dwc_otg_pcd_check_vbus_timer;
-    pcd->check_vbus_timer.data = (unsigned long)(pcd);
+    pcd->check_vbus_timer.data = (unsigned long)(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))
-        mod_timer(&pcd->check_vbus_timer, jiffies+(HZ<<4)); // delay 16 S
-//     dwc_otg_pcd_start_vbus_timer( pcd );
+    pcd->phy_suspend  = 0; 
+    if(dwc_otg_is_device_mode(core_if)){
+#ifdef CONFIG_RK_USB_UART        
+        if(pldata->get_status(USB_STATUS_BVABLID))
+        {
+             pldata->dwc_otg_uart_mode(pldata, PHY_USB_MODE);
+        }//phy usb mode
+        else
+        {
+            pldata->phy_suspend(pldata,USB_PHY_SUSPEND);
+            pldata->dwc_otg_uart_mode(pldata, PHY_UART_MODE);
+        }//phy bypass to uart mode
+#endif
+        mod_timer(&pcd->check_vbus_timer, jiffies+(HZ<<4)); // delay 16 S 
+    }
+#ifdef CONFIG_RK_USB_UART
+    else if(pldata->dwc_otg_uart_mode != NULL)
+        pldata->dwc_otg_uart_mode(pldata, PHY_USB_MODE);//disable phy bypass uart  
+#endif
+
        return 0;
 }
 /**
@@ -1914,7 +2024,7 @@ int dwc_otg_pcd_init(struct device *dev)
  */
 void dwc_otg_pcd_remove( struct device *dev )
 {
-       dwc_otg_device_t *otg_dev = dev->platform_data;
+       dwc_otg_device_t *otg_dev = (dwc_otg_device_t *)(*((uint32_t *)dev->platform_data));
        dwc_otg_pcd_t *pcd = otg_dev->pcd;
        
        DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
@@ -1949,7 +2059,7 @@ void dwc_otg_pcd_remove( struct device *dev )
        
        kfree( pcd );
        otg_dev->pcd = 0;
-            s_pcd = 0; // HSL@RK,20090901
+    s_pcd = 0; 
 }
 
 /**
@@ -1963,14 +2073,23 @@ void dwc_otg_pcd_remove( struct device *dev )
  * @param _driver The driver being registered
  */
  
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
+int usb_gadget_probe_driver(struct usb_gadget_driver *_driver,
+               int (*bind)(struct usb_gadget *))
+#else
 int usb_gadget_register_driver(struct usb_gadget_driver *_driver)
+#endif
 {
        int retval;
 
        DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n", _driver->driver.name);
                
        if (!_driver || _driver->speed == USB_SPEED_UNKNOWN || 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
+               !bind ||
+#else
                !_driver->bind || 
+#endif
                !_driver->unbind || 
                !_driver->disconnect || 
                !_driver->setup) 
@@ -1994,7 +2113,11 @@ int usb_gadget_register_driver(struct usb_gadget_driver *_driver)
        s_pcd->gadget.dev.driver = &_driver->driver;
 
        DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", _driver->driver.name);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
+       retval = bind(&s_pcd->gadget);
+#else
        retval = _driver->bind(&s_pcd->gadget);
+#endif
        if (retval) 
        {
                DWC_ERROR("bind to driver %s --> error %d\n",
@@ -2007,8 +2130,11 @@ int usb_gadget_register_driver(struct usb_gadget_driver *_driver)
                                        _driver->driver.name);
        return 0;
 }
-
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
+EXPORT_SYMBOL(usb_gadget_probe_driver);
+#else
 EXPORT_SYMBOL(usb_gadget_register_driver);
+#endif
 
 /**
  * This function unregisters a gadget driver