MT8163平台otg实现代码流程分析

相关代码

\mt8163-kernel-3.18\drivers\misc\mediatek\power\mt8163\tbl_helper_func.c

mt8163-kernel-3.18\drivers\misc\mediatek\usb20\mt8163\usb20.c
mt8163-kernel-3.18\drivers\misc\mediatek\usb20\mt8163\usb20.h
mt8163-kernel-3.18\drivers\misc\mediatek\usb20\mt8163\ usb20_host.c

使能OTG功能的函数接口

void tbl_charger_otg_vbus(int mode)
{
    pr_debug("Power/Battery [tbl_charger_otg_vbus] mode = %d\n", mode);

    if (mode & 0xFF) {
#ifdef CONFIG_MTK_BQ24196_SUPPORT
        bq24196_set_chg_config(0x3); /*OTG*/
        bq24196_set_boost_lim(0x1);  /*1.3A on VBUS*/
        bq24196_set_en_hiz(0x0);
#endif

#ifdef CONFIG_MTK_BQ24297_SUPPORT
        bq24297_set_otg_config(0x1); /*OTG*/
        bq24297_set_boost_lim(0x1);  /*1.5A on VBUS*/
        bq24297_set_en_hiz(0x0);
#endif

#ifdef CONFIG_MTK_BQ24296_SUPPORT
        bq24296_set_chg_config(0x0); /*disable charge*/
        bq24296_set_otg_config(0x1); /*OTG*/
        bq24296_set_boostv(0x7); /*boost voltage 4.998V*/
        bq24296_set_boost_lim(0x1); /*1.5A on VBUS*/
        bq24296_set_en_hiz(0x0);
#endif

#ifdef CONFIG_MTK_NCP1851_SUPPORT
        ncp1851_set_chg_en(0x0); /*charger disable*/
        ncp1851_set_otg_en(0x1); /*otg enable*/
#endif

#ifdef CONFIG_MTK_NCP1854_SUPPORT
        ncp1854_set_chg_en(0x0); /*charger disable*/
        ncp1854_set_otg_en(0x1); /*otg enable*/
#endif
    } else {
#ifdef CONFIG_MTK_BQ24196_SUPPORT
        bq24196_set_chg_config(0x0); /*OTG & Charge disabled*/
#endif

#ifdef CONFIG_MTK_BQ24297_SUPPORT
        bq24297_set_otg_config(0x0); /*OTG & Charge disabled*/
#endif

#ifdef CONFIG_MTK_BQ24296_SUPPORT
        bq24296_set_otg_config(0x0); /*OTG disabled*/
        bq24296_set_chg_config(0x0); /*Charge disabled*/
#endif

#ifdef CONFIG_MTK_NCP1851_SUPPORT
        ncp1851_set_otg_en(0x0);
#endif

#ifdef CONFIG_MTK_NCP1854_SUPPORT
        ncp1854_set_otg_en(0x0);
#endif
    }
}

tbl_charger_otg_vbus这个函数是什么在哪里调用的?

void mt_usb_set_vbus(struct musb *musb, int is_on)
{
    DBG(0, "mt65xx_usb20_vbus++,is_on=%d\r\n", is_on);
#ifndef FPGA_PLATFORM
    if (is_on) {
        /* power on VBUS, implement later... */
#if defined OTG_BOOST_BY_SWITCH_CHARGER
        tbl_charger_otg_vbus((work_busy(&musb->id_pin_work.work) << 8) | 1);//**打开otg功能**
#else
#ifdef CONFIG_OF
#if defined(CONFIG_MTK_LEGACY)
        mt_set_gpio_mode(drvvbus_pin, drvvbus_pin_mode);
        mt_set_gpio_out(drvvbus_pin, GPIO_OUT_ONE);
#else
        DBG(0, "****%s:%d Drive VBUS ON!!!!!\n", __func__, __LINE__);
        pinctrl_select_state(pinctrl, pinctrl_drvvbus_high);
#endif
#else
        mt_set_gpio_mode(GPIO_OTG_DRVVBUS_PIN, GPIO_OTG_DRVVBUS_PIN_M_GPIO);
        mt_set_gpio_out(GPIO_OTG_DRVVBUS_PIN, GPIO_OUT_ONE);
#endif
#endif
    } else {
        /* power off VBUS, implement later... */
#if defined OTG_BOOST_BY_SWITCH_CHARGER
        tbl_charger_otg_vbus((work_busy(&musb->id_pin_work.work) << 8) | 0);//关闭otg
#else
#ifdef CONFIG_OF
#if defined(CONFIG_MTK_LEGACY)
        mt_set_gpio_mode(drvvbus_pin, drvvbus_pin_mode);
        mt_set_gpio_out(drvvbus_pin, GPIO_OUT_ZERO);
#else
        DBG(0, "****%s:%d Drive VBUS OFF!!!!!\n", __func__, __LINE__);
        pinctrl_select_state(pinctrl, pinctrl_drvvbus_low);
#endif
#else
        mt_set_gpio_mode(GPIO_OTG_DRVVBUS_PIN, GPIO_OTG_DRVVBUS_PIN_M_GPIO);
        mt_set_gpio_out(GPIO_OTG_DRVVBUS_PIN, GPIO_OUT_ZERO);
#endif
#endif
    }
#endif
}

上面的代码中需要检查宏OTG_BOOST_BY_SWITCH_CHARGER是否定义

#if (defined(CONFIG_MTK_FAN5405_SUPPORT) \
        || defined(CONFIG_MTK_BQ24158_SUPPORT) \
        || defined(CONFIG_MTK_NCP1851_SUPPORT) \
        || defined(CONFIG_MTK_BQ24196_SUPPORT) \
        || defined(CONFIG_MTK_NCP1854_SUPPORT) \
        || defined(CONFIG_MTK_BQ24297_SUPPORT) \
        || defined(CONFIG_MTK_BQ24296_SUPPORT)) \
    && !defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT)
#define OTG_BOOST_BY_SWITCH_CHARGER 1
#endif

mt_usb_set_vbus这个函数又是什么时候在哪里调用的?

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_probe函数中设置ops函数 pdata->platform_ops = &mt_usb_ops;设置它的set_vbus函数为mt_usb_set_vbus,那么肯定有地方会调用set_vbus函数

在musb_id_pin_work函数中

if (mtk_musb->is_host) {
        /*setup fifo for host mode*/
        ep_config_from_table_for_host(mtk_musb);
        wake_lock(&mtk_musb->usb_lock);
        musb_platform_set_vbus(mtk_musb, 1);//**set_vbus函数**
        ……
}else{

        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);
        musb_platform_set_vbus(mtk_musb, 0);//**set_vbus函数**
}

到这里大概流程基本清楚了,我们再从头来看具体是怎么实现的?
Otg依赖于usb_id管脚的状态,低电平时认为有otg设备插入。

static int mt_usb_init(struct musb *musb)
{
……
#ifdef CONFIG_USB_MTK_OTG  //如果需要otg功能需要在kernel的config文件打开该宏
    DBG(0, "%s, init_otg\n", __func__);
    mt_usb_otg_init(musb);
#endif
}
void mt_usb_otg_init(struct musb *musb)
{
……
    INIT_DELAYED_WORK(&musb->id_pin_work, musb_id_pin_work);//初始化处理usb id状态的工作队列
    otg_int_init();//usb id中断初始化
}
static void otg_int_init(void)
{
。。。。。。
usb_iddig_number = __gpio_to_irq(iddig_pin);//获得中断号
    DBG(0, "usb usb_iddig_number %d\n", usb_iddig_number);

    ret = request_irq(usb_iddig_number, mt_usb_ext_iddig_int, IRQF_TRIGGER_LOW, "USB_IDDIG", NULL);//申请中断,注册中断处理函数低电平触发,当usb id状态改变时调用mt_usb_ext_iddig_int函数
    if (ret > 0)
        DBG(0, "USB IDDIG IRQ LINE not available!!\n");
    else
        DBG(0, "USB IDDIG IRQ LINE available!!\n");

    irq_set_irq_wake(usb_iddig_number, 1);
}
static irqreturn_t mt_usb_ext_iddig_int(int irq, void *dev_id)
{
    if (!mtk_musb->is_ready) {
        /* dealy 5 sec if usb function is not ready */
        schedule_delayed_work(&mtk_musb->id_pin_work, 7000*HZ/1000);
    } else {
        schedule_delayed_work(&mtk_musb->id_pin_work, sw_deboun_time*HZ/1000);
    }
    disable_irq_nosync(usb_iddig_number);
    DBG(0, "disable iddig irq @lin %d\n", __LINE__);
    DBG(0, "id pin interrupt assert\n");
    return IRQ_HANDLED;
}

在中断处理函数中调度工作队列运行

static void musb_id_pin_work(struct work_struct *data)
{
。。。。。。
if (mtk_musb->is_host) {//如果是host模式
        /*setup fifo for host mode*/
        ep_config_from_table_for_host(mtk_musb);
        wake_lock(&mtk_musb->usb_lock);
        musb_platform_set_vbus(mtk_musb, 1);//使能otg功能

        /* 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 */
        USBPHY_SET8(0x6c, 0x10);
        USBPHY_CLR8(0x6c, 0x2e);
        USBPHY_SET8(0x6d, 0x3e);
        DBG(0, “force PHY to idle, 0x6d=%x, 0x6c=%x\n”, USBPHY_READ8(0x6d), USBPHY_READ8(0x6c));
        /* wait */
        mdelay(5);

        /* remove babble: NOISE_STILL_SOF:1, BABBLE_CLR_EN:0 */
        devctl = musb_readb(mtk_musb->mregs, MUSB_ULPI_REG_DATA);
        devctl = devctl | 0x80;
        devctl = devctl & 0xbf;
        musb_writeb(mtk_musb->mregs, MUSB_ULPI_REG_DATA, devctl);
        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 */
        USBPHY_CLR8(0x6c, 0x10);
        USBPHY_SET8(0x6c, 0x2c);
        USBPHY_SET8(0x6d, 0x3e);
        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);

#ifdef CONFIG_PM_RUNTIME
        mtk_musb->is_active = 0;
        DBG(0, “set active to 0 in Pm runtime issue\n”);
#endif
    }else {
        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);
        musb_platform_set_vbus(mtk_musb, 0);//关闭otg功能

    /* for no VBUS sensing IP */
#if 1
        /* USB MAC OFF*/
        /* VBUSVALID=0, AVALID=0, BVALID=0, SESSEND=1, IDDIG=X */
        USBPHY_SET8(0x6c, 0x10);
        USBPHY_CLR8(0x6c, 0x2e);
        USBPHY_SET8(0x6d, 0x3e);
        DBG(0, "force PHY to idle, 0x6d=%x, 0x6c=%x\n", USBPHY_READ8(0x6d), USBPHY_READ8(0x6c));
#endif

#if !defined(MTK_HDMI_SUPPORT)
        musb_stop(mtk_musb);
#else
        mt_usb_check_reconnect();/*ALPS01688604, IDDIG noise caused by MHL init*/
#endif
        mtk_musb->xceiv->state = OTG_STATE_B_IDLE;
        MUSB_DEV_MODE(mtk_musb);
        switch_int_to_host(mtk_musb);
    }
}

到这里就回到了刚开始分析的地方

扫描二维码关注公众号,回复: 1533606 查看本文章
musb_platform_set_vbus
musb->ops->set_vbus(musb, is_on);
     mt_usb_set_vbus
         tbl_charger_otg_vbus
            #ifdef CONFIG_MTK_BQ24296_SUPPORT
            bq24296_set_chg_config(0x0); /*disable charge*/
            bq24296_set_otg_config(0x1); /*OTG*/
            bq24296_set_boostv(0x7); /*boost voltage 4.998V*/
            bq24296_set_boost_lim(0x1); /*1.5A on VBUS*/
            bq24296_set_en_hiz(0x0);
#endif

猜你喜欢

转载自blog.csdn.net/yuewen2008/article/details/78385191