in at_xdmac.c [2023:2178]
static int at_xdmac_probe(struct platform_device *pdev)
{
struct at_xdmac *atxdmac;
int irq, nr_channels, i, ret;
void __iomem *base;
u32 reg;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
/*
* Read number of xdmac channels, read helper function can't be used
* since atxdmac is not yet allocated and we need to know the number
* of channels to do the allocation.
*/
reg = readl_relaxed(base + AT_XDMAC_GTYPE);
nr_channels = AT_XDMAC_NB_CH(reg);
if (nr_channels > AT_XDMAC_MAX_CHAN) {
dev_err(&pdev->dev, "invalid number of channels (%u)\n",
nr_channels);
return -EINVAL;
}
atxdmac = devm_kzalloc(&pdev->dev,
struct_size(atxdmac, chan, nr_channels),
GFP_KERNEL);
if (!atxdmac) {
dev_err(&pdev->dev, "can't allocate at_xdmac structure\n");
return -ENOMEM;
}
atxdmac->regs = base;
atxdmac->irq = irq;
atxdmac->layout = of_device_get_match_data(&pdev->dev);
if (!atxdmac->layout)
return -ENODEV;
atxdmac->clk = devm_clk_get(&pdev->dev, "dma_clk");
if (IS_ERR(atxdmac->clk)) {
dev_err(&pdev->dev, "can't get dma_clk\n");
return PTR_ERR(atxdmac->clk);
}
/* Do not use dev res to prevent races with tasklet */
ret = request_irq(atxdmac->irq, at_xdmac_interrupt, 0, "at_xdmac", atxdmac);
if (ret) {
dev_err(&pdev->dev, "can't request irq\n");
return ret;
}
ret = clk_prepare_enable(atxdmac->clk);
if (ret) {
dev_err(&pdev->dev, "can't prepare or enable clock\n");
goto err_free_irq;
}
atxdmac->at_xdmac_desc_pool =
dmam_pool_create(dev_name(&pdev->dev), &pdev->dev,
sizeof(struct at_xdmac_desc), 4, 0);
if (!atxdmac->at_xdmac_desc_pool) {
dev_err(&pdev->dev, "no memory for descriptors dma pool\n");
ret = -ENOMEM;
goto err_clk_disable;
}
dma_cap_set(DMA_CYCLIC, atxdmac->dma.cap_mask);
dma_cap_set(DMA_INTERLEAVE, atxdmac->dma.cap_mask);
dma_cap_set(DMA_MEMCPY, atxdmac->dma.cap_mask);
dma_cap_set(DMA_MEMSET, atxdmac->dma.cap_mask);
dma_cap_set(DMA_MEMSET_SG, atxdmac->dma.cap_mask);
dma_cap_set(DMA_SLAVE, atxdmac->dma.cap_mask);
/*
* Without DMA_PRIVATE the driver is not able to allocate more than
* one channel, second allocation fails in private_candidate.
*/
dma_cap_set(DMA_PRIVATE, atxdmac->dma.cap_mask);
atxdmac->dma.dev = &pdev->dev;
atxdmac->dma.device_alloc_chan_resources = at_xdmac_alloc_chan_resources;
atxdmac->dma.device_free_chan_resources = at_xdmac_free_chan_resources;
atxdmac->dma.device_tx_status = at_xdmac_tx_status;
atxdmac->dma.device_issue_pending = at_xdmac_issue_pending;
atxdmac->dma.device_prep_dma_cyclic = at_xdmac_prep_dma_cyclic;
atxdmac->dma.device_prep_interleaved_dma = at_xdmac_prep_interleaved;
atxdmac->dma.device_prep_dma_memcpy = at_xdmac_prep_dma_memcpy;
atxdmac->dma.device_prep_dma_memset = at_xdmac_prep_dma_memset;
atxdmac->dma.device_prep_dma_memset_sg = at_xdmac_prep_dma_memset_sg;
atxdmac->dma.device_prep_slave_sg = at_xdmac_prep_slave_sg;
atxdmac->dma.device_config = at_xdmac_device_config;
atxdmac->dma.device_pause = at_xdmac_device_pause;
atxdmac->dma.device_resume = at_xdmac_device_resume;
atxdmac->dma.device_terminate_all = at_xdmac_device_terminate_all;
atxdmac->dma.src_addr_widths = AT_XDMAC_DMA_BUSWIDTHS;
atxdmac->dma.dst_addr_widths = AT_XDMAC_DMA_BUSWIDTHS;
atxdmac->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
atxdmac->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
/* Disable all chans and interrupts. */
at_xdmac_off(atxdmac);
/* Init channels. */
INIT_LIST_HEAD(&atxdmac->dma.channels);
for (i = 0; i < nr_channels; i++) {
struct at_xdmac_chan *atchan = &atxdmac->chan[i];
atchan->chan.device = &atxdmac->dma;
list_add_tail(&atchan->chan.device_node,
&atxdmac->dma.channels);
atchan->ch_regs = at_xdmac_chan_reg_base(atxdmac, i);
atchan->mask = 1 << i;
spin_lock_init(&atchan->lock);
INIT_LIST_HEAD(&atchan->xfers_list);
INIT_LIST_HEAD(&atchan->free_descs_list);
tasklet_setup(&atchan->tasklet, at_xdmac_tasklet);
/* Clear pending interrupts. */
while (at_xdmac_chan_read(atchan, AT_XDMAC_CIS))
cpu_relax();
}
platform_set_drvdata(pdev, atxdmac);
ret = dma_async_device_register(&atxdmac->dma);
if (ret) {
dev_err(&pdev->dev, "fail to register DMA engine device\n");
goto err_clk_disable;
}
ret = of_dma_controller_register(pdev->dev.of_node,
at_xdmac_xlate, atxdmac);
if (ret) {
dev_err(&pdev->dev, "could not register of dma controller\n");
goto err_dma_unregister;
}
dev_info(&pdev->dev, "%d channels, mapped at 0x%p\n",
nr_channels, atxdmac->regs);
at_xdmac_axi_config(pdev);
return 0;
err_dma_unregister:
dma_async_device_unregister(&atxdmac->dma);
err_clk_disable:
clk_disable_unprepare(atxdmac->clk);
err_free_irq:
free_irq(atxdmac->irq, atxdmac);
return ret;
}