高通Android9.0_Kernel4.9 USB主从切换检测调试总结

戏子无情 提交于 2019-12-27 20:40:42

一、主要问题

       本项目采用的是高通的SDM450平台,单USB口出来后接了USB HUB 同时可以连接电脑等,这就有个问题,当我同时连接电脑并将USB HUB上电后,在主从切换之间就有问题,也就是当处于主模式的时候,通过拉高USB_ID管脚进入从模式,这时候就会切换失败;或者处于从模式的时候,将USB_ID管脚拉低进入主模式的时候,也会切换失败。

二、原理图

主控部分原理图

 

usb_ID 控制部分原理图

Vbus电路原理图

 

通过原理图可以很清晰的看出,通过HOST_EN管脚可以控制USB_ID管脚,然后进行主从的状态切换

三、原理

高通Android9.0 kernel4.9 主从切换问题主要涉及到两个方面,一是通过OTG_ID 管脚的高低电平进行中断进行主模式的进入和退出;一是通过VBUS电压检测进行从模式的进入和退出。(注意这里只是相应模式的进入和退出,例如退出主模式后不一定是进入从模式,退出从模式不一定是进入主模式)

四、软件分析过程

用于VBUS和OTG_ID检测相关驱动

kernel/msm-4.9/drivers/platform/msm/gpio-usbdetect.c

用于设置主从状态相关驱动

kernel/msm-4.9/drivers/extcon/extcon.c

kernel/msm-4.9/drivers/extcon/driver.c

 

驱动简单分析

USB驱动器状态控制模块(extcon)主要做两件事
A、    注册extcon设备类
B、    提供相关的状态注册,状态设置等接口
状态检测驱动(gpio-usbdetect.c) 主要做三件事
A、    获取相关管脚并注册对应的中断处理函数
B、    向USB驱动器状态控制模块(extcon) 申请状态监听
C、    应对相关中断产生并向USB驱动器状态控制模块(extcon) 设置相应的状态用于上报
 

相关代码gpio-usbdetect.c

gpio_usbdetect_probe()
A、        获取id管脚并注册对应的中断处理函数

B、    向USB驱动器状态控制模块(extcon) 申请状态监听

C、应对相关中断产生并向USB驱动器状态控制模块(extcon) 设置相应的状态用于上报

Extcon.c驱动
注册 extcon类

还有一些其他相关的接口,不再一一贴出来

int extcon_dev_register(struct extcon_dev *edev)

int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id,
                unsigned int prop,
                union extcon_property_value prop_val)
int extcon_get_property_capability(struct extcon_dev *edev, unsigned int id,
                    unsigned int prop)
int extcon_set_property(struct extcon_dev *edev, unsigned int id,
                unsigned int prop,
                union extcon_property_value prop_val)
 

int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
                bool cable_state)

说明: Extcon 主要是实现usb驱动器的管理,提供包括USB状态器的注册,同步等,具体可以查看文件

kernel/msm-4.9/drivers/extcon/extcon.c

 

在我们的项目中对于USB驱动器状态管理模块来说,USB的状态有三种
EXTCON_USB
EXTCON_USB_HOST
EXTCON_NONE
当然实际不止这三种状态

根据调试过程log分析,得到以下一个问题
任何的一个切换都必须先USB退出当前状态,此时USB处于 EXTCON_NONE状态,然后再切换到HOST或者USB模式,否则就会有切换不过去的情况,而这些动作只是在两个中断处理函数里面做:

static irqreturn_t gpio_usbdetect_id_irq_thread(int irq, void *data)

static irqreturn_t gpio_usbdetect_vbus_irq(int irq, void *data)

这两个函数主要是处理VBUS产生中断和USB_ID产生中断,我们要做的就是修改里面的逻辑,使得当退出主模式时,不仅仅是将EXTCON_USB_HOST状态设置为0;当退出从模式的时候,不仅仅是将EXTCON_USB设置为0,而是完整的退出相应的模式。通过对比修改前后大概可以知道

gpio_usbdetect_id_irq_thread处理函数修改前

gpio_usbdetect_id_irq_thread处理函数修改后

由于我们的硬件设计时候,没有考虑到VBUS中断管脚的连接,使得VBUS的中断无法产生,我们只能在usb_id的中断处理函数里面通过一个 work来处理,若果插拔USB线可以产生VBUS中断的话,就可以把这个work的内容换到gpio_usbdetect_vbus_irq 里面,以下是work的处理

 

这两部分主要是进入EXTCON_USB_HOST 或者EXTCON_USB模式,只是在中断处理函数里面已经通过          extcon_set_property函数来完全退出上一个模式,然后再调用相应的work来进入一个新的模式

例如完全退出 EXTCON_USB 模式

        val.intval = false;
        extcon_set_property(usb->extcon_dev, EXTCON_USB,
                    EXTCON_PROP_USB_SS, val);
        extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 0);

完全退出EXTCON_USB_HOST模式

        val.intval = false;
        extcon_set_property(usb->extcon_dev, EXTCON_USB_HOST,
                    EXTCON_PROP_USB_SS, val);
        extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 0);

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!