in sun6i-dma.c [1258:1446]
static int sun6i_dma_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct sun6i_dma_dev *sdc;
struct resource *res;
int ret, i;
sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL);
if (!sdc)
return -ENOMEM;
sdc->cfg = of_device_get_match_data(&pdev->dev);
if (!sdc->cfg)
return -ENODEV;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sdc->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(sdc->base))
return PTR_ERR(sdc->base);
sdc->irq = platform_get_irq(pdev, 0);
if (sdc->irq < 0)
return sdc->irq;
sdc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(sdc->clk)) {
dev_err(&pdev->dev, "No clock specified\n");
return PTR_ERR(sdc->clk);
}
if (sdc->cfg->has_mbus_clk) {
sdc->clk_mbus = devm_clk_get(&pdev->dev, "mbus");
if (IS_ERR(sdc->clk_mbus)) {
dev_err(&pdev->dev, "No mbus clock specified\n");
return PTR_ERR(sdc->clk_mbus);
}
}
sdc->rstc = devm_reset_control_get(&pdev->dev, NULL);
if (IS_ERR(sdc->rstc)) {
dev_err(&pdev->dev, "No reset controller specified\n");
return PTR_ERR(sdc->rstc);
}
sdc->pool = dmam_pool_create(dev_name(&pdev->dev), &pdev->dev,
sizeof(struct sun6i_dma_lli), 4, 0);
if (!sdc->pool) {
dev_err(&pdev->dev, "No memory for descriptors dma pool\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, sdc);
INIT_LIST_HEAD(&sdc->pending);
spin_lock_init(&sdc->lock);
dma_cap_set(DMA_PRIVATE, sdc->slave.cap_mask);
dma_cap_set(DMA_MEMCPY, sdc->slave.cap_mask);
dma_cap_set(DMA_SLAVE, sdc->slave.cap_mask);
dma_cap_set(DMA_CYCLIC, sdc->slave.cap_mask);
INIT_LIST_HEAD(&sdc->slave.channels);
sdc->slave.device_free_chan_resources = sun6i_dma_free_chan_resources;
sdc->slave.device_tx_status = sun6i_dma_tx_status;
sdc->slave.device_issue_pending = sun6i_dma_issue_pending;
sdc->slave.device_prep_slave_sg = sun6i_dma_prep_slave_sg;
sdc->slave.device_prep_dma_memcpy = sun6i_dma_prep_dma_memcpy;
sdc->slave.device_prep_dma_cyclic = sun6i_dma_prep_dma_cyclic;
sdc->slave.copy_align = DMAENGINE_ALIGN_4_BYTES;
sdc->slave.device_config = sun6i_dma_config;
sdc->slave.device_pause = sun6i_dma_pause;
sdc->slave.device_resume = sun6i_dma_resume;
sdc->slave.device_terminate_all = sun6i_dma_terminate_all;
sdc->slave.src_addr_widths = sdc->cfg->src_addr_widths;
sdc->slave.dst_addr_widths = sdc->cfg->dst_addr_widths;
sdc->slave.directions = BIT(DMA_DEV_TO_MEM) |
BIT(DMA_MEM_TO_DEV);
sdc->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
sdc->slave.dev = &pdev->dev;
sdc->num_pchans = sdc->cfg->nr_max_channels;
sdc->num_vchans = sdc->cfg->nr_max_vchans;
sdc->max_request = sdc->cfg->nr_max_requests;
ret = of_property_read_u32(np, "dma-channels", &sdc->num_pchans);
if (ret && !sdc->num_pchans) {
dev_err(&pdev->dev, "Can't get dma-channels.\n");
return ret;
}
ret = of_property_read_u32(np, "dma-requests", &sdc->max_request);
if (ret && !sdc->max_request) {
dev_info(&pdev->dev, "Missing dma-requests, using %u.\n",
DMA_CHAN_MAX_DRQ_A31);
sdc->max_request = DMA_CHAN_MAX_DRQ_A31;
}
/*
* If the number of vchans is not specified, derive it from the
* highest port number, at most one channel per port and direction.
*/
if (!sdc->num_vchans)
sdc->num_vchans = 2 * (sdc->max_request + 1);
sdc->pchans = devm_kcalloc(&pdev->dev, sdc->num_pchans,
sizeof(struct sun6i_pchan), GFP_KERNEL);
if (!sdc->pchans)
return -ENOMEM;
sdc->vchans = devm_kcalloc(&pdev->dev, sdc->num_vchans,
sizeof(struct sun6i_vchan), GFP_KERNEL);
if (!sdc->vchans)
return -ENOMEM;
tasklet_setup(&sdc->task, sun6i_dma_tasklet);
for (i = 0; i < sdc->num_pchans; i++) {
struct sun6i_pchan *pchan = &sdc->pchans[i];
pchan->idx = i;
pchan->base = sdc->base + 0x100 + i * 0x40;
}
for (i = 0; i < sdc->num_vchans; i++) {
struct sun6i_vchan *vchan = &sdc->vchans[i];
INIT_LIST_HEAD(&vchan->node);
vchan->vc.desc_free = sun6i_dma_free_desc;
vchan_init(&vchan->vc, &sdc->slave);
}
ret = reset_control_deassert(sdc->rstc);
if (ret) {
dev_err(&pdev->dev, "Couldn't deassert the device from reset\n");
goto err_chan_free;
}
ret = clk_prepare_enable(sdc->clk);
if (ret) {
dev_err(&pdev->dev, "Couldn't enable the clock\n");
goto err_reset_assert;
}
if (sdc->cfg->has_mbus_clk) {
ret = clk_prepare_enable(sdc->clk_mbus);
if (ret) {
dev_err(&pdev->dev, "Couldn't enable mbus clock\n");
goto err_clk_disable;
}
}
ret = devm_request_irq(&pdev->dev, sdc->irq, sun6i_dma_interrupt, 0,
dev_name(&pdev->dev), sdc);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
goto err_mbus_clk_disable;
}
ret = dma_async_device_register(&sdc->slave);
if (ret) {
dev_warn(&pdev->dev, "Failed to register DMA engine device\n");
goto err_irq_disable;
}
ret = of_dma_controller_register(pdev->dev.of_node, sun6i_dma_of_xlate,
sdc);
if (ret) {
dev_err(&pdev->dev, "of_dma_controller_register failed\n");
goto err_dma_unregister;
}
if (sdc->cfg->clock_autogate_enable)
sdc->cfg->clock_autogate_enable(sdc);
return 0;
err_dma_unregister:
dma_async_device_unregister(&sdc->slave);
err_irq_disable:
sun6i_kill_tasklet(sdc);
err_mbus_clk_disable:
clk_disable_unprepare(sdc->clk_mbus);
err_clk_disable:
clk_disable_unprepare(sdc->clk);
err_reset_assert:
reset_control_assert(sdc->rstc);
err_chan_free:
sun6i_dma_free(sdc);
return ret;
}