MTK OTG 流程
一、注册mt_usb驱动
kernel-3.18/drivers/misc/mediatek/usb20/mt6735/usb20.c
static int __init usb20_init(void) { DBG(0, "usb20 init\n"); #ifdef CONFIG_MTK_USB2JTAG_SUPPORT if (usb2jtag_mode()) { pr_err("[USB2JTAG] in usb2jtag mode, not to initialize usb driver\n"); return 0; } #endif #ifdef FPGA_PLATFORM add_usb_i2c_driver(); #endif platform_driver_register(&mt_usb_driver); return platform_driver_register(&mt_usb_dts_driver); } fs_initcall(usb20_init);
mt_usb_driver定义如下:
static struct platform_driver mt_usb_driver = { .remove = mt_usb_remove, .probe = mt_usb_probe, .driver = { .name = "mt_usb", }, };
mt_usb_probe负责初始化mt_usb设备,mt_usb_probe在mt_usb设备注册时会通过设备模型被调用
static int mt_usb_probe(struct platform_device *pdev) { struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; struct platform_device *musb; struct mt_usb_glue *glue; #ifdef CONFIG_OF struct musb_hdrc_config *config; struct device_node *np = pdev->dev.of_node; #endif #ifdef CONFIG_MTK_UART_USB_SWITCH struct device_node *ap_uart0_node = NULL; #endif int ret = -ENOMEM; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { /* dev_err(&pdev->dev, "failed to allocate glue context\n"); */ goto err0; } musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); goto err1; } #ifdef CONFIG_OF dts_np = pdev->dev.of_node; /* usb_irq_number1 = irq_of_parse_and_map(pdev->dev.of_node, 0); */ usb_phy_base = (unsigned long)of_iomap(pdev->dev.of_node, 1); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { dev_err(&pdev->dev, "failed to allocate musb platform data\n"); goto err2; } config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); if (!config) { /* dev_err(&pdev->dev, "failed to allocate musb hdrc config\n"); */ goto err2; } #ifdef CONFIG_USB_MTK_OTG pdata->mode = MUSB_OTG; #else of_property_read_u32(np, "mode", (u32 *) &pdata->mode); #endif #ifdef CONFIG_MTK_UART_USB_SWITCH ap_uart0_node = of_find_compatible_node(NULL, NULL, AP_UART0_COMPATIBLE_NAME); if (ap_uart0_node == NULL) { dev_err(&pdev->dev, "USB get ap_uart0_node failed\n"); if (ap_uart0_base) iounmap(ap_uart0_base); ap_uart0_base = 0; } else { ap_uart0_base = of_iomap(ap_uart0_node, 0); } #endif of_property_read_u32(np, "num_eps", (u32 *) &config->num_eps); config->multipoint = of_property_read_bool(np, "multipoint"); /* deprecated on musb.h, mark it to reduce build warning */ #if 0 of_property_read_u32(np, "dma_channels", (u32 *) &config->dma_channels); config->dyn_fifo = of_property_read_bool(np, "dyn_fifo"); config->soft_con = of_property_read_bool(np, "soft_con"); config->dma = of_property_read_bool(np, "dma"); #endif pdata->config = config; #endif musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &mt_usb_dmamask; musb->dev.coherent_dma_mask = mt_usb_dmamask; #ifdef CONFIG_OF pdev->dev.dma_mask = &mt_usb_dmamask; pdev->dev.coherent_dma_mask = mt_usb_dmamask; #endif glue->dev = &pdev->dev; glue->musb = musb; pdata->platform_ops = &mt_usb_ops; platform_set_drvdata(pdev, glue); ret = platform_device_add_resources(musb, pdev->resource, pdev->num_resources); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); goto err2; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); goto err2; } ret = platform_device_add(musb); if (ret) { dev_err(&pdev->dev, "failed to register musb device\n"); goto err2; } ret = device_create_file(&pdev->dev, &dev_attr_cmode); ret = device_create_file(&pdev->dev, &dev_attr_saving); #ifdef CONFIG_MTK_UART_USB_SWITCH ret = device_create_file(&pdev->dev, &dev_attr_portmode); ret = device_create_file(&pdev->dev, &dev_attr_tx); ret = device_create_file(&pdev->dev, &dev_attr_rx); ret = device_create_file(&pdev->dev, &dev_attr_uartpath); #endif if (ret) { dev_err(&pdev->dev, "failed to create musb device\n"); goto err2; } #ifdef CONFIG_OF DBG(0, "USB probe done!\n"); #endif #if defined(FPGA_PLATFORM) || defined(FOR_BRING_UP) musb_force_on = 1; #endif if (get_boot_mode() == META_BOOT) { DBG(0, "in special mode %d\n", get_boot_mode()); musb_force_on = 1; } return 0; err2: platform_device_put(musb); err1: kfree(glue); err0: return ret; }
二、mt_usb设备在哪里注册
在usb20_init函数中mt_usb驱动注册之后,紧接着又注册了mt_usb_dts驱动
static struct platform_driver mt_usb_dts_driver = { .remove = mt_usb_dts_remove, .probe = mt_usb_dts_probe, .driver = { .name = "mt_dts_usb", #ifdef CONFIG_OF .of_match_table = apusb_of_ids, #endif }, };
当系统启动之后,解析设备树,当满足apusb_of_ids时候就会调用mt_usb_dts_probe函数
static int mt_usb_dts_probe(struct platform_device *pdev) { int retval = 0; /* enable uart log */ musb_uart_debug = 1; DBG(0, "first_connect, check_delay_done to 0\n"); first_connect = 0; check_delay_done = 0; DBG(0, "set musb_connect_legacy to 0\n"); musb_connect_legacy = 0; DBG(0, "init connection_work\n"); INIT_DELAYED_WORK(&connection_work, do_connection_work); DBG(0, "keep musb->power & mtk_usb_power in the samae value\n"); mtk_usb_power = false; #ifndef CONFIG_MTK_CLKMGR musb_clk = devm_clk_get(&pdev->dev, "usb0"); if (IS_ERR(musb_clk)) { DBG(0, KERN_WARNING "cannot get musb clock\n"); return PTR_ERR(musb_clk); } DBG(0, KERN_WARNING "get musb clock ok, prepare it\n"); retval = clk_prepare(musb_clk); if (retval == 0) { DBG(0, KERN_WARNING "prepare done\n"); } else { DBG(0, KERN_WARNING "prepare fail\n"); return retval; } #endif mt_usb_device.dev.of_node = pdev->dev.of_node; retval = platform_device_register(&mt_usb_device); if (retval != 0) DBG(0, "register musbfsh device fail!\n"); if (usb20_phy_init_debugfs()) DBG(0, "usb20_phy_init_debugfs fail!\n"); return retval; }
三、初始化mt_usb设备
mt_usb_dts_probe函数中调用platform_device_register(&mt_usb_device); 根据Linux设备模型,此处会match到mt_usb_driver,调用mt_usb_probe函数
static int mt_usb_probe(struct platform_device *pdev) { struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; struct platform_device *musb; struct mt_usb_glue *glue; #ifdef CONFIG_OF struct musb_hdrc_config *config; struct device_node *np = pdev->dev.of_node; #endif #ifdef CONFIG_MTK_UART_USB_SWITCH struct device_node *ap_uart0_node = NULL; #endif int ret = -ENOMEM; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { /* dev_err(&pdev->dev, "failed to allocate glue context\n"); */ goto err0; } musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); goto err1; } #ifdef CONFIG_OF dts_np = pdev->dev.of_node; /* usb_irq_number1 = irq_of_parse_and_map(pdev->dev.of_node, 0); */ usb_phy_base = (unsigned long)of_iomap(pdev->dev.of_node, 1); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { dev_err(&pdev->dev, "failed to allocate musb platform data\n"); goto err2; } config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); if (!config) { /* dev_err(&pdev->dev, "failed to allocate musb hdrc config\n"); */ goto err2; } #ifdef CONFIG_USB_MTK_OTG pdata->mode = MUSB_OTG; #else of_property_read_u32(np, "mode", (u32 *) &pdata->mode); #endif #ifdef CONFIG_MTK_UART_USB_SWITCH ap_uart0_node = of_find_compatible_node(NULL, NULL, AP_UART0_COMPATIBLE_NAME); if (ap_uart0_node == NULL) { dev_err(&pdev->dev, "USB get ap_uart0_node failed\n"); if (ap_uart0_base) iounmap(ap_uart0_base); ap_uart0_base = 0; } else { ap_uart0_base = of_iomap(ap_uart0_node, 0); } #endif of_property_read_u32(np, "num_eps", (u32 *) &config->num_eps); config->multipoint = of_property_read_bool(np, "multipoint"); /* deprecated on musb.h, mark it to reduce build warning */ #if 0 of_property_read_u32(np, "dma_channels", (u32 *) &config->dma_channels); config->dyn_fifo = of_property_read_bool(np, "dyn_fifo"); config->soft_con = of_property_read_bool(np, "soft_con"); config->dma = of_property_read_bool(np, "dma"); #endif pdata->config = config; #endif musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &mt_usb_dmamask; musb->dev.coherent_dma_mask = mt_usb_dmamask; #ifdef CONFIG_OF pdev->dev.dma_mask = &mt_usb_dmamask; pdev->dev.coherent_dma_mask = mt_usb_dmamask; #endif glue->dev = &pdev->dev; glue->musb = musb; pdata->platform_ops = &mt_usb_ops; platform_set_drvdata(pdev, glue); ret = platform_device_add_resources(musb, pdev->resource, pdev->num_resources); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); goto err2; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); goto err2; } ret = platform_device_add(musb); if (ret) { dev_err(&pdev->dev, "failed to register musb device\n"); goto err2; } ret = device_create_file(&pdev->dev, &dev_attr_cmode); ret = device_create_file(&pdev->dev, &dev_attr_saving); #ifdef CONFIG_MTK_UART_USB_SWITCH ret = device_create_file(&pdev->dev, &dev_attr_portmode); ret = device_create_file(&pdev->dev, &dev_attr_tx); ret = device_create_file(&pdev->dev, &dev_attr_rx); ret = device_create_file(&pdev->dev, &dev_attr_uartpath); #endif if (ret) { dev_err(&pdev->dev, "failed to create musb device\n"); goto err2; } #ifdef CONFIG_OF DBG(0, "USB probe done!\n"); #endif #if defined(FPGA_PLATFORM) || defined(FOR_BRING_UP) musb_force_on = 1; #endif if (get_boot_mode() == META_BOOT) { DBG(0, "in special mode %d\n", get_boot_mode()); musb_force_on = 1; } return 0; err2: platform_device_put(musb); err1: kfree(glue); err0: return ret; }
static const struct musb_platform_ops mt_usb_ops = { .init = mt_usb_init, .exit = mt_usb_exit, /*.set_mode = mt_usb_set_mode, */ .try_idle = mt_usb_try_idle, .enable = mt_usb_enable, .disable = mt_usb_disable, .set_vbus = mt_usb_set_vbus, .vbus_status = mt_usb_get_vbus_status };
四、mt_usb具体初始化过程
mt_usb设备被初始化成一个很大的数据机构struct musb,初始过程就是对该struct musb结构初始化
static int mt_usb_init(struct musb *musb) { #ifndef CONFIG_MTK_LEGACY int ret; #endif DBG(0, "mt_usb_init\n"); usb_phy_generic_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { DBG(0, "[MUSB] usb_get_phy error!!\n"); return -EPROBE_DEFER; } #ifdef CONFIG_OF /* musb->nIrq = usb_irq_number1; */ #else musb->nIrq = USB_MCU_IRQ_BIT1_ID; #endif musb->dma_irq = (int)SHARE_IRQ; musb->fifo_cfg = fifo_cfg; musb->fifo_cfg_size = ARRAY_SIZE(fifo_cfg); musb->dyn_fifo = true; musb->power = false; musb->is_host = false; musb->fifo_size = 8 * 1024; wake_lock_init(&musb->usb_lock, WAKE_LOCK_SUSPEND, "USB suspend lock"); #ifndef FPGA_PLATFORM #ifdef CONFIG_ARCH_MT6735 INIT_WORK(&vcore_work, do_vcore_work); vcore_wq = create_singlethread_workqueue("usb20_vcore_work"); INIT_LIST_HEAD(&vcore_req_free_pool); INIT_LIST_HEAD(&vcore_req_execute_pool); #endif #endif #ifndef FPGA_PLATFORM #ifdef CONFIG_MTK_LEGACY hwPowerOn(MT6328_POWER_LDO_VUSB33, VOL_3300, "VUSB_LDO"); DBG(0, "enable VBUS LDO\n"); #else reg = regulator_get(musb->controller, "vusb33"); if (!IS_ERR(reg)) { #define VUSB33_VOL_MIN 3300000 #define VUSB33_VOL_MAX 3300000 ret = regulator_set_voltage(reg, VUSB33_VOL_MIN, VUSB33_VOL_MAX); if (ret < 0) DBG(0, "regulator set vol failed: %d\n", ret); else DBG(0, "regulator set vol ok, <%d,%d>\n", VUSB33_VOL_MIN, VUSB33_VOL_MAX); ret = regulator_enable(reg); if (ret < 0) { DBG(0, "regulator_enable failed: %d\n", ret); regulator_put(reg); } else { DBG(0, "enable USB regulator\n"); } } else { DBG(0, "regulator_get failed\n"); } #endif #endif /* mt_usb_enable(musb); */ musb->isr = mt_usb_interrupt; musb_writel(musb->mregs, MUSB_HSDMA_INTR, 0xff | (0xff << DMA_INTR_UNMASK_SET_OFFSET)); DBG(0, "musb platform init %x\n", musb_readl(musb->mregs, MUSB_HSDMA_INTR)); #ifdef MUSB_QMU_SUPPORT /* FIXME, workaround for device_qmu + host_dma */ musb_writel(musb->mregs, USB_L1INTM, TX_INT_STATUS | RX_INT_STATUS | USBCOM_INT_STATUS | DMA_INT_STATUS | QINT_STATUS); #else musb_writel(musb->mregs, USB_L1INTM, TX_INT_STATUS | RX_INT_STATUS | USBCOM_INT_STATUS | DMA_INT_STATUS); #endif setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long)musb); #ifdef CONFIG_USB_MTK_OTG mt_usb_otg_init(musb); #endif return 0; }
五、OTG设备初始化与OTG中断处理
1. OTG初始化
void mt_usb_otg_init(struct musb *musb) { /* BYPASS OTG function in special mode */ if (get_boot_mode() == META_BOOT #ifdef CONFIG_MTK_KERNEL_POWER_OFF_CHARGING || get_boot_mode() == KERNEL_POWER_OFF_CHARGING_BOOT || get_boot_mode() == LOW_POWER_OFF_CHARGING_BOOT #endif ) { DBG(0, "in special mode %d\n", get_boot_mode()); return; } /* test */ host_plug_test_wq = create_singlethread_workqueue("host_plug_test_wq"); INIT_DELAYED_WORK(&host_plug_test_work, do_host_plug_test_work); #ifdef CONFIG_OF usb_node = of_find_compatible_node(NULL, NULL, "mediatek,mt6735-usb20"); if (usb_node == NULL) { pr_err("USB OTG - get USB0 node failed\n"); } else { if (of_property_read_u32_index(usb_node, "iddig_gpio", 0, &iddig_pin)) { iddig_if_config = 0; pr_err("get dtsi iddig_pin fail\n"); } if (of_property_read_u32_index(usb_node, "iddig_gpio", 1, &iddig_pin_mode)) pr_err("get dtsi iddig_pin_mode fail\n"); } #if !defined(CONFIG_MTK_LEGACY) pinctrl = devm_pinctrl_get(mtk_musb->controller); if (IS_ERR(pinctrl)) { dev_err(mtk_musb->controller, "Cannot find usb pinctrl!\n"); } #endif #endif /* init idpin interrupt */ ktime_start = ktime_get(); INIT_DELAYED_WORK(&musb->id_pin_work, musb_id_pin_work); otg_int_init(); /* EP table */ musb->fifo_cfg_host = fifo_cfg_host; musb->fifo_cfg_host_size = ARRAY_SIZE(fifo_cfg_host); otg_state.name = "otg_state"; otg_state.index = 0; otg_state.state = 0; if (switch_dev_register(&otg_state)) pr_err("switch_dev_register fail\n"); else pr_debug("switch_dev register success\n"); }
2. otg中断初始化
static void otg_int_init(void) { #ifdef ID_PIN_USE_EX_EINT int ret = 0; #ifndef CONFIG_MTK_FPGA #ifdef CONFIG_OF #if defined(CONFIG_MTK_LEGACY) mt_set_gpio_mode(iddig_pin, iddig_pin_mode); mt_set_gpio_dir(iddig_pin, GPIO_DIR_IN); mt_set_gpio_pull_enable(iddig_pin, GPIO_PULL_ENABLE); mt_set_gpio_pull_select(iddig_pin, GPIO_PULL_UP); #else pr_debug("****%s:%d before Init IDDIG KS!!!!!\n", __func__, __LINE__); pinctrl_iddig = pinctrl_lookup_state(pinctrl, "iddig_irq_init"); if (IS_ERR(pinctrl_iddig)) { ret = PTR_ERR(pinctrl_iddig); dev_err(mtk_musb->controller, "Cannot find usb pinctrl iddig_irq_init\n"); } pinctrl_select_state(pinctrl, pinctrl_iddig); pr_debug("****%s:%d end Init IDDIG KS!!!!!\n", __func__, __LINE__); #endif #else mt_set_gpio_mode(GPIO_OTG_IDDIG_EINT_PIN, GPIO_OTG_IDDIG_EINT_PIN_M_IDDIG); mt_set_gpio_dir(GPIO_OTG_IDDIG_EINT_PIN, GPIO_DIR_IN); mt_set_gpio_pull_enable(GPIO_OTG_IDDIG_EINT_PIN, GPIO_PULL_ENABLE); mt_set_gpio_pull_select(GPIO_OTG_IDDIG_EINT_PIN, GPIO_PULL_UP); #endif #endif #if defined(CONFIG_MTK_LEGACY) mt_gpio_set_debounce(IDDIG_EINT_PIN, 64000); usb_iddig_number = mt_gpio_to_irq(IDDIG_EINT_PIN); pr_debug("USB IDDIG IRQ LINE %d, %d!!\n", IDDIG_EINT_PIN, mt_gpio_to_irq(IDDIG_EINT_PIN)); ret = request_irq(usb_iddig_number, mt_usb_ext_iddig_int, IRQF_TRIGGER_LOW, "USB_IDDIG", NULL); #else /*gpio_request(iddig_pin, "USB_IDDIG");*/ gpio_direction_input(iddig_pin); gpio_set_debounce(iddig_pin, 4000); //64000 usb_iddig_number = mt_gpio_to_irq(iddig_pin); ret = request_irq(usb_iddig_number, mt_usb_ext_iddig_int, IRQF_TRIGGER_LOW, "USB_IDDIG", NULL); #endif if (ret > 0) pr_err("USB IDDIG IRQ LINE not available!!\n"); else pr_debug("USB IDDIG IRQ LINE available!!\n"); #else u32 phy_id_pull = 0; phy_id_pull = __raw_readl(U2PHYDTM1); phy_id_pull |= ID_PULL_UP; __raw_writel(phy_id_pull, U2PHYDTM1); musb_writel(mtk_musb->mregs, USB_L1INTM, IDDIG_INT_STATUS|musb_readl(mtk_musb->mregs, USB_L1INTM)); #endif }
3. otg中断处理
当otg插入或拔出,产生中断时,会调用otg_int_init函数中注册的mt_usb_ext_iddig_int函数
static irqreturn_t mt_usb_ext_iddig_int(int irq, void *dev_id) { iddig_cnt++; queue_delayed_work(mtk_musb->st_wq, &mtk_musb->id_pin_work, msecs_to_jiffies(sw_deboun_time)); DBG(0, "id pin interrupt assert\n"); disable_irq_nosync(usb_iddig_number); return IRQ_HANDLED; }
4. 中断处理函数唤醒之前注册的id_pin_work
mtk_musb->id_pin_work在mt_usb_otg_init函数中注册
INIT_DELAYED_WORK(&musb->id_pin_work, musb_id_pin_work);
static void musb_id_pin_work(struct work_struct *data) { u8 devctl = 0; int temp1,temp2; unsigned long flags; static int inited, timeout; /* default to 0 */ static DEFINE_RATELIMIT_STATE(ratelimit, 1 * HZ, 3); static s64 diff_time; int val = -1; /* kernel_init_done should be set in early-init stage through init.$platform.usb.rc */ if (!inited && !kernel_init_done && !mtk_musb->is_ready && !timeout) { ktime_end = ktime_get(); diff_time = ktime_to_ms(ktime_sub(ktime_end, ktime_start)); if (__ratelimit(&ratelimit)) { DBG(0, "init_done:%d, is_ready:%d, inited:%d, TO:%d, diff:%lld\n", kernel_init_done, mtk_musb->is_ready, inited, timeout, diff_time); } if (diff_time > ID_PIN_WORK_BLOCK_TIMEOUT) { DBG(0, "diff_time:%lld\n", diff_time); timeout = 1; } queue_delayed_work(mtk_musb->st_wq, &mtk_musb->id_pin_work, msecs_to_jiffies(ID_PIN_WORK_RECHECK_TIME)); return; } else if (!inited) { DBG(0, "PASS, init_done:%d, is_ready:%d, inited:%d, TO:%d\n", kernel_init_done, mtk_musb->is_ready, inited, timeout); } inited = 1; spin_lock_irqsave(&mtk_musb->lock, flags); musb_generic_disable(mtk_musb); spin_unlock_irqrestore(&mtk_musb->lock, flags); down(&mtk_musb->musb_lock); DBG(0, "work start, is_host=%d\n", mtk_musb->is_host); if (mtk_musb->in_ipo_off) { DBG(0, "do nothing due to in_ipo_off\n"); goto out; } while(1){ mtk_musb->is_host = musb_is_host(); temp1 = mtk_musb->is_host; msleep(5); mtk_musb->is_host = musb_is_host(); temp2 = mtk_musb->is_host; printk("temp1=%d; temp2=%d!!!\n", temp1, temp2); if(temp1 == temp2) break; } DBG(0, "musb is as %s\n", mtk_musb->is_host?"host":"device"); switch_set_state((struct switch_dev *)&otg_state, mtk_musb->is_host); if (mtk_musb->is_host) { printk("#######################host!!!\n"); /* setup fifo for host mode */ ep_config_from_table_for_host(mtk_musb); wake_lock(&mtk_musb->usb_lock); do{ mt_usb_set_vbus(mtk_musb, 1); msleep(1); val = fan5405_get_boost_status(); printk("lucky debug host boost state=%d!!!\n", val); }while(val != 1); //OTG mode should close red light gpio_direction_output(red_led_en, 1); gpio_direction_output(red_led_en1, 0); /* for no VBUS sensing IP*/ #if 1 /* wait VBUS ready */ msleep(100); /* clear session*/ devctl = musb_readb(mtk_musb->mregs, MUSB_DEVCTL); musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, (devctl&(~MUSB_DEVCTL_SESSION))); /* USB MAC OFF*/ /* VBUSVALID=0, AVALID=0, BVALID=0, SESSEND=1, IDDIG=X, IDPULLUP=1 */ USBPHY_SET8(0x6c, 0x11); USBPHY_CLR8(0x6c, 0x2e); USBPHY_SET8(0x6d, 0x3f); DBG(0, "force PHY to idle, 0x6d=%x, 0x6c=%x\n", USBPHY_READ8(0x6d), USBPHY_READ8(0x6c)); /* wait */ mdelay(5); /* restart session */ devctl = musb_readb(mtk_musb->mregs, MUSB_DEVCTL); musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, (devctl | MUSB_DEVCTL_SESSION)); /* USB MAC ONand Host Mode*/ /* VBUSVALID=1, AVALID=1, BVALID=1, SESSEND=0, IDDIG=0, IDPULLUP=1 */ USBPHY_CLR8(0x6c, 0x10); USBPHY_SET8(0x6c, 0x2d); USBPHY_SET8(0x6d, 0x3f); DBG(0, "force PHY to host mode, 0x6d=%x, 0x6c=%x\n", USBPHY_READ8(0x6d), USBPHY_READ8(0x6c)); #endif musb_start(mtk_musb); MUSB_HST_MODE(mtk_musb); switch_int_to_device(mtk_musb); if (host_plug_test_enable && !host_plug_test_triggered) queue_delayed_work(host_plug_test_wq, &host_plug_test_work, 0); } else { /* for device no disconnect interrupt */ printk("#######################device!!!\n"); spin_lock_irqsave(&mtk_musb->lock, flags); if (mtk_musb->is_active) { DBG(0, "for not receiving disconnect interrupt\n"); usb_hcd_resume_root_hub(musb_to_hcd(mtk_musb)); musb_root_disconnect(mtk_musb); } spin_unlock_irqrestore(&mtk_musb->lock, flags); DBG(0, "devctl is %x\n", musb_readb(mtk_musb->mregs, MUSB_DEVCTL)); musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, 0); if (wake_lock_active(&mtk_musb->usb_lock)) wake_unlock(&mtk_musb->usb_lock); do{ mt_usb_set_vbus(mtk_musb, 0); msleep(1); val = fan5405_get_boost_status(); printk("lucky debug dev boost state=%d!!!\n", val); }while(val != 0); //OTG out recover //gpio_direction_output(red_led_en, 0); //gpio_direction_output(red_led_en1, 0); /* for no VBUS sensing IP */ #if 1 /* USB MAC OFF*/ /* VBUSVALID=0, AVALID=0, BVALID=0, SESSEND=1, IDDIG=X, IDPULLUP=1 */ USBPHY_SET8(0x6c, 0x11); USBPHY_CLR8(0x6c, 0x2e); USBPHY_SET8(0x6d, 0x3f); DBG(0, "force PHY to idle, 0x6d=%x, 0x6c=%x\n", USBPHY_READ8(0x6d), USBPHY_READ8(0x6c)); #endif musb_stop(mtk_musb); mtk_musb->xceiv->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(mtk_musb); switch_int_to_host(mtk_musb); } out: DBG(0, "work end, is_host=%d\n", mtk_musb->is_host); up(&mtk_musb->musb_lock); }