本文共 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/