Linux内核SPI子系统驱动架构以及其数据传输
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
device{} *parent *p *bus *driver ……
device_driver{} *name *p *bus ……
spi设备模型总图
spi_master_class ……
device_private{} knode_bus ……
driver_private{} knode_bus ……
3
spi 重要的数据结构
struct spi_board_info {//该结构主要用来匹配 spi master 和初始化 spi_device
char
modalias[SPI_NAME_SIZE];
const void *platform_data;
void
*controller_data;
int
图示如下:
spi_board_info{} char modalias[MAX] ... ...
... ...
spi_board_info{} char modalias[MAX] ... ...
spi_board_info{}[] spi_board_info[0] ... ... spi_board_info[n-1]
spi_master{}.mode_bits 会和它适配(见 spi_setup())。
bus_num 用于和 spi _master{}.bus_num 适配(见 scan_boardinfo()),硬件上该设备会连接到系统的某个 spi master 上
chip_select spi_new_device()中将初始化 spi_device{}.chip_select,表示该 spi 设备在硬件上是连接到 spi 控制器的第几个片
开发人员定义
注1:platform_device{}是spi_master{}控制器的平台设备资源数据结构; 注2:spi_device{}.modalias由spi_board_info{}.modalias获得;
spi_driver{}.device_driver{}.name和spi_driver{}.id_table[].name由驱动直接指定;需注意的是,spi_device{}.modalias 优先与 spi_driver{}.id_table[].name匹配,当驱动中spi_driver{}.id_table为空时,spi_device{}.modalias将与spi_driver{} .device_driver{}.name匹配;
#define SPI_NO_CS 0x40
wk.baidu.com
/* 1 dev/bus, no chipselect */只有单个从设备
#define SPI_READY 0x80
/* slave pulls low to pause */
4
SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置, 时钟极性(CPOL)对传输协议没有重大的影响。
irq;
u32
max_speed_hz;
u16
bus_num;
u16
chip_select;
u8
mode;
};
成员变量解说:
modalias spi_new_device()中将初始化 spi_device{}.modalias, 用来和 spi_driver{}.driver->name 等进行匹配;
boardinfo{} list n_board_info board_info[0] ... ... board_info[n_board_info - 1]
注
board_list
boardinfo{} list
... ...
... ...
注:一般 spi_board_info{}[]实际长度为 1,即一个数组元素 spi_board_info{}[0],图中只是形式上描绘一个数组; 通过 spi_register_board_ino(struct spi_board_info const *info, unsigned n); n (n 一般为 1)用来初始化 n_board_info,表
注2: 显然板卡注册需先于控制器注册,这里稍稍提醒;
2
spi_master{} dev ……
spi_device{} *master dev modalias ……
spi_diver{} .driver *id_table *probe ……
mcu_probe()
device{} *parent *class ……
关于 mode 传输模式:
spi_board_info{}.mode 定义
#define SPI_CPHA 0x01
/* clock phase */时钟相位
#define SPI_CPOL 0x02
/* clock polarity */时钟极性
#define SPI_MODE_0 (0|0)
/* (original MicroWire) */四种传输模式
SCL KMOSI MISO SS1 SS2
… … (片选信号可以有多个)
Slave1
……
Slave2
SPI Master2
……
SCL KMOSI MISO SS1 SS2
……
数据结构:
1
platform_driver{}.probe()
spi_device{}的构造及其关系
板卡注册
开发人员定义
#define SPI_LSB_FIRST 0x08
/* per-word bits-on-wire */先输出低比特位
#define SPI_3WIRE 0x10
/* SI/SO signals shared */输入输出共享接口,此时只能够半双工
#define SPI_LOOP 0x20
/* loopback mode */回写/回显模式
注1 device{} ……
platform_device{}
dev ……
spi_match_device()
spi_bus_type{} .match *p ……
bus_type_private{} *devices_kset *drivers_kset ……
x0 … xi … xn 数组
spi_device_id{} char name[32] 注2 driver_data
spi_master_class ……
boardinfo{} board_info[0] list …… 注1
spi_register_board_info()
spi_board_info{}
复制一份
spi_board_info{}
注2
bus_num chip_select max_speed_hz modalias *controller_data *platform_data ……
mxc_spi{} mxc_bitbang …… spi_bitbang{} *master ……
platform_device{} id dev ……
device{} ……
构建
spi_register_master()
spi_master{} bus_num dev ……
device{} *parent *class ……
platform_data spi_new_device()中将初始化 spi_device{}.dev.platform_data,存储驱动的特定数据
controller_data spi_new_device()中将初始化 spi_device{}.controller_data,有些控制器需要有关硬件设置的数据,如 DMA 等
irq
spi_new_device()中将初始化 spi_device{}.irq,由硬件原理图连线确定
max_speed_hz,最大的传输速率,取决于 spi 设备芯片的 datasheet 以及 spi master
mode 模 式 信 息 , 取 决 于 使 用 哪 种 传 输 模 式 , 控 制 器 是 否 三 线 连 线 模 式 , 片 选 信 号 激 活 时 候 电 平 高 低 等 ,
n_board_info;
struct spi_board_info board_info[0];
};
成员变量解说: list 链表,连接到一个名叫 board_list 的链表 n_board_info 有几个 spi_board_info 结构。spi_register_board_ino(struct spi_board_info const *info, unsigned n)
最终生成
注1: spi_register_master()执行到完成spi_master{}注册后,会调用scan_boardinfo(),查询匹配board_list链表上的外设数据结构;当确认某外 设使用当前被注册的控制器(即spi_master{}.bus_num==spi_board_info{}.bus_num成立)后,将调用 spi_new_device() ,构造该外设对 应的spi_device{}并注册;
#define SPI_MODE_1 (0|SPI_CPHA)
#define SPI_MODE_2 (SPI_CPOL|0)
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH 0x04
/* chipselect active high? */片选电位为高
函数中的 n 用来初始化该成员 board_info 根据 n_board_info 的数目,组成一个 spi_board_info[].
spi_board_info{}与 boardinfo{}的关系: spi_board_info{}:每个 spi_board_info{}代表一个设备,spi_board_info 以数组的形式组织 boardinfo{} : boardinfo{} 会 将 spi_board_info{}[] 的 内 容 拷 贝 过 来 填 充 其 board_info[] 结 构 , 相 关 函 数 为 spi_register_board_ino(struct spi_board_info const *info, unsigned n),其中 n 代表有多少个 spi_board_info{}这 样的数组元素。一个 board_info{}对应一个 spi_board_info{}数组(即 1 个以上的 spi_board_info{},但实际上 spi_board_info{}数组元素一般只定义一个,以对应 board_list 上的一个节点仅表示一个设备的逻辑关系), 每个 boardinfo{}都会连接到一个全局 board_list 链表。
选脚。起始为 0,不能大过 spi_master{}.num_chipselect(由硬件决定,即 spi 控制器的 SS 片选管脚的个数)
platform_data 和 controller_data 区别:platform_data 存储驱动需要的额外内容(非标准定制,视需要定义具体内容), controller_data 则是存储的与 spi 控制器相关的内容(非标准定制,视需要定义)
SPI 子系统驱动架构以及其数据传输
2013 年 1 月 24 日 linux 2.6.35
目标:
分析整理 SPI 子系统初始化驱动架构;
本文要点:
1、spi 重要数据结构及关系图; 2、spi 子系统初始化驱动架构; 3、spi 数据的传输;
硬件框图:
Slave1
Slave2
……
SPI Master1
如果 CPOL=0,串行同步时钟的空闲状态为低电平;如果 CPOL=1,串行同步时钟的空闲状态为高电 平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果 CPHA=0,在串 行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果 CPHA=1,在串行同步时钟的第二个跳变沿 (上升或下降)数据被采样。
SPI 主模块和与之通信的外设备时钟相位和极性应该一致。
spi 的四种传输模式
LSB(Least Significant Bit),意为最低有效位;MSB(Most Significant Bit),意为最高有效位
5
struct boardinfo {
struct list_head list;
unsigned
board_list
开发人员自己使用
spi_new_device()构造、并注册 spi_device{}
device{} *parent ……
*master chip_select max_speed_hz modalias *controller_data *platform_data dev ……
device_driver{} *name *p *bus ……
spi设备模型总图
spi_master_class ……
device_private{} knode_bus ……
driver_private{} knode_bus ……
3
spi 重要的数据结构
struct spi_board_info {//该结构主要用来匹配 spi master 和初始化 spi_device
char
modalias[SPI_NAME_SIZE];
const void *platform_data;
void
*controller_data;
int
图示如下:
spi_board_info{} char modalias[MAX] ... ...
... ...
spi_board_info{} char modalias[MAX] ... ...
spi_board_info{}[] spi_board_info[0] ... ... spi_board_info[n-1]
spi_master{}.mode_bits 会和它适配(见 spi_setup())。
bus_num 用于和 spi _master{}.bus_num 适配(见 scan_boardinfo()),硬件上该设备会连接到系统的某个 spi master 上
chip_select spi_new_device()中将初始化 spi_device{}.chip_select,表示该 spi 设备在硬件上是连接到 spi 控制器的第几个片
开发人员定义
注1:platform_device{}是spi_master{}控制器的平台设备资源数据结构; 注2:spi_device{}.modalias由spi_board_info{}.modalias获得;
spi_driver{}.device_driver{}.name和spi_driver{}.id_table[].name由驱动直接指定;需注意的是,spi_device{}.modalias 优先与 spi_driver{}.id_table[].name匹配,当驱动中spi_driver{}.id_table为空时,spi_device{}.modalias将与spi_driver{} .device_driver{}.name匹配;
#define SPI_NO_CS 0x40
wk.baidu.com
/* 1 dev/bus, no chipselect */只有单个从设备
#define SPI_READY 0x80
/* slave pulls low to pause */
4
SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置, 时钟极性(CPOL)对传输协议没有重大的影响。
irq;
u32
max_speed_hz;
u16
bus_num;
u16
chip_select;
u8
mode;
};
成员变量解说:
modalias spi_new_device()中将初始化 spi_device{}.modalias, 用来和 spi_driver{}.driver->name 等进行匹配;
boardinfo{} list n_board_info board_info[0] ... ... board_info[n_board_info - 1]
注
board_list
boardinfo{} list
... ...
... ...
注:一般 spi_board_info{}[]实际长度为 1,即一个数组元素 spi_board_info{}[0],图中只是形式上描绘一个数组; 通过 spi_register_board_ino(struct spi_board_info const *info, unsigned n); n (n 一般为 1)用来初始化 n_board_info,表
注2: 显然板卡注册需先于控制器注册,这里稍稍提醒;
2
spi_master{} dev ……
spi_device{} *master dev modalias ……
spi_diver{} .driver *id_table *probe ……
mcu_probe()
device{} *parent *class ……
关于 mode 传输模式:
spi_board_info{}.mode 定义
#define SPI_CPHA 0x01
/* clock phase */时钟相位
#define SPI_CPOL 0x02
/* clock polarity */时钟极性
#define SPI_MODE_0 (0|0)
/* (original MicroWire) */四种传输模式
SCL KMOSI MISO SS1 SS2
… … (片选信号可以有多个)
Slave1
……
Slave2
SPI Master2
……
SCL KMOSI MISO SS1 SS2
……
数据结构:
1
platform_driver{}.probe()
spi_device{}的构造及其关系
板卡注册
开发人员定义
#define SPI_LSB_FIRST 0x08
/* per-word bits-on-wire */先输出低比特位
#define SPI_3WIRE 0x10
/* SI/SO signals shared */输入输出共享接口,此时只能够半双工
#define SPI_LOOP 0x20
/* loopback mode */回写/回显模式
注1 device{} ……
platform_device{}
dev ……
spi_match_device()
spi_bus_type{} .match *p ……
bus_type_private{} *devices_kset *drivers_kset ……
x0 … xi … xn 数组
spi_device_id{} char name[32] 注2 driver_data
spi_master_class ……
boardinfo{} board_info[0] list …… 注1
spi_register_board_info()
spi_board_info{}
复制一份
spi_board_info{}
注2
bus_num chip_select max_speed_hz modalias *controller_data *platform_data ……
mxc_spi{} mxc_bitbang …… spi_bitbang{} *master ……
platform_device{} id dev ……
device{} ……
构建
spi_register_master()
spi_master{} bus_num dev ……
device{} *parent *class ……
platform_data spi_new_device()中将初始化 spi_device{}.dev.platform_data,存储驱动的特定数据
controller_data spi_new_device()中将初始化 spi_device{}.controller_data,有些控制器需要有关硬件设置的数据,如 DMA 等
irq
spi_new_device()中将初始化 spi_device{}.irq,由硬件原理图连线确定
max_speed_hz,最大的传输速率,取决于 spi 设备芯片的 datasheet 以及 spi master
mode 模 式 信 息 , 取 决 于 使 用 哪 种 传 输 模 式 , 控 制 器 是 否 三 线 连 线 模 式 , 片 选 信 号 激 活 时 候 电 平 高 低 等 ,
n_board_info;
struct spi_board_info board_info[0];
};
成员变量解说: list 链表,连接到一个名叫 board_list 的链表 n_board_info 有几个 spi_board_info 结构。spi_register_board_ino(struct spi_board_info const *info, unsigned n)
最终生成
注1: spi_register_master()执行到完成spi_master{}注册后,会调用scan_boardinfo(),查询匹配board_list链表上的外设数据结构;当确认某外 设使用当前被注册的控制器(即spi_master{}.bus_num==spi_board_info{}.bus_num成立)后,将调用 spi_new_device() ,构造该外设对 应的spi_device{}并注册;
#define SPI_MODE_1 (0|SPI_CPHA)
#define SPI_MODE_2 (SPI_CPOL|0)
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH 0x04
/* chipselect active high? */片选电位为高
函数中的 n 用来初始化该成员 board_info 根据 n_board_info 的数目,组成一个 spi_board_info[].
spi_board_info{}与 boardinfo{}的关系: spi_board_info{}:每个 spi_board_info{}代表一个设备,spi_board_info 以数组的形式组织 boardinfo{} : boardinfo{} 会 将 spi_board_info{}[] 的 内 容 拷 贝 过 来 填 充 其 board_info[] 结 构 , 相 关 函 数 为 spi_register_board_ino(struct spi_board_info const *info, unsigned n),其中 n 代表有多少个 spi_board_info{}这 样的数组元素。一个 board_info{}对应一个 spi_board_info{}数组(即 1 个以上的 spi_board_info{},但实际上 spi_board_info{}数组元素一般只定义一个,以对应 board_list 上的一个节点仅表示一个设备的逻辑关系), 每个 boardinfo{}都会连接到一个全局 board_list 链表。
选脚。起始为 0,不能大过 spi_master{}.num_chipselect(由硬件决定,即 spi 控制器的 SS 片选管脚的个数)
platform_data 和 controller_data 区别:platform_data 存储驱动需要的额外内容(非标准定制,视需要定义具体内容), controller_data 则是存储的与 spi 控制器相关的内容(非标准定制,视需要定义)
SPI 子系统驱动架构以及其数据传输
2013 年 1 月 24 日 linux 2.6.35
目标:
分析整理 SPI 子系统初始化驱动架构;
本文要点:
1、spi 重要数据结构及关系图; 2、spi 子系统初始化驱动架构; 3、spi 数据的传输;
硬件框图:
Slave1
Slave2
……
SPI Master1
如果 CPOL=0,串行同步时钟的空闲状态为低电平;如果 CPOL=1,串行同步时钟的空闲状态为高电 平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果 CPHA=0,在串 行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果 CPHA=1,在串行同步时钟的第二个跳变沿 (上升或下降)数据被采样。
SPI 主模块和与之通信的外设备时钟相位和极性应该一致。
spi 的四种传输模式
LSB(Least Significant Bit),意为最低有效位;MSB(Most Significant Bit),意为最高有效位
5
struct boardinfo {
struct list_head list;
unsigned
board_list
开发人员自己使用
spi_new_device()构造、并注册 spi_device{}
device{} *parent ……
*master chip_select max_speed_hz modalias *controller_data *platform_data dev ……