aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
authorVinod Koul <vinod.koul@intel.com>2014-07-28 07:56:36 -0400
committerVinod Koul <vinod.koul@intel.com>2014-07-28 07:56:36 -0400
commitdb0e7018191e1deb33e3ed8bb8ed89e5a4ae1ba1 (patch)
tree97dbc5853a1849bcd72c06f4191452b2adab167b /drivers/dma
parent8e8805d5bf704f24acb14d67d506cbd4c5893be5 (diff)
parentcaf18c27ddb2fb8ae2a7591b908e7efb7484e459 (diff)
Merge commit 'renesas-rcar-audmapp-for-v3.17' into for-linus
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/sh/rcar-audmapp.c114
1 files changed, 84 insertions, 30 deletions
diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c
index 2de77289a2e9..dabbf0aba2e9 100644
--- a/drivers/dma/sh/rcar-audmapp.c
+++ b/drivers/dma/sh/rcar-audmapp.c
@@ -22,6 +22,7 @@
22#include <linux/module.h> 22#include <linux/module.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/dmaengine.h> 24#include <linux/dmaengine.h>
25#include <linux/of_dma.h>
25#include <linux/platform_data/dma-rcar-audmapp.h> 26#include <linux/platform_data/dma-rcar-audmapp.h>
26#include <linux/platform_device.h> 27#include <linux/platform_device.h>
27#include <linux/shdma-base.h> 28#include <linux/shdma-base.h>
@@ -45,8 +46,9 @@
45 46
46struct audmapp_chan { 47struct audmapp_chan {
47 struct shdma_chan shdma_chan; 48 struct shdma_chan shdma_chan;
48 struct audmapp_slave_config *config;
49 void __iomem *base; 49 void __iomem *base;
50 dma_addr_t slave_addr;
51 u32 chcr;
50}; 52};
51 53
52struct audmapp_device { 54struct audmapp_device {
@@ -56,7 +58,16 @@ struct audmapp_device {
56 void __iomem *chan_reg; 58 void __iomem *chan_reg;
57}; 59};
58 60
61struct audmapp_desc {
62 struct shdma_desc shdma_desc;
63 dma_addr_t src;
64 dma_addr_t dst;
65};
66
67#define to_shdma_chan(c) container_of(c, struct shdma_chan, dma_chan)
68
59#define to_chan(chan) container_of(chan, struct audmapp_chan, shdma_chan) 69#define to_chan(chan) container_of(chan, struct audmapp_chan, shdma_chan)
70#define to_desc(sdesc) container_of(sdesc, struct audmapp_desc, shdma_desc)
60#define to_dev(chan) container_of(chan->shdma_chan.dma_chan.device, \ 71#define to_dev(chan) container_of(chan->shdma_chan.dma_chan.device, \
61 struct audmapp_device, shdma_dev.dma_dev) 72 struct audmapp_device, shdma_dev.dma_dev)
62 73
@@ -90,70 +101,82 @@ static void audmapp_halt(struct shdma_chan *schan)
90} 101}
91 102
92static void audmapp_start_xfer(struct shdma_chan *schan, 103static void audmapp_start_xfer(struct shdma_chan *schan,
93 struct shdma_desc *sdecs) 104 struct shdma_desc *sdesc)
94{ 105{
95 struct audmapp_chan *auchan = to_chan(schan); 106 struct audmapp_chan *auchan = to_chan(schan);
96 struct audmapp_device *audev = to_dev(auchan); 107 struct audmapp_device *audev = to_dev(auchan);
97 struct audmapp_slave_config *cfg = auchan->config; 108 struct audmapp_desc *desc = to_desc(sdesc);
98 struct device *dev = audev->dev; 109 struct device *dev = audev->dev;
99 u32 chcr = cfg->chcr | PDMACHCR_DE; 110 u32 chcr = auchan->chcr | PDMACHCR_DE;
100 111
101 dev_dbg(dev, "src/dst/chcr = %pad/%pad/%x\n", 112 dev_dbg(dev, "src/dst/chcr = %pad/%pad/%08x\n",
102 &cfg->src, &cfg->dst, cfg->chcr); 113 &desc->src, &desc->dst, chcr);
103 114
104 audmapp_write(auchan, cfg->src, PDMASAR); 115 audmapp_write(auchan, desc->src, PDMASAR);
105 audmapp_write(auchan, cfg->dst, PDMADAR); 116 audmapp_write(auchan, desc->dst, PDMADAR);
106 audmapp_write(auchan, chcr, PDMACHCR); 117 audmapp_write(auchan, chcr, PDMACHCR);
107} 118}
108 119
109static struct audmapp_slave_config * 120static void audmapp_get_config(struct audmapp_chan *auchan, int slave_id,
110audmapp_find_slave(struct audmapp_chan *auchan, int slave_id) 121 u32 *chcr, dma_addr_t *dst)
111{ 122{
112 struct audmapp_device *audev = to_dev(auchan); 123 struct audmapp_device *audev = to_dev(auchan);
113 struct audmapp_pdata *pdata = audev->pdata; 124 struct audmapp_pdata *pdata = audev->pdata;
114 struct audmapp_slave_config *cfg; 125 struct audmapp_slave_config *cfg;
115 int i; 126 int i;
116 127
128 *chcr = 0;
129 *dst = 0;
130
131 if (!pdata) { /* DT */
132 *chcr = ((u32)slave_id) << 16;
133 auchan->shdma_chan.slave_id = (slave_id) >> 8;
134 return;
135 }
136
137 /* non-DT */
138
117 if (slave_id >= AUDMAPP_SLAVE_NUMBER) 139 if (slave_id >= AUDMAPP_SLAVE_NUMBER)
118 return NULL; 140 return;
119 141
120 for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++) 142 for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
121 if (cfg->slave_id == slave_id) 143 if (cfg->slave_id == slave_id) {
122 return cfg; 144 *chcr = cfg->chcr;
123 145 *dst = cfg->dst;
124 return NULL; 146 break;
147 }
125} 148}
126 149
127static int audmapp_set_slave(struct shdma_chan *schan, int slave_id, 150static int audmapp_set_slave(struct shdma_chan *schan, int slave_id,
128 dma_addr_t slave_addr, bool try) 151 dma_addr_t slave_addr, bool try)
129{ 152{
130 struct audmapp_chan *auchan = to_chan(schan); 153 struct audmapp_chan *auchan = to_chan(schan);
131 struct audmapp_slave_config *cfg = 154 u32 chcr;
132 audmapp_find_slave(auchan, slave_id); 155 dma_addr_t dst;
156
157 audmapp_get_config(auchan, slave_id, &chcr, &dst);
133 158
134 if (!cfg)
135 return -ENODEV;
136 if (try) 159 if (try)
137 return 0; 160 return 0;
138 161
139 auchan->config = cfg; 162 auchan->chcr = chcr;
163 auchan->slave_addr = slave_addr ? : dst;
140 164
141 return 0; 165 return 0;
142} 166}
143 167
144static int audmapp_desc_setup(struct shdma_chan *schan, 168static int audmapp_desc_setup(struct shdma_chan *schan,
145 struct shdma_desc *sdecs, 169 struct shdma_desc *sdesc,
146 dma_addr_t src, dma_addr_t dst, size_t *len) 170 dma_addr_t src, dma_addr_t dst, size_t *len)
147{ 171{
148 struct audmapp_chan *auchan = to_chan(schan); 172 struct audmapp_desc *desc = to_desc(sdesc);
149 struct audmapp_slave_config *cfg = auchan->config;
150
151 if (!cfg)
152 return -ENODEV;
153 173
154 if (*len > (size_t)AUDMAPP_LEN_MAX) 174 if (*len > (size_t)AUDMAPP_LEN_MAX)
155 *len = (size_t)AUDMAPP_LEN_MAX; 175 *len = (size_t)AUDMAPP_LEN_MAX;
156 176
177 desc->src = src;
178 desc->dst = dst;
179
157 return 0; 180 return 0;
158} 181}
159 182
@@ -164,7 +187,9 @@ static void audmapp_setup_xfer(struct shdma_chan *schan,
164 187
165static dma_addr_t audmapp_slave_addr(struct shdma_chan *schan) 188static dma_addr_t audmapp_slave_addr(struct shdma_chan *schan)
166{ 189{
167 return 0; /* always fixed address */ 190 struct audmapp_chan *auchan = to_chan(schan);
191
192 return auchan->slave_addr;
168} 193}
169 194
170static bool audmapp_channel_busy(struct shdma_chan *schan) 195static bool audmapp_channel_busy(struct shdma_chan *schan)
@@ -183,7 +208,7 @@ static bool audmapp_desc_completed(struct shdma_chan *schan,
183 208
184static struct shdma_desc *audmapp_embedded_desc(void *buf, int i) 209static struct shdma_desc *audmapp_embedded_desc(void *buf, int i)
185{ 210{
186 return &((struct shdma_desc *)buf)[i]; 211 return &((struct audmapp_desc *)buf)[i].shdma_desc;
187} 212}
188 213
189static const struct shdma_ops audmapp_shdma_ops = { 214static const struct shdma_ops audmapp_shdma_ops = {
@@ -234,16 +259,39 @@ static void audmapp_chan_remove(struct audmapp_device *audev)
234 dma_dev->chancnt = 0; 259 dma_dev->chancnt = 0;
235} 260}
236 261
262static struct dma_chan *audmapp_of_xlate(struct of_phandle_args *dma_spec,
263 struct of_dma *ofdma)
264{
265 dma_cap_mask_t mask;
266 struct dma_chan *chan;
267 u32 chcr = dma_spec->args[0];
268
269 if (dma_spec->args_count != 1)
270 return NULL;
271
272 dma_cap_zero(mask);
273 dma_cap_set(DMA_SLAVE, mask);
274
275 chan = dma_request_channel(mask, shdma_chan_filter, NULL);
276 if (chan)
277 to_shdma_chan(chan)->hw_req = chcr;
278
279 return chan;
280}
281
237static int audmapp_probe(struct platform_device *pdev) 282static int audmapp_probe(struct platform_device *pdev)
238{ 283{
239 struct audmapp_pdata *pdata = pdev->dev.platform_data; 284 struct audmapp_pdata *pdata = pdev->dev.platform_data;
285 struct device_node *np = pdev->dev.of_node;
240 struct audmapp_device *audev; 286 struct audmapp_device *audev;
241 struct shdma_dev *sdev; 287 struct shdma_dev *sdev;
242 struct dma_device *dma_dev; 288 struct dma_device *dma_dev;
243 struct resource *res; 289 struct resource *res;
244 int err, i; 290 int err, i;
245 291
246 if (!pdata) 292 if (np)
293 of_dma_controller_register(np, audmapp_of_xlate, pdev);
294 else if (!pdata)
247 return -ENODEV; 295 return -ENODEV;
248 296
249 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 297 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -260,7 +308,7 @@ static int audmapp_probe(struct platform_device *pdev)
260 308
261 sdev = &audev->shdma_dev; 309 sdev = &audev->shdma_dev;
262 sdev->ops = &audmapp_shdma_ops; 310 sdev->ops = &audmapp_shdma_ops;
263 sdev->desc_size = sizeof(struct shdma_desc); 311 sdev->desc_size = sizeof(struct audmapp_desc);
264 312
265 dma_dev = &sdev->dma_dev; 313 dma_dev = &sdev->dma_dev;
266 dma_dev->copy_align = LOG2_DEFAULT_XFER_SIZE; 314 dma_dev->copy_align = LOG2_DEFAULT_XFER_SIZE;
@@ -305,12 +353,18 @@ static int audmapp_remove(struct platform_device *pdev)
305 return 0; 353 return 0;
306} 354}
307 355
356static const struct of_device_id audmapp_of_match[] = {
357 { .compatible = "renesas,rcar-audmapp", },
358 {},
359};
360
308static struct platform_driver audmapp_driver = { 361static struct platform_driver audmapp_driver = {
309 .probe = audmapp_probe, 362 .probe = audmapp_probe,
310 .remove = audmapp_remove, 363 .remove = audmapp_remove,
311 .driver = { 364 .driver = {
312 .owner = THIS_MODULE, 365 .owner = THIS_MODULE,
313 .name = "rcar-audmapp-engine", 366 .name = "rcar-audmapp-engine",
367 .of_match_table = audmapp_of_match,
314 }, 368 },
315}; 369};
316module_platform_driver(audmapp_driver); 370module_platform_driver(audmapp_driver);