说明:
spi,i2c,usb等总线,在cpu上均有相应的控制器,与之对应的数据结构是spi_master,i2c_adapter等.主机控制器和外设分离,外设用于
驱动不同的芯片,通过这样设计避免了外设驱动与控制器关联.
spi驱动包括spi核心(/drivers/spi/spi.c),主要包括主机控制器,外设的注册,注销
driver和device的关系:driver用于将外设挂载到总线上,device描述设备的特性,与platform_device使用board_info来描述device类似,
spi使用spi_board_info来描述spi_device.通过spi_driver将spi外设挂载到spi总线,在driver的probe函数中,注册spi所属本身设备驱动.
变量:
spi_master{//用于描述spi主机控制器
struct device dev;
bus_num
num_chipselect
(setup)(struct spi_device)
(transfer)(spi_device dev,spi_message *msg);
(*cleanup)(spi_device *dev);
}spi_driver{//用于描述外设,挂载外设驱动
probe
remove
shutdown
suspend
resume
device_driver driver;
}spi_device{//用于描述外设
struct device dev;
struct spi_master *master;
max_speed_hz;
chip_select;
mode;
bits_per_word;
irq;
*controller_state;
*controller_data;
modalias[SPI_NAME_SIZE];
}spi_transfer{//用于描述传输数据
*tx_buf;
*rx_buf;
len
dma_addr_t tx_dma;
dma_addr_t rx_dma;
cs_change;
bits_per_word;
delay_usecs;
speed_hz;
list_head transfer_list;
}spi_message{//用于组织spi_transfer
list_head transfers;
spi_device *spi;
is_dma_mapped;
(*complete)(void*context);
void *context;
actual_length;
status;
list_head queue;
void *state;
}struct spi_board_info{//描述spi外设数据结构
modalias;外设驱动的名称
bus_num;//用到的spi主机控制器号
chip_select;//片选信号
max_speed_hz;//spi传输速率
plat_form_data;//平台数据,用在spi_device.dev.platform_data;
controller_data;//用在spi_device.controller_data中
}
函数:
spi核心函数:
- spi外设函数
(struct spi_device *)
spi_alloc_device(struct spi_master* master);int spi_add_device(struct spi_device *dev);
int spi_new_device(struct spi_device dev,struct spi_board_info info);//调用alloc_device和add_device
void spi_unregister_device(struct spi_device *dev);
int spi_register_board_info(struct spi_board_info* info,int nr);//将外设与master联系的函数,会调用spi_new_device
int spi_register_driver(struct spi_driver *driver);
int spi_unregister_driver(struct spi_driver *driver);
- spi控制器函数
struct spi_master *
spi_alloc_master(stuct device *dev,int size);
int spi_register_master(struct spi_master *master);
int spi_unregister_master(struct spi_master *master);
spi_master_get_dev_data(struct spi_master*master)//通常通过此函数获得用户定义的控制器的spi资源,
xx_spi{
int irq;
struct clk *clk;
void *buf;
…
struct spi_device *dev;
}
spi_master_set_dev_data(struct spi_master *master,void *data); - spi传输函数
spi_message_init 初始化spi message
spi_message_add_tail(struct spi_transfer *t,struct spi_message *msg)
spi_sync(spi_device *spi,spi_message *msg)
spi_write(spi_device *spi,char *buf,size_t len);
spi_read(spi_device*spi,char *buf,size_t len);
用法:
-
spi适配器驱动实现:
-
适配器驱动文件
xx_transfer(struct spi_device* dev,struct spi_message *msg){
}
xx_setup(struct *spi_device *dev){
}int xx_probe(struct platform_device *dev){
读取适配器资源,配置资源
spi_alloc_master();
…
填充spi_master中的setup,transfer等函数
spi_register_master();
}struct platform_driver xx_spi_driver={
.driver={
.name=”xx_spi_driver”;
.owner=THIS_MODULE;
}
.probe=xx_probe;
.remove=xx_remove;
.resume=xx_resume;
}
xx_init(){
platform_driver_register(&xx_spi_driver);
}xx_exit(){
platform_driver_unregister(&xx_spi_driver);
}
或者
module_platform_driver(&xx_spi_driver);//不需要init,exit函数 适配器资源描述
struct resources={
[0]={
.start
.end
.flags=
}
…
}
struct platform_device xx_spi_device={
[0]={
name=”xx_spi_driver”,
resources=&xx_spi_resources;
num_resorces=
dev={
.platform_data=xx_spi_data;
}
}
}合适的地方调用
platform_device_register(&xx_spi_device);
-
-
spi外设驱动实现
xx外设驱动文件
定义外设自身的驱动
xx_fun();
定义外设driver函数
xx_probe(struct platform_device *pdev){
注册外设功能函数
}定义driver
xx_driver={
.probe=xx_probe;
.remove=xx_remove;
.driver={
.name=”xx_driver”;
.owner=THIS_MODULE;
}
}
xx_init(void){
spi_register_driver(&xx_driver);
}
xx_exit(void){
spi_unregister_driver(&xx_driver);
}外设的资源描述,通常在板子的初始化文件中
描述spi外设,填充spi_board_info
struct spi_board_info xx_spi_device={
.modalias=”xx_driver”;//对应的外设驱动名称
.bus_num
.max_speed_hz
.chip_select
.platform_data
.mode;
…
}- 在合适的地方调用
spi_register_board_info(&xx_spi_device,ARRAY_SIZE(xx_spi_device));
可以看出spi驱动与上面讲的rtc驱动很像,除了最后驱动注册函数不一样外,以上rtc部分均可以套用.