aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/sh
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2013-07-28 21:58:50 -0400
committerMark Brown <broonie@linaro.org>2013-08-06 12:56:13 -0400
commit0a4d94c07ce782e645a8c0484d52221758b4c398 (patch)
tree06b9b94e4da866f625d5754a94dcd199687798f4 /sound/soc/sh
parent4b4dab82340d969521f4f86108441cb597c8595d (diff)
ASoC: rsnd: add common DMAEngine method
R-Car Sound driver will support DMA transfer in the future, then, SSI/SRU/SRC will use it. Current R-Car can't use soc-dmaengine-pcm.c since its DMAEngine doesn't support dmaengine_prep_dma_cyclic(), and SSI needs double plane transfer (which needs special submit) on DMAC. This patch adds common DMAEngine method for it Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound/soc/sh')
-rw-r--r--sound/soc/sh/rcar/core.c132
-rw-r--r--sound/soc/sh/rcar/rsnd.h32
2 files changed, 164 insertions, 0 deletions
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 420d6df9c3d0..a35706028514 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -174,6 +174,138 @@ void rsnd_mod_init(struct rsnd_priv *priv,
174} 174}
175 175
176/* 176/*
177 * rsnd_dma functions
178 */
179static void rsnd_dma_continue(struct rsnd_dma *dma)
180{
181 /* push next A or B plane */
182 dma->submit_loop = 1;
183 schedule_work(&dma->work);
184}
185
186void rsnd_dma_start(struct rsnd_dma *dma)
187{
188 /* push both A and B plane*/
189 dma->submit_loop = 2;
190 schedule_work(&dma->work);
191}
192
193void rsnd_dma_stop(struct rsnd_dma *dma)
194{
195 dma->submit_loop = 0;
196 cancel_work_sync(&dma->work);
197 dmaengine_terminate_all(dma->chan);
198}
199
200static void rsnd_dma_complete(void *data)
201{
202 struct rsnd_dma *dma = (struct rsnd_dma *)data;
203 struct rsnd_priv *priv = dma->priv;
204 unsigned long flags;
205
206 rsnd_lock(priv, flags);
207
208 dma->complete(dma);
209
210 if (dma->submit_loop)
211 rsnd_dma_continue(dma);
212
213 rsnd_unlock(priv, flags);
214}
215
216static void rsnd_dma_do_work(struct work_struct *work)
217{
218 struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work);
219 struct rsnd_priv *priv = dma->priv;
220 struct device *dev = rsnd_priv_to_dev(priv);
221 struct dma_async_tx_descriptor *desc;
222 dma_addr_t buf;
223 size_t len;
224 int i;
225
226 for (i = 0; i < dma->submit_loop; i++) {
227
228 if (dma->inquiry(dma, &buf, &len) < 0)
229 return;
230
231 desc = dmaengine_prep_slave_single(
232 dma->chan, buf, len, dma->dir,
233 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
234 if (!desc) {
235 dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
236 return;
237 }
238
239 desc->callback = rsnd_dma_complete;
240 desc->callback_param = dma;
241
242 if (dmaengine_submit(desc) < 0) {
243 dev_err(dev, "dmaengine_submit() fail\n");
244 return;
245 }
246
247 }
248
249 dma_async_issue_pending(dma->chan);
250}
251
252int rsnd_dma_available(struct rsnd_dma *dma)
253{
254 return !!dma->chan;
255}
256
257static bool rsnd_dma_filter(struct dma_chan *chan, void *param)
258{
259 chan->private = param;
260
261 return true;
262}
263
264int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
265 int is_play, int id,
266 int (*inquiry)(struct rsnd_dma *dma,
267 dma_addr_t *buf, int *len),
268 int (*complete)(struct rsnd_dma *dma))
269{
270 struct device *dev = rsnd_priv_to_dev(priv);
271 dma_cap_mask_t mask;
272
273 if (dma->chan) {
274 dev_err(dev, "it already has dma channel\n");
275 return -EIO;
276 }
277
278 dma_cap_zero(mask);
279 dma_cap_set(DMA_SLAVE, mask);
280
281 dma->slave.shdma_slave.slave_id = id;
282
283 dma->chan = dma_request_channel(mask, rsnd_dma_filter,
284 &dma->slave.shdma_slave);
285 if (!dma->chan) {
286 dev_err(dev, "can't get dma channel\n");
287 return -EIO;
288 }
289
290 dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
291 dma->priv = priv;
292 dma->inquiry = inquiry;
293 dma->complete = complete;
294 INIT_WORK(&dma->work, rsnd_dma_do_work);
295
296 return 0;
297}
298
299void rsnd_dma_quit(struct rsnd_priv *priv,
300 struct rsnd_dma *dma)
301{
302 if (dma->chan)
303 dma_release_channel(dma->chan);
304
305 dma->chan = NULL;
306}
307
308/*
177 * rsnd_dai functions 309 * rsnd_dai functions
178 */ 310 */
179#define rsnd_dai_call(rdai, io, fn) \ 311#define rsnd_dai_call(rdai, io, fn) \
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 9243e387104c..15dccd598960 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -13,9 +13,12 @@
13 13
14#include <linux/clk.h> 14#include <linux/clk.h>
15#include <linux/device.h> 15#include <linux/device.h>
16#include <linux/dma-mapping.h>
16#include <linux/io.h> 17#include <linux/io.h>
17#include <linux/list.h> 18#include <linux/list.h>
18#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/sh_dma.h>
21#include <linux/workqueue.h>
19#include <sound/rcar_snd.h> 22#include <sound/rcar_snd.h>
20#include <sound/soc.h> 23#include <sound/soc.h>
21#include <sound/pcm_params.h> 24#include <sound/pcm_params.h>
@@ -79,6 +82,32 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
79 u32 mask, u32 data); 82 u32 mask, u32 data);
80 83
81/* 84/*
85 * R-Car DMA
86 */
87struct rsnd_dma {
88 struct rsnd_priv *priv;
89 struct sh_dmae_slave slave;
90 struct work_struct work;
91 struct dma_chan *chan;
92 enum dma_data_direction dir;
93 int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len);
94 int (*complete)(struct rsnd_dma *dma);
95
96 int submit_loop;
97};
98
99void rsnd_dma_start(struct rsnd_dma *dma);
100void rsnd_dma_stop(struct rsnd_dma *dma);
101int rsnd_dma_available(struct rsnd_dma *dma);
102int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
103 int is_play, int id,
104 int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len),
105 int (*complete)(struct rsnd_dma *dma));
106void rsnd_dma_quit(struct rsnd_priv *priv,
107 struct rsnd_dma *dma);
108
109
110/*
82 * R-Car sound mod 111 * R-Car sound mod
83 */ 112 */
84 113
@@ -103,9 +132,12 @@ struct rsnd_mod {
103 struct rsnd_priv *priv; 132 struct rsnd_priv *priv;
104 struct rsnd_mod_ops *ops; 133 struct rsnd_mod_ops *ops;
105 struct list_head list; /* connect to rsnd_dai playback/capture */ 134 struct list_head list; /* connect to rsnd_dai playback/capture */
135 struct rsnd_dma dma;
106}; 136};
107 137
108#define rsnd_mod_to_priv(mod) ((mod)->priv) 138#define rsnd_mod_to_priv(mod) ((mod)->priv)
139#define rsnd_mod_to_dma(mod) (&(mod)->dma)
140#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
109#define rsnd_mod_id(mod) ((mod)->id) 141#define rsnd_mod_id(mod) ((mod)->id)
110#define for_each_rsnd_mod(pos, n, io) \ 142#define for_each_rsnd_mod(pos, n, io) \
111 list_for_each_entry_safe(pos, n, &(io)->head, list) 143 list_for_each_entry_safe(pos, n, &(io)->head, list)