7.10.5. 设计说明

7.10.5.1. 源码说明

相关模块

源码路径

SPI subsystem

linux-5.10/drivers/spi/

Driver

linux-5.10/drivers/spi/

7.10.5.2. 模块架构

../../../_images/spi_kernel_arch.png

图 7.50 内核 SPI 框图

由于使用 SPI 的外设较多,内核中通过 SPI 子系统来支持各种 SPI 外设,整体架构如上图所示,包括:

  • ZX SPI 驱动

  • SPI Core

  • SPI-MEM

  • 面向内核的 API

  • 面向用户空间的接口(SPIDEV)

由于 SPI 传输需要使用 DMA,因此 DMA 子系统是一个相关模块。

7.10.5.3. 关键流程

7.10.5.3.1. 初始化

aic_spi_probe();
|-> irq = platform_get_irq(pdev, 0);
|-> ctlr = spi_alloc_master(&pdev->dev, sizeof(struct aic_spi));
|-> platform_set_drvdata(pdev, ctlr);
|-> aicspi->dma_rx = dma_request_slave_channel(aicspi->dev, "rx");
|-> aicspi->dma_tx = dma_request_slave_channel(aicspi->dev, "tx");
    |-> request_irq(aicspi->irq, aic_spi_handle_irq, 0, aicspi->dev_name, aicspi);
|-> spi_register_controller(ctlr);

7.10.5.3.2. 中断流程

SPI 控制器驱动中的中断处理并不复杂,当中断发生时,首先在 irq handler 中读取相关状态寄存器, 然后判断如何处理:

static irqreturn_t aic_spi_handle_irq(int irq, void *dev_id)
{
    ...

    spi_ctlr_pending_irq_clr(status, base_addr);
    /* master mode, Transfer Complete Interrupt */
    if (status & ISR_BIT_TC) {
        ...
        spi_ctlr_irq_disable(ISR_BIT_TC | ISR_BIT_ERRS, base_addr);
        spi_finalize_current_transfer(aicspi->ctlr);    // 传输完成,通知调用者
        ...
        return IRQ_HANDLED;
    } else if (status & ISR_BIT_ERRS) {
        ...
        spi_ctlr_irq_disable(ISR_BIT_TC | ISR_BIT_ERRS, base_addr);
        spi_ctlr_soft_reset(base_addr);                 // 传输出错,reset 控制器
        spi_finalize_current_transfer(aicspi->ctlr);
        ...
        return IRQ_HANDLED;
    }
    ...
    return IRQ_NONE;
}

7.10.5.4. 数据结构

enum spi_mode_type {
    SINGLE_HALF_DUPLEX_RX,
    SINGLE_HALF_DUPLEX_TX,
    SINGLE_FULL_DUPLEX_RX_TX,
    DUAL_HALF_DUPLEX_RX,
    DUAL_HALF_DUPLEX_TX,
    QUAD_HALF_DUPLEX_RX,
    QUAD_HALF_DUPLEX_TX,
    MODE_TYPE_NULL,
};

设备数据结构。

struct aic_spi {
    struct device *dev;                 // 设备指针
    struct spi_controller *ctlr;        // SPI CORE 的控制器指针
    void __iomem *base_addr;            // 映射后的 SPI 控制器地址
    struct clk *mclk;                   // SPI 控制器的时钟
    struct reset_control *rst;          // SPI 控制器的复位
    struct dma_chan *dma_rx;            // SPI 控制器的接收 DMA Channel
    struct dma_chan *dma_tx;            // SPI 控制器的发送 DMA Channel
    dma_addr_t dma_addr_rx;             // SPI 控制器 RX FIFO 地址
    dma_addr_t dma_addr_tx;             // SPI 控制器 TX FIFO 地址
    enum spi_mode_type mode_type;
    unsigned int irq;                   // 中断号
    char dev_name[48];
    spinlock_t lock;
};

7.10.5.5. 接口设计

7.10.5.5.1. aic_spi_setup

函数原型

int aic_spi_setup(struct spi_device *spi)

功能说明

SPI 设备的传输位宽、模式的检查和配置

参数定义

struct spi_device *spi
SPI 设备指针

返回值

0: 成功
其他: 失败

注意事项

7.10.5.5.2. aic_spi_set_cs

函数原型

void aic_spi_set_cs(struct spi_device *spi, bool cs_high)

功能说明

设置 SPI 设备的片选信号

参数定义

struct spi_device *spi
SPI 设备指针
bool cs_high
是否选择该设备

返回值

注意事项

7.10.5.5.3. aic_spi_max_transfer_size

函数原型

size_t aic_spi_max_transfer_size(struct spi_device *spi)

功能说明

SPI CORE 获取当前 SPI 控制器单次最大可传输的数据长度

参数定义

struct spi_device *spi
SPI 设备指针

返回值

单次可传输的数据长度

注意事项

7.10.5.5.4. aic_spi_transfer_one

函数原型

int aic_spi_transfer_one(struct spi_controller *ctlr,struct spi_device *spi, struct spi_transfer *t)

功能说明

执行一次传输

参数定义

struct spi_controller *ctlr
SPI 控制器指针
struct spi_device *spi
SPI 设备指针
struct spi_transfer *t
单次 SPI 传输结构体指针

返回值

0: 成功
其他: 失败

注意事项