一、概览linux spi驱动子系统
2015-06-17 00:34
591 查看
1、概要
Linux 中的spi驱动主要是由spi子系统来管理的,其核心代码位于kernel/drivers/spi/spi.c中。具体的spi控制器驱动也在kernel/drivers/spi/目录中。目前spi子系统只支持spi主机模式,还不支持spi从机模式。spi通常是由spiI控制器、spi总线和连接在spi总线上的设备构成:这里的总线只是指物理的spi连线,并不是指Linux设备模型中逻辑上的总线概念。可以把spi控制器和spi总线看成是一体的,spi总线就是spi控制器加上和spi设备的连接线。spi设备包含很多种,它可以是一个spi接口的nor flash,例如ST的M25P80。它也可以是一个spi网卡,例如ENC28J60。
2、spi控制器
Linux的spi子系统对spi控制器的描述使用的是struct spi_master这个数据结构,所以在内核中,一个spi_master结构就代表了一个spi控制器,或者说代表一个spi主机。它的主要定义如下:
[code]struct spi_master { struct device dev; struct list_head list; s16 bus_num; //总线(或控制器)编号,总线和设备匹配时用到 u16 num_chipselect; //片选数量,决定该控制器下面挂接多少个SPI设备 u16 dma_alignment; u16 mode_bits; u16 flags; spinlock_t bus_lock_spinlock; struct mutex bus_lock_mutex; bool bus_lock_flag; int (*setup)(struct spi_device *spi); //这个需要我们自己具体实现, //主要设置SPI控制器和工作方式 int (*transfer)(struct spi_device *spi, struct spi_message *mesg); //这个不同的控制器要具体实现, //传输数据最后都要调用这个函数 void (*cleanup)(struct spi_device *spi); //注销时使用 };
在Linux-2.6以后引入设备模型概念,所有的设备和驱动都需要依附于总线。附于Spi总线的设备驱动对应的总线类型为spi_bus_type,在内核的drivers/spi/spi.c中定义。
[code]struct bus_type spi_bus_type = { .name = "spi", .dev_attrs = spi_dev_attrs, .match = spi_match_device, .uevent = spi_uevent, .pm = &spi_pm, }; EXPORT_SYMBOL_GPL(spi_bus_type);
后续会有文章专门讲述如何构建一个struct spi_master对象,并将之注册到spi子系统中去。
3、spi设备
Linux spi子系统对spi总线上的设备用struct spi_device结构来描述,运行的内核中,通常一个struct spi_device对象对应一个spi设备:[code]struct spi_device { struct device dev; struct spi_master *master; //挂在哪个主控器下 u32 max_speed_hz; //设备支持的最大速度 u8 chip_select; //设备的片选号 u8 mode; //SPI的模式,参见SPI的四种模式 u8 bits_per_word; //每个字的位数 int irq; //中断号 void *controller_state; void *controller_data; char modalias[SPI_NAME_SIZE]; //设备名 };
struct spi_device主要用来描述连接在spi总线上的一个spi设备的一些电气信息的。
在2.6.xx版本的内核中可能会经常看到平台代码中用 struct spi_board_info来描述spi设备的电气信息,该结构体包含外设的片选号、总线号、模式以及传输速率等信息。struct spi_board_info原型如下:
[code]struct spi_board_info { /* the device name and module name are coupled, like platform_bus; * "modalias" is normally the driver name. * * platform_data goes to spi_device.dev.platform_data, * controller_data goes to spi_device.controller_data, * irq is copied too */ char modalias[SPI_NAME_SIZE]; const void *platform_data; void *controller_data; int irq; /* slower signaling on noisy or low voltage boards */ u32 max_speed_hz; /* bus_num is board specific and matches the bus_num of some * spi_master that will probably be registered later. * * chip_select reflects how this chip is wired to that master; * it's less than num_chipselect. */ u16 bus_num; u16 chip_select; /* mode becomes spi_device.mode, and is essential for chips * where the default of SPI_CS_HIGH = 0 is wrong. */ u8 mode; /* ... may need additional spi_device chip config data here. * avoid stuff protocol drivers can set; but include stuff * needed to behave without being bound to a driver: * - quirks like clock rate mattering when not selected */ };
在板级初始化代码中,2.6.xx版本的内核中通常会用一个 struct spi_board_info数组来描述系统中的spi设备信息,然后调用spi_register_board_info()将这些设备信息注册到系统中。当然这些struct spi_board_info最终也会转化为struct spi_device结构。关于spi_device是如何构建和注册的,请关注后面的博文。
4、spi设备驱动
spi设备的驱动都会有一个struc spi_driver结构体来描述,结构体中定义对应的操作函数指针,用来管理依附于总线上的相关设备:[code]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; };
通常对于从事Linux驱动工作人员来说,spi设备的驱动主要就是实现这个结构体中的各个接口,并将之注册到spi子系统中去。后面也会有文章专门讲解如何实现struct spi_driver。
5、数据传输相关数据结构
第一个与数据传输相关的数据结构为struct spi_transfer,数据结构定义如下:[code]struct spi_transfer { /* it's ok if tx_buf == rx_buf (right?) * for MicroWire, one buffer must be null * buffers must work with dma_*map_single() calls, unless * spi_message.is_dma_mapped reports a pre-existing mapping */ const void *tx_buf; //发送数据的缓冲区 void *rx_buf; //接收数据的缓冲区 unsigned len; //需要交换数据的长度 dma_addr_t tx_dma; dma_addr_t rx_dma; unsigned cs_change:1; //片选信号 u8 bits_per_word; u16 delay_usecs; u32 speed_hz; struct list_head transfer_list; };
一个struct spi_transfer对象代表了一次单段的spi数据传输。struct spi_transfer结构体中记录了本段传输需要交换的数据和长度,传输的速度,传输时片选信号的变化情况。
另外一个与数据交换相关的数据结构为struct spi_message,定义如下:
[code]struct spi_message { struct list_head transfers; struct spi_device *spi; /* 传输数据到这个设备 */ unsigned is_dma_mapped:1; /* REVISIT: we might want a flag affecting the behavior of the * last transfer ... allowing things like "read 16 bit length L" * immediately followed by "read L bytes". Basically imposing * a specific message scheduling algorithm. * * Some controller drivers (message-at-a-time queue processing) * could provide that as their default scheduling algorithm. But * others (with multi-message pipelines) could need a flag to * tell them about such special cases. */ /* completion is reported through a callback */ void (*complete)(void *context); void *context; unsigned actual_length; int status; /* for optional use by whatever driver currently owns the * spi_message ... between calls to spi_async and then later * complete(), that's the spi_master controller driver. */ struct list_head queue; void *state; };
一个struct spi_message代表对一个设备进行一个多段spi数据传输。每一段传输其实就是使用上面提到的struct spi_trasnfer对象完成的。struct spi_message主要记录了这次传输针对的设备。上面提到的struct spi_transfer对象会被链接到struct spi_message对象中。
6、其他数据结构
对于3.0内核以前,ARM平台通常的做法是在板级代码中注册struct platform_device来描述各种控制器,例如spi控制器,i2c控制器等等。然后再向系统中注册struct platform_driver来管理和驱动对应的平台设备。spi控制器驱动也是同样的做法。3.0以后的内核引入Device Tree来描述ARM平台及板级设备。这样一来我们就不需要在板级代码手动的构建并注册描述spi的platform_device数据了。这一切可以由Device Tree来描述,并且又Device Tree相关代码来解析Device Tree对应spi的相关描述信息,并自动创建并注册表示spi控制器的platform_device数据。与之对应的platform_driver和以前差不多,只不过支持Device Tree后,platform_driver中可以通过Device Tree获取spi控制器的相关信息。引入Device Tree之后platform_driver数据结构中引入下面数据结构:
[code]struct of_device_id { char name[32]; char type[32]; char compatible[128]; const void *data; };
引入Device Tree后platform_driver优先使用struct of_device_id对象中的compatible成员和platform_device中dev.of_node中的compatible成员匹配的。在一些spi控制器驱动代码中常常可以看到如下定义。
[code]static struct of_device_id xxx_spi_of_match[] = { { .compatible = "vendor,chip-spi", }, {} }; MODULE_DEVICE_TABLE(of, xxx_spi_of_match);
另外一个有spi设备和spi驱动相关的数据结构struct of_spi_device_id,定义如下:
[code]struct spi_device_id { char name[SPI_NAME_SIZE]; kernel_ulong_t driver_data /* Data private to the driver */ __attribute__((aligned(sizeof(kernel_ulong_t)))); };
这个数据结构主要是用来匹配spi设备和驱动使用的。
关于device tree在spi驱动中的使用,后面也会有博文进行介绍。
未完待续………
相关文章推荐
- Linux学习--命令(1)
- linux时钟同步
- [转] linux虚拟带库操作笔记
- [转] 在Linux平台使用mhVTL虚拟化磁带库
- linux常用命令汇总
- vmware克隆linux虚拟机网卡无法上网的解决办法
- 在CentOS上安装phpMyAdmin的教程
- Linux 用户的 3 个命令行小技巧
- Linux设置IP别名的方式
- linux常用工具
- CentOS下如何完全卸载MySQL?解决卸载不干净的问题
- CentOS 7 之Helloworld with c
- linux磁盘的基本概念
- 一、Linux USB驱动之USB规范初探
- 二、Linux spi 控制器驱动
- Linux 20150616-2 Linux Basic
- Linux进程&线程
- Redhat/CentOS系统KVM虚拟机安装过程详解
- 夸平台telnet
- linux用户的秘密之login.defs文件详解