static int hidma_probe()

in qcom/hidma.c [742:896]


static int hidma_probe(struct platform_device *pdev)
{
	struct hidma_dev *dmadev;
	struct resource *trca_resource;
	struct resource *evca_resource;
	int chirq;
	void __iomem *evca;
	void __iomem *trca;
	int rc;
	bool msi;

	pm_runtime_set_autosuspend_delay(&pdev->dev, HIDMA_AUTOSUSPEND_TIMEOUT);
	pm_runtime_use_autosuspend(&pdev->dev);
	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(&pdev->dev);

	trca_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	trca = devm_ioremap_resource(&pdev->dev, trca_resource);
	if (IS_ERR(trca)) {
		rc = -ENOMEM;
		goto bailout;
	}

	evca_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	evca = devm_ioremap_resource(&pdev->dev, evca_resource);
	if (IS_ERR(evca)) {
		rc = -ENOMEM;
		goto bailout;
	}

	/*
	 * This driver only handles the channel IRQs.
	 * Common IRQ is handled by the management driver.
	 */
	chirq = platform_get_irq(pdev, 0);
	if (chirq < 0) {
		rc = -ENODEV;
		goto bailout;
	}

	dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev), GFP_KERNEL);
	if (!dmadev) {
		rc = -ENOMEM;
		goto bailout;
	}

	INIT_LIST_HEAD(&dmadev->ddev.channels);
	spin_lock_init(&dmadev->lock);
	dmadev->ddev.dev = &pdev->dev;
	pm_runtime_get_sync(dmadev->ddev.dev);

	dma_cap_set(DMA_MEMCPY, dmadev->ddev.cap_mask);
	dma_cap_set(DMA_MEMSET, dmadev->ddev.cap_mask);
	if (WARN_ON(!pdev->dev.dma_mask)) {
		rc = -ENXIO;
		goto dmafree;
	}

	dmadev->dev_evca = evca;
	dmadev->evca_resource = evca_resource;
	dmadev->dev_trca = trca;
	dmadev->trca_resource = trca_resource;
	dmadev->ddev.device_prep_dma_memcpy = hidma_prep_dma_memcpy;
	dmadev->ddev.device_prep_dma_memset = hidma_prep_dma_memset;
	dmadev->ddev.device_alloc_chan_resources = hidma_alloc_chan_resources;
	dmadev->ddev.device_free_chan_resources = hidma_free_chan_resources;
	dmadev->ddev.device_tx_status = hidma_tx_status;
	dmadev->ddev.device_issue_pending = hidma_issue_pending;
	dmadev->ddev.device_pause = hidma_pause;
	dmadev->ddev.device_resume = hidma_resume;
	dmadev->ddev.device_terminate_all = hidma_terminate_all;
	dmadev->ddev.copy_align = 8;

	/*
	 * Determine the MSI capability of the platform. Old HW doesn't
	 * support MSI.
	 */
	msi = hidma_test_capability(&pdev->dev, HIDMA_MSI_CAP);
	device_property_read_u32(&pdev->dev, "desc-count",
				 &dmadev->nr_descriptors);

	if (nr_desc_prm) {
		dev_info(&pdev->dev, "overriding number of descriptors as %d\n",
			 nr_desc_prm);
		dmadev->nr_descriptors = nr_desc_prm;
	}

	if (!dmadev->nr_descriptors)
		dmadev->nr_descriptors = HIDMA_NR_DEFAULT_DESC;

	if (hidma_test_capability(&pdev->dev, HIDMA_IDENTITY_CAP))
		dmadev->chidx = readl(dmadev->dev_trca + 0x40);
	else
		dmadev->chidx = readl(dmadev->dev_trca + 0x28);

	/* Set DMA mask to 64 bits. */
	rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
	if (rc) {
		dev_warn(&pdev->dev, "unable to set coherent mask to 64");
		rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
		if (rc)
			goto dmafree;
	}

	dmadev->lldev = hidma_ll_init(dmadev->ddev.dev,
				      dmadev->nr_descriptors, dmadev->dev_trca,
				      dmadev->dev_evca, dmadev->chidx);
	if (!dmadev->lldev) {
		rc = -EPROBE_DEFER;
		goto dmafree;
	}

	platform_set_drvdata(pdev, dmadev);
	if (msi)
		rc = hidma_request_msi(dmadev, pdev);

	if (!msi || rc) {
		hidma_ll_setup_irq(dmadev->lldev, false);
		rc = devm_request_irq(&pdev->dev, chirq, hidma_chirq_handler,
				      0, "qcom-hidma", dmadev->lldev);
		if (rc)
			goto uninit;
	}

	INIT_LIST_HEAD(&dmadev->ddev.channels);
	rc = hidma_chan_init(dmadev, 0);
	if (rc)
		goto uninit;

	rc = dma_async_device_register(&dmadev->ddev);
	if (rc)
		goto uninit;

	dmadev->irq = chirq;
	tasklet_setup(&dmadev->task, hidma_issue_task);
	hidma_debug_init(dmadev);
	hidma_sysfs_init(dmadev);
	dev_info(&pdev->dev, "HI-DMA engine driver registration complete\n");
	pm_runtime_mark_last_busy(dmadev->ddev.dev);
	pm_runtime_put_autosuspend(dmadev->ddev.dev);
	return 0;

uninit:
	if (msi)
		hidma_free_msis(dmadev);

	hidma_ll_uninit(dmadev->lldev);
dmafree:
	if (dmadev)
		hidma_free(dmadev);
bailout:
	pm_runtime_put_sync(&pdev->dev);
	pm_runtime_disable(&pdev->dev);
	return rc;
}