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