Allein.Cao原创作品,转载请注明出处:
http://blog.csdn.net/alleincao/article/details/7522418
内核版本:2.6.32.2
硬件:S3C2440
SPI总线是一种比较通用的数据传输总线,遵从主从模式,由主设备发起通讯请求,通常工作于全双工模式,由4条数据时钟线组成,下面这段话摘自s3c2440数据手册:
There are 4 I/O pin signals associated with SPItransfers: SCK (SPICLK0,1), MISO (SPIMISO0,1) data line, MOSI (SPIMOSI0,1) dataline and active low /SS (nSS0,1) pin (input).
SPI作为linux里面比较小的一个子系统,其驱动程序位于/drivers/spi/*目录,首先,我们可以通过Makefile及Kconfig来确定我们需要看的源文件:
Makefile:
-
<pre class="csharp" name="code">#
-
# Makefile for kernel SPI drivers.
-
#
-
……………………………………………….
-
# small core, mostly translating board-specific
-
# config declarations into driver model code
-
obj-$(CONFIG_SPI_MASTER) += spi.o
-
-
# SPI master controller drivers (bus)
-
…………………………………………………
-
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
-
…………………………………………………
-
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
-
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
-
…………………………………………………
-
# ... add above this line ...
-
-
# SPI protocol drivers (device/link on bus)
-
obj-$(CONFIG_SPI_SPIDEV) += spidev.o
-
…………………………………………………
-
# ... add above this line ...pre>
-
<pre>pre>
-
<p>p>
-
<p>通过以上分析我们知道,spi驱动由三部分组成,分别是core(spi.c),master controller driver (spi_s3c24xx.c or spi_s3c24xx_gpio.)以及SPIprotocol drivers (spidev.c),这里spi_s3c24xx_gpio.c文件是用普通的io口来模拟spi时序,具体见Kconfig描述:p>
-
<pre class="csharp" name="code">config SPI_S3C24XX_GPIO
-
tristate "Samsung S3C24XX series SPI by GPIO"
-
depends on ARCH_S3C2410 && EXPERIMENTAL
-
select SPI_BITBANG
-
help
-
SPI driver for Samsung S3C24XX series ARM SoCs using
-
GPIO lines to provide the SPI bus. This can be used where
-
the inbuilt hardware cannot provide the transfer mode, or
-
where the board is using non hardware connected pins.
-
pre>
-
<p>在此,我们以spi控制器方式进行分析。p>
-
<p>p>
-
<ul>
-
<li>数据结构li>ul>
-
<p>p>
-
<p>Spi驱动涉及的数据结构主要位于/include/linux/spi.h,对各个结构有比较详细的解释,限于篇幅,简单介绍如下:p>
-
<p>1、Spi_device代表一个外围spi设备,由master controller driver注册完成后扫描BSP中注册设备产生的设备链表并向spi_bus注册产生。p>
-
<p>p>
-
<pre class="csharp" name="code">struct spi_device {
-
struct device dev; //设备模型使用
-
struct spi_master *master; //设备使用的master结构
-
u32 max_speed_hz; //通讯时钟
-
u8 chip_select; //片选号,每个master支持多个spi_device
-
u8 mode; //设备支持的模式,如片选是高or低?
-
#define SPI_CPHA 0x01 /* clock phase */
-
#define SPI_CPOL 0x02 /* clock polarity */
-
#define SPI_MODE_0 (0|0) /* (original MicroWire) */
-
#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? */
-
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
-
#define SPI_3WIRE 0x10 /* SI/SO signals shared */
-
#define SPI_LOOP 0x20 /* loopback mode */
-
#define SPI_NO_CS 0x40 /* 1 dev/bus, no chipselect */
-
#define SPI_READY 0x80 /* slave pulls low to pause */
-
u8 bits_per_word; //每个字长的比特数
-
int irq; //中断号
-
void *controller_state; //控制器寄存器状态
-
void *controller_data;
-
char modalias[SPI_NAME_SIZE]; //设备名称
-
};
-
pre>
-
<p>2、 spi_driver代表一个SPI protocol drivers,即外设驱动。p>
-
<p>p>
-
<pre class="csharp" name="code">struct spi_driver {
-
const struct spi_device_id *id_table; //支持的spi_device设备表
-
int (*probe)(struct spi_device *spi); //probe函数
-
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; //设备模型使用
-
};
-
pre>
-
<p>3、spi_master代表一个主机控制器,此处即S3C2440中的SPI控制器p>
-
<p>p>
-
<pre class="csharp" name="code">struct spi_master {
-
struct device dev; //设备模型使用
-
s16 bus_num; //master编号,s3c2440有2个spi控制器,编号为0 1
-
u16 num_chipselect; //支持的片选的数量,从设备的片选号不能大于这个数量
-
u16 dma_alignment;
-
/* spi_device.mode flags understood by this controller driver */
-
u16 mode_bits; //master支持的设备模式
-
-
/* other constraints relevant to this driver */
-
u16 flags; //一些额外的标志
-
#define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */
-
#define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */
-
#define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */
-
-
int (*setup)(struct spi_device *spi); //设置模式、时钟等
-
-
int (*transfer)(struct spi_device *spi, //数据发送函数
-
struct spi_message *mesg);
-
-
/* called on release() to free memory provided by spi_master */
-
void (*cleanup)(struct spi_device *spi);
-
};
-
pre>
-
<p>4、spi_transfer代表一个读写缓冲对,包含接收缓冲区及发送缓冲区,其实,spi_transfer的发送是通过构建spi_message实现,通过将spi_transfer中的链表transfer_list链接到spi_message中的transfers,再以spi_message形势向底层发送数据。<span style="color: red;">每个span><span style="color: red;">spi_transferspan><span style="color: red;">都可以对传输的一些参数进行设置,使得span><span style="color: red;">master
-
controllerspan><span style="color: red;">按照它要求的参数进行数据发送。span>p>
-
<p>p>
-
<pre class="csharp" name="code">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; // 当前spi_transfer发送完成之后重新片选?
-
u8 bits_per_word; //每个字长的比特数,0代表使用Spi_device中的默认值
-
u16 delay_usecs; //发送完成一个spi_transfer后延时时间
-
u32 speed_hz; //速率
-
-
struct list_head transfer_list; //用于链接到spi_message
-
};<span style="color: rgb(255, 0, 0);">
-
span>pre>5、spi_message代表spi消息,由多个spi_ transfer段组成:
-
<p>struct spi_message {p>
-
<pre class="csharp" name="code"> struct list_head transfers; // spi_transfer链表队列
-
-
struct spi_device *spi; //该消息的目标设备
-
-
unsigned is_dma_mapped:1;
-
-
/* completion is reported through a callback */
-
void (*complete)(void *context); //消息完成后调用的回调函数
-
void *context; //回调函数参数
-
unsigned actual_length; //实际传输的数据长度
-
int status; //该消息的发送结果,0:成功
-
-
struct list_head queue; //用于添加到bitbang的list
-
void *state;
-
};pre><pre class="csharp" name="code">pre><pre style="text-align: left;" class="csharp" name="code">6、s3c24xx_spi代表具体的s3c2440中的spi控制器,包含了控制器的信息,如中断,寄存器等信息,定义于/drivers/spi/spi_s3c24xx.c(因为该结构与具体的硬件有关,属于linux里面的非通用代码)pre><pre class="csharp" name="code"><pre class="csharp" name="code"><div style="text-align: left;">
-
div><pre>pre><pre class="csharp" name="code">pre><pre class="csharp" name="code">struct s3c24xx_spi {
-
/* bitbang has to be first */
-
struct spi_bitbang bitbang; //见下面分析
-
struct completion done;
-
-
void __iomem *regs;
-
int irq;
-
int len;
-
int count;
-
-
void (*set_cs)(struct s3c2410_spi_info *spi,
-
int cs, int pol);
-
-
/* data buffers */
-
const unsigned char *tx;
-
unsigned char *rx;
-
-
struct clk *clk;
-
struct resource *ioarea;
-
struct spi_master *master;
-
struct spi_device *curdev;
-
struct device *dev;
-
struct s3c2410_spi_info *pdata;
-
};
-
pre>7、struct spi_bitbang是具体的负责信息传输的数据结构,它维护一个workqueue_struct,每收到一个消息,都会向其中添加一个work_struct,由内核守护进程在将来的某个时间调用该work_struct中的function进行消息发送。
-
<p>p>
-
<p>p>
-
<p align="left">p>
-
<pre class="csharp" name="code">struct spi_bitbang {
-
struct workqueue_struct *workqueue; //工作队列头,spi master初始化时建立
-
struct work_struct work; //spi master初始化时初始化
-
-
spinlock_t lock;
-
struct list_head queue; //挂接spi_message
-
u8 busy; //忙标志
-
u8 use_dma;
-
u8 flags; /* extra spi->mode support */
-
-
struct spi_master *master; //对应的spi_master
-
-
/* setup_transfer() changes clock and/or wordsize to match settings
-
* for this transfer; zeroes restore defaults from spi_device.
-
*/
-
int (*setup_transfer)(struct spi_device *spi, //对数据传输进行设置
-
struct spi_transfer *t);
-
-
void (*chipselect)(struct spi_device *spi, int is_on); //控制片选
-
#define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */
-
#define BITBANG_CS_INACTIVE 0
-
-
/* txrx_bufs() may handle dma mapping for transfers that don't
-
* already have one (transfer.{tx,rx}_dma is zero), or use PIO
-
*/
-
int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t); //实际的数据传输函数
-
-
/* txrx_word[SPI_MODE_*]() just looks like a shift register */
-
u32 (*txrx_word[4])(struct spi_device *spi,
-
unsigned nsecs,
-
u32 word, u8 bits);
-
};
-
pre><br>
-
<br>
-
<p>p>
-
<pre>pre>
-
<pre class="csharp" name="code">pre><pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
<pre>pre>
-
-
pre>pre>
阅读(1269) | 评论(0) | 转发(0) |