aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2013-11-11 15:09:35 -0500
committerStephen Warren <swarren@nvidia.com>2013-12-11 18:43:27 -0500
commit996556c92a706058cf5ce6b3ef8dacc4032a3e0d (patch)
tree8a0df4fe6165488e9f1f218cea50cc5043d1a277
parent9aa433d2a77220fc261cb8248bb93bdd8e3944ef (diff)
dma: tegra: register as an OF DMA controller
Call of_dma_controller_register() so that DMA clients can look up the Tegra DMA controller using standard APIs. This requires the of_xlate() function to save off the DMA slave ID, and for tegra_dma_slave_config() not to over-write this information; once DMA client drivers are converted to dma_request_slave_channel() and DT-based lookups, they won't set this field of struct dma_slave_config anymore. Signed-off-by: Stephen Warren <swarren@nvidia.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Reviewed-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/dma/tegra20-apb-dma.c39
1 files changed, 36 insertions, 3 deletions
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index afa5844c9346..d11bb3620f27 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * DMA driver for Nvidia's Tegra20 APB DMA controller. 2 * DMA driver for Nvidia's Tegra20 APB DMA controller.
3 * 3 *
4 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 4 * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved.
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify it 6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License, 7 * under the terms and conditions of the GNU General Public License,
@@ -29,6 +29,7 @@
29#include <linux/module.h> 29#include <linux/module.h>
30#include <linux/of.h> 30#include <linux/of.h>
31#include <linux/of_device.h> 31#include <linux/of_device.h>
32#include <linux/of_dma.h>
32#include <linux/platform_device.h> 33#include <linux/platform_device.h>
33#include <linux/pm.h> 34#include <linux/pm.h>
34#include <linux/pm_runtime.h> 35#include <linux/pm_runtime.h>
@@ -199,6 +200,7 @@ struct tegra_dma_channel {
199 void *callback_param; 200 void *callback_param;
200 201
201 /* Channel-slave specific configuration */ 202 /* Channel-slave specific configuration */
203 unsigned int slave_id;
202 struct dma_slave_config dma_sconfig; 204 struct dma_slave_config dma_sconfig;
203 struct tegra_dma_channel_regs channel_reg; 205 struct tegra_dma_channel_regs channel_reg;
204}; 206};
@@ -340,6 +342,8 @@ static int tegra_dma_slave_config(struct dma_chan *dc,
340 } 342 }
341 343
342 memcpy(&tdc->dma_sconfig, sconfig, sizeof(*sconfig)); 344 memcpy(&tdc->dma_sconfig, sconfig, sizeof(*sconfig));
345 if (!tdc->slave_id)
346 tdc->slave_id = sconfig->slave_id;
343 tdc->config_init = true; 347 tdc->config_init = true;
344 return 0; 348 return 0;
345} 349}
@@ -942,7 +946,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
942 ahb_seq |= TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_32; 946 ahb_seq |= TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_32;
943 947
944 csr |= TEGRA_APBDMA_CSR_ONCE | TEGRA_APBDMA_CSR_FLOW; 948 csr |= TEGRA_APBDMA_CSR_ONCE | TEGRA_APBDMA_CSR_FLOW;
945 csr |= tdc->dma_sconfig.slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT; 949 csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
946 if (flags & DMA_PREP_INTERRUPT) 950 if (flags & DMA_PREP_INTERRUPT)
947 csr |= TEGRA_APBDMA_CSR_IE_EOC; 951 csr |= TEGRA_APBDMA_CSR_IE_EOC;
948 952
@@ -1086,7 +1090,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
1086 csr |= TEGRA_APBDMA_CSR_FLOW; 1090 csr |= TEGRA_APBDMA_CSR_FLOW;
1087 if (flags & DMA_PREP_INTERRUPT) 1091 if (flags & DMA_PREP_INTERRUPT)
1088 csr |= TEGRA_APBDMA_CSR_IE_EOC; 1092 csr |= TEGRA_APBDMA_CSR_IE_EOC;
1089 csr |= tdc->dma_sconfig.slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT; 1093 csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
1090 1094
1091 apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1; 1095 apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1;
1092 1096
@@ -1206,6 +1210,25 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
1206 kfree(sg_req); 1210 kfree(sg_req);
1207 } 1211 }
1208 clk_disable_unprepare(tdma->dma_clk); 1212 clk_disable_unprepare(tdma->dma_clk);
1213
1214 tdc->slave_id = 0;
1215}
1216
1217static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
1218 struct of_dma *ofdma)
1219{
1220 struct tegra_dma *tdma = ofdma->of_dma_data;
1221 struct dma_chan *chan;
1222 struct tegra_dma_channel *tdc;
1223
1224 chan = dma_get_any_slave_channel(&tdma->dma_dev);
1225 if (!chan)
1226 return NULL;
1227
1228 tdc = to_tegra_dma_chan(chan);
1229 tdc->slave_id = dma_spec->args[0];
1230
1231 return chan;
1209} 1232}
1210 1233
1211/* Tegra20 specific DMA controller information */ 1234/* Tegra20 specific DMA controller information */
@@ -1383,10 +1406,20 @@ static int tegra_dma_probe(struct platform_device *pdev)
1383 goto err_irq; 1406 goto err_irq;
1384 } 1407 }
1385 1408
1409 ret = of_dma_controller_register(pdev->dev.of_node,
1410 tegra_dma_of_xlate, tdma);
1411 if (ret < 0) {
1412 dev_err(&pdev->dev,
1413 "Tegra20 APB DMA OF registration failed %d\n", ret);
1414 goto err_unregister_dma_dev;
1415 }
1416
1386 dev_info(&pdev->dev, "Tegra20 APB DMA driver register %d channels\n", 1417 dev_info(&pdev->dev, "Tegra20 APB DMA driver register %d channels\n",
1387 cdata->nr_channels); 1418 cdata->nr_channels);
1388 return 0; 1419 return 0;
1389 1420
1421err_unregister_dma_dev:
1422 dma_async_device_unregister(&tdma->dma_dev);
1390err_irq: 1423err_irq:
1391 while (--i >= 0) { 1424 while (--i >= 0) {
1392 struct tegra_dma_channel *tdc = &tdma->channels[i]; 1425 struct tegra_dma_channel *tdc = &tdma->channels[i];