Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1433130
  • 博文数量: 1334
  • 博客积分: 645
  • 博客等级: 上士
  • 技术积分: 5762
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-25 16:56
文章分类

全部博文(1334)

文章存档

2014年(108)

2013年(1059)

2012年(169)

分类: LINUX

2013-06-06 01:01:05

//插入usb b cable前的状态是 OTG_STATE_B_IDLE
static void msm_otg_sm_work(struct work_struct *w)
{

    switch (state) {
    case OTG_STATE_UNDEFINED:
         {
            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);
        if ((test_bit(ID, &dev->inputs)) &&
                !test_bit(ID_A, &dev->inputs)) {
            dev->otg.state = OTG_STATE_B_IDLE;//什么都不插入,初始化时的状态
        }
        work = 1;
        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");
        pr_info("%s: -->>entering into lpm.\n",__func__);
        msm_otg_put_suspend(dev);

        if (dev->pdata->ldo_set_voltage)
            dev->pdata->ldo_set_voltage(3075);
    }
    break;
}
//插入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(ID_A, &dev->inputs) || test_bit(ID_B, &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
        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;
case OTG_STATE_B_IDLE:
    dev->otg.default_a = 0;
    else{
    msm_otg_set_power(&dev->otg, 0);
    pr_debug("entering into lpm\n");
    pr_info("%s: -->>entering into lpm.\n",__func__);
    msm_otg_put_suspend(dev);

    if (dev->pdata->ldo_set_voltage)
        dev->pdata->ldo_set_voltage(3075);
    }
    break;
//驱动该状态机的状态如下
1、在中断中
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)) {
        queue_work(dev->wq, &dev->otg_resume_work);
        goto out;
    }
    
    /*读出状态寄存器的值*/
    otgsc = readl(USB_OTGSC);
    sts = readl(USB_USBSTS);

    state = dev->otg.state;//状态机的当前状态

    if ((otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {
        if (otgsc & OTGSC_ID) {//拔出a cable时的触发状态  
            pr_debug("Id set\n");
            set_bit(ID, &dev->inputs);
        } else {
            pr_debug("Id clear\n");//插入a cable时的触发状态  
            set_bit(A_BUS_REQ, &dev->inputs);
            clear_bit(ID, &dev->inputs);
        }
        writel(otgsc, USB_OTGSC);
        work = 1;//调度work,驱动状态机状态迁移
    } else 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 (sts & STS_PCI) {
        pc = readl(USB_PORTSC);
        pr_debug("portsc = %x\n", pc);
        work = 1;
        switch (state) {
            .............
        default:
            work = 0;
            break;
        }
    }
    if (work) {
        wake_lock(&dev->wlock);
        queue_work(dev->wq, &dev->sm_work);//调度驱动状态机
    }
}
阅读(173) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~