bigfish0506

extcon,是External Connector的简称,用于抽象外部连接器,比如说Audio Jack、USB MicroB/TypeC接口等。它的原型是Android的switch-class驱动,经过修改后在kernel 3.4.0版本时被引入内核中。

Extcon (external connector): import Android's switch class and modify.

External connector class (extcon) is based on and an extension of Android kernel's switch class located at linux/drivers/switch/.

https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/drivers/extcon?h=next-20220502&id=de55d8716ac50a356cea736c29bb7db5ac3d0190

extcon驱动的主要功能是识别外部连接器状态变化,并将状态变化通知到与外部连接器相关的其他驱动。

使用extcon驱动,有什么好处呢?之前的内核都没有extcon驱动,又是怎么处理这些外部连接器的?不妨以USB驱动为例,看看使用extcon驱动前后的变化。

USB常见的外部接口有TypeA/B/C三种,其中TypeA/B又有标准A/B、Mini A/B和Micro A/B三种,直接上图:

这三种不同的接口,TypeA/B只是物理信号上的连接,主控芯片内部没有针对TypeA/B的专用控制器,可通过VBUS和ID两个脚的状态来识别是否接入了USB主机或USB外设。接入主机前,VBUS脚上没有电压,接入主机后,主机端会在VBUS脚上提供5V电压;接入外设前,ID脚为高电平,接入外设后,ID脚被拉低。于是软件可以通过主动读取这两个脚的电平或者异步响应这两个脚的中断来获知状态的变化。

TypeC就有点特别,从TypeC规范可以看到,TypeC是有一个状态机的,从Unattached状态走到Attached Sink状态(做从设备)或者Attached Source状态(做主机),主控芯片内部是有相应的控制器的,控制器会通过寄存器汇报状态变化,并产生中断通知主控。TypeC控制器需要软件进行相应的编程来配置和使能它。

截图来自官方规范:USB Type-C 2.1 Release

https://www.usb.org/document-library/usb-type-cr-cable-and-connector-specification-release-21

 

以上就是USB针对不同外部接口所面临的状况。在extcon驱动出现之前,同一份USB控制器驱动代码,比较常见的做法就是在设备树(dts)中指明是哪种接口,USB控制器驱动代码中会解析设备树中的定义,通过if...else...来走不同的代码逻辑。如果是MicroB接口,就注册VBUS和ID脚的中断、查询IO脚的电平状态;如果是TypeC接口,就注册TypeC的中断,查询TypeC的状态。假设后续又有新的接口出现,工作原理不同于已有的接口,那就又需要在USB控制器驱动中去增加相关代码。

在extcon驱动出现后,USB控制器驱动就能和外部接口驱动解耦。在USB控制器驱动看来,不管外部接口是什么,我只需知道外部接口状态的变化就好了,比如是否接入主机了、是否有设备接入了。使用extcon驱动提供的函数接口来注册notifier,当外部接口状态变化时,extcon驱动负责回调notifier,USB控制器驱动代码无需再针对不同的外部接口改来改去。不同的外部接口,都用extcon来抽象自己的行为。

以上都是原理性的介绍,最后还是要落实到代码上才够清晰。以内核原生代码为例:

drivers\extcon\extcon-usb-gpio.c  //extcon驱动示例drivers\usb\dwc3\dwc3-omap.c  //使用extcon示例

extcon-usb-gpio.c实现了通过IO脚(VBUS和ID)检测USB插拔的extcon驱动。整个驱动是以platform driver为框架。

在驱动的probe函数中,会从设备树获取VBUS和ID脚对应的GPIO。设备树中定义了这个extcon设备的相关属性。

接着会分配并注册一个extcon device。usb_extcon_cable数组定义了这个extcon device所支持的状态类型,EXTCON_USB表示USB做Device,EXTCON_USB_HOST表示USB做Host。状态值当然是插入或者拔出。

最后注册ID脚和VBUS脚的中断,注意这里两个脚的中断处理函数都是usb_irq_handler。两个脚的中断处理函数也不是非要是同一个,这里设置为同一个,是为了逻辑处理上的方便,因为VBUS和ID脚要联合判断。

usb_irq_handler函数里会queue work,这个work对应的处理函数如下图。通过extcon_set_state_sync函数通知其他驱动,只要有驱动注册了相应的notifier,就会被通知到。

以上是extcon-usb-gpio.c的实现,类似地,TypeC驱动也可以注册extcon device,通过extcon_set_state_sync函数向其他驱动汇报状态,这里就不再重复地举例。

最后看看dwc3-omap.c如何使用extcon。该驱动的probe函数中会调用下图函数,该函数首先调用extcon_get_edev_by_phandle从设备树获取extcon device,然后注册notifier,当extcon device状态变化时,notifier被回调;也可以通过extcon_get_state主动查询extcon device的状态。

 

------ END ------

作者:bigfish99

博客:https://www.cnblogs.com/bigfish0506/

公众号:大鱼嵌入式

相关文章: