下面看下三大控制器的配合:
/*在设备控制器注册的最后,调用了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;
}