aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2015-02-20 05:25:55 -0500
committerMark Brown <broonie@kernel.org>2015-03-07 10:04:29 -0500
commitbfe834be9525a82c8a40380c7df8ca3b149e9c93 (patch)
tree348466c39f45f3a5b820d02a7ca81a9f19664085 /sound
parentc5212b4556b6bd120b0f4e4ae7c4a1cb9f5efe07 (diff)
ASoC: rsnd: add dma.c for Audio DMAC / Audio DMAC peri peri
Renesas sound driver had been assumed that Audio DMAC / Audio DMAC peri peri are implemented by DMAEngine. But, result of DMA ML discussion, it was concluded that it is not a general purpose DMAC. And it should be moved from current DMAEngine to rsnd driver. So, Audio DMAC peri peri become non DMAEngine. OTOH, ALSA SoC has soc-generic-dmaengine-pcm implementation. but it seems difficult to use this generic implementation on rsnd driver at this point, since it needs to fallback to PIO mode if DMA can't use. and additionally it needs 2 DMAC (= Audio DMAC / Audio DMAC peri peri). These are not "generic" feature. Of course I will try to use this generic dmaengine in the future somehow, but just use current style at this point until it can formally use 2 DMACs. This patch adds new dma.c and moves current dma code to dma.c from core.c. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/sh/rcar/Makefile2
-rw-r--r--sound/soc/sh/rcar/core.c218
-rw-r--r--sound/soc/sh/rcar/dma.c231
3 files changed, 232 insertions, 219 deletions
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
index 9ac536429800..7b204925b8c5 100644
--- a/sound/soc/sh/rcar/Makefile
+++ b/sound/soc/sh/rcar/Makefile
@@ -1,2 +1,2 @@
1snd-soc-rcar-objs := core.o gen.o src.o adg.o ssi.o dvc.o 1snd-soc-rcar-objs := core.o gen.o dma.o src.o adg.o ssi.o dvc.o
2obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file 2obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 7db686d0cbd8..9beea9ba338a 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -161,224 +161,6 @@ void rsnd_mod_init(struct rsnd_mod *mod,
161} 161}
162 162
163/* 163/*
164 * rsnd_dma functions
165 */
166void rsnd_dma_stop(struct rsnd_dma *dma)
167{
168 dmaengine_terminate_all(dma->chan);
169}
170
171static void rsnd_dma_complete(void *data)
172{
173 struct rsnd_dma *dma = (struct rsnd_dma *)data;
174 struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
175 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
176
177 /*
178 * Renesas sound Gen1 needs 1 DMAC,
179 * Gen2 needs 2 DMAC.
180 * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri.
181 * But, Audio-DMAC-peri-peri doesn't have interrupt,
182 * and this driver is assuming that here.
183 *
184 * If Audio-DMAC-peri-peri has interrpt,
185 * rsnd_dai_pointer_update() will be called twice,
186 * ant it will breaks io->byte_pos
187 */
188
189 rsnd_dai_pointer_update(io, io->byte_per_period);
190}
191
192void rsnd_dma_start(struct rsnd_dma *dma)
193{
194 struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
195 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
196 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
197 struct snd_pcm_substream *substream = io->substream;
198 struct device *dev = rsnd_priv_to_dev(priv);
199 struct dma_async_tx_descriptor *desc;
200
201 desc = dmaengine_prep_dma_cyclic(dma->chan,
202 (dma->addr) ? dma->addr :
203 substream->runtime->dma_addr,
204 snd_pcm_lib_buffer_bytes(substream),
205 snd_pcm_lib_period_bytes(substream),
206 dma->dir,
207 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
208
209 if (!desc) {
210 dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
211 return;
212 }
213
214 desc->callback = rsnd_dma_complete;
215 desc->callback_param = dma;
216
217 if (dmaengine_submit(desc) < 0) {
218 dev_err(dev, "dmaengine_submit() fail\n");
219 return;
220 }
221
222 dma_async_issue_pending(dma->chan);
223}
224
225#define DMA_NAME_SIZE 16
226#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */
227static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod)
228{
229 if (mod)
230 return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d",
231 rsnd_mod_dma_name(mod), rsnd_mod_id(mod));
232 else
233 return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem");
234
235}
236
237static void rsnd_dma_of_name(struct rsnd_mod *mod_from,
238 struct rsnd_mod *mod_to,
239 char *dma_name)
240{
241 int index = 0;
242
243 index = _rsnd_dma_of_name(dma_name + index, mod_from);
244 *(dma_name + index++) = '_';
245 index = _rsnd_dma_of_name(dma_name + index, mod_to);
246}
247
248static void rsnd_dma_of_path(struct rsnd_dma *dma,
249 int is_play,
250 struct rsnd_mod **mod_from,
251 struct rsnd_mod **mod_to)
252{
253 struct rsnd_mod *this = rsnd_dma_to_mod(dma);
254 struct rsnd_dai_stream *io = rsnd_mod_to_io(this);
255 struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
256 struct rsnd_mod *src = rsnd_io_to_mod_src(io);
257 struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
258 struct rsnd_mod *mod[MOD_MAX];
259 int i, index;
260
261
262 for (i = 0; i < MOD_MAX; i++)
263 mod[i] = NULL;
264
265 /*
266 * in play case...
267 *
268 * src -> dst
269 *
270 * mem -> SSI
271 * mem -> SRC -> SSI
272 * mem -> SRC -> DVC -> SSI
273 */
274 mod[0] = NULL; /* for "mem" */
275 index = 1;
276 for (i = 1; i < MOD_MAX; i++) {
277 if (!src) {
278 mod[i] = ssi;
279 } else if (!dvc) {
280 mod[i] = src;
281 src = NULL;
282 } else {
283 if ((!is_play) && (this == src))
284 this = dvc;
285
286 mod[i] = (is_play) ? src : dvc;
287 i++;
288 mod[i] = (is_play) ? dvc : src;
289 src = NULL;
290 dvc = NULL;
291 }
292
293 if (mod[i] == this)
294 index = i;
295
296 if (mod[i] == ssi)
297 break;
298 }
299
300 if (is_play) {
301 *mod_from = mod[index - 1];
302 *mod_to = mod[index];
303 } else {
304 *mod_from = mod[index];
305 *mod_to = mod[index - 1];
306 }
307}
308
309int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id)
310{
311 struct device *dev = rsnd_priv_to_dev(priv);
312 struct dma_slave_config cfg;
313 struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
314 struct rsnd_mod *mod_from;
315 struct rsnd_mod *mod_to;
316 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
317 int is_play = rsnd_io_is_play(io);
318 char dma_name[DMA_NAME_SIZE];
319 dma_cap_mask_t mask;
320 int ret;
321
322 if (dma->chan) {
323 dev_err(dev, "it already has dma channel\n");
324 return -EIO;
325 }
326
327 dma_cap_zero(mask);
328 dma_cap_set(DMA_SLAVE, mask);
329
330 rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to);
331 rsnd_dma_of_name(mod_from, mod_to, dma_name);
332
333 cfg.slave_id = id;
334 cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
335 cfg.src_addr = rsnd_gen_dma_addr(priv, mod_from, is_play, 1);
336 cfg.dst_addr = rsnd_gen_dma_addr(priv, mod_to, is_play, 0);
337 cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
338 cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
339
340 dev_dbg(dev, "dma : %s %pad -> %pad\n",
341 dma_name, &cfg.src_addr, &cfg.dst_addr);
342
343 dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
344 (void *)id, dev,
345 dma_name);
346 if (!dma->chan) {
347 dev_err(dev, "can't get dma channel\n");
348 goto rsnd_dma_channel_err;
349 }
350
351 ret = dmaengine_slave_config(dma->chan, &cfg);
352 if (ret < 0)
353 goto rsnd_dma_init_err;
354
355 dma->addr = is_play ? cfg.src_addr : cfg.dst_addr;
356 dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
357
358 return 0;
359
360rsnd_dma_init_err:
361 rsnd_dma_quit(dma);
362rsnd_dma_channel_err:
363
364 /*
365 * DMA failed. try to PIO mode
366 * see
367 * rsnd_ssi_fallback()
368 * rsnd_rdai_continuance_probe()
369 */
370 return -EAGAIN;
371}
372
373void rsnd_dma_quit(struct rsnd_dma *dma)
374{
375 if (dma->chan)
376 dma_release_channel(dma->chan);
377
378 dma->chan = NULL;
379}
380
381/*
382 * settting function 164 * settting function
383 */ 165 */
384u32 rsnd_get_adinr(struct rsnd_mod *mod) 166u32 rsnd_get_adinr(struct rsnd_mod *mod)
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
new file mode 100644
index 000000000000..37acd409e88c
--- /dev/null
+++ b/sound/soc/sh/rcar/dma.c
@@ -0,0 +1,231 @@
1/*
2 * Renesas R-Car Audio DMAC support
3 *
4 * Copyright (C) 2015 Renesas Electronics Corp.
5 * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include "rsnd.h"
12
13static void rsnd_dma_complete(void *data)
14{
15 struct rsnd_dma *dma = (struct rsnd_dma *)data;
16 struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
17 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
18
19 /*
20 * Renesas sound Gen1 needs 1 DMAC,
21 * Gen2 needs 2 DMAC.
22 * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri.
23 * But, Audio-DMAC-peri-peri doesn't have interrupt,
24 * and this driver is assuming that here.
25 *
26 * If Audio-DMAC-peri-peri has interrpt,
27 * rsnd_dai_pointer_update() will be called twice,
28 * ant it will breaks io->byte_pos
29 */
30
31 rsnd_dai_pointer_update(io, io->byte_per_period);
32}
33
34#define DMA_NAME_SIZE 16
35#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */
36static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod)
37{
38 if (mod)
39 return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d",
40 rsnd_mod_dma_name(mod), rsnd_mod_id(mod));
41 else
42 return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem");
43
44}
45
46static void rsnd_dma_of_name(struct rsnd_mod *mod_from,
47 struct rsnd_mod *mod_to,
48 char *dma_name)
49{
50 int index = 0;
51
52 index = _rsnd_dma_of_name(dma_name + index, mod_from);
53 *(dma_name + index++) = '_';
54 index = _rsnd_dma_of_name(dma_name + index, mod_to);
55}
56
57void rsnd_dma_stop(struct rsnd_dma *dma)
58{
59 dmaengine_terminate_all(dma->chan);
60}
61
62void rsnd_dma_start(struct rsnd_dma *dma)
63{
64 struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
65 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
66 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
67 struct snd_pcm_substream *substream = io->substream;
68 struct device *dev = rsnd_priv_to_dev(priv);
69 struct dma_async_tx_descriptor *desc;
70
71 desc = dmaengine_prep_dma_cyclic(dma->chan,
72 (dma->addr) ? dma->addr :
73 substream->runtime->dma_addr,
74 snd_pcm_lib_buffer_bytes(substream),
75 snd_pcm_lib_period_bytes(substream),
76 dma->dir,
77 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
78
79 if (!desc) {
80 dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
81 return;
82 }
83
84 desc->callback = rsnd_dma_complete;
85 desc->callback_param = dma;
86
87 if (dmaengine_submit(desc) < 0) {
88 dev_err(dev, "dmaengine_submit() fail\n");
89 return;
90 }
91
92 dma_async_issue_pending(dma->chan);
93}
94
95static void rsnd_dma_of_path(struct rsnd_dma *dma,
96 int is_play,
97 struct rsnd_mod **mod_from,
98 struct rsnd_mod **mod_to);
99
100int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id)
101{
102 struct device *dev = rsnd_priv_to_dev(priv);
103 struct dma_slave_config cfg = {};
104 struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
105 struct rsnd_mod *mod_from;
106 struct rsnd_mod *mod_to;
107 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
108 int is_play = rsnd_io_is_play(io);
109 char dma_name[DMA_NAME_SIZE];
110 dma_cap_mask_t mask;
111 int ret;
112
113 if (dma->chan) {
114 dev_err(dev, "it already has dma channel\n");
115 return -EIO;
116 }
117
118 dma_cap_zero(mask);
119 dma_cap_set(DMA_SLAVE, mask);
120
121 rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to);
122 rsnd_dma_of_name(mod_from, mod_to, dma_name);
123
124 cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
125 cfg.src_addr = rsnd_gen_dma_addr(priv, mod_from, is_play, 1);
126 cfg.dst_addr = rsnd_gen_dma_addr(priv, mod_to, is_play, 0);
127 cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
128 cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
129
130 dev_dbg(dev, "dma : %s %pad -> %pad\n",
131 dma_name, &cfg.src_addr, &cfg.dst_addr);
132
133 dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
134 (void *)id, dev,
135 dma_name);
136 if (!dma->chan) {
137 dev_err(dev, "can't get dma channel\n");
138 goto rsnd_dma_channel_err;
139 }
140
141 ret = dmaengine_slave_config(dma->chan, &cfg);
142 if (ret < 0)
143 goto rsnd_dma_init_err;
144
145 dma->addr = is_play ? cfg.src_addr : cfg.dst_addr;
146 dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
147
148 return 0;
149
150rsnd_dma_init_err:
151 rsnd_dma_quit(dma);
152rsnd_dma_channel_err:
153
154 /*
155 * DMA failed. try to PIO mode
156 * see
157 * rsnd_ssi_fallback()
158 * rsnd_rdai_continuance_probe()
159 */
160 return -EAGAIN;
161}
162
163void rsnd_dma_quit(struct rsnd_dma *dma)
164{
165 if (dma->chan)
166 dma_release_channel(dma->chan);
167
168 dma->chan = NULL;
169}
170
171static void rsnd_dma_of_path(struct rsnd_dma *dma,
172 int is_play,
173 struct rsnd_mod **mod_from,
174 struct rsnd_mod **mod_to)
175{
176 struct rsnd_mod *this = rsnd_dma_to_mod(dma);
177 struct rsnd_dai_stream *io = rsnd_mod_to_io(this);
178 struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
179 struct rsnd_mod *src = rsnd_io_to_mod_src(io);
180 struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
181 struct rsnd_mod *mod[MOD_MAX];
182 int i, index;
183
184
185 for (i = 0; i < MOD_MAX; i++)
186 mod[i] = NULL;
187
188 /*
189 * in play case...
190 *
191 * src -> dst
192 *
193 * mem -> SSI
194 * mem -> SRC -> SSI
195 * mem -> SRC -> DVC -> SSI
196 */
197 mod[0] = NULL; /* for "mem" */
198 index = 1;
199 for (i = 1; i < MOD_MAX; i++) {
200 if (!src) {
201 mod[i] = ssi;
202 } else if (!dvc) {
203 mod[i] = src;
204 src = NULL;
205 } else {
206 if ((!is_play) && (this == src))
207 this = dvc;
208
209 mod[i] = (is_play) ? src : dvc;
210 i++;
211 mod[i] = (is_play) ? dvc : src;
212 src = NULL;
213 dvc = NULL;
214 }
215
216 if (mod[i] == this)
217 index = i;
218
219 if (mod[i] == ssi)
220 break;
221 }
222
223 if (is_play) {
224 *mod_from = mod[index - 1];
225 *mod_to = mod[index];
226 } else {
227 *mod_from = mod[index];
228 *mod_to = mod[index - 1];
229 }
230}
231