Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1297933
  • 博文数量: 860
  • 博客积分: 425
  • 博客等级: 下士
  • 技术积分: 1464
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-20 19:57
个人简介

对技术执着

文章分类

全部博文(860)

文章存档

2019年(16)

2018年(12)

2015年(732)

2013年(85)

2012年(15)

我的朋友

分类: LINUX

2013-07-03 13:44:48

下面看下三大控制器的配合:
/*在设备控制器注册的最后,调用了msm_otg_set_peripheral ()*/
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);//在这里调度msm_otg_sm_work
 return 0;
}
//下面看调度的结果
static void msm_otg_sm_work(struct work_struct *w)
{
 if (atomic_read(&dev->in_lpm))//如果处于低功耗模式,则先退出该模式
  msm_otg_set_suspend(&dev->otg, 0);
 spin_lock_irqsave(&dev->lock, flags);
 state = dev->otg.state;//取出otg的当前状态
 spin_unlock_irqrestore(&dev->lock, flags);
 switch (state) {
  case OTG_STATE_UNDEFINED://状态机的初始状态
   /* Reset both phy and link */
   otg_reset(&dev->otg, 1);
   if(dev->pdata->otg_mode == OTG_USER_CONTROL){
    ..........
   }else{
    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);
   }
   spin_lock_irqsave(&dev->lock, flags);//保护otg状态的自旋锁
   if ((test_bit(ID, &dev->inputs)) && !test_bit(ID_A, &dev->inputs)) {
    dev->otg.state = OTG_STATE_B_IDLE;//什么都不插入,初始化时的状态
   }
   .................
   spin_unlock_irqrestore(&dev->lock, flags);
   work = 1;//继续调度work
   break;
  case OTG_STATE_B_IDLE:
   dev->otg.default_a = 0;
   .............. 
    else {//初始时,会停留在OTG_STATE_B_IDLE状态并睡眠
    msm_otg_set_power(&dev->otg, 0);
    pr_debug("entering into lpm\n");
    msm_otg_put_suspend(dev);//进入low power mode
    
    .............
   }
   break;
 }
 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))//看是否有work和timer在运行?
  wake_unlock(&dev->wlock);//解锁wakelock
}
//调度的结果是otg状态机停留在了OTG_STATE_B_IDLE状态,并进入low power mode,等待着有事件触发,驱动状态机的状态迁移。
//下面就等待着事件的触发,触发的事件如下:
1、当有usb a cable插入的时候。
2、当有usb b cable插入的时候。
下面分别进行分析,先分析插入usb b cable,也就是普通的usb线,咱们的手机作为device,pc作为host。
当插入usb b cable的时候,会触发中断,进入下面的中断处理函数:
static irqreturn_t msm_otg_irq(int irq, void *data)
{
 struct msm_otg *dev = data;
 int work = 0;
 enum usb_otg_state state;
 unsigned long flags;
 if (atomic_read(&dev->in_lpm)) {//如果otg控制器已经处于low power模式,则先唤醒
  queue_work(dev->wq, &dev->otg_resume_work);//该work在otg控制器注册的时候已经初始化
  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;
 }
 ....................
  if (otgsc & OTGSC_BSVIS) {
  writel(otgsc, USB_OTGSC);//清除中断状态位
  if ((state >= OTG_STATE_A_IDLE) && !test_bit(ID_A, &dev->inputs))
   goto out;
  if (otgsc & OTGSC_BSV) {//插入b cable时候,所触发的条件
   pr_debug("BSV set\n");
   set_bit(B_SESS_VLD, &dev->inputs);
  } else {//拔出b cable的时候,所触发的条件
   pr_debug("BSV clear\n");
   clear_bit(B_SESS_VLD, &dev->inputs);
  }
  work = 1;//调度work,驱动状态机状态迁移
 }
 
 ..............
 
 if (work) {
  wake_lock(&dev->wlock);//锁定wake lock防止睡眠
  queue_work(dev->wq, &dev->sm_work);//调度驱动otg状态机sm_work
 }
out:
 return ret;
}
插入usb b cable前的状态是 OTG_STATE_B_IDLE
static void msm_otg_sm_work(struct work_struct *w)
{
 if (atomic_read(&dev->in_lpm))//如果处于低功耗模式,则先退出该模式
  msm_otg_set_suspend(&dev->otg, 0);
 spin_lock_irqsave(&dev->lock, flags);
 state = dev->otg.state;//取出otg的当前状态
 spin_unlock_irqrestore(&dev->lock, flags);
 switch (state) {
  ................
  //插入usb b cable的时候,状态机迁移如下
  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;//状态机迁移到OTG_STATE_B_PERIPHERAL
    spin_unlock_irqrestore(&dev->lock, flags);
    msm_otg_set_power(&dev->otg, 0);
    msm_otg_start_peripheral(&dev->otg, 1);//启动设备控制器
   }
   break;
  case OTG_STATE_B_PERIPHERAL:
   //下面的if-else条件都不满足,状态机停留在OTG_STATE_B_PERIPHERAL状态
   break;
  //拔出usb b cable的时候,状态机迁移如下
  case OTG_STATE_B_PERIPHERAL:
   if (!test_bit(ID, &dev->inputs) || !test_bit(B_SESS_VLD, &dev->inputs)) { //B_SESS_VLD为0
    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; //状态机迁移到OTG_STATE_B_IDLE,进而进入low power mode
    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;//继续调度work,进入low power 模式
   }
   break;
  .......................
 }
 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))//看是否有work和timer在运行?
  wake_unlock(&dev->wlock);//解锁wakelock
}
/*因为在usb b cable插入前,otg控制器是进入low power mode的,先看下进入low power mode的实现*/
static void msm_otg_put_suspend(struct msm_otg *dev)
{
 //因为定义了runtime,所以走该流程,该流程比较复杂,不过最终还是走的msm_otg_suspend(dev);runtime的过程就不列啦
#ifdef CONFIG_PM_RUNTIME
 pm_runtime_put_sync(dev->otg.dev);
 if (!atomic_read(&dev->in_lpm))
  pm_runtime_get_sync(dev->otg.dev);
#else
 msm_otg_suspend(dev);
#endif
}
static int msm_otg_suspend(struct msm_otg *dev)
{
    ..................
    if (dev->pdata->pmic_id_notif_init && !host_bus_suspend && !test_bit(ID_A, &dev->inputs)) {
        ..........
        ret = dev->pdata->pmic_id_notif_init(&msm_otg_set_id_state, 1);//在这里注册回调函数usb id引脚的处理函数
        if (!ret) {
            dev->pmic_id_notif_supp = 1;//支持otg 的id引脚
            if (dev->pdata->pmic_id_irq)
                dev->id_irq = dev->pdata->pmic_id_irq;//保存处理id引脚中断的中断号
        }
        ............
    }
    ..................
    atomic_set(&dev->in_lpm, 1);//设置处于low power mode的标记
    .........................
}
/*上面是进入low power mode,下面看下退出low power mode的实现*/
static void msm_otg_resume_w(struct work_struct *w)
{
 struct msm_otg *dev = container_of(w, struct msm_otg, otg_resume_work);
 unsigned long timeout;
 if (can_phy_power_collapse(dev) && dev->pdata->ldo_enable)
  dev->pdata->ldo_enable(1);
 msm_otg_get_resume(dev);//resume流程,下面分析
 ................
phy_resumed:
 if (readl_relaxed(USB_OTGSC) & OTGSC_BSVIS) {//重新设备位域,调度work
  set_bit(B_SESS_VLD, &dev->inputs);
  queue_work(dev->wq, &dev->sm_work);
 }
 if (dev->pmic_id_notif_supp) {
  dev->pdata->pmic_id_notif_init(&msm_otg_set_id_state, 0);//注销id引脚的中断处理
  dev->pmic_id_notif_supp = 0;
  enable_idgnd(dev);
 }
 ..............
 enable_irq(dev->irq);
}
下面看下里面调用的msm_otg_get_resume(dev);函数:
static void msm_otg_get_resume(struct msm_otg *dev)
{
#ifdef CONFIG_PM_RUNTIME//由于定义了runtime宏,走该流程,不过最终还是调用msm_otg_resume(dev);,runtime的过程就不列啦!
 pm_runtime_get_noresume(dev->otg.dev);
 pm_runtime_resume(dev->otg.dev);
#else
 msm_otg_resume(dev);
#endif
}
static int msm_otg_resume(struct msm_otg *dev)
{
    ...........
    atomic_set(&dev->in_lpm, 0);
    pr_info("%s: usb exited from low power mode\n", __func__);
    return 0;
}
阅读(848) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~