Linux spi驱动框架之执行流程

来源:互联网 发布:手机棋牌源码 编辑:程序博客网 时间:2024/05/21 09:51

Linux spi驱动架构由三部分构成:SPI核心层、SPI控制器驱动层、和SPI设备驱动程序。

 

1.SPI核心层:

       SPI核心层是Linux的SPI核心部分,提供了核心数据结构的定义、SPI控制器驱动和设备驱动的注册、注销管理等API。其为硬件平台无关层,向下屏蔽了物理总线控制器的差异,定义了统一的访问策略和接口;其向上提供了统一的接口,以便SPI设备驱动通过总线控制器进行数据收发。

 

2.SPI控制器驱动程序:

       SPI控制器驱动层,每种处理器平台都有自己的控制器驱动,属于平台移植相关层。它的职责是为系统中每条SPI总线实现相应的读写方法。在物理上,每个SPI控制器可以连接若干个SPI从设备。在系统开机时,SPI控制器驱动被首先装载。一个控制器驱动用于支持一条特定的SPI总线的读写。一个控制器驱动可以用数据结构struct spi_master来描述

在include/liunx/spi/spi.h文件中,在数据结构struct spi_master定义如下: 

struct spi_master {    

       struct device   dev;  

       s16         bus_num;  

       u16         num_chipselect;  

       int         (*setup)(struct spi_device *spi);  

       int         (*transfer)(struct spi_device *spi, struct spi_message *mesg);  

       void        (*cleanup)(struct spi_device *spi);  

}

       SPI控制器不用关心设备的具体功能,它只负责把上层协议驱动准备好的数据按SPI总线的时序要求发送给SPI设备,同时把从设备收到的数据返回给上层的协议驱动,因此,内核把SPI控制器的驱动程序独立出来。SPI控制器驱动负责控制具体的控制器硬件,诸如DMA和中断操作等等,因为多个上层的协议驱动可能会通过控制器请求数据传输操作,所以,SPI控制器驱动同时也要负责对这些请求进行队列管理,保证先进先出的原则 。

01.-->nuc970_spi0_probe(struct platform_device *pdev)   //完成如下的初始化  02.    -->1. init_completion(&hw->done); //完成量初始化  03.    -->2. hw->bitbang.setup_transfer = nuc970_spi0_setupxfer; //设置spi的寄存器参数  04.        2.1 nuc970_spi0_update_state(spi, t);       //更新传输模式  05.        2.2 nuc970_spi0_setup_txbitlen(hw, hw->pdata->txbitlen);  //字节发送长度  06.        2.3 nuc970_tx_edge(hw, hw->pdata->txneg); //发送边沿  07.        2.4 nuc970_rx_edge(hw, hw->pdata->rxneg); //接受边沿  08.        2.5 nuc970_set_clock_polarity(hw, hw->pdata->clkpol); //空闲时的时钟极性  09.        2.6 nuc970_send_first(hw, hw->pdata->lsb);    //字节传输顺序,0-高bit先传输  10.    -->3. hw->bitbang.chipselect  = nuc970_spi0_chipsel;  //芯片选择,目前同一个spi总线下面芯唐支持2个从设备  11.        3.1 nuc970_slave_select(spi, 0);    //BITBANG_CS_INACTIVE  12.        3.2 nuc970_slave_select(spi, 1);    //BITBANG_CS_ACTIVE  13.    -->4. hw->bitbang.txrx_bufs = nuc970_spi0_txrx;   //这个函数很重要!负责spi驱动与底层寄存器数据的发  14.                            //送、接收,这里直接发送,通过中断接收数据(第7.2点),  15.                            //发送与接收的桥梁是通过“完成量”完成的(第1.点)  16.        4.1 nuc970_spi0_gobusy(hw);     //发送完数据进入忙等待  17.        4.2 wait_for_completion(&hw->done);  //等待完成量(第7.2.1),否则进入休眠等待  18.    -->5. hw->bitbang.master->setup  = nuc970_spi0_setup;  //spi0设置  19.    -->6. platform_get_resource(pdev, IORESOURCE_MEM, 0) //获取寄存器的IO资源  20.        6.1 hw->ioarea = request_mem_region(hw->res->start,resource_size(hw->res), pdev->name);  //资源申请  21.        6.2 hw->regs = ioremap(hw->res->start, resource_size(hw->res)); //资源映射  22.    -->7. hw->irq = platform_get_irq(pdev, 0);    //获取中断资源  23.        7.1 request_irq(hw->irq, nuc970_spi0_irq, 0, pdev->name, hw);     //申请中断功能  24.        7.2 nuc970_spi0_irq(int irq, void *dev) //注意这个终端函数很重要,它负责接收底层spi寄存器上传的数据(与第4点相反)  25.            7.2.1 complete(&hw->done);   //中断接收数据完成,置“完成量”标志,唤醒第4.2  26.    -->8. nuc970_init_spi(hw);   //spi初始化  27.        8.1 clk_prepare(hw->clk);  28.        8.2 clk_enable(hw->clk);  29.        8.3 spin_lock_init(&hw->lock);  30.        8.4 nuc970_tx_edge(hw, hw->pdata->txneg);  31.        8.5 nuc970_rx_edge(hw, hw->pdata->rxneg);  32.        8.6 nuc970_send_first(hw, hw->pdata->lsb);  33.        8.7 nuc970_set_sleep(hw, hw->pdata->sleep);  34.        8.8 nuc970_spi0_setup_txbitlen(hw, hw->pdata->txbitlen);  35.        8.9 nuc970_spi0_setup_txnum(hw, hw->pdata->txnum);  36.        8.10 nuc970_set_divider(hw);  37.        8.11 nuc970_enable_int(hw);  38.    -->9. spi_bitbang_start(&hw->bitbang);  39.        9.1 INIT_WORK(&bitbang->work, bitbang_work); //初始化工作队列,绑定工作队列处理的函数  40.        9.2 bitbang_work(struct work_struct *work)  //工作队列处理函数  41.        9.3 status = bitbang->setup_transfer(spi, t);    //设置spi寄存器参数,函数初始化见第2.点,函数内容见第2.1~2.6  42.        9.4 bitbang->chipselect(spi, BITBANG_CS_ACTIVE); //  43.        9.5 master->transfer = spi_bitbang_transfer; //这个函数很重要,下面的第7.点将被调用  44.        9.6 bitbang->txrx_bufs(spi, t);      //发送、接收数据,见第4.点初始化,这个函数很重要!!!  

 

3、SPI设备驱动程序:

       这里要注意struct spi_device *spi 该spi的参数是通过arch/arm/mach-nuc970.c struct spi_device att7022e = {...};中进行定义的,在注册att7022e设备驱动的时候,检测到板级文件中存在该设备名就调用att7022e_prope函数。

 

att7022e.c  //没有使用内核自带的设备驱动spidev.c,而是自己编写的设备驱动att7022.c,具体实现细节,略...  

执行流程如下: 

01.-->1 att7022e_read_reg() //发送、接收消息, 将调用spi.c核心层
02.-->2 spi_write_then_read(spi,txbuf, n_tx, rxbuf, n_rx)     03.-->3 spi_sync(spi, &message)  04.-->4 __spi_sync(spi, message, 0)  05.-->5 spi_async_locked(spi, message)  06.-->6 __spi_async(spi, message)  07.-->7 master->transfer(spi, message)   //回调函数初始化见上9.5  08.-->7.1 queue_work(bitbang->workqueue, &bitbang->work); //这个工作队列很重要,当数据加入队列后,它将调用下面接口  09.-->7.1.1 bitbang_work(struct work_struct *work)  //该函数是在在工作队列中初始化的,见上9.1  10.-->7.1.2 bitbang->txrx_bufs(spi, t)   //最终发送、接收消息,调用上面的9.6  11.-->7.1.3 wait_for_completion(&hw->done); //发送消息结束后等待数据接收,是通过下面的中断产生  12.-->7.1.4 nuc970_spi0_irq(int irq, void *dev) //见上7.2中断初始化                                  



 

1 0
原创粉丝点击