aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/sh
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2013-06-18 12:16:57 -0400
committerVinod Koul <vinod.koul@intel.com>2013-07-05 02:11:00 -0400
commit67eacc1583909d0588c8d5d80c16298c899a6382 (patch)
tree093794f972e21cf084efcb734667453db1c68926 /drivers/dma/sh
parentd0951a23383d09276f7976ed34d8f1cede629b48 (diff)
DMA: shdma: add DT support
This patch adds Device Tree support to the shdma driver. No special DT properties are used, only standard DMA DT bindings are implemented. Since shdma controllers reside on SoCs, their configuration is SoC-specific and shall be passed to the driver from the SoC platform data, using the auxdata procedure. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski+renesas@gmail.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma/sh')
-rw-r--r--drivers/dma/sh/Makefile2
-rw-r--r--drivers/dma/sh/shdma-base.c26
-rw-r--r--drivers/dma/sh/shdma-of.c82
-rw-r--r--drivers/dma/sh/shdma.c31
4 files changed, 128 insertions, 13 deletions
diff --git a/drivers/dma/sh/Makefile b/drivers/dma/sh/Makefile
index c07ca4612e46..c962138dde96 100644
--- a/drivers/dma/sh/Makefile
+++ b/drivers/dma/sh/Makefile
@@ -1,3 +1,3 @@
1obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o 1obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.o
2obj-$(CONFIG_SH_DMAE) += shdma.o 2obj-$(CONFIG_SH_DMAE) += shdma.o
3obj-$(CONFIG_SUDMAC) += sudmac.o 3obj-$(CONFIG_SUDMAC) += sudmac.o
diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c
index 4acb85a10250..28ca36121631 100644
--- a/drivers/dma/sh/shdma-base.c
+++ b/drivers/dma/sh/shdma-base.c
@@ -175,7 +175,18 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
175{ 175{
176 struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device); 176 struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
177 const struct shdma_ops *ops = sdev->ops; 177 const struct shdma_ops *ops = sdev->ops;
178 int ret; 178 int ret, match;
179
180 if (schan->dev->of_node) {
181 match = schan->hw_req;
182 ret = ops->set_slave(schan, match, true);
183 if (ret < 0)
184 return ret;
185
186 slave_id = schan->slave_id;
187 } else {
188 match = slave_id;
189 }
179 190
180 if (slave_id < 0 || slave_id >= slave_num) 191 if (slave_id < 0 || slave_id >= slave_num)
181 return -EINVAL; 192 return -EINVAL;
@@ -183,7 +194,7 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
183 if (test_and_set_bit(slave_id, shdma_slave_used)) 194 if (test_and_set_bit(slave_id, shdma_slave_used))
184 return -EBUSY; 195 return -EBUSY;
185 196
186 ret = ops->set_slave(schan, slave_id, false); 197 ret = ops->set_slave(schan, match, false);
187 if (ret < 0) { 198 if (ret < 0) {
188 clear_bit(slave_id, shdma_slave_used); 199 clear_bit(slave_id, shdma_slave_used);
189 return ret; 200 return ret;
@@ -206,23 +217,26 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
206 * services would have to provide their own filters, which first would check 217 * services would have to provide their own filters, which first would check
207 * the device driver, similar to how other DMAC drivers, e.g., sa11x0-dma.c, do 218 * the device driver, similar to how other DMAC drivers, e.g., sa11x0-dma.c, do
208 * this, and only then, in case of a match, call this common filter. 219 * this, and only then, in case of a match, call this common filter.
220 * NOTE 2: This filter function is also used in the DT case by shdma_of_xlate().
221 * In that case the MID-RID value is used for slave channel filtering and is
222 * passed to this function in the "arg" parameter.
209 */ 223 */
210bool shdma_chan_filter(struct dma_chan *chan, void *arg) 224bool shdma_chan_filter(struct dma_chan *chan, void *arg)
211{ 225{
212 struct shdma_chan *schan = to_shdma_chan(chan); 226 struct shdma_chan *schan = to_shdma_chan(chan);
213 struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device); 227 struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
214 const struct shdma_ops *ops = sdev->ops; 228 const struct shdma_ops *ops = sdev->ops;
215 int slave_id = (int)arg; 229 int match = (int)arg;
216 int ret; 230 int ret;
217 231
218 if (slave_id < 0) 232 if (match < 0)
219 /* No slave requested - arbitrary channel */ 233 /* No slave requested - arbitrary channel */
220 return true; 234 return true;
221 235
222 if (slave_id >= slave_num) 236 if (!schan->dev->of_node && match >= slave_num)
223 return false; 237 return false;
224 238
225 ret = ops->set_slave(schan, slave_id, true); 239 ret = ops->set_slave(schan, match, true);
226 if (ret < 0) 240 if (ret < 0)
227 return false; 241 return false;
228 242
diff --git a/drivers/dma/sh/shdma-of.c b/drivers/dma/sh/shdma-of.c
new file mode 100644
index 000000000000..11bcb05cd79c
--- /dev/null
+++ b/drivers/dma/sh/shdma-of.c
@@ -0,0 +1,82 @@
1/*
2 * SHDMA Device Tree glue
3 *
4 * Copyright (C) 2013 Renesas Electronics Inc.
5 * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
6 *
7 * This is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/dmaengine.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/of_dma.h>
16#include <linux/of_platform.h>
17#include <linux/platform_device.h>
18#include <linux/shdma-base.h>
19
20#define to_shdma_chan(c) container_of(c, struct shdma_chan, dma_chan)
21
22static struct dma_chan *shdma_of_xlate(struct of_phandle_args *dma_spec,
23 struct of_dma *ofdma)
24{
25 u32 id = dma_spec->args[0];
26 dma_cap_mask_t mask;
27 struct dma_chan *chan;
28
29 if (dma_spec->args_count != 1)
30 return NULL;
31
32 dma_cap_zero(mask);
33 /* Only slave DMA channels can be allocated via DT */
34 dma_cap_set(DMA_SLAVE, mask);
35
36 chan = dma_request_channel(mask, shdma_chan_filter, (void *)id);
37 if (chan)
38 to_shdma_chan(chan)->hw_req = id;
39
40 return chan;
41}
42
43static int shdma_of_probe(struct platform_device *pdev)
44{
45 const struct of_dev_auxdata *lookup = pdev->dev.platform_data;
46 int ret;
47
48 if (!lookup)
49 return -EINVAL;
50
51 ret = of_dma_controller_register(pdev->dev.of_node,
52 shdma_of_xlate, pdev);
53 if (ret < 0)
54 return ret;
55
56 ret = of_platform_populate(pdev->dev.of_node, NULL, lookup, &pdev->dev);
57 if (ret < 0)
58 of_dma_controller_free(pdev->dev.of_node);
59
60 return ret;
61}
62
63static const struct of_device_id shdma_of_match[] = {
64 { .compatible = "renesas,shdma-mux", },
65 { }
66};
67MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
68
69static struct platform_driver shdma_of = {
70 .driver = {
71 .owner = THIS_MODULE,
72 .name = "shdma-of",
73 .of_match_table = shdma_of_match,
74 },
75 .probe = shdma_of_probe,
76};
77
78module_platform_driver(shdma_of);
79
80MODULE_LICENSE("GPL v2");
81MODULE_DESCRIPTION("SH-DMA driver DT glue");
82MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c
index a5a1887c34b5..b67f45f5c271 100644
--- a/drivers/dma/sh/shdma.c
+++ b/drivers/dma/sh/shdma.c
@@ -301,20 +301,32 @@ static void sh_dmae_setup_xfer(struct shdma_chan *schan,
301 } 301 }
302} 302}
303 303
304/*
305 * Find a slave channel configuration from the contoller list by either a slave
306 * ID in the non-DT case, or by a MID/RID value in the DT case
307 */
304static const struct sh_dmae_slave_config *dmae_find_slave( 308static const struct sh_dmae_slave_config *dmae_find_slave(
305 struct sh_dmae_chan *sh_chan, int slave_id) 309 struct sh_dmae_chan *sh_chan, int match)
306{ 310{
307 struct sh_dmae_device *shdev = to_sh_dev(sh_chan); 311 struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
308 struct sh_dmae_pdata *pdata = shdev->pdata; 312 struct sh_dmae_pdata *pdata = shdev->pdata;
309 const struct sh_dmae_slave_config *cfg; 313 const struct sh_dmae_slave_config *cfg;
310 int i; 314 int i;
311 315
312 if (slave_id >= SH_DMA_SLAVE_NUMBER) 316 if (!sh_chan->shdma_chan.dev->of_node) {
313 return NULL; 317 if (match >= SH_DMA_SLAVE_NUMBER)
318 return NULL;
314 319
315 for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++) 320 for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
316 if (cfg->slave_id == slave_id) 321 if (cfg->slave_id == match)
317 return cfg; 322 return cfg;
323 } else {
324 for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
325 if (cfg->mid_rid == match) {
326 sh_chan->shdma_chan.slave_id = cfg->slave_id;
327 return cfg;
328 }
329 }
318 330
319 return NULL; 331 return NULL;
320} 332}
@@ -920,11 +932,18 @@ static int sh_dmae_remove(struct platform_device *pdev)
920 return 0; 932 return 0;
921} 933}
922 934
935static const struct of_device_id sh_dmae_of_match[] = {
936 { .compatible = "renesas,shdma", },
937 { }
938};
939MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
940
923static struct platform_driver sh_dmae_driver = { 941static struct platform_driver sh_dmae_driver = {
924 .driver = { 942 .driver = {
925 .owner = THIS_MODULE, 943 .owner = THIS_MODULE,
926 .pm = &sh_dmae_pm, 944 .pm = &sh_dmae_pm,
927 .name = SH_DMAE_DRV_NAME, 945 .name = SH_DMAE_DRV_NAME,
946 .of_match_table = sh_dmae_of_match,
928 }, 947 },
929 .remove = sh_dmae_remove, 948 .remove = sh_dmae_remove,
930 .shutdown = sh_dmae_shutdown, 949 .shutdown = sh_dmae_shutdown,