Linux倾向于将主机端的驱动和外设端的驱动分离,而通过一个核心层将某种总线的协议进行抽象,外设端的驱动调用核心层API间接过渡到对主机驱动传输函数的调用。对于I2C、SPI这类不具备热插拔能力的总线而言,一般在arch/arm/match-xxx或者arch/arm/boot/dts中会有相应的板级描述信息,描述外设与主机的连接状况。
主机侧 | 项目 | I2C | SPI | USB |
描述主机的数据结构 | i2c_adapter | spi_master | usb_hcd | |
主机驱动传输成员函数 | master_xfer() | transfer() | usb_enqueue() | |
核心层 | 主机的枚举方法 | 由I2C控制器挂接的总线决定(一般是platform) | 由SPI控制器挂接的总线决定(一般是platform) | 有USB控制器挂接的总线决定(一般是platform) |
描述传输协议的数据结构 | i2c_msg | spi_message | URB | |
外设端 | 传输API | i2c_transfer() | spi_sync() spi_async() | usb_submit_urb |
外设枚举方法 | i2c_driver | spi_driver | usb_driver | |
描述外设的数据结构 | i2c_client | spi_device | usb_device | |
板级逻辑 | 非设备树模式 | i2c_board_info | spi_board_info | 总线具备热插拔能力 |
设备树模式 | 在I2C控制器节点下添加子节点 | 在SPI控制器节点下添加子节点 | 总线具备热插拔能力 |
我们注意到,I2C、SPI、USB控制器虽然给别人提供了总线,但是其实自己也是由它自身依附的总线枚举出来的。比如,对于SoC而言,这些控制器一般集成在芯片内部,通过内存访问指令来访问的,因此它们自身是通过platform_driver、platform_device这种模型枚举出来的。
I2C控制器所在驱动的platform_driver与platform_device(或者设备树中的节点)通过platform总线的match()函数匹配导致platform_driver.probe()执行,从而完成I2C控制器的注册;而I2C上面挂的触摸屏依附于i2c_driver与i2c_board_info指向的设备通过I2C总线的match()函数匹配导致i2c_driver.probe()执行,从而使触摸屏展开。
原文:https://www.cnblogs.com/lc0811/p/14622080.html