allein.cao原创作品,转载请注明出处:
内核版本: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:
-
<preclass="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>
-
<preclass="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>
-
<preclass="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>
-
<preclass="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>
-
<preclass="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形势向底层发送数据。<spanstyle="color: red;">每个span><spanstyle="color: red;">spi_transferspan><spanstyle="color: red;">都可以对传输的一些参数进行设置,使得span><spanstyle="color: red;">master
-
controllerspan><spanstyle="color: red;">按照它要求的参数进行数据发送。span>p>
-
<p>p>
-
<preclass="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
-
};<spanstyle="color: rgb(255, 0, 0);">
-
span>pre>5、spi_message代表spi消息,由多个spi_ transfer段组成:
-
<p>struct spi_message {p>
-
<preclass="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><preclass="csharp"name="code">pre><prestyle="text-align: left;"class="csharp"name="code">6、s3c24xx_spi代表具体的s3c2440中的spi控制器,包含了控制器的信息,如中断,寄存器等信息,定义于/drivers/spi/spi_s3c24xx.c(因为该结构与具体的硬件有关,属于linux里面的非通用代码)pre><preclass="csharp"name="code"><preclass="csharp"name="code"><divstyle="text-align: left;">
-
div><pre>pre><preclass="csharp"name="code">pre><preclass="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>
-
<palign="left">p>
-
<preclass="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>
-
<preclass="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>
阅读(5793) | 评论(0) | 转发(3) |