SPI子系统分析之二:数据结构【转】
转自:http://www.cnblogs.com/jason-lu/articles/3164901.html
内核版本:3.9.5
spi_master
struct spi_master用来描述一个SPI主控制器,我们一般不需要自己编写spi控制器驱动.
1 /*结构体master代表一个SPI接口,或者叫一个SPI主机控制器,一个接口对应一条SPI总线,master->bus_num则记录了这个总线号*/
2 struct spi_master {
3 struct device dev;
4
5 struct list_head list;
6
7 /* other than negative (== assign one dynamically), bus_num is fully
8 * board-specific. usually that simplifies to being SOC-specific.
9 * example: one SOC has three SPI controllers, numbered 0..2,
10 * and one board's schematics might show it using SPI-2. software
11 * would normally use bus_num=2 for that controller.
12 */
13 s16 bus_num;/*总线编号,从零开始.系统会用这个值去和系统中board_list链表中加入的每一个boardinfo结构
14 (每个boardinfo结构都是一个spi_board_info的集合,每一个spi_board_info都是对应一个SPI(从)设备的描述)中的每一个
15 spi_board_info中的bus_num进行匹配,如果匹配上就说明这个spi_board_info描述的SPI(从)设备是链接在此总线上的,因
16 此就会调用spi_new_device去创建一个spi_device*/
17
18 /* chipselects will be integral to many controllers; some others
19 * might use board-specific GPIOs.
20 */
21 u16 num_chipselect;//支持的片选的数量.从设备的片选号不能大于这个数.该值当然不能为0,否则会注册失败
22
23 /* some SPI controllers pose alignment requirements on DMAable
24 * buffers; let protocol drivers know about these requirements.
25 */
26 u16 dma_alignment;
27
28 /* spi_device.mode flags understood by this controller driver */
29 u16 mode_bits;
30
31 /* other constraints relevant to this driver */
32 u16 flags;
33 #define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */
34 #define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */
35 #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */
36
37 /* lock and mutex for SPI bus locking */
38 spinlock_t bus_lock_spinlock;
39 struct mutex bus_lock_mutex;
40
41 /* flag indicating that the SPI bus is locked for exclusive use */
42 bool bus_lock_flag;
43
44 /* Setup mode and clock, etc (spi driver may call many times).
45 *
46 * IMPORTANT: this may be called when transfers to another
47 * device are active. DO NOT UPDATE SHARED REGISTERS in ways
48 * which could break those transfers.
49 */
50 int (*setup)(struct spi_device *spi);//根据spi设备更新硬件配置
51
52 /* bidirectional bulk transfers
53 *
54 * + The transfer() method may not sleep; its main role is
55 * just to add the message to the queue.
56 * + For now there's no remove-from-queue operation, or
57 * any other request management
58 * + To a given spi_device, message queueing is pure fifo
59 *
60 * + The master's main job is to process its message queue,
61 * selecting a chip then transferring data
62 * + If there are multiple spi_device children, the i/o queue
63 * arbitration algorithm is unspecified (round robin, fifo,
64 * priority, reservations, preemption, etc)
65 *
66 * + Chipselect stays active during the entire message
67 * (unless modified by spi_transfer.cs_change != 0).
68 * + The message transfers use clock and SPI mode parameters
69 * previously established by setup() for this device
70 */
71 int (*transfer)(struct spi_device *spi,
72 struct spi_message *mesg);/*添加消息到队列的方法.此函数不可睡眠,其作用只是安排需要的传送,并且在适当的时候(传\
73 送完成或者失败)调用spi_message中的complete方法,来将结果报告给用户*/
74
75 /* called on release() to free memory provided by spi_master */
76 void (*cleanup)(struct spi_device *spi);/*cleanup函数会在spidev_release函数中被调用,spidev_release被登记为spi dev的release
77 函数*/
78
79 /*
80 * These hooks are for drivers that want to use the generic
81 * master transfer queueing mechanism. If these are used, the
82 * transfer() function above must NOT be specified by the driver.
83 * Over time we expect SPI drivers to be phased over to this API.
84 */
85 bool queued;
86 struct kthread_worker kworker;
87 struct task_struct *kworker_task;
88 struct kthread_work pump_messages;
89 spinlock_t queue_lock;
90 struct list_head queue;
91 struct spi_message *cur_msg;
92 bool busy;
93 bool running;
94 bool rt;
95
96 int (*prepare_transfer_hardware)(struct spi_master *master);
97 int (*transfer_one_message)(struct spi_master *master,
98 struct spi_message *mesg);
99 int (*unprepare_transfer_hardware)(struct spi_master *master);
100 /* gpio chip select */
101 int *cs_gpios;
102 };
spi控制器的驱动一般在arch/.../mach-*/board-*.c声明,注册一个平台设备,然后在driver/spi下面建立一个平台驱动.spi_master注册过程中会扫描arch/.../mach-*/board-*.c 中调用spi_register_board_info注册的信息,为每一个与本总线编号相同的信息建立一个spi_device.根据Linux内核的驱动模型,注册在同一总线下的驱动和设备会进行匹配.spi_bus_type总线匹配的依据是名字.这样当自己编写的spi_driver和spi_device同名的时候,spi_driver的probe方法就会被调用.spi_driver就能看到与自己匹配的spi_device了.
spi_device
struct spi_device用来描述一个SPI从设备.
1 /*该结构用于描述SPI设备,也就是从设备的相关信息.
2 NOTE:SPI子系统只支持主模式,也就是说SOC上的SPI只能工作在master模式,外围设备只能为slave模式*/
3 struct spi_device {
4 struct device dev;
5 struct spi_master *master;//对应的控制器指针
6 u32 max_speed_hz;//spi传输时钟
7 u8 chip_select;//片选号,用来区分同一主控制器上的设备
8 u8 mode;//各bit的定义如下,主要是传输模式/片选极性
9 #define SPI_CPHA 0x01 /* clock phase */
10 #define SPI_CPOL 0x02 /* clock polarity */
11 #define SPI_MODE_0 (0|0) /* (original MicroWire) */
12 #define SPI_MODE_1 (0|SPI_CPHA)
13 #define SPI_MODE_2 (SPI_CPOL|0)
14 #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
15 #define SPI_CS_HIGH 0x04 /* chipselect active high? *//*片选电位为高*/
16 #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire *//*先输出低比特*/
17 #define SPI_3WIRE 0x10 /* SI/SO signals shared *//*输入输出共享接口,此时只能做半双工*/
18 #define SPI_LOOP 0x20 /* loopback mode *//*回写/回显模式*/
19 #define SPI_NO_CS 0x40 /* 1 dev/bus, no chipselect */
20 #define SPI_READY 0x80 /* slave pulls low to pause */
21 u8 bits_per_word;/*每个字长的比特数*/
22 int irq;/*使用到的中断号*/
23 void *controller_state;
24 void *controller_data;
25 char modalias[SPI_NAME_SIZE];/*spi设备的名字*/
26 int cs_gpio; /* chip select gpio */
27
28 /*
29 * likely need more hooks for more protocol options affecting how
30 * the controller talks to each chip, like:
31 * - memory packing (12 bit samples into low bits, others zeroed)
32 * - priority
33 * - drop chipselect after each word
34 * - chipselect delays
35 * - ...
36 */
37 };
spi_driver
struct spi_driver用于描述SPI(从)设备驱动.驱动核心将根据driver.name和spi_board_info的modalias进行匹配,如过modalia和name相等,则绑定驱动程序和arch/.../mach-xxx/board-xxx.c中调用spi_register_board_info注册的信息对应的spi_device设备.它的形式和struct platform_driver是一致的.
1 struct spi_driver {
2 const struct spi_device_id *id_table;
3 int (*probe)(struct spi_device *spi);/*和spi_device匹配成功之后会调用这个方法.因此这个方法需要对设备和私有数据进行初始化*/
4 int (*remove)(struct spi_device *spi);/*解除spi_device和spi_driver的绑定,释放probe申请的资源*/
5 void (*shutdown)(struct spi_device *spi);/*一般牵扯到电源管理会用到,关闭*/
6 int (*suspend)(struct spi_device *spi, pm_message_t mesg);/*一般牵扯到电源管理会用到,挂起*/
7 int (*resume)(struct spi_device *spi);/*一般牵扯到电源管理会用到,恢复*/
8 struct device_driver driver;
9 };
spi_board_info
struct spi_board_info是板级信息,是在移植时就写好的,并且要将其注册.
1 /*该结构也是对SPI(从)设备(spi_device)的描述,只不过它是板级信息,最终该结构的所有字段都将用于初始化SPI设备结构体spi_device*/
2 struct spi_board_info {
3 /* the device name and module name are coupled, like platform_bus;
4 * "modalias" is normally the driver name.
5 *
6 * platform_data goes to spi_device.dev.platform_data,
7 * controller_data goes to spi_device.controller_data,
8 * irq is copied too
9 */
10 char modalias[SPI_NAME_SIZE];/*spi设备名,会拷贝到spi_device的相应字段中.这是设备spi_device在SPI总线spi_bus_type上匹配驱动的唯一标识*/
11 const void *platform_data;/*平台数据*/
12 void *controller_data;
13 int irq;/*中断号*/
14
15 /* slower signaling on noisy or low voltage boards */
16 u32 max_speed_hz;/*SPI设备工作时的波特率*/
17
18
19 /* bus_num is board specific and matches the bus_num of some
20 * spi_master that will probably be registered later.
21 *
22 * chip_select reflects how this chip is wired to that master;
23 * it's less than num_chipselect.
24 */
25 u16 bus_num;/*该SPI(从)设备所在总线的总线号,就记录了所属的spi_master之中的bus_num编号.一个spi_master就对应一条总线*/
26 u16 chip_select;/*片选号.该SPI(从)设备在该条SPI总线上的设备号的唯一标识*/
27
28 /* mode becomes spi_device.mode, and is essential for chips
29 * where the default of SPI_CS_HIGH = 0 is wrong.
30 */
31 u8 mode;/*参考spi_device中的成员*/
32
33 /* ... may need additional spi_device chip config data here.
34 * avoid stuff protocol drivers can set; but include stuff
35 * needed to behave without being bound to a driver:
36 * - quirks like clock rate mattering when not selected
37 */
38 };
spi_transfer
struct spi_transfer是对一次完整的数据传输的描述.每个spi_transfer总是读取和写入同样长度的比特数,但是可以很容易的使用空指针舍弃读或写.为spi_transfer和spi_message分配的内存应该在消息处理期间保证是完整的.
1 struct spi_transfer {
2 /* it's ok if tx_buf == rx_buf (right?)
3 * for MicroWire, one buffer must be null
4 * buffers must work with dma_*map_single() calls, unless
5 * spi_message.is_dma_mapped reports a pre-existing mapping
6 */
7 const void *tx_buf;/*发送缓冲区地址,这里存放要写入设备的数据(必须是dma_safe),或者为NULL*/
8 void *rx_buf;/*接收缓冲区地址,从设备中读取的数据(必须是dma_safe)就放在这里,或者为NULL*/
9 unsigned len;/*传输数据的长度.记录了tx和rx的大小(字节数),这里不是指它的和,而是各自的长度,他们总是相等的*/
10
11 dma_addr_t tx_dma;/*如果spi_message.is_dma_mapped是真,这个是tx的dma地址*/
12 dma_addr_t rx_dma;/*如果spi_message.is_dma_mapped是真,这个是rx的dma地址*/
13
14 unsigned cs_change:1;/*影响此次传输之后的片选.指示本次transfer结束之后是否要重新片选并调用setup改变设置.若为1则表示当该transfer
15 传输完后,改变片选信号.这个标志可以减少系统开销*/
16 u8 bits_per_word;/*每个字长的比特数.如果是0,使用默认值*/
17 u16 delay_usecs;/*此次传输结束和片选改变之间的延时,之后就会启动另一个传输或者结束整个消息*/
18 u32 speed_hz;/*通信时钟.如果是0,使用默认值*/
19
20 struct list_head transfer_list;/*用来连接的双向链表节点,用于将该transfer链入message*/
21 };
再说一下:cs_change影响此transfer完成后是否禁用片选线并调用setup改变配置.(这个标志量就是chip select change片选改变的意思).没有特殊情况,一个spi_message因该只在最后一个transfer置位该标志量.
spi_message
struct spi_message就是对多个spi_transfer的封装.spi_message用来原子的执行spi_transfer表示的一串数组传输请求.这个传输队列是原子的,这意味着在这个消息完成之前不会有其它消息占用总线.消息的执行总是按照FIFO的顺序.向底层提交spi_message的代码要负责管理它的内存空间.未显示初始化的内存需要使用0来初始化.为spi_transfer和spi_message分配的内存应该在消息处理期间保证是完整的.
1 struct spi_message {
2 struct list_head transfers;/*此次消息的传输段(spi_transfer)队列,一个消息可以包含多个传输段(spi_transfer)*/
3
4 struct spi_device *spi;/*传输的目的设备,无论如何这里都是spi从设备,至于数据流向(是从主机到从设备还是从从设备到主机)这是由write/read
5 每个传输段(spi_transfer)内部的tx_buf或者是rx_buf决定的*/
6
7 unsigned is_dma_mapped:1;/*如果为真,此次调用提供dma和cpu虚拟地址.spi主机提供了dma缓存池.如果此消息确定要使用dma(那当然更好
8 了).则从那个缓存池中申请高速缓存.替代传输段(spi_transfer)中的tx_buf/rx_buf*/
9
10 /* REVISIT: we might want a flag affecting the behavior of the
11 * last transfer ... allowing things like "read 16 bit length L"
12 * immediately followed by "read L bytes". Basically imposing
13 * a specific message scheduling algorithm.
14 *
15 * Some controller drivers (message-at-a-time queue processing)
16 * could provide that as their default scheduling algorithm. But
17 * others (with multi-message pipelines) could need a flag to
18 * tell them about such special cases.
19 */
20
21 /* completion is reported through a callback */
22 void (*complete)(void *context);/*用于异步传输完成时调用的回调函数*/
23 void *context;/*回调函数的参数*/
24 unsigned actual_length;/*此次传输的实际长度,这个长度包括了此消息spi_message中所有传输段spi_transfer传输的长度之和(不管每个传
25 输段spi_transfer到底是输入还是输出,因为本来具体的传输就是针对每一个传输段spi_transfer来进行的)*/
26 int status;/*执行的结果.成功被置0,否则是一个负的错误码*/
27
28 /* for optional use by whatever driver currently owns the
29 * spi_message ... between calls to spi_async and then later
30 * complete(), that's the spi_master controller driver.
31 */
32 /*下面两个成员是给拥有本消息的驱动选用的.spi_master会使用它们.自己最好不要使用*/
33 struct list_head queue;/*用于将该message链入bitbang等待队列*/
34 void *state;
35 };
spi_bitbang
struct spi_bitbang结构用于控制实际的数据传输.
1 struct spi_bitbang {
2 struct workqueue_struct *workqueue;/*工作队列*/
3 struct work_struct work;
4
5 spinlock_t lock;
6 struct list_head queue;
7 u8 busy;
8 u8 use_dma;
9 u8 flags; /* extra spi->mode support */
10
11 struct spi_master *master;/*bitbang所属的master*/
12
13 /* setup_transfer() changes clock and/or wordsize to match settings
14 * for this transfer; zeroes restore defaults from spi_device.
15 */
16 int (*setup_transfer)(struct spi_device *spi,
17 struct spi_transfer *t);/*用于设置设备传输时的时钟,字长等*/
18
19 void (*chipselect)(struct spi_device *spi, int is_on);
20 #define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */
21 #define BITBANG_CS_INACTIVE 0
22
23 /* txrx_bufs() may handle dma mapping for transfers that don't
24 * already have one (transfer.{tx,rx}_dma is zero), or use PIO
25 */
26 int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);
27
28 /* txrx_word[SPI_MODE_*]() just looks like a shift register */
29 u32 (*txrx_word[4])(struct spi_device *spi,
30 unsigned nsecs,
31 u32 word, u8 bits);
32 };
本文引用:http://blog.csdn.net/yuanlulu/article/details/6318165
SPI子系统分析之二:数据结构【转】的更多相关文章
- SPI子系统分析之二:数据结构
内核版本:3.9.5 spi_master struct spi_master用来描述一个SPI主控制器,我们一般不需要自己编写spi控制器驱动. /*结构体master代表一个SPI接口,或者叫一个 ...
- input子系统分析之二:数据结构
内核版本:3.9.5 1. input_dev,用来标识输入设备 struct input_dev { const char *name; const char *phys; const char * ...
- SPI子系统分析之一:框架
内核版本:3.9.5 SPI子系统概述: 一个SPI主控制器对应一条SPI总线,当然在系统中有唯一的总线编号. SPI总线上有两类设备: 其一是主控端,通常作为SOC系统的一个子模块出现,很多嵌入式M ...
- SPI子系统分析之四:驱动模块
内核版本:3.9.5 SPI控制器层(平台相关) 上一节讲了SPI核心层的注册和匹配函数,它是平台无关的.正是在核心层抽象了SPI控制器层的相同部分然后提供了统一的API给SPI设备层来使用.我们这一 ...
- SPI子系统分析之三:驱动模块
内核版本:3.9.5 SPI核心层(平台无关) SPI子系统初始化的第一步就是将SPI总线注册进内核,并且在/sys下创建一个spi_master的类,以后注册的从设备都将挂接在该总线下. 下列函数位 ...
- Linux spi驱动分析(二)----SPI核心(bus、device_driver和device)
一.spi总线注册 这里所说的SPI核心,就是指/drivers/spi/目录下spi.c文件中提供给其他文件的函数,首先看下spi核心的初始化函数spi_init(void).程序如下: 点击(此处 ...
- Linux input子系统分析
输入输出是用户和产品交互的手段,因此输入驱动开发在Linux驱动开发中很常见.同时,input子系统的分层架构思想在Linux驱动设计中极具代表性和先进性,因此对Linux input子系统进行深入分 ...
- Linux kernel的中断子系统之(二):IRQ Domain介绍
返回目录:<ARM-Linux中断系统>. 总结:一.二概述了软硬件不同角度的IRQ Number和HW Interrupt ID,这就需要他们之间架个桥梁. 三介绍了架设这种桥梁的几种方 ...
- SPI子系统
一.SPI子系统模型 三个组成部分: SPI核心:连通了SPI客户驱动.SPI主控制器驱动 SPI控制器驱动:驱动芯片中的SPI控制器 SPI的FLASH(客户驱动) 二.SPI控制器驱动分析 sta ...
随机推荐
- python 查看与更换工作目录
1. 进入python控制台 2. 查看工作路径,需要导入os包: import os 3. 查看工作路径的命令: os.getcwd() 4. 修改工作路径的命令: os.chdir("d ...
- 题解 P2026 【求一次函数解析式】
高中方式轻松解决这个模拟题. 首先我们了解斜率的简单求法: \[k= {y2-y1 \over x2-x1}{=}{\Delta y \over \Delta x}\] 然后我们了解到让我们求解一次函 ...
- P3119 [USACO15JAN]草鉴定Grass Cownoisseur
题目描述 In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-w ...
- Tomcat8.0配置JNDI多数据源
jndi配置 :此种配置需要在Tomcat的server.xml中和context.xml中配置数据源,在项目中引用. 需要在tomcat下加入数据库连接的jar包,相关包(ojdbc14;c3p0数 ...
- PKUWC Slay The Spire
题面链接 LOJ sol 好神啊.果然\(dp\)还是做少了,纪录一下现在的思维吧\(QAQ\). 我们首先可以发现期望是骗人的,要不然他乘的是什么xjb玩意. 其实就是要求所有方案的最优方案和. 因 ...
- python入门:1-100所有数的和
#!/usr/bin/env python # -*- coding:utf-8 -*- #1-100所有数的和 """ 给x赋值为1,y赋值为0,while循环真,循环 ...
- gdb调试3_显示变量 和 数组
http://www.cnblogs.com/shipfi/archive/2008/08/04/1260293.html 感谢作者! 程序变量查看文件中某变量的值:file::variablefu ...
- sqlalchemy常用语法
一.新增数据 # 新增一条数据 user_obj = User(name="bigberg", passwd="twgdh123") Session.add(u ...
- python map对象
工作中遇到需要将List对象中的元素(list类型)转化为集合(set)类型,转化完成之后需要需要访问其中的元素. 第一步,使用map方法进行转换 data = [[1, 3, 4], [2, 3, ...
- css实现0.5像素的边框
公司的设计师在做设计图的时候都是以iphone6(宽为750物理像素)为基准进行设计的.iphone6的设备像素比(即css像素与物理像素的比例)是2,所以设计师在设计图画了边框为1px的box的时候 ...