Linux SPI总线和设备驱动架构之二:SPI通用接口层
来源:互联网 发布:linux mint 18安装 编辑:程序博客网 时间:2024/05/20 06:25
通过上一篇文章的介绍,我们知道,SPI通用接口层用于把具体SPI设备的协议驱动和SPI控制器驱动联接在一起,通用接口层除了为协议驱动和控制器驱动提供一系列的标准接口API,同时还为这些接口API定义了相应的数据结构,这些数据结构一部分是SPI设备、SPI协议驱动和SPI控制器的数据抽象,一部分是为了协助数据传输而定义的数据结构。另外,通用接口层还负责SPI系统与Linux设备模型相关的初始化工作。本章的我们就通过这些数据结构和API的讨论来对整个通用接口层进行深入的了解。
/*****************************************************************************************************/
声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢!
/*****************************************************************************************************/
SPI通用接口层的代码集中在:/drivers/spi/spi.c中。
SPI设备模型的初始化
通常地,根据linux设备模型的组织方式,各种设备会挂在合适的总线上,设备驱动和设备通过总线互相进行匹配,使得设备能够找到正确的驱动程序进行控制和驱动。同时,性质相似的设备可以归为某一个类的设备,它们具有某些共同的设备属性,在设备模型上就是所谓的class。SPI设备也不例外,它们也遵循linux的设备模型的规则:
- struct bus_type spi_bus_type = {
- .name = "spi",
- .dev_attrs = spi_dev_attrs,
- .match = spi_match_device,
- .uevent = spi_uevent,
- .pm = &spi_pm,
- };
- static struct class spi_master_class = {
- .name = "spi_master",
- .owner = THIS_MODULE,
- .dev_release = spi_master_release,
- };
- static int __init spi_init(void)
- {
- int status;
- buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
- ......
- status = bus_register(&spi_bus_type);
- ......
- status = class_register(&spi_master_class);
- ......
- return 0;
- ......
- }
- postcore_initcall(spi_init);
- sys/bus/spi
- sys/class/spi_master
spi_master结构
SPI控制器负责按照设定的物理信号格式在主控和spi设备之间交换数据,SPI控制器数据是如何被传输的,而不关心数据的内容。SPI通用接口层用spi_master结构来表示一个spi控制器,我们看看它的主要字段的意义:
spi_master结构通常由控制器驱动定义,然后通过以下通用接口层的API注册到系统中:
- int spi_register_master(struct spi_master *master);
spi_device结构
SPI通用接口层用spi_device结构来表示一个spi设备,它的各个字段的意义如下:
struct device dev代表该spi设备的device结构struct spi_master *master指向该spi设备所使用的控制器u32 max_speed_hz该设备的最大工作时钟频率u8 chip_select在控制器中的片选引脚编号索引u16 mode设备的工作模式,包括时钟格式,片选信号的有效电平等等u8 bits_per_word设备每个单位数据所需要的比特数int irq设备使用的irq编号char modalias[SPI_NAME_SIZE]该设备的名字,用于spi总线和驱动进行配对int cs_gpio片选信号的gpio编号,通常不用我们自己设置,接口层会根据上面的chip_select字段在spi_master结构中进行查找并赋值要完成向系统增加并注册一个SPI设备,我们还需要另一个数据结构:
- struct spi_board_info {
- char modalias[SPI_NAME_SIZE];
- const void *platform_data;
- void *controller_data;
- int irq;
- u32 max_speed_hz;
- u16 bus_num;
- u16 chip_select;
- u16 mode;
- };
- struct spi_device *spi_new_device(struct spi_master *master, struct spi_board_info *chip);
- int spi_register_board_info(struct spi_board_info const *info, unsigned n);
spi_driver结构
根据linux的设备模型,有device就必定有driver与之对应,上一节介绍的spi_device结构中内嵌了device结构字段dev,同样地,代表驱动程序的spi_driver结构也内嵌了device_driver结构:
- struct spi_driver {
- const struct spi_device_id *id_table;
- int (*probe)(struct spi_device *spi);
- int (*remove)(struct spi_device *spi);
- void (*shutdown)(struct spi_device *spi);
- int (*suspend)(struct spi_device *spi, pm_message_t mesg);
- int (*resume)(struct spi_device *spi);
- struct device_driver driver;
- };
- int spi_register_driver(struct spi_driver *sdrv)
- {
- sdrv->driver.bus = &spi_bus_type;
- if (sdrv->probe)
- sdrv->driver.probe = spi_drv_probe;
- if (sdrv->remove)
- sdrv->driver.remove = spi_drv_remove;
- if (sdrv->shutdown)
- sdrv->driver.shutdown = spi_drv_shutdown;
- return driver_register(&sdrv->driver);
- }
需要注意的是,这里的spi_driver结构代表的是具体的SPI协议驱动程序。
spi_message和spi_transfer结构
要完成和SPI设备的数据传输工作,我们还需要另外两个数据结构:spi_message和spi_transfer。spi_message包含了一个的spi_transfer结构序列,一旦控制器接收了一个spi_message,其中的spi_transfer应该按顺序被发送,并且不能被其它spi_message打断,所以我们认为spi_message就是一次SPI数据交换的原子操作。下面我们看看这两个数据结构的定义:
- struct spi_message {
- struct list_head transfers;
- struct spi_device *spi;
- unsigned is_dma_mapped:1;
- /* completion is reported through a callback */
- void (*complete)(void *context);
- void *context;
- unsigned frame_length;
- unsigned actual_length;
- int status;
- struct list_head queue;
- void *state;
- };
- struct spi_transfer {
- const void *tx_buf;
- void *rx_buf;
- unsigned len;
- dma_addr_t tx_dma;
- dma_addr_t rx_dma;
- unsigned cs_change:1;
- u8 tx_nbits;
- u8 rx_nbits;
- u8 bits_per_word;
- u16 delay_usecs;
- u32 speed_hz;
- struct list_head transfer_list;
- };
通用接口层为我们提供了一系列用于操作和维护spi_message和spi_transfer的API函数,这里也列一下。
用于初始化spi_message结构:
- void spi_message_init(struct spi_message *m);
- void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m);
- void spi_transfer_del(struct spi_transfer *t);
- void spi_message_init_with_transfers(struct spi_message *m, struct spi_transfer *xfers, unsigned int num_xfers);
- struct spi_message *spi_message_alloc(unsigned ntrans, gfp_t flags);
- 异步版本 int spi_async(struct spi_device *spi, struct spi_message *message);
- 同步版本 int spi_sync(struct spi_device *spi, struct spi_message *message);
总结一下,协议驱动发送数据的流程大致是这样的:
- 定义一个spi_message结构;
- 用spi_message_init函数初始化spi_message;
- 定义一个或数个spi_transfer结构,初始化并为数据准备缓冲区并赋值给spi_transfer相应的字段(tx_buf,rx_buf等);
- 通过spi_message_init函数把这些spi_transfer挂在spi_message结构下;
- 如果使用同步方式,调用spi_sync(),如果使用异步方式,调用spi_async();
- int spi_write(struct spi_device *spi, const void *buf, size_t len); ---- 同步方式发送数据。
- int spi_read(struct spi_device *spi, void *buf, size_t len); ---- 同步方式接收数据。
- int spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers, unsigned int num_xfers); ---- 同步方式,直接传送数个spi_transfer,接收和发送。
- int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx, void *rxbuf, unsigned n_rx); ---- 先写后读。
- ssize_t spi_w8r8(struct spi_device *spi, u8 cmd); ---- 写8位,然后读8位。
- ssize_t spi_w8r16(struct spi_device *spi, u8 cmd); ---- 写8位,然后读16位。
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- Linux SPI总线和设备驱动架构
- Linux SPI总线和设备驱动架构之三:SPI控制器驱动
- Linux SPI总线和设备驱动架构之三:SPI控制器驱动
- Linux SPI总线和设备驱动架构之三:SPI控制器驱动
- Linux SPI总线和设备驱动架构之三:SPI控制器驱动
- Linux SPI总线和设备驱动架构之三:SPI控制器驱动
- 快速排序
- 中断初始化
- 2015-第16周项目3-max带来的冲突
- 端午节
- ListView 中使用onItemClick和onItemLongClick的常见问题
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
- 平稳退化(优雅降级)与渐进增强
- 01-数据分析之始末-概览篇
- 6.22 输出日期时间--友元类 oj 嘻唰唰 1
- 万物互联下的企业新生态
- 什么叫闭包
- 文本相似度算法(余弦定理)
- extern "c"
- PATBasic——1011. A+B和C (15)