From: lyz Date: Thu, 20 Mar 2014 03:40:39 +0000 (+0800) Subject: usb: add force host mode & force device mode X-Git-Tag: firefly_0821_release~5977 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=c7cd3001a4c3bc93432359f6f35a0545febe47a9;p=firefly-linux-kernel-4.4.55.git usb: add force host mode & force device mode --- diff --git a/drivers/usb/dwc_otg_310/dwc_otg_cil.c b/drivers/usb/dwc_otg_310/dwc_otg_cil.c index 75039cb9cddd..1eda4c0fd79c 100755 --- a/drivers/usb/dwc_otg_310/dwc_otg_cil.c +++ b/drivers/usb/dwc_otg_310/dwc_otg_cil.c @@ -5131,6 +5131,7 @@ void dwc_otg_core_reset(dwc_otg_core_if_t * core_if) { dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; volatile grstctl_t greset = {.d32 = 0 }; + volatile gusbcfg_data_t usbcfg = { .d32 = 0 }; int count = 0; DWC_DEBUGPL(DBG_CILV, "%s\n", __func__); @@ -5160,6 +5161,21 @@ void dwc_otg_core_reset(dwc_otg_core_if_t * core_if) dwc_udelay(1); } while (greset.b.csftrst == 1); + usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg); + if(core_if->usb_mode == USB_MODE_FORCE_HOST) + { + usbcfg.b.force_host_mode = 1; + usbcfg.b.force_dev_mode = 0; + } else if(core_if->usb_mode == USB_MODE_FORCE_DEVICE) + { + usbcfg.b.force_host_mode = 0; + usbcfg.b.force_dev_mode = 1; + } else + { + usbcfg.b.force_host_mode = 0; + usbcfg.b.force_dev_mode = 0; + } + DWC_WRITE_REG32( &global_regs->gusbcfg, usbcfg.d32 ); /* Wait for 3 PHY Clocks */ dwc_mdelay(100); diff --git a/drivers/usb/dwc_otg_310/dwc_otg_cil.h b/drivers/usb/dwc_otg_310/dwc_otg_cil.h index ac8e4a168599..a7c5960577f5 100755 --- a/drivers/usb/dwc_otg_310/dwc_otg_cil.h +++ b/drivers/usb/dwc_otg_310/dwc_otg_cil.h @@ -842,6 +842,11 @@ struct dwc_otg_core_if { /** Timer for SRP. If it expires before SRP is successful * clear the SRP. */ dwc_timer_t *srp_timer; + + uint8_t usb_mode; +#define USB_MODE_NORMAL (0) +#define USB_MODE_FORCE_HOST (1) +#define USB_MODE_FORCE_DEVICE (2) #ifdef DWC_DEV_SRPCAP /* This timer is needed to power on the hibernated host core if SRP is not diff --git a/drivers/usb/dwc_otg_310/dwc_otg_cil_intr.c b/drivers/usb/dwc_otg_310/dwc_otg_cil_intr.c index 762e4434c1c8..ef82bef5f8c8 100755 --- a/drivers/usb/dwc_otg_310/dwc_otg_cil_intr.c +++ b/drivers/usb/dwc_otg_310/dwc_otg_cil_intr.c @@ -375,10 +375,12 @@ int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if) */ gintmsk_data_t gintmsk = {.d32 = 0 }; gintsts_data_t gintsts = {.d32 = 0 }; + + if(core_if->usb_mode != USB_MODE_NORMAL) + goto out; 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")); @@ -393,7 +395,7 @@ int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if) DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change, core_if, "connection id status change"); DWC_SPINLOCK(core_if->lock); - +out: /* 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_310/dwc_otg_driver.c b/drivers/usb/dwc_otg_310/dwc_otg_driver.c index 10f5c1857930..581b4481f8d2 100755 --- a/drivers/usb/dwc_otg_310/dwc_otg_driver.c +++ b/drivers/usb/dwc_otg_310/dwc_otg_driver.c @@ -368,6 +368,177 @@ 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); +extern void hcd_start(dwc_otg_core_if_t *core_if); +extern void hub_disconnect_device(struct usb_hub *hub); + +void dwc_otg_force_host(dwc_otg_core_if_t *core_if) +{ + dwc_otg_device_t *otg_dev = core_if->otg_dev; + dctl_data_t dctl = {.d32=0}; + u32 flags; + + if(core_if->op_state == A_HOST) + { + printk("dwc_otg_force_host,already in A_HOST mode,everest\n"); + return; + } + core_if->op_state = A_HOST; + + cancel_delayed_work(&otg_dev->pcd->check_vbus_work); + 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); + + local_irq_save(flags); + cil_pcd_stop(core_if); + /* + * Initialize the Core for Host mode. + */ + + dwc_otg_core_init(core_if); + dwc_otg_enable_global_interrupts(core_if); + cil_hcd_start(core_if); + local_irq_restore(flags); +} +void dwc_otg_force_device(dwc_otg_core_if_t *core_if) +{ + dwc_otg_device_t *otg_dev = core_if->otg_dev; + u32 flags; + + local_irq_save(flags); + + if(core_if->op_state == B_PERIPHERAL) { + printk("dwc_otg_force_device,already in B_PERIPHERAL,everest\n"); + return; + } + core_if->op_state = B_PERIPHERAL; + cil_hcd_stop(core_if); + //hub_disconnect_device(g_root_hub20); + otg_dev->pcd->phy_suspend = 1; + otg_dev->pcd->vbus_status = 0; + dwc_otg_pcd_start_check_vbus_work(otg_dev->pcd); + + /* Reset the Controller */ + dwc_otg_core_reset( core_if ); + + dwc_otg_core_init(core_if); + dwc_otg_disable_global_interrupts(core_if); + cil_pcd_start(core_if); + + local_irq_restore(flags); +} +static void dwc_otg_set_force_mode(dwc_otg_core_if_t *core_if, int mode) +{ + gusbcfg_data_t usbcfg = { .d32 = 0 }; + printk("!!!dwc_otg_set_force_mode\n"); + usbcfg.d32 = DWC_READ_REG32( &core_if->core_global_regs->gusbcfg); + switch(mode) { + case USB_MODE_FORCE_HOST: + usbcfg.b.force_host_mode = 1; + usbcfg.b.force_dev_mode = 0; + break; + case USB_MODE_FORCE_DEVICE: + usbcfg.b.force_host_mode = 0; + usbcfg.b.force_dev_mode = 1; + break; + case USB_MODE_NORMAL: + usbcfg.b.force_host_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_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; + + return sprintf(buf, "%d\n", core_if->usb_mode); +} + +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; + + if(!otg_dev) + return -EINVAL; + + dwc_otg_core_if_t *core_if = otg_dev->core_if; + struct dwc_otg_platform_data *pldata = otg_dev->pldata; + + DWC_PRINTF("%s %d->%d\n",__func__, core_if->usb_mode, new_mode); + + if(core_if->usb_mode == new_mode) { + return count; + } + + if(pldata->phy_status == USB_PHY_SUSPEND) { + pldata->clock_enable(pldata, 1); + pldata->phy_suspend(pldata, USB_PHY_ENABLED); + } + + 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_force_mode(core_if, new_mode); + } else { + dwc_otg_force_host(core_if); + } + } + 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_force_mode(core_if, new_mode); + } else { + dwc_otg_force_device(core_if); + } + } + break; + + case USB_MODE_NORMAL: + if(USB_MODE_FORCE_DEVICE == core_if->usb_mode) { + core_if->usb_mode = new_mode; + cancel_delayed_work(&otg_dev->pcd->check_vbus_work); + dwc_otg_set_force_mode(core_if, new_mode); + //msleep(100); + if(dwc_otg_is_host_mode(core_if)) { + dwc_otg_force_host(core_if); + } else { + dwc_otg_pcd_start_check_vbus_work(otg_dev->pcd); + } + } else if(USB_MODE_FORCE_HOST == core_if->usb_mode) { + core_if->usb_mode = new_mode; + dwc_otg_set_force_mode(core_if, new_mode); + //msleep(100); + if(dwc_otg_is_device_mode(core_if)) { + dwc_otg_force_device(core_if); + } + } + break; + + default: + break; + } + return count; +} + +static DRIVER_ATTR(force_usb_mode, S_IRUGO | S_IWUSR, force_usb_mode_show, force_usb_mode_store); + static ssize_t dwc_otg_conn_en_show(struct device_driver *_drv, char *_buf) { @@ -1305,7 +1476,7 @@ static int otg20_driver_probe(struct platform_device *_dev) * Initialize the DWC_otg core. */ dwc_otg_core_init(dwc_otg_device->core_if); - + dwc_otg_device->core_if->usb_mode = 0;// TODO: Can be read from Device-Tree #ifndef DWC_HOST_ONLY /* * Initialize the PCD @@ -1378,25 +1549,11 @@ static int __init dwc_otg_driver_init(void) { int retval = 0; int error; - //register host20 -#ifdef CONFIG_USB20_HOST - printk(KERN_INFO "%s: version %s\n", dwc_host20_driver_name, - DWC_DRIVER_VERSION); - - retval = platform_driver_register(&dwc_host_driver); - if (retval < 0) { - printk(KERN_ERR "%s retval=%d\n", __func__, retval); - return retval; - } - - error = driver_create_file(&dwc_host_driver.driver, &driver_attr_version); - error = driver_create_file(&dwc_host_driver.driver, &driver_attr_debuglevel); -#endif - + #ifdef CONFIG_USB20_OTG //register otg20 printk(KERN_INFO "%s: version %s\n", dwc_otg20_driver_name, - DWC_DRIVER_VERSION); + DWC_DRIVER_VERSION); retval = platform_driver_register(&dwc_otg_driver); if (retval < 0) { @@ -1408,6 +1565,23 @@ static int __init dwc_otg_driver_init(void) error = driver_create_file(&dwc_otg_driver.driver, &driver_attr_debuglevel); error = driver_create_file(&dwc_otg_driver.driver, &driver_attr_dwc_otg_conn_en); error = driver_create_file(&dwc_otg_driver.driver, &driver_attr_vbus_status); + error = driver_create_file(&dwc_otg_driver.driver, &driver_attr_force_usb_mode); + +#endif + + //register host20 +#ifdef CONFIG_USB20_HOST + printk(KERN_INFO "%s: version %s\n", dwc_host20_driver_name, + DWC_DRIVER_VERSION); + + retval = platform_driver_register(&dwc_host_driver); + if (retval < 0) { + printk(KERN_ERR "%s retval=%d\n", __func__, retval); + return retval; + } + + error = driver_create_file(&dwc_host_driver.driver, &driver_attr_version); + error = driver_create_file(&dwc_host_driver.driver, &driver_attr_debuglevel); #endif return retval; } @@ -1438,6 +1612,7 @@ static void __exit dwc_otg_driver_cleanup(void) driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel); driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version); driver_remove_file(&dwc_otg_driver.driver, &driver_attr_vbus_status); + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_force_usb_mode); platform_driver_unregister(&dwc_otg_driver); printk(KERN_INFO "%s module removed\n", dwc_otg20_driver_name); #endif