博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MSM8X60 USB控制器流程分析
阅读量:4214 次
发布时间:2019-05-26

本文共 4468 字,大约阅读时间需要 14 分钟。

MSM8X60 USB控制器流程分析,其中去掉了没有用到的代码,以便把握整个主线不被干扰。

/*没有插入usb线之前的流程*/
static int msm_otg_set_peripheral(struct otg_transceiver *xceiv,
            struct usb_gadget *gadget)
{
    struct msm_otg *dev = container_of(xceiv, struct msm_otg, otg);
    ............
    dev->otg.gadget = gadget;
    pr_info("peripheral driver registered w/ tranceiver\n");
    wake_lock(&dev->wlock);//锁定wakelock,防止睡眠
    queue_work(dev->wq, &dev->sm_work);//调度work
    return 0;
}
/*usb线插入拔出时,调度work的流程*/
static irqreturn_t msm_otg_irq(int irq, void *data)
{
    struct msm_otg *dev = data;
    u32 otgsc, sts, pc, sts_mask;
    int work = 0;
    enum usb_otg_state state;
    if (atomic_read(&dev->in_lpm)) {//插入usb时,如果处于睡眠,则唤醒
        disable_irq_nosync(dev->irq);
        wake_lock(&dev->wlock);//锁定wakelock
        queue_work(dev->wq, &dev->otg_resume_work);//进入唤醒流程
        goto out;
    }
    
    /*读出寄存器的状态,判断有没有变化*/
    otgsc = readl(USB_OTGSC);
    sts = readl(USB_USBSTS);
    sts_mask = (otgsc & OTGSC_INTR_MASK) >> 8;//该寄存器的中断使能掩码
    if (!((otgsc & sts_mask) || (sts & STS_PCI))) {//如果没有变化,则迅速退出,因为该中断为共享中断
        ret = IRQ_NONE;
        goto out;
    }
    state = dev->otg.state;//取出上次的状态
    if ((otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {//检测到id引脚有变换
        if (otgsc & OTGSC_ID) {//id引脚值为1,则设置id位,为client
            pr_debug("Id set\n");
            set_bit(ID, &dev->inputs);
        } else {//id引脚值为0,则清除id位,host
            pr_debug("Id clear\n");
            set_bit(A_BUS_REQ, &dev->inputs);
            clear_bit(ID, &dev->inputs);
        }
        writel(otgsc, USB_OTGSC);//清除该寄存器,以便下次接收中断
        work = 1;
    } else if (otgsc & OTGSC_BSVIS) {//检测到VBUS有变换
        writel(otgsc, USB_OTGSC);//清除该寄存器,以便下次接收中断
        if ((state >= OTG_STATE_A_IDLE) &&
            !test_bit(ID_A, &dev->inputs))
            goto out;
        if (otgsc & OTGSC_BSV) {//表示usb cable插入
            pr_debug("BSV set\n");
            set_bit(B_SESS_VLD, &dev->inputs);
        } else {//表示usb cable移除
            pr_debug("BSV clear\n");
            clear_bit(B_SESS_VLD, &dev->inputs);
        }
        work = 1;
    } else if (sts & STS_PCI) {//表示端口变化中断
        pc = readl(USB_PORTSC);
        pr_debug("portsc = %x\n", pc);
        ret = IRQ_NONE;
        work = 1;
        switch (state) {
        ..............
        default:
            PR_DEBUG_ON
            work = 0;
            break;
        }
    }
    if (work) {//work为1,则调度work,并锁定wakelock
        wake_lock(&dev->wlock);
        queue_work(dev->wq, &dev->sm_work);
    }
out:
    return ret;
}
调度的work如下:
static void msm_otg_sm_work(struct work_struct *w)
{
    struct msm_otg    *dev = container_of(w, struct msm_otg, sm_work);
    int work = 0;
    enum usb_otg_state state;
    if (atomic_read(&dev->in_lpm))//进入runtime唤醒流程
        msm_otg_set_suspend(&dev->otg, 0);
    state = dev->otg.state;//第一次状态没有初始化,默认为0
    switch (state) {
    case OTG_STATE_UNDEFINED:
        /* Reset both phy and link */
        otg_reset(&dev->otg, 1);//第一次所走路线
        if (!dev->otg.host || !is_host())//第一次所走路线
            set_bit(ID, &dev->inputs);
        if (dev->otg.gadget && is_b_sess_vld())
            set_bit(B_SESS_VLD, &dev->inputs);
        if ((test_bit(ID, &dev->inputs)) &&
                !test_bit(ID_A, &dev->inputs)) {
            dev->otg.state = OTG_STATE_B_IDLE;//第一次所走路线
        } else {
            set_bit(A_BUS_REQ, &dev->inputs);
            dev->otg.state = OTG_STATE_A_IDLE;
        }
        work = 1;//调度work
        break;
    case OTG_STATE_B_IDLE:
        dev->otg.default_a = 0;
        if (test_bit(B_SESS_VLD, &dev->inputs) &&
                !test_bit(ID_B, &dev->inputs)) {//第二次所走路线
            pr_debug("b_sess_vld\n");
            spin_lock_irqsave(&dev->lock, flags);
            dev->otg.state = OTG_STATE_B_PERIPHERAL;
            spin_unlock_irqrestore(&dev->lock, flags);
            msm_otg_set_power(&dev->otg, 0);
            msm_otg_start_peripheral(&dev->otg, 1);
        } else {
            msm_otg_set_power(&dev->otg, 0);第一次所走路线
            pr_debug("entering into lpm\n");
            msm_otg_put_suspend(dev);//进入runtime睡眠流程
            if (dev->pdata->ldo_set_voltage)
                dev->pdata->ldo_set_voltage(3075);
        }
        break;
    case OTG_STATE_B_PERIPHERAL:
        if (!test_bit(ID, &dev->inputs) ||
                test_bit(ID_A, &dev->inputs) ||
                test_bit(ID_B, &dev->inputs) ||
                !test_bit(B_SESS_VLD, &dev->inputs)) {
            pr_debug("!id  || id_a/b || !b_sess_vld\n");
            clear_bit(B_BUS_REQ, &dev->inputs);
            spin_lock_irqsave(&dev->lock, flags);
            dev->otg.state = OTG_STATE_B_IDLE;
            spin_unlock_irqrestore(&dev->lock, flags);
            msm_otg_start_peripheral(&dev->otg, 0);
            dev->b_last_se0_sess = jiffies;
            /* Workaround: Reset phy after session */
            otg_reset(&dev->otg, 1);
            work = 1;
        }
        break;
    default:
        pr_err("invalid OTG state\n");
    }
    if (work)
        queue_work(dev->wq, &dev->sm_work);//第一次所走路线
        
    if (!work_pending(&dev->sm_work) && !hrtimer_active(&dev->timer) &&
            !work_pending(&dev->otg_resume_work))
        wake_unlock(&dev->wlock);//所用的work,timer的处理函数都执行完时,解锁wakelock
}
1、没有插入usb时,系统初始化第一次调度work后dev->otg.state为OTG_STATE_B_IDLE,再次调度work,进入low power模式,解锁wakelock,睡眠。
2、插入usb时,系统从OTG_STATE_B_IDLE醒来,在otg irq中唤醒系统,并锁定wakelock,然后继续处理硬件中断,开启外围设备控制器。并设置dev->otg.state的状态为OTG_STATE_B_PERIPHERAL;
3、当usb移除的时候,调度work,再次设置dev->otg.state为OTG_STATE_B_IDLE,并关闭设备控制器。继续调度work,进入low power模式,并解锁wakelock,进入系统睡眠。

 

转载地址:http://urdmi.baihongyu.com/

你可能感兴趣的文章
机器学习: 线性回归正则化
查看>>
HDOJ 1847 轮流取牌 博弈 SG函数
查看>>
51Nod 1072 威佐夫游戏 (博弈)
查看>>
51Nod 1069 Nim游戏
查看>>
机器学习 LogsticRegression 正则化(matlab实现)
查看>>
python 数字识别 SVM
查看>>
python sklern学习 波士顿房屋价格预测(线性回归)
查看>>
matlab 实验
查看>>
使用conda安装包
查看>>
python 搭建web服务器
查看>>
python 获取wifi信息遇到的问题
查看>>
POJ 1321 搜索
查看>>
flask 接收wifi信息遇到的问题
查看>>
ubuntu 16.04 安装python虚拟环境产生的问题
查看>>
Linux screen简单用法
查看>>
蓝桥杯 决赛 2012_2 数据压缩
查看>>
scikit-learn 分类 KNeighborsClassifier
查看>>
支持浮点数的表达式求值
查看>>
基数排序
查看>>
蓝桥杯 2012 决赛 拼音字母
查看>>