in stm32-mdma.c [1506:1660]
static int stm32_mdma_probe(struct platform_device *pdev)
{
struct stm32_mdma_chan *chan;
struct stm32_mdma_device *dmadev;
struct dma_device *dd;
struct device_node *of_node;
struct resource *res;
struct reset_control *rst;
u32 nr_channels, nr_requests;
int i, count, ret;
of_node = pdev->dev.of_node;
if (!of_node)
return -ENODEV;
ret = device_property_read_u32(&pdev->dev, "dma-channels",
&nr_channels);
if (ret) {
nr_channels = STM32_MDMA_MAX_CHANNELS;
dev_warn(&pdev->dev, "MDMA defaulting on %i channels\n",
nr_channels);
}
ret = device_property_read_u32(&pdev->dev, "dma-requests",
&nr_requests);
if (ret) {
nr_requests = STM32_MDMA_MAX_REQUESTS;
dev_warn(&pdev->dev, "MDMA defaulting on %i request lines\n",
nr_requests);
}
count = device_property_count_u32(&pdev->dev, "st,ahb-addr-masks");
if (count < 0)
count = 0;
dmadev = devm_kzalloc(&pdev->dev,
struct_size(dmadev, ahb_addr_masks, count),
GFP_KERNEL);
if (!dmadev)
return -ENOMEM;
dmadev->nr_channels = nr_channels;
dmadev->nr_requests = nr_requests;
device_property_read_u32_array(&pdev->dev, "st,ahb-addr-masks",
dmadev->ahb_addr_masks,
count);
dmadev->nr_ahb_addr_masks = count;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dmadev->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dmadev->base))
return PTR_ERR(dmadev->base);
dmadev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dmadev->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(dmadev->clk),
"Missing clock controller\n");
ret = clk_prepare_enable(dmadev->clk);
if (ret < 0) {
dev_err(&pdev->dev, "clk_prep_enable error: %d\n", ret);
return ret;
}
rst = devm_reset_control_get(&pdev->dev, NULL);
if (IS_ERR(rst)) {
ret = PTR_ERR(rst);
if (ret == -EPROBE_DEFER)
goto err_clk;
} else {
reset_control_assert(rst);
udelay(2);
reset_control_deassert(rst);
}
dd = &dmadev->ddev;
dma_cap_set(DMA_SLAVE, dd->cap_mask);
dma_cap_set(DMA_PRIVATE, dd->cap_mask);
dma_cap_set(DMA_CYCLIC, dd->cap_mask);
dma_cap_set(DMA_MEMCPY, dd->cap_mask);
dd->device_alloc_chan_resources = stm32_mdma_alloc_chan_resources;
dd->device_free_chan_resources = stm32_mdma_free_chan_resources;
dd->device_tx_status = stm32_mdma_tx_status;
dd->device_issue_pending = stm32_mdma_issue_pending;
dd->device_prep_slave_sg = stm32_mdma_prep_slave_sg;
dd->device_prep_dma_cyclic = stm32_mdma_prep_dma_cyclic;
dd->device_prep_dma_memcpy = stm32_mdma_prep_dma_memcpy;
dd->device_config = stm32_mdma_slave_config;
dd->device_pause = stm32_mdma_pause;
dd->device_resume = stm32_mdma_resume;
dd->device_terminate_all = stm32_mdma_terminate_all;
dd->device_synchronize = stm32_mdma_synchronize;
dd->descriptor_reuse = true;
dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) |
BIT(DMA_MEM_TO_MEM);
dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
dd->max_burst = STM32_MDMA_MAX_BURST;
dd->dev = &pdev->dev;
INIT_LIST_HEAD(&dd->channels);
for (i = 0; i < dmadev->nr_channels; i++) {
chan = &dmadev->chan[i];
chan->id = i;
chan->vchan.desc_free = stm32_mdma_desc_free;
vchan_init(&chan->vchan, dd);
}
dmadev->irq = platform_get_irq(pdev, 0);
if (dmadev->irq < 0) {
ret = dmadev->irq;
goto err_clk;
}
ret = devm_request_irq(&pdev->dev, dmadev->irq, stm32_mdma_irq_handler,
0, dev_name(&pdev->dev), dmadev);
if (ret) {
dev_err(&pdev->dev, "failed to request IRQ\n");
goto err_clk;
}
ret = dmaenginem_async_device_register(dd);
if (ret)
goto err_clk;
ret = of_dma_controller_register(of_node, stm32_mdma_of_xlate, dmadev);
if (ret < 0) {
dev_err(&pdev->dev,
"STM32 MDMA DMA OF registration failed %d\n", ret);
goto err_clk;
}
platform_set_drvdata(pdev, dmadev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_put(&pdev->dev);
dev_info(&pdev->dev, "STM32 MDMA driver registered\n");
return 0;
err_clk:
clk_disable_unprepare(dmadev->clk);
return ret;
}