in ste_dma40.c [3505:3705]
static int __init d40_probe(struct platform_device *pdev)
{
struct stedma40_platform_data *plat_data = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
int ret = -ENOENT;
struct d40_base *base;
struct resource *res;
int num_reserved_chans;
u32 val;
if (!plat_data) {
if (np) {
if (d40_of_probe(pdev, np)) {
ret = -ENOMEM;
goto report_failure;
}
} else {
d40_err(&pdev->dev, "No pdata or Device Tree provided\n");
goto report_failure;
}
}
base = d40_hw_detect_init(pdev);
if (!base)
goto report_failure;
num_reserved_chans = d40_phy_res_init(base);
platform_set_drvdata(pdev, base);
spin_lock_init(&base->interrupt_lock);
spin_lock_init(&base->execmd_lock);
/* Get IO for logical channel parameter address */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lcpa");
if (!res) {
ret = -ENOENT;
d40_err(&pdev->dev, "No \"lcpa\" memory resource\n");
goto destroy_cache;
}
base->lcpa_size = resource_size(res);
base->phy_lcpa = res->start;
if (request_mem_region(res->start, resource_size(res),
D40_NAME " I/O lcpa") == NULL) {
ret = -EBUSY;
d40_err(&pdev->dev, "Failed to request LCPA region %pR\n", res);
goto destroy_cache;
}
/* We make use of ESRAM memory for this. */
val = readl(base->virtbase + D40_DREG_LCPA);
if (res->start != val && val != 0) {
dev_warn(&pdev->dev,
"[%s] Mismatch LCPA dma 0x%x, def %pa\n",
__func__, val, &res->start);
} else
writel(res->start, base->virtbase + D40_DREG_LCPA);
base->lcpa_base = ioremap(res->start, resource_size(res));
if (!base->lcpa_base) {
ret = -ENOMEM;
d40_err(&pdev->dev, "Failed to ioremap LCPA region\n");
goto destroy_cache;
}
/* If lcla has to be located in ESRAM we don't need to allocate */
if (base->plat_data->use_esram_lcla) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"lcla_esram");
if (!res) {
ret = -ENOENT;
d40_err(&pdev->dev,
"No \"lcla_esram\" memory resource\n");
goto destroy_cache;
}
base->lcla_pool.base = ioremap(res->start,
resource_size(res));
if (!base->lcla_pool.base) {
ret = -ENOMEM;
d40_err(&pdev->dev, "Failed to ioremap LCLA region\n");
goto destroy_cache;
}
writel(res->start, base->virtbase + D40_DREG_LCLA);
} else {
ret = d40_lcla_allocate(base);
if (ret) {
d40_err(&pdev->dev, "Failed to allocate LCLA area\n");
goto destroy_cache;
}
}
spin_lock_init(&base->lcla_pool.lock);
base->irq = platform_get_irq(pdev, 0);
ret = request_irq(base->irq, d40_handle_interrupt, 0, D40_NAME, base);
if (ret) {
d40_err(&pdev->dev, "No IRQ defined\n");
goto destroy_cache;
}
if (base->plat_data->use_esram_lcla) {
base->lcpa_regulator = regulator_get(base->dev, "lcla_esram");
if (IS_ERR(base->lcpa_regulator)) {
d40_err(&pdev->dev, "Failed to get lcpa_regulator\n");
ret = PTR_ERR(base->lcpa_regulator);
base->lcpa_regulator = NULL;
goto destroy_cache;
}
ret = regulator_enable(base->lcpa_regulator);
if (ret) {
d40_err(&pdev->dev,
"Failed to enable lcpa_regulator\n");
regulator_put(base->lcpa_regulator);
base->lcpa_regulator = NULL;
goto destroy_cache;
}
}
writel_relaxed(D40_DREG_GCC_ENABLE_ALL, base->virtbase + D40_DREG_GCC);
pm_runtime_irq_safe(base->dev);
pm_runtime_set_autosuspend_delay(base->dev, DMA40_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(base->dev);
pm_runtime_mark_last_busy(base->dev);
pm_runtime_set_active(base->dev);
pm_runtime_enable(base->dev);
ret = d40_dmaengine_init(base, num_reserved_chans);
if (ret)
goto destroy_cache;
ret = dma_set_max_seg_size(base->dev, STEDMA40_MAX_SEG_SIZE);
if (ret) {
d40_err(&pdev->dev, "Failed to set dma max seg size\n");
goto destroy_cache;
}
d40_hw_init(base);
if (np) {
ret = of_dma_controller_register(np, d40_xlate, NULL);
if (ret)
dev_err(&pdev->dev,
"could not register of_dma_controller\n");
}
dev_info(base->dev, "initialized\n");
return 0;
destroy_cache:
kmem_cache_destroy(base->desc_slab);
if (base->virtbase)
iounmap(base->virtbase);
if (base->lcla_pool.base && base->plat_data->use_esram_lcla) {
iounmap(base->lcla_pool.base);
base->lcla_pool.base = NULL;
}
if (base->lcla_pool.dma_addr)
dma_unmap_single(base->dev, base->lcla_pool.dma_addr,
SZ_1K * base->num_phy_chans,
DMA_TO_DEVICE);
if (!base->lcla_pool.base_unaligned && base->lcla_pool.base)
free_pages((unsigned long)base->lcla_pool.base,
base->lcla_pool.pages);
kfree(base->lcla_pool.base_unaligned);
if (base->lcpa_base)
iounmap(base->lcpa_base);
if (base->phy_lcpa)
release_mem_region(base->phy_lcpa,
base->lcpa_size);
if (base->phy_start)
release_mem_region(base->phy_start,
base->phy_size);
if (base->clk) {
clk_disable_unprepare(base->clk);
clk_put(base->clk);
}
if (base->lcpa_regulator) {
regulator_disable(base->lcpa_regulator);
regulator_put(base->lcpa_regulator);
}
kfree(base->lcla_pool.alloc_map);
kfree(base->lookup_log_chans);
kfree(base->lookup_phy_chans);
kfree(base->phy_res);
kfree(base);
report_failure:
d40_err(&pdev->dev, "probe failed\n");
return ret;
}