From f2bdd004a1598dff6820fcd2c9625dcf0b7188a4 Mon Sep 17 00:00:00 2001 From: yangkai Date: Fri, 20 May 2011 14:39:46 +0800 Subject: [PATCH] usb support otg mode --- drivers/usb/core/hub.c | 5 + drivers/usb/dwc_otg/Kconfig | 23 +- drivers/usb/dwc_otg/Makefile | 9 +- drivers/usb/dwc_otg/dwc_otg_attr.c | 1 + drivers/usb/dwc_otg/dwc_otg_cil.c | 11 +- drivers/usb/dwc_otg/dwc_otg_cil_intr.c | 82 +++++++ drivers/usb/dwc_otg/dwc_otg_driver.c | 326 +++++++++++++++++++++++-- drivers/usb/dwc_otg/dwc_otg_hcd.c | 72 ++++-- drivers/usb/dwc_otg/dwc_otg_pcd.c | 3 +- 9 files changed, 478 insertions(+), 54 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 9478cf70509b..7a631055ce64 100755 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -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; diff --git a/drivers/usb/dwc_otg/Kconfig b/drivers/usb/dwc_otg/Kconfig index 004b92d016aa..5116703c1a3a 100755 --- a/drivers/usb/dwc_otg/Kconfig +++ b/drivers/usb/dwc_otg/Kconfig @@ -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 diff --git a/drivers/usb/dwc_otg/Makefile b/drivers/usb/dwc_otg/Makefile index 9b5cd633712e..e60402dff923 100755 --- a/drivers/usb/dwc_otg/Makefile +++ b/drivers/usb/dwc_otg/Makefile @@ -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 diff --git a/drivers/usb/dwc_otg/dwc_otg_attr.c b/drivers/usb/dwc_otg/dwc_otg_attr.c index 710c9ca9e27b..01d5a74f57e1 100755 --- a/drivers/usb/dwc_otg/dwc_otg_attr.c +++ b/drivers/usb/dwc_otg/dwc_otg_attr.c @@ -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) { diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.c b/drivers/usb/dwc_otg/dwc_otg_cil.c index 4c20f6ba3a26..679abfe28f0f 100755 --- a/drivers/usb/dwc_otg/dwc_otg_cil.c +++ b/drivers/usb/dwc_otg/dwc_otg_cil.c @@ -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; diff --git a/drivers/usb/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/dwc_otg/dwc_otg_cil_intr.c index eac5dc5c74b2..bb3a89600371 100755 --- a/drivers/usb/dwc_otg/dwc_otg_cil_intr.c +++ b/drivers/usb/dwc_otg/dwc_otg_cil_intr.c @@ -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); diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.c b/drivers/usb/dwc_otg/dwc_otg_driver.c index 79560d98e39c..1547f6b8a29a 100755 --- a/drivers/usb/dwc_otg/dwc_otg_driver.c +++ b/drivers/usb/dwc_otg/dwc_otg_driver.c @@ -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); diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.c b/drivers/usb/dwc_otg/dwc_otg_hcd.c index 054000fb9234..22355510b8b4 100755 --- a/drivers/usb/dwc_otg/dwc_otg_hcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_hcd.c @@ -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. */ diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.c b/drivers/usb/dwc_otg/dwc_otg_pcd.c index 4df9ff25b86c..ba6aba4d2f15 100755 --- a/drivers/usb/dwc_otg/dwc_otg_pcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_pcd.c @@ -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 = -- 2.34.1