static int k3_dma_probe()

in k3dma.c [838:975]


static int k3_dma_probe(struct platform_device *op)
{
	const struct k3dma_soc_data *soc_data;
	struct k3_dma_dev *d;
	const struct of_device_id *of_id;
	int i, ret, irq = 0;

	d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL);
	if (!d)
		return -ENOMEM;

	soc_data = device_get_match_data(&op->dev);
	if (!soc_data)
		return -EINVAL;

	d->base = devm_platform_ioremap_resource(op, 0);
	if (IS_ERR(d->base))
		return PTR_ERR(d->base);

	of_id = of_match_device(k3_pdma_dt_ids, &op->dev);
	if (of_id) {
		of_property_read_u32((&op->dev)->of_node,
				"dma-channels", &d->dma_channels);
		of_property_read_u32((&op->dev)->of_node,
				"dma-requests", &d->dma_requests);
		ret = of_property_read_u32((&op->dev)->of_node,
				"dma-channel-mask", &d->dma_channel_mask);
		if (ret) {
			dev_warn(&op->dev,
				 "dma-channel-mask doesn't exist, considering all as available.\n");
			d->dma_channel_mask = (u32)~0UL;
		}
	}

	if (!(soc_data->flags & K3_FLAG_NOCLK)) {
		d->clk = devm_clk_get(&op->dev, NULL);
		if (IS_ERR(d->clk)) {
			dev_err(&op->dev, "no dma clk\n");
			return PTR_ERR(d->clk);
		}
	}

	irq = platform_get_irq(op, 0);
	ret = devm_request_irq(&op->dev, irq,
			k3_dma_int_handler, 0, DRIVER_NAME, d);
	if (ret)
		return ret;

	d->irq = irq;

	/* A DMA memory pool for LLIs, align on 32-byte boundary */
	d->pool = dmam_pool_create(DRIVER_NAME, &op->dev,
					LLI_BLOCK_SIZE, 32, 0);
	if (!d->pool)
		return -ENOMEM;

	/* init phy channel */
	d->phy = devm_kcalloc(&op->dev,
		d->dma_channels, sizeof(struct k3_dma_phy), GFP_KERNEL);
	if (d->phy == NULL)
		return -ENOMEM;

	for (i = 0; i < d->dma_channels; i++) {
		struct k3_dma_phy *p;

		if (!(d->dma_channel_mask & BIT(i)))
			continue;

		p = &d->phy[i];
		p->idx = i;
		p->base = d->base + i * 0x40;
	}

	INIT_LIST_HEAD(&d->slave.channels);
	dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
	dma_cap_set(DMA_MEMCPY, d->slave.cap_mask);
	dma_cap_set(DMA_CYCLIC, d->slave.cap_mask);
	d->slave.dev = &op->dev;
	d->slave.device_free_chan_resources = k3_dma_free_chan_resources;
	d->slave.device_tx_status = k3_dma_tx_status;
	d->slave.device_prep_dma_memcpy = k3_dma_prep_memcpy;
	d->slave.device_prep_slave_sg = k3_dma_prep_slave_sg;
	d->slave.device_prep_dma_cyclic = k3_dma_prep_dma_cyclic;
	d->slave.device_issue_pending = k3_dma_issue_pending;
	d->slave.device_config = k3_dma_config;
	d->slave.device_pause = k3_dma_transfer_pause;
	d->slave.device_resume = k3_dma_transfer_resume;
	d->slave.device_terminate_all = k3_dma_terminate_all;
	d->slave.device_synchronize = k3_dma_synchronize;
	d->slave.copy_align = DMAENGINE_ALIGN_8_BYTES;

	/* init virtual channel */
	d->chans = devm_kcalloc(&op->dev,
		d->dma_requests, sizeof(struct k3_dma_chan), GFP_KERNEL);
	if (d->chans == NULL)
		return -ENOMEM;

	for (i = 0; i < d->dma_requests; i++) {
		struct k3_dma_chan *c = &d->chans[i];

		c->status = DMA_IN_PROGRESS;
		INIT_LIST_HEAD(&c->node);
		c->vc.desc_free = k3_dma_free_desc;
		vchan_init(&c->vc, &d->slave);
	}

	/* Enable clock before accessing registers */
	ret = clk_prepare_enable(d->clk);
	if (ret < 0) {
		dev_err(&op->dev, "clk_prepare_enable failed: %d\n", ret);
		return ret;
	}

	k3_dma_enable_dma(d, true);

	ret = dma_async_device_register(&d->slave);
	if (ret)
		goto dma_async_register_fail;

	ret = of_dma_controller_register((&op->dev)->of_node,
					k3_of_dma_simple_xlate, d);
	if (ret)
		goto of_dma_register_fail;

	spin_lock_init(&d->lock);
	INIT_LIST_HEAD(&d->chan_pending);
	tasklet_setup(&d->task, k3_dma_tasklet);
	platform_set_drvdata(op, d);
	dev_info(&op->dev, "initialized\n");

	return 0;

of_dma_register_fail:
	dma_async_device_unregister(&d->slave);
dma_async_register_fail:
	clk_disable_unprepare(d->clk);
	return ret;
}