Edit online

Demo

26 Nov 2024
Read time: 2 minute(s)

SPI 驱动(详见 drivers/spi/spi-artinchip.c)中调用了 DMA 进行数据传输,其使用过程可以当作 Demo 参考。

DMA 通道的申请

static int aic_spi_probe(struct platform_device *pdev)
{
    ...

    aicspi->dma_rx = dma_request_slave_channel(aicspi->dev, "rx");
    if (!aicspi->dma_rx)
        dev_warn(aicspi->dev, "failed to request rx dma channel\n");

    aicspi->dma_tx = dma_request_slave_channel(aicspi->dev, "tx");
    if (!aicspi->dma_tx)
        dev_warn(aicspi->dev, "failed to request tx dma channel\n");

    ...
}

DMA 数据提交

static int aic_spi_dma_rx_cfg(struct aic_spi *aicspi, struct spi_transfer *t)
{
    struct dma_async_tx_descriptor *dma_desc = NULL;
    struct dma_slave_config dma_conf = {0};

    dma_conf.direction = DMA_DEV_TO_MEM;
    dma_conf.src_addr = aicspi->dma_addr_rx;
    dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
    dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
    dma_conf.src_maxburst = 1;
    dma_conf.dst_maxburst = 1;
    dmaengine_slave_config(aicspi->dma_rx, &dma_conf);

    dma_desc = dmaengine_prep_slave_sg(aicspi->dma_rx, t->rx_sg.sgl,
                       t->rx_sg.nents, dma_conf.direction,
                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
    if (!dma_desc) {
        dev_err(aicspi->dev, "spi-%d prepare slave sg failed.\n",
            aicspi->ctlr->bus_num);
        return -EINVAL;
    }

    dma_desc->callback = aic_spi_dma_cb_rx;
    dma_desc->callback_param = (void *)aicspi;
    dmaengine_submit(dma_desc);

    return 0;
}

启动 DMA 数据传输

static int aic_spi_dma_rx_start(struct spi_device *spi, struct spi_transfer *t)
{
    struct aic_spi *aicspi = spi_controller_get_devdata(spi->master);
    int ret = 0;

    spi_ctlr_dma_rx_enable(aicspi->base_addr);
    ret = aic_spi_dma_rx_cfg(aicspi, t);
    if (ret < 0)
        return ret;
    dma_async_issue_pending(aicspi->dma_rx);

    return ret;
}