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