SPI是一种高速、全双工、同步总线。这样就允许单个SPI总线上连接多个SPI从设备。对于SPI总线从设备并没有固化的地址,而是通过CS信号区分不同的设备。另外因为SPI总线频率最高可以达到70MHz,所以需要较大吞吐量的操作方案进行数据传输,通常使用DMA进行操作。总体上来说,系统对于SPI总线驱动的需求就是要能实现总线的各种功能,并且满足类似于I2C总线的各种无关性需求。图7-5SPI总线数据传输信号规范......
2023-11-22
1.总线相关以及核心框架
同I2C总线相同,先来了解SPI总线的实现。在介绍系统初始化的时候,整个SPI的初始化函数spi_init定义为postcore_initcall,这样可保证SPI总线在SPI设备或者驱动注册之前进行注册,从而确保总线的功能。初始化中包含如下语句:
这里注册了总线类型,其中bus_register设置总线自动probe功能。而spi_bus_type作为了解整个总线框架的入口,详细定义如下:
这里重点的接口是match。下面详细分析该接口:
从分析中可见,主要就是进行名字匹配。这里并没有像I2C验证设备类型,这是为什么呢?难道总线控制器不是设备吗?总线控制器还是设备,但是SPI的实现方式不同,在初始化函数spi_init中有如下代码:
这里创建了class功能类,总线控制器作为class设备进行管理,而match只是匹配相同bus的设备,这样总线控制器设备就不会进行match操作了。总线进行匹配的设备是spi_de-vice,这就是总线连接设备的管理实体。
在spi_bus_type中并没有看到probe接口,probe操作是match之后就需要进行的操作,主要有设备特殊资源的探测、申请以及初始化的操作。SPI总线是如何实现该功能的呢?下面来看看对应的spi_driver注册的操作:
这里直接将接口赋值给驱动的接口,在设备模型的统一操作中如果找不到总线相关的接口就会执行driver的接口,这样问题就解决了。与I2C比较又是不同的实现方式。系统提供了统一的框架,具体的实现方法还是仁者见仁的。
SPI总线框架对这两类设备进行管理,具体的框架如图7-6所示。
图7-6 LinuxSPI总线框架
从图7-6中可见,SPI设备主要是为内核中不同的功能模块服务的,当不同功能模块的驱动需要使用SPI设备进行操作时,通常会在具体的管理实体中嵌入spi_device,实际的总线操作通过spi_device来实现。图中右侧可见特殊的spidev,这是对应用开放的接口设备,SPI通过CS信号进行设备管理,而相应的CS排列主要属于板级信息,所以不适合像I2C总线一样将总线控制器对应用开放(应用程序操作设备需要对不同板子进行修改)。将CS信息对应用屏蔽,只开放具体的设备,这就是spidev的作用,应用只是针对具体的设备进行操作,即设备的应用层驱动(驱动在用户态执行),要在应用层使用该功能需要在注册设备时将spi_board_info中的modalias设置为spidev,这样就可以在应用层实现相应设备的驱动。通常的SPI驱动都是在内核实现并在内核态执行的,所以就不对spidev进行详细的分析。
SPI总线框架整体的功能就是这样,接下来看看具体各部分的实现。
2.总线控制器相关
SPI总线框架对总线控制器的管理主要是通过i2c_adapter来实现的,其详细分析如下:
关于setup接口,框架为设备进行操作提供了统一的接口spi_setup,其中会对信号属性、传输字长、总线频率等进行匹配和设置。
这里所有的接口都是与设备总线控制器相关的,通过这些接口设备的总线控制器实现总线操作。
SPI总线框架为总线控制器驱动开发提供了相关的接口,具体如下:
下面详细看看spi_alloc_master的具体实现过程:
这里还为设备分配了所需的空间,设备不需要进行相应的操作,只要通过spi_master_get_devdata来获得相应的指针即可。
spi_register_master注册了总线控制器,就相当于建立了总线,相应的会将总线中的设备创建并注册。这里主要通过如下操作完成相应功能:
这里是实现总线设备发现相关功能,根据板级的信息注册spi_device。
总线的主要功能(包括总线传输事务、总线设备发现)就都在代表SPI总线的SPI总线控制器部分有了完整的支持。(www.chuimin.cn)
3.总线设备相关
对SPI总线设备的管理,SPI总线框架提供了spi_device来完成该功能,详细内容如下:
从相关属性来看,主要是master及其与总线信号相关的属性。下面来看看与之关联driver的详细信息:
从spi_driver的内容分析可见,其主要负责总线相关以及电源管理相关的操作,操作接口中并不涉及实际的信息传输,可以说该驱动同样是处理总线和设备模型相关的事务,并不涉及功能的事务。功能型事务涉及操作的具体内容是在功能型驱动中通过SPI的接口实现的。而功能型的事务需要有总线设备的信息。这就要求功能型驱动管理实体中能够包含spi_device的信息。这个桥梁是与SPI总线事务相关的,所以该工作自然就由spi_driver来实现,具体的接口就是probe,这样各种实体就关联起来。以ads7846_probe接口为例,ads7846是SPI总线接口的触屏控制器,在功能类型中对应于输入设备,相应的spi_driver_的probe接口即ads7846_probe中有如下代码:
从中可见,spi device、触屏设备管理实体以及input device建立了关联,这样从功能型设备到总线设备就形成了一个整体,可以进行完整的操作。只有总线设备与功能管理实体关联后才能完成功能性的工作。
无论spi_device还是spi_driver都属于SPI总线框架管理的运行时实体,而SPI总线设备通常是直接焊接在板子上面,这些固定的信息同样需要进行表示,在创建动态管理的设备实体时需要这些信息。在SPI总线框架中相应的实体是spi_board_info,内容如下:
其中的主要信息是与总线信号相关的属性。
对SPI总线设备的创建,框架提供了相应的函数接口,具体如下:
从中可见,要创建总线设备需要spi_master和spi_board_info,对于特定总线设备有spi_board_info信息,这就需要明确与spi_master关联。
创建总线设备有两种方法:
方法一是通过struct spi_master *spi_busnum_to_master(u16 busnum);来获得指定的spi_master,然后调用spi_new_device来创建总线设备。
方法二是早期的初始化阶段调用spi_register_board_info(struct spi_board_info const *info,unsignedn);函数注册某个SPI总线上的所有设备信息,在总线控制器spi_master会在注册时遍历这些信息为总线上的设备创建spi_device。
方法一主要用于总线设备信息初始化晚于spi_master初始化的情况,如使用SPI总线的V4L2子设备;而方法二则用于较早初始化的情况。
4.总线传输接口
总线传输是完成功能型事务的基础。SPI总线传输是由spi_message和spi_transfer共同进行管理的,下面来看一下详细内容:
可见SPI总线设备的总线传输是以spi_transfer为单位的,可以进行批处理,将一次批处理所有的spi_transfer,并形成链表通过spi_message进行管理。而spi_message中会与具体的spi_device关联,这样某个SPI总线设备的总线传输需要的所有信息就可以通过spi_message进行管理。
通常设备进行SPI传输的操作流程如下:
功能型驱动可以根据自身的需要设置spi_transfer,读写操作信息都设置在一起,然后通过spi_message_add_tail加入spi_message链表中;在spi_message准备好之后,就可以通过spi_sync进行实际的传输操作。具体如下:
这样设备就同步等待操作完成,具体的实现是通过__spi_sync来完成的,细节如下:
可见主要操作是由总线控制器驱动完成的,而在总线框架层则是等待completion同步操作完成后返回,这样就可保证整个传输的操作是以同步方式实现的。
有关深入剖析Linux内核与设备驱动的文章
SPI是一种高速、全双工、同步总线。这样就允许单个SPI总线上连接多个SPI从设备。对于SPI总线从设备并没有固化的地址,而是通过CS信号区分不同的设备。另外因为SPI总线频率最高可以达到70MHz,所以需要较大吞吐量的操作方案进行数据传输,通常使用DMA进行操作。总体上来说,系统对于SPI总线驱动的需求就是要能实现总线的各种功能,并且满足类似于I2C总线的各种无关性需求。图7-5SPI总线数据传输信号规范......
2023-11-22
USB的设计为非对称式的,它是主从式总线,任何USB事务都是由主机引发的。USB总线拓扑如图7-12所示。图7-12引自《USB2.0规范》。USB总线已经成为使用最广泛的设备连接标准。每个USB设备至少有两个端点/管道,分别是进和出两个方向,编号为0,用于控制总线上的设备。总体上来说,系统对USB总线驱动的需求就是要能按规范实现总线的各种功能,并且满足总线的各种无关性的需求。......
2023-11-22
也正是因为Linux内核的唯一性,各个不同发布版本拥有相同的框架。Linux内核是在整个Linux系统的最底层,它负责管理硬件,运行用户程序,并保持系统整体的安全性和完整性。可以说是Linux系统的根和灵魂。图3-1中看到Linux内核还有另一层面的含义。这对于Linux内核同样适用。所以对Linux内核的剖析、学习和研究也不能独立于系统进行,而是要综合考虑应用、内核和硬件等各方面的信息和内容。这样才能更全面、深刻地理解Linux内核。......
2023-11-22
VFS的实现是以“一切皆是文件”为需求出发点的。要理解VFS的框架首先看一下VFS和系统的静态关系框图,如图5-1所示。从图5-1可见,VFS是用户层的直接接口,是面向用户的服务。图5-1VFS和系统静态关系图在图5-2中每个节点被使用时都会在VFS层中创建dentry,这样可以快速通过文件名进行查找和定位,Linux内核中对dentry的管理组织形式如图5-3所示。以上是系统运行时VFS对文件名的组织管理,这是VFS管理的一个方面。......
2023-11-22
整体的frame buffer框架如图6-5所示。了解frame buffer的框架还要先从为用户提供的接口开始。图6-7可变参数中硬件信息的含义固定信息是在frame buffer的操作过程中并不发生变化的。从整体分析,frame buffer的框架很直接,主要就是直接管理实际的设备,而相关的操作与应用层直接相关。......
2023-11-22
DM 3730的I2C控制器框架如图7-4所示。图7-4引自《DM 3730芯片手册》中第2798页的框图。关于DM 3730I2C的驱动部分,主要分析相关初始化和总线传输的操作。由于I2C作为控制和获取状态信息,数据量并不大,而且相关的操作频率并不高,这样在中断中进行相关的处理,对系统的影响并不大。......
2023-11-22
考虑到电源管理的需求涉及处理器和各种设备,一方面是处理器尽可能减少功耗,另一方面是设备尽可能减少功耗。图5-30Linux电源管理各个功能从图5-30可见Linux内核的电源管理功能有与处理器相关的CPUIdle和CPUFreq,也有与设备相关的runtime pm,另外还有与整个系统待机时SLM相关的低功耗电源管理功能。下面分别对这些功能框架进行介绍。具体的驱动同样会在SoC电源管理部分进行讲解。对具体设备的电源管理实现,将在设备驱动中进行详细分析。......
2023-11-22
相关推荐