Edit online

Demo

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;
    }