static int __init d40_probe()

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