usb support otg mode
authoryangkai <yangkai@ubuntu-fs>
Fri, 20 May 2011 06:39:46 +0000 (14:39 +0800)
committeryangkai <yangkai@ubuntu-fs>
Fri, 20 May 2011 06:39:46 +0000 (14:39 +0800)
drivers/usb/core/hub.c
drivers/usb/dwc_otg/Kconfig
drivers/usb/dwc_otg/Makefile
drivers/usb/dwc_otg/dwc_otg_attr.c
drivers/usb/dwc_otg/dwc_otg_cil.c
drivers/usb/dwc_otg/dwc_otg_cil_intr.c
drivers/usb/dwc_otg/dwc_otg_driver.c
drivers/usb/dwc_otg/dwc_otg_hcd.c
drivers/usb/dwc_otg/dwc_otg_pcd.c

index 9478cf70509b9f1632afa530eb87ca3f02ce8b85..7a631055ce64250aff1f007f2c27f7e770004b62 100755 (executable)
@@ -1168,6 +1168,7 @@ static void hub_disconnect(struct usb_interface *intf)
 
        kref_put(&hub->kref, hub_release);
 }
+struct usb_hub *g_root_hub20 = NULL;
 static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
        struct usb_host_interface *desc;
@@ -1218,6 +1219,10 @@ descriptor_error:
                dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");
                return -ENOMEM;
        }
+       if(!g_root_hub20)
+       {
+               g_root_hub20 = hub;
+       }
        kref_init(&hub->kref);
        INIT_LIST_HEAD(&hub->event_list);
        hub->intfdev = &intf->dev;
index 004b92d016aa940aa0ad585a967e704566eeafa9..5116703c1a3a886f6cb78590c7554f14af0d239a 100755 (executable)
@@ -50,11 +50,30 @@ config DWC_OTG_DEVICE_ONLY
          USB2.0 OTG controller worked in device mode
          and device can connect to PC via USB cable.
 
+config DWC_OTG_BOTH_HOST_SLAVE
+       bool "BOTH HOST AND SLAVE"
+       depends on USB20_OTG && USB_GADGET && USB
+
+endchoice
+
+choice 
+       bool "    Controller default status"
+       depends on DWC_OTG_BOTH_HOST_SLAVE
+       default DWC_OTG_DEFAULT_ID
+
+config DWC_OTG_DEFAULT_ID
+       bool "depends on USB_ID"
+
+config DWC_OTG_DEFAULT_HOST
+       bool "HOST"
+
+config DWC_OTG_DEFAULT_DEVICE
+       bool "DEVICE"
 endchoice
 
 config DWC_CONN_EN
        bool "---connect to PC when vbus detect"
-       depends on DWC_OTG_DEVICE_ONLY
+       depends on USB_GADGET
        default y
        help
          USB2.0 OTG controller always polling the USB vbus
@@ -63,7 +82,7 @@ config DWC_CONN_EN
 
 config USB20_OTG_EN
        bool "---usb2.0 otg host controller enable"
-       depends on DWC_OTG_HOST_ONLY
+       depends on DWC_OTG_HOST_ONLY || DWC_OTG_BOTH_HOST_SLAVE
        default y
 
 config DWC_OTG_DEBUG
index 9b5cd633712efc4965862c013af97e06cb0c02ae..e60402dff9239c2c7cb575774e0175f02675e6ab 100755 (executable)
@@ -13,10 +13,13 @@ ifeq ($(CONFIG_DWC_OTG_HOST_ONLY),y)
 EXTRA_CFLAGS   += -DDWC_HOST_ONLY
 endif
 
-ifneq ($(CONFIG_USB),y)
-EXTRA_CFLAGS   += -DDWC_DEVICE_ONLY
-endif
+#ifeq ($(CONFIG_DWC_OTG_DEVICE_ONLY),y)
+#EXTRA_CFLAGS   += -DDWC_DEVICE_ONLY
+#endif
 
+ifeq ($(CONFIG_DWC_OTG_BOTH_HOST_SLAVE),y)
+EXTRA_CFLAGS   += -DDWC_BOTH_HOST_SLAVE
+endif
 #EXTRA_CFLAGS += -Dlinux -DDWC_HS_ELECT_TST
 
 dwc_otg-objs    := dwc_otg_driver.o dwc_otg_attr.o
index 710c9ca9e27b1441be0e02c2cdd096a23d068f65..01d5a74f57e18f341e15b96277c82ba81c9d54c2 100755 (executable)
@@ -736,6 +736,7 @@ static ssize_t wr_reg_test_show( struct device *_dev,
 
 DEVICE_ATTR(wr_reg_test, S_IRUGO|S_IWUSR, wr_reg_test_show, 0);
 extern int dwc_debug(dwc_otg_core_if_t *core_if, int flag);
+
 static ssize_t debug_show( struct device *_dev, 
                                                                struct device_attribute *attr, char *buf) 
 {
index 4c20f6ba3a2672c17b71019c50e597b76c1819e6..679abfe28f0fde3535665ad41f6c71c605aac722 100755 (executable)
@@ -454,6 +454,7 @@ void dwc_otg_core_init(dwc_otg_core_if_t *_core_if)
 
        /* Reset the Controller */
        dwc_otg_core_reset( _core_if );
+    DWC_PRINT("GINTSTS:0x%x \n",_core_if->core_global_regs->gintsts);
 
        /* Initialize parameters from Hardware configuration registers. */
        dev_if->num_in_eps = calc_num_in_eps(_core_if);
@@ -628,7 +629,7 @@ void dwc_otg_core_init(dwc_otg_core_if_t *_core_if)
 
        /* Enable common interrupts */
        dwc_otg_enable_common_interrupts( _core_if );
-
+    DWC_PRINT("GINTSTS:0x%x kever@rk 20110425\n",_core_if->core_global_regs->gintsts);
        /* Do device or host intialization based on mode during PCD
         * and HCD initialization  */
        if (dwc_otg_is_host_mode( _core_if )) 
@@ -3337,14 +3338,14 @@ void dwc_otg_dump_flags(dwc_otg_core_if_t *_core_if)
        DWC_PRINT("core_if->usb_wakeup = %x\n",_core_if->usb_wakeup);
 }
 
-#ifdef CONFIG_DWC_OTG_DEVICE_ONLY
+#ifndef CONFIG_DWC_OTG_HOST_ONLY
 extern void dwc_otg_pcd_stop(dwc_otg_pcd_t *_pcd);
 #endif
 int dwc_debug(dwc_otg_core_if_t *core_if, int flag)
 {
     dctl_data_t dctl = {.d32=0};
        //dwc_otg_core_if_t *core_if = dwc_core_if;
-       #ifdef CONFIG_DWC_OTG_DEVICE_ONLY
+       #ifndef CONFIG_DWC_OTG_HOST_ONLY
         dwc_otg_pcd_t * pcd;
     #endif
        struct dwc_otg_device *otg_dev;
@@ -3355,7 +3356,7 @@ int dwc_debug(dwc_otg_core_if_t *core_if, int flag)
                        dwc_otg_dump_host_registers(core_if);
                        break;
                case 2:
-               #ifdef CONFIG_DWC_OTG_DEVICE_ONLY
+               #ifndef CONFIG_DWC_OTG_HOST_ONLY
                    otg_dev = core_if->otg_dev;
                    pcd = otg_dev->pcd;
                    pcd->vbus_status = 0;
@@ -3383,7 +3384,7 @@ int dwc_debug(dwc_otg_core_if_t *core_if, int flag)
                        dwc_otg_dump_flags(core_if);
                        break;
                case 8:
-               #ifdef CONFIG_DWC_OTG_DEVICE_ONLY
+               #ifndef CONFIG_DWC_OTG_HOST_ONLY
                    otg_dev = core_if->otg_dev;
                    pcd = otg_dev->pcd;
                    //pcd->vbus_status = 0;
index eac5dc5c74b24c1be21e44a41d75815fa9a05136..bb3a896003713284a4a9a152f01067da59357a29 100755 (executable)
@@ -337,11 +337,93 @@ int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t *_core_if)
  *
  * @param _core_if Programming view of DWC_otg controller.
  */
+#ifdef DWC_BOTH_HOST_SLAVE
+extern void dwc_otg_force_device(dwc_otg_core_if_t *core_if);
+extern void dwc_otg_force_host(dwc_otg_core_if_t *core_if);
+extern int rk28_usb_suspend( int exitsuspend );
+#endif
 
 int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *_core_if)
 {
        gintsts_data_t gintsts = { .d32 = 0 };
+    #ifdef DWC_BOTH_HOST_SLAVE
+    uint32_t count = 0;
+    dwc_otg_pcd_t *pcd = _core_if->otg_dev->pcd;
+       gintmsk_data_t gintmsk = { .d32 = 0 };
+    gotgctl_data_t gotgctl = { .d32 = 0 }; 
+       if(pcd &&(pcd->phy_suspend == 1))
+       {
+               rk28_usb_suspend( 1 );
+       }
+       
+    /*
+    * yangkai@rk, 20100331
+    * ³äµçÆ÷½ÓÈëʱÓпÉÄÜUSB IDΪµÍ, ´ËÊ±Ó¦ÌØ±ð´¦Àí£¬²»Çл»³ÉHOST£»
+       * ×¢Òâ,Èç¹ûhostÉ豸Èç¹û¿ìËٰβ壬»áµ±³ÉUSB_IDΪµÍµÄ³äµçÆ÷´¦Àí
+    */
+    gotgctl.d32 = dwc_read_reg32( &_core_if->core_global_regs->gotgctl );
+       #if 1
+    if((!gotgctl.b.conidsts)&&( gotgctl.b.bsesvld ))
+    {
+       if(pcd &&(pcd->vbus_status == 0))
+               pcd->vbus_status = 1;
+       gintsts.b.conidstschng = 1;
+       dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32);
+       return 1;
+    }
+    #endif
+// cmy: Ö»Óе±usb´¦ÓÚÕý³£Ä£Ê½Ê±£¬²Å´¦Àí¸ÃÖжϽøÐÐÇл»
+    if(_core_if->usb_mode != USB_MODE_NORMAL)
+    {
+        DWC_PRINT("_core_if->usb_mode=%d\n", _core_if->usb_mode);
+       gintsts.b.conidstschng = 1;
+       dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32);
+       return 1;
+    }
+    DWC_DEBUGPL(DBG_CIL, "switch\n");
+
+       /*
+        * Need to disable SOF interrupt immediately. If switching from device
+        * to host, the PCD interrupt handler won't handle the interrupt if
+        * host mode is already set. The HCD interrupt handler won't get
+        * called if the HCD state is HALT. This means that the interrupt does
+        * not get handled and Linux complains loudly.
+        */
+       gintmsk.b.sofintr = 1;
+       dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
+
+       DWC_DEBUGPL(DBG_CIL, " ++Connector ID Status Change Interrupt++  (%s)\n",
+                    (dwc_otg_is_host_mode(_core_if)?"Host":"Device"));
+        gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl);
+       DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
+       DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
+        
+        /* B-Device connector (Device Mode) */
+        if (gotgctl.b.conidsts) {
+                /* Wait for switch to device mode. */
+                while (!dwc_otg_is_device_mode(_core_if) ){
+                        DWC_PRINT("Waiting for Peripheral Mode, Mode=%s\n",
+                                  (dwc_otg_is_host_mode(_core_if)?"Host":"Peripheral"));
+                        MDELAY(100);
+                        if (++count > 10000) *(uint32_t*)NULL=0;
+                }
 
+        hcd_stop(_core_if);
+        _core_if->op_state = B_PERIPHERAL;
+        //pcd->phy_suspend = 1;
+        pcd->vbus_status = 0;
+       dwc_otg_pcd_start_vbus_timer( pcd );
+        } else {
+                /* A-Device connector (Host Mode) */
+                while (!dwc_otg_is_host_mode(_core_if) ) {
+                        DWC_PRINT("Waiting for Host Mode, Mode=%s\n",
+                                  (dwc_otg_is_host_mode(_core_if)?"Host":"Peripheral"));
+                        MDELAY(100);
+                        if (++count > 10000) *(uint32_t*)NULL=0;
+                }
+            dwc_otg_force_host(_core_if);
+        }
+       #endif
        /* Set flag and clear interrupt */
        gintsts.b.conidstschng = 1;
        dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32);
index 79560d98e39c893b5ef20ba2251c608b728f7de8..1547f6b8a29a13bab4111b7c6e02802d3f1e76f4 100755 (executable)
@@ -331,6 +331,221 @@ static ssize_t dbg_level_store(struct device_driver *_drv, const char *_buf,
 }
 static DRIVER_ATTR(debuglevel, S_IRUGO|S_IWUSR, dbg_level_show, dbg_level_store);
 #ifdef CONFIG_USB
+
+extern struct usb_hub *g_root_hub20;
+#ifdef DWC_BOTH_HOST_SLAVE
+extern void hcd_start( dwc_otg_core_if_t *_core_if );
+
+extern int rk28_usb_suspend( int exitsuspend );
+extern void hub_disconnect_device(struct usb_hub *hub);
+
+static ssize_t force_usb_mode_show(struct device_driver *_drv, char *_buf)
+{
+    dwc_otg_device_t *otg_dev = g_otgdev;
+    dwc_otg_core_if_t *core_if = otg_dev->core_if;
+#if 1
+    return sprintf (_buf, "%d\n", core_if->usb_mode);
+#else
+    dwc_otg_device_t *otg_dev = lm_get_drvdata(g_lmdev);
+    dwc_otg_core_if_t *core_if = otg_dev->core_if;
+    gotgctl_data_t    gctrl;
+    gctrl.d32 = dwc_read_reg32( &core_if->core_global_regs->gotgctl );
+    printk("OTGCTL=0x%08X\n", gctrl.d32);
+
+    if(g_usb_mode == USB_NORMAL_MODE)
+        return sprintf (_buf, "Current usb mode: Normal Mode\n");
+    else if(g_usb_mode == FORCE_HOST_MODE)
+        return sprintf (_buf, "Current usb mode: Force Host\n");
+    else if(g_usb_mode == FORCE_DEVICE_MODE)
+        return sprintf (_buf, "Current usb mode: Force Device\n");
+    else
+        return sprintf (_buf, "Current usb mode: Unknown\n");
+#endif        
+}
+
+void dwc_otg_force_host(dwc_otg_core_if_t *core_if)
+{
+    dwc_otg_device_t *otg_dev = g_otgdev;
+    dctl_data_t dctl = {.d32=0};
+    if(core_if->op_state == A_HOST)
+    {
+       printk("dwc_otg_force_host,already in A_HOST mode,everest\n");
+       return;
+    }
+       if((otg_dev->pcd)&&(otg_dev->pcd->phy_suspend == 1))
+       {
+               rk28_usb_suspend( 1 );
+       }
+    del_timer(&otg_dev->pcd->check_vbus_timer);
+    // force disconnect 
+    /* 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 );
+    
+    if (core_if->pcd_cb && core_if->pcd_cb->stop ) {
+            core_if->pcd_cb->stop( core_if->pcd_cb->p );
+    }
+    
+    //core_if->op_state = A_HOST;
+    /*
+     * Initialize the Core for Host mode.
+     */
+       dwc_otg_core_init(core_if);
+       dwc_otg_enable_global_interrupts(core_if);
+    hcd_start( core_if );
+    
+}
+void dwc_otg_force_device(dwc_otg_core_if_t *core_if)
+{
+    dwc_otg_device_t *otg_dev = g_otgdev;
+    dwc_otg_disable_global_interrupts( core_if );
+    if (core_if->hcd_cb && core_if->hcd_cb->stop) {
+       core_if->hcd_cb->stop( core_if->hcd_cb->p );
+    }
+    if(core_if->op_state == B_PERIPHERAL)
+    {
+       printk("dwc_otg_force_device,already in B_PERIPHERAL,everest\n");
+       return;
+    }
+       hub_disconnect_device(g_root_hub20);
+    otg_dev->core_if->op_state = B_PERIPHERAL;
+       /* Reset the Controller */
+       dwc_otg_core_reset( core_if );
+    //otg_dev->pcd->phy_suspend = 1;
+    otg_dev->pcd->vbus_status = 0;
+    dwc_otg_pcd_start_vbus_timer( otg_dev->pcd );
+       
+}
+static void dwc_otg_set_gusbcfg(dwc_otg_core_if_t *core_if, int mode)
+{
+       gusbcfg_data_t usbcfg = { .d32 = 0 };
+       
+    usbcfg.d32 = dwc_read_reg32( &core_if->core_global_regs->gusbcfg);
+    switch(mode)
+    {
+    case USB_MODE_FORCE_HOST:
+        usbcfg.b.force_hst_mode = 1;
+        usbcfg.b.force_dev_mode = 0;
+        break;
+    case USB_MODE_FORCE_DEVICE:
+        usbcfg.b.force_hst_mode = 0;
+        usbcfg.b.force_dev_mode = 1;
+        break;
+    case USB_MODE_NORMAL:
+        usbcfg.b.force_hst_mode = 0;
+        usbcfg.b.force_dev_mode = 0;
+        break;
+    }
+    dwc_write_reg32( &core_if->core_global_regs->gusbcfg, usbcfg.d32 );
+}
+
+static ssize_t force_usb_mode_store(struct device_driver *_drv, const char *_buf, 
+                         size_t _count ) 
+{
+    int new_mode = simple_strtoul(_buf, NULL, 16);
+    dwc_otg_device_t *otg_dev = g_otgdev;
+    dwc_otg_core_if_t *core_if = otg_dev->core_if;
+    DWC_PRINT("%s %d->%d\n",__func__, core_if->usb_mode, new_mode);
+    if(core_if->usb_mode == new_mode)
+    {
+       return _count;
+    }
+
+       switch(new_mode)
+       {
+               case USB_MODE_FORCE_HOST:
+                       if(USB_MODE_FORCE_DEVICE == core_if->usb_mode)
+                       {/* device-->host */
+                               core_if->usb_mode = new_mode;
+                               dwc_otg_force_host(core_if);
+                       }
+                       else if(USB_MODE_NORMAL == core_if->usb_mode)
+                       {
+                               core_if->usb_mode = new_mode;
+                               if(dwc_otg_is_host_mode(core_if))
+                               {
+                                       dwc_otg_set_gusbcfg(core_if, new_mode);
+                               }
+                               else
+                               {
+                                       dwc_otg_force_host(core_if);
+                               }
+                       }
+                       else
+                           core_if->usb_mode = new_mode;
+                       break;
+               case USB_MODE_FORCE_DEVICE:
+                       if(USB_MODE_FORCE_HOST == core_if->usb_mode)
+                       {
+                               core_if->usb_mode = new_mode;
+                               dwc_otg_force_device(core_if);
+                       }
+                       else if(USB_MODE_NORMAL == core_if->usb_mode)
+                       {
+                               core_if->usb_mode = new_mode;
+                               if(dwc_otg_is_device_mode(core_if))
+                               {
+                                       dwc_otg_set_gusbcfg(core_if, new_mode);
+                               }
+                               else
+                               {
+                                       dwc_otg_force_device(core_if);
+                               }
+                       }
+                       break;
+               case USB_MODE_NORMAL:
+                       #if 1
+                       if(USB_MODE_FORCE_DEVICE == core_if->usb_mode)
+                       {
+                               core_if->usb_mode = new_mode;
+                               if((otg_dev->pcd)&&(otg_dev->pcd->phy_suspend == 1))
+                               {
+                                       rk28_usb_suspend( 1 );
+                               }
+                               del_timer(&otg_dev->pcd->check_vbus_timer);
+                               dwc_otg_set_gusbcfg(core_if, new_mode);
+                               msleep(50);
+                               if(dwc_otg_is_host_mode(core_if))
+                               {
+                                       dwc_otg_force_host(core_if);
+                               }
+                               else
+                               {
+                                       dwc_otg_pcd_start_vbus_timer( otg_dev->pcd );
+                               }
+                               //mdelay(10);
+                               //core_if->usb_mode = new_mode;
+                               //if(!dwc_otg_connid(core_if))
+                               //      dwc_otg_force_host(core_if);
+                       }
+                       else if(USB_MODE_FORCE_HOST == core_if->usb_mode)
+                       {
+                               if((otg_dev->pcd)&&(otg_dev->pcd->phy_suspend == 1))
+                               {
+                                       rk28_usb_suspend( 1 );
+                               }
+                               core_if->usb_mode = new_mode;
+                               dwc_otg_set_gusbcfg(core_if, new_mode);
+                               msleep(100);
+                               if(dwc_otg_is_device_mode(core_if))
+                               {
+                                       dwc_otg_force_device(core_if);
+                               }
+                               //if(dwc_otg_connid(core_if))
+                               //      hub_disconnect_device();
+                               //core_if->usb_mode = new_mode;
+                               //      dwc_otg_force_device(core_if);
+                       }
+                       #endif
+                       break;
+               default:
+                       break;
+       }       
+       return _count;  
+}
+static DRIVER_ATTR(force_usb_mode, 0666/*S_IRUGO|S_IWUSR*/, force_usb_mode_show, force_usb_mode_store);
+#endif
 static ssize_t dwc_otg_enable_show( struct device *_dev, 
                                                                struct device_attribute *attr, char *buf)
 {
@@ -388,7 +603,7 @@ static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, dwc_otg_enable_show, dwc_otg_enable_
 #endif
 static ssize_t dwc_otg_conn_en_show(struct device_driver *_drv, char *_buf)
 {
-#ifdef CONFIG_DWC_OTG_DEVICE_ONLY
+#ifndef CONFIG_DWC_OTG_HOST_ONLY
     dwc_otg_device_t *otg_dev = g_otgdev;
     dwc_otg_pcd_t *_pcd = otg_dev->pcd;
     return sprintf (_buf, "%d\n", _pcd->conn_en);
@@ -400,7 +615,7 @@ static ssize_t dwc_otg_conn_en_show(struct device_driver *_drv, char *_buf)
 static ssize_t dwc_otg_conn_en_store(struct device_driver *_drv, const char *_buf,
                                     size_t _count)
 {
-#ifdef CONFIG_DWC_OTG_DEVICE_ONLY
+#ifndef CONFIG_DWC_OTG_HOST_ONLY
     int enable = simple_strtoul(_buf, NULL, 10);
     dwc_otg_device_t *otg_dev = g_otgdev;
     dwc_otg_pcd_t *_pcd = otg_dev->pcd;
@@ -411,7 +626,7 @@ static ssize_t dwc_otg_conn_en_store(struct device_driver *_drv, const char *_bu
     return _count;
 }
 static DRIVER_ATTR(dwc_otg_conn_en, S_IRUGO|S_IWUSR, dwc_otg_conn_en_show, dwc_otg_conn_en_store);
-#ifdef CONFIG_DWC_OTG_DEVICE_ONLY
+#ifndef CONFIG_DWC_OTG_HOST_ONLY
 static ssize_t vbus_status_show(struct device_driver *_drv, char *_buf)
 {
     dwc_otg_device_t *otg_dev = g_otgdev;
@@ -420,6 +635,51 @@ static ssize_t vbus_status_show(struct device_driver *_drv, char *_buf)
 }
 static DRIVER_ATTR(vbus_status, S_IRUGO|S_IWUSR, vbus_status_show, NULL);
 #endif
+volatile depctl_data_t depctl_ep0 = {.d32 = 0};
+volatile depctl_data_t depctl_ep2 = {.d32 = 0};
+volatile depctl_data_t depctl_ep4 = {.d32 = 0};
+void dwc_otg_epout_save(void)
+{
+    dwc_otg_device_t *otg_dev = g_otgdev;
+       dwc_otg_dev_if_t *dev_if = otg_dev->core_if->dev_if;
+    volatile depctl_data_t depctl = {.d32 = 0};
+    volatile grstctl_t grstctl = {.d32 = 0};
+    grstctl.d32 = dwc_read_reg32(&otg_dev->core_if->core_global_regs->grstctl);
+
+    while(grstctl.b.ahbidle != 1)
+    {
+        grstctl.d32 = dwc_read_reg32(&otg_dev->core_if->core_global_regs->grstctl);
+    }
+    depctl_ep0.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl);
+    depctl.d32 = depctl_ep0.d32;
+    if(depctl.b.epena)
+    {
+        depctl.b.epena = 0;
+        dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, depctl.d32);
+    }
+    depctl_ep2.d32 = dwc_read_reg32(&dev_if->out_ep_regs[2]->doepctl);
+    depctl.d32 = depctl_ep2.d32;
+    if(depctl.b.epena)
+    {
+        depctl.b.epena = 0;
+        dwc_write_reg32(&dev_if->out_ep_regs[2]->doepctl, depctl.d32);
+    }
+    depctl_ep4.d32 = dwc_read_reg32(&dev_if->out_ep_regs[4]->doepctl);
+    depctl.d32 = depctl_ep4.d32;
+    if(depctl.b.epena)
+    {
+        depctl.b.epena = 0;
+        dwc_write_reg32(&dev_if->out_ep_regs[4]->doepctl, depctl.d32);
+    }
+}
+void dwc_otg_epout_restore(void)
+{
+    dwc_otg_device_t *otg_dev = g_otgdev;
+       dwc_otg_dev_if_t *dev_if = otg_dev->core_if->dev_if;
+    dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, depctl_ep0.d32);
+    dwc_write_reg32(&dev_if->out_ep_regs[2]->doepctl, depctl_ep2.d32);
+    dwc_write_reg32(&dev_if->out_ep_regs[4]->doepctl, depctl_ep4.d32);
+}
 
 /**
  * This function is called during module intialization to verify that
@@ -856,14 +1116,14 @@ static int dwc_otg_driver_remove(struct platform_device *pdev)
                free_irq( platform_get_irq(to_platform_device(dev),0), otg_dev );
        }
 
-#ifdef CONFIG_DWC_OTG_HOST_ONLY
+#ifndef CONFIG_DWC_OTG_DEVICE_ONLY
        if (otg_dev->hcd != NULL) 
        {
                dwc_otg_hcd_remove(dev);
        }
 #endif
 
-#ifdef CONFIG_DWC_OTG_DEVICE_ONLY
+#ifndef CONFIG_DWC_OTG_HOST_ONLY
        if (otg_dev->pcd != NULL) 
        {
                dwc_otg_pcd_remove(dev);
@@ -1119,7 +1379,7 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev)
         * Create Device Attributes in sysfs
         */      
        dwc_otg_attr_create(dev);
-#ifdef CONFIG_DWC_OTG_HOST_ONLY
+#ifndef CONFIG_DWC_OTG_DEVICE_ONLY
        retval |= device_create_file(dev, &dev_attr_enable);
 #endif
 
@@ -1154,8 +1414,18 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev)
 
 #ifdef CONFIG_DWC_OTG_DEVICE_ONLY
         dwc_otg_device->core_if->usb_mode = USB_MODE_FORCE_DEVICE;
+#else 
+#ifdef CONFIG_DWC_OTG_HOST_ONLY
+        dwc_otg_device->core_if->usb_mode = USB_MODE_FORCE_HOST;
 #else
+        
+#ifdef CONFIG_DWC_OTG_DEFAULT_HOST
         dwc_otg_device->core_if->usb_mode = USB_MODE_FORCE_HOST;
+#else 
+        dwc_otg_device->core_if->usb_mode = USB_MODE_NORMAL;
+#endif
+
+#endif
 #endif
 
        /*
@@ -1165,7 +1435,7 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev)
 
 /* Initialize the bus state.  If the core is in Device Mode
  * HALT the USB bus and return. */
-#ifdef CONFIG_DWC_OTG_HOST_ONLY
+#ifndef CONFIG_DWC_OTG_DEVICE_ONLY
     USB_IOMUX_INIT(GPIO4A5_OTG0DRVVBUS_NAME, GPIO4L_OTG0_DRV_VBUS);
        /*
         * Initialize the HCD
@@ -1178,7 +1448,7 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev)
                goto fail;
        }
 #endif
-#ifdef CONFIG_DWC_OTG_DEVICE_ONLY
+#ifndef CONFIG_DWC_OTG_HOST_ONLY
        /*
         * Initialize the PCD
         */
@@ -1197,13 +1467,14 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev)
         * handlers are installed.
         */
        dwc_otg_enable_global_interrupts( dwc_otg_device->core_if );
-#ifdef CONFIG_DWC_OTG_HOST_ONLY
-#ifndef CONFIG_USB20_OTG_EN
-    clk_disable(dwc_otg_device->phyclk);
-    clk_disable(dwc_otg_device->ahbclk);
-    *otg_phy_con1 |= (0x01<<2);
-    *otg_phy_con1 &= ~(0x01<<3);    // enter suspend.
-#endif
+#ifndef CONFIG_DWC_OTG_DEVICE_ONLY
+    if(dwc_otg_device->hcd->host_enabled == 0)
+    {
+        clk_disable(dwc_otg_device->phyclk);
+        clk_disable(dwc_otg_device->ahbclk);
+        *otg_phy_con1 |= (0x01<<2);
+        *otg_phy_con1 &= ~(0x01<<3);    // enter suspend.
+    }
 #endif
        DWC_PRINT("dwc_otg_driver_probe end, everest\n");
        return 0;
@@ -1213,7 +1484,7 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev)
        return retval;
 }
 
-#ifndef DWC_HOST_ONLY
+#ifndef CONFIG_DWC_OTG_HOST_ONLY
 extern int rk28_usb_suspend( int exitsuspend );
 static int dwc_otg_driver_suspend(struct platform_device *_dev , pm_message_t state )
 {
@@ -1256,6 +1527,9 @@ static int dwc_otg_driver_resume(struct platform_device *_dev )
        DWC_PRINT("%s,A_HOST mode\n", __func__);
        return 0;
     }
+#ifndef CONFIG_DWC_OTG_HOST_ONLY
+
+    rk28_usb_suspend(1);
 
     /* soft disconnect */
     /* 20100226,HSL@RK,if not disconnect,when usb cable in,will auto reconnect 
@@ -1268,6 +1542,7 @@ static int dwc_otg_driver_resume(struct platform_device *_dev )
     
     /* Clear any pending interrupts */
     dwc_write_reg32( &global_regs->gintsts, 0xeFFFFFFF); 
+    
     dwc_otg_enable_global_interrupts(core_if);
     mod_timer(&otg_dev->pcd->check_vbus_timer , jiffies + (HZ<<2));
 
@@ -1276,6 +1551,8 @@ static int dwc_otg_driver_resume(struct platform_device *_dev )
     {
         core_if->usb_wakeup = 0;
     }
+    DWC_PRINT("%s gahbcfg:0x%x\n", __func__, global_regs->gahbcfg);
+#endif    
     return 0;
 }
 
@@ -1892,13 +2169,18 @@ static int __init dwc_otg_driver_init(void)
                pr_warning("DWC_OTG: Failed to create driver version file\n");
        if (driver_create_file(&dwc_otg_driver.driver, &driver_attr_debuglevel))
                pr_warning("DWC_OTG: Failed to create driver debug level file\n");
-
-#ifdef CONFIG_DWC_OTG_DEVICE_ONLY
+#ifndef CONFIG_DWC_OTG_HOST_ONLY
        if(driver_create_file(&dwc_otg_driver.driver, &driver_attr_dwc_otg_conn_en))
                pr_warning("DWC_OTG: Failed to create driver dwc_otg_conn_en file");
+#endif
+#ifndef CONFIG_DWC_OTG_HOST_ONLY
        if(driver_create_file(&dwc_otg_driver.driver, &driver_attr_vbus_status))
                pr_warning("DWC_OTG: Failed to create driver vbus status file");
 #endif
+#ifdef DWC_BOTH_HOST_SLAVE
+    if(driver_create_file(&dwc_otg_driver.driver, &driver_attr_force_usb_mode))
+               pr_warning("DWC_OTG: Failed to create driver force usb mode file\n");
+#endif
 
     /*
      *  USB1.1 host controller
@@ -1942,9 +2224,15 @@ static void __exit dwc_otg_driver_cleanup(void)
        driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
        driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
     
-#ifdef CONFIG_DWC_OTG_DEVICE_ONLY
+#ifdef DWC_BOTH_HOST_SLAVE     
+        driver_remove_file(&dwc_otg_driver.driver, &driver_attr_force_usb_mode);
+#endif
+#ifndef CONFIG_DWC_OTG_HOST_ONLY
     driver_remove_file(&dwc_otg_driver.driver, &driver_attr_dwc_otg_conn_en);
 #endif
+#ifdef CONFIG_DWC_OTG_DEVICE_ONLY
+    driver_remove_file(&dwc_otg_driver.driver, &driver_attr_vbus_status);
+#endif
 
        platform_driver_unregister(&dwc_otg_driver);
        
index 054000fb9234532a9ca1e1776a8ba38d22019d3d..22355510b8b4348053cb7267e3878d4501096460 100755 (executable)
@@ -388,6 +388,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);
@@ -396,8 +398,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);
                }
@@ -428,28 +444,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.
-         */
-//     DWC_PRINT("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);
 
@@ -517,10 +532,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;
 }
 
 /**
@@ -1558,7 +1573,7 @@ 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;
@@ -3254,7 +3269,16 @@ __acquires(_hcd->lock)
        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.
  */
index 4df9ff25b86c03c2b0a40be4e1f7d18751bcd42b..ba6aba4d2f152fac29a6342251bfb0ed2cc42cae 100755 (executable)
@@ -1001,7 +1001,7 @@ static int dwc_otg_pcd_wakeup(struct usb_gadget *_gadget)
 
 static int dwc_otg_pcd_pullup(struct usb_gadget *_gadget, int is_on)
 {
-       unsigned long flags;
+       //unsigned long flags;
        dwc_otg_pcd_t *pcd;
     dctl_data_t dctl = {.d32=0};
     dwc_otg_core_if_t *core_if;
@@ -1028,6 +1028,7 @@ static int dwc_otg_pcd_pullup(struct usb_gadget *_gadget, int is_on)
         dctl.b.sftdiscon = 1;
         dwc_write_reg32( &core_if->dev_if->dev_global_regs->dctl, dctl.d32 );
     }
+    return 0;
 }
 
 static const struct usb_gadget_ops dwc_otg_pcd_ops =