in tegra20-apb-dma.c [1439:1588]
static int tegra_dma_probe(struct platform_device *pdev)
{
const struct tegra_dma_chip_data *cdata;
struct tegra_dma *tdma;
unsigned int i;
size_t size;
int ret;
cdata = of_device_get_match_data(&pdev->dev);
size = struct_size(tdma, channels, cdata->nr_channels);
tdma = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (!tdma)
return -ENOMEM;
tdma->dev = &pdev->dev;
tdma->chip_data = cdata;
platform_set_drvdata(pdev, tdma);
tdma->base_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(tdma->base_addr))
return PTR_ERR(tdma->base_addr);
tdma->dma_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(tdma->dma_clk)) {
dev_err(&pdev->dev, "Error: Missing controller clock\n");
return PTR_ERR(tdma->dma_clk);
}
tdma->rst = devm_reset_control_get(&pdev->dev, "dma");
if (IS_ERR(tdma->rst)) {
dev_err(&pdev->dev, "Error: Missing reset\n");
return PTR_ERR(tdma->rst);
}
spin_lock_init(&tdma->global_lock);
ret = clk_prepare(tdma->dma_clk);
if (ret)
return ret;
ret = tegra_dma_init_hw(tdma);
if (ret)
goto err_clk_unprepare;
pm_runtime_irq_safe(&pdev->dev);
pm_runtime_enable(&pdev->dev);
INIT_LIST_HEAD(&tdma->dma_dev.channels);
for (i = 0; i < cdata->nr_channels; i++) {
struct tegra_dma_channel *tdc = &tdma->channels[i];
int irq;
tdc->chan_addr = tdma->base_addr +
TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET +
(i * cdata->channel_reg_size);
irq = platform_get_irq(pdev, i);
if (irq < 0) {
ret = irq;
goto err_pm_disable;
}
snprintf(tdc->name, sizeof(tdc->name), "apbdma.%d", i);
ret = devm_request_irq(&pdev->dev, irq, tegra_dma_isr, 0,
tdc->name, tdc);
if (ret) {
dev_err(&pdev->dev,
"request_irq failed with err %d channel %d\n",
ret, i);
goto err_pm_disable;
}
tdc->dma_chan.device = &tdma->dma_dev;
dma_cookie_init(&tdc->dma_chan);
list_add_tail(&tdc->dma_chan.device_node,
&tdma->dma_dev.channels);
tdc->tdma = tdma;
tdc->id = i;
tdc->slave_id = TEGRA_APBDMA_SLAVE_ID_INVALID;
tasklet_setup(&tdc->tasklet, tegra_dma_tasklet);
spin_lock_init(&tdc->lock);
init_waitqueue_head(&tdc->wq);
INIT_LIST_HEAD(&tdc->pending_sg_req);
INIT_LIST_HEAD(&tdc->free_sg_req);
INIT_LIST_HEAD(&tdc->free_dma_desc);
INIT_LIST_HEAD(&tdc->cb_desc);
}
dma_cap_set(DMA_SLAVE, tdma->dma_dev.cap_mask);
dma_cap_set(DMA_PRIVATE, tdma->dma_dev.cap_mask);
dma_cap_set(DMA_CYCLIC, tdma->dma_dev.cap_mask);
tdma->global_pause_count = 0;
tdma->dma_dev.dev = &pdev->dev;
tdma->dma_dev.device_alloc_chan_resources =
tegra_dma_alloc_chan_resources;
tdma->dma_dev.device_free_chan_resources =
tegra_dma_free_chan_resources;
tdma->dma_dev.device_prep_slave_sg = tegra_dma_prep_slave_sg;
tdma->dma_dev.device_prep_dma_cyclic = tegra_dma_prep_dma_cyclic;
tdma->dma_dev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
tdma->dma_dev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
tdma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
tdma->dma_dev.device_config = tegra_dma_slave_config;
tdma->dma_dev.device_terminate_all = tegra_dma_terminate_all;
tdma->dma_dev.device_synchronize = tegra_dma_synchronize;
tdma->dma_dev.device_tx_status = tegra_dma_tx_status;
tdma->dma_dev.device_issue_pending = tegra_dma_issue_pending;
ret = dma_async_device_register(&tdma->dma_dev);
if (ret < 0) {
dev_err(&pdev->dev,
"Tegra20 APB DMA driver registration failed %d\n", ret);
goto err_pm_disable;
}
ret = of_dma_controller_register(pdev->dev.of_node,
tegra_dma_of_xlate, tdma);
if (ret < 0) {
dev_err(&pdev->dev,
"Tegra20 APB DMA OF registration failed %d\n", ret);
goto err_unregister_dma_dev;
}
dev_info(&pdev->dev, "Tegra20 APB DMA driver registered %u channels\n",
cdata->nr_channels);
return 0;
err_unregister_dma_dev:
dma_async_device_unregister(&tdma->dma_dev);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
err_clk_unprepare:
clk_unprepare(tdma->dma_clk);
return ret;
}