linux spi不使用框架,Linux spi驱动框架之执行流程

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

1.SPI核心层:

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

2.SPI控制器驱动程序:

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

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

structspi_master {

structdevice   dev;

s16         bus_num;

u16         num_chipselect;

int(*setup)(structspi_device *spi);

int(*transfer)(structspi_device *spi,structspi_message *mesg);

void(*cleanup)(structspi_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设备驱动程序:

这里要注意structspi_device *spi 该spi的参数是通过arch/arm/mach-nuc970.cstructspi_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中断初始化

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值