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) |