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);

}

 

posted @ 2018-12-29 14:43  爱无限  阅读(2525)  评论(0编辑  收藏  举报