Linux spi子系统源码分析--Apple的学习笔记

前言

Linux i2c子系统源码分析--Apple的学习笔记源码分析过,那么接下来就分析下spi的。从makefile来看spi要比i2c的结构简单。但是看源码的时候特别是发送函数一开始会混乱,没找到函数注册的地方。后来网上查了资料后,原来我kthread相关的API不清楚导致我快速看关键函数时候没注意到关联关系。

一,kthread学习

简单来说可以理解为我之前学习c++时候自己做的线程池的概念。它有一个worker就是一个线程池,把work挂入到worker后,就由worker线程池来调度运行了。

二,spi子系统源码分析

首先思考一个问题,看i2c的时候没有用到内核线程kthread,或者说kthread可能用到了,但是不是重点内容,为什么spi中它很重要呢?为什么要用这样的设计。我思考了下因为spi传输速度快,所以一般使用fifo并且开启DMA,而不像i2c用个thread中断即可解决,但是我调试了源码的时候用的是pio(可以理解为非中断而是polling),之后查了下为什么不是DMA的原因是can_dma返回值为false。因为要使用DMA,这里设置了至少传输长度为160字节。而我的陀螺仪用不到160字节,按block传输最大也只能传输32字节。

/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
 * cache operations; better heuristics consider wordsize and bitrate.
 */
#define DMA_MIN_BYTES           160

static bool omap2_mcspi_can_dma(struct spi_master *master,
                struct spi_device *spi,
                struct spi_transfer *xfer)
{
......
    return (xfer->len >= DMA_MIN_BYTES);
}
static int omap2_mcspi_transfer_one(struct spi_master *master,
                    struct spi_device *spi,
                    struct spi_transfer *t)
{
......
        if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
            master->cur_msg_mapped &&
            master->can_dma(master, spi, t))
            count = omap2_mcspi_txrx_dma(spi, t);
        else
            count = omap2_mcspi_txrx_pio(spi, t);
......
}
./ev2
[   24.858765] apple6500sensor spi0.0: chconf=0x201123ff,mytmp=0x30
[   24.864984] apple6500sensor spi0.0: pio rx
[   24.869110] apple6500sensor spi0.0: write-8 f5
[   24.874598] apple6500sensor spi0.0: chconf=0x201113ff,mytmp=0x30
[   24.880762] apple6500sensor spi0.0: pio rx
[   24.884888] apple6500sensor spi0.0: read-8 70
[   24.890309] apple6500sensor spi0.0: chconf=0x201123ff,mytmp=0x30
[   24.896359] apple6500sensor spi0.0: pio rx
[   24.900587] apple6500sensor spi0.0: write-8 6b
[   24.905410] apple6500sensor spi0.0: write-8 81
[   24.910648] apple6500sensor spi0.0: chconf=0x201123ff,mytmp=0x30
[   24.916694] apple6500sensor spi0.0: pio rx
[   24.920894] apple6500sensor spi0.0: write-8 6c
[   24.925646] apple6500sensor spi0.0: write-8 00
[   24.930824] apple6500sensor spi0.0: chconf=0x201123ff,mytmp=0x30
[   24.936868] apple6500sensor spi0.0: pio rx
[   24.941067] apple6500sensor spi0.0: write-8 1d
[   24.945806] apple6500sensor spi0.0: write-8 04

好了,言归正传,我其实想通过对比i2c来学习。

  1. 比如i2c它的omap芯片级别的probe函数中会调用core中的register函数来注册设备。是否spi也如此?答案是的。probe函数会调用spi_register_controller,此函数里面会创建设备device_add,然后会调用初始化工作线程spi_controller_initialize_queue包括spi_pump_messages绑定到工作线程中。同时会注册ctlr->transfer_one_message = spi_transfer_one_message;

  2. i2c的probe函数会给adapter适配器注册每个芯片的algo传输算法(就是底层和芯片寄存器设置相关的的发送函数啦)。答案是的。
    它比i2c简单,没有适配器的概念。直接在master中的chip注册发送函数master->transfer_one = omap2_mcspi_transfer_one;

  3. 发送函数使用了内核线程,函数关系如下
    spi_sync
    -->spi_queued_transfer
    ---->__spi_queued_transfer里面会调用kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);开启内核工作线程spi_pump_messages
    spi_pump_messages中调用
    -->__spi_pump_messages
    ----> ctlr->transfer_one_message里面会调用ctlr->transfer_one(ctlr, msg->spi, xfer);而这个回调函数就是omap probe函数中注册的。

  4. linux的spi有spi_transfer是最小单位包含在spi_message中。message可以当然任务控制对象,而transfer可以当做数据对象。所以任务装载数据去控制发送,所以transfer包含在message中,我是这样理解的哈~

你可能感兴趣的:(Linux spi子系统源码分析--Apple的学习笔记)