aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dmaengine-pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-dmaengine-pcm.c')
-rw-r--r--sound/soc/soc-dmaengine-pcm.c150
1 files changed, 98 insertions, 52 deletions
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c
index 111b7d921e89..aa924d9b7986 100644
--- a/sound/soc/soc-dmaengine-pcm.c
+++ b/sound/soc/soc-dmaengine-pcm.c
@@ -33,8 +33,6 @@ struct dmaengine_pcm_runtime_data {
33 dma_cookie_t cookie; 33 dma_cookie_t cookie;
34 34
35 unsigned int pos; 35 unsigned int pos;
36
37 void *data;
38}; 36};
39 37
40static inline struct dmaengine_pcm_runtime_data *substream_to_prtd( 38static inline struct dmaengine_pcm_runtime_data *substream_to_prtd(
@@ -43,33 +41,6 @@ static inline struct dmaengine_pcm_runtime_data *substream_to_prtd(
43 return substream->runtime->private_data; 41 return substream->runtime->private_data;
44} 42}
45 43
46/**
47 * snd_dmaengine_pcm_set_data - Set dmaengine substream private data
48 * @substream: PCM substream
49 * @data: Data to set
50 */
51void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data)
52{
53 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
54
55 prtd->data = data;
56}
57EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_data);
58
59/**
60 * snd_dmaengine_pcm_get_data - Get dmaeinge substream private data
61 * @substream: PCM substream
62 *
63 * Returns the data previously set with snd_dmaengine_pcm_set_data
64 */
65void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream)
66{
67 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
68
69 return prtd->data;
70}
71EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_data);
72
73struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) 44struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
74{ 45{
75 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); 46 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
@@ -118,10 +89,49 @@ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
118 slave_config->src_addr_width = buswidth; 89 slave_config->src_addr_width = buswidth;
119 } 90 }
120 91
92 slave_config->device_fc = false;
93
121 return 0; 94 return 0;
122} 95}
123EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config); 96EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config);
124 97
98/**
99 * snd_dmaengine_pcm_set_config_from_dai_data() - Initializes a dma slave config
100 * using DAI DMA data.
101 * @substream: PCM substream
102 * @dma_data: DAI DMA data
103 * @slave_config: DMA slave configuration
104 *
105 * Initializes the {dst,src}_addr, {dst,src}_maxburst, {dst,src}_addr_width and
106 * slave_id fields of the DMA slave config from the same fields of the DAI DMA
107 * data struct. The src and dst fields will be initialized depending on the
108 * direction of the substream. If the substream is a playback stream the dst
109 * fields will be initialized, if it is a capture stream the src fields will be
110 * initialized. The {dst,src}_addr_width field will only be initialized if the
111 * addr_width field of the DAI DMA data struct is not equal to
112 * DMA_SLAVE_BUSWIDTH_UNDEFINED.
113 */
114void snd_dmaengine_pcm_set_config_from_dai_data(
115 const struct snd_pcm_substream *substream,
116 const struct snd_dmaengine_dai_dma_data *dma_data,
117 struct dma_slave_config *slave_config)
118{
119 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
120 slave_config->dst_addr = dma_data->addr;
121 slave_config->dst_maxburst = dma_data->maxburst;
122 if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
123 slave_config->dst_addr_width = dma_data->addr_width;
124 } else {
125 slave_config->src_addr = dma_data->addr;
126 slave_config->src_maxburst = dma_data->maxburst;
127 if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
128 slave_config->src_addr_width = dma_data->addr_width;
129 }
130
131 slave_config->slave_id = dma_data->slave_id;
132}
133EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data);
134
125static void dmaengine_pcm_dma_complete(void *arg) 135static void dmaengine_pcm_dma_complete(void *arg)
126{ 136{
127 struct snd_pcm_substream *substream = arg; 137 struct snd_pcm_substream *substream = arg;
@@ -244,44 +254,48 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
244} 254}
245EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); 255EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
246 256
247static int dmaengine_pcm_request_channel(struct dmaengine_pcm_runtime_data *prtd, 257/**
248 dma_filter_fn filter_fn, void *filter_data) 258 * snd_dmaengine_pcm_request_channel - Request channel for the dmaengine PCM
259 * @filter_fn: Filter function used to request the DMA channel
260 * @filter_data: Data passed to the DMA filter function
261 *
262 * Returns NULL or the requested DMA channel.
263 *
264 * This function request a DMA channel for usage with dmaengine PCM.
265 */
266struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
267 void *filter_data)
249{ 268{
250 dma_cap_mask_t mask; 269 dma_cap_mask_t mask;
251 270
252 dma_cap_zero(mask); 271 dma_cap_zero(mask);
253 dma_cap_set(DMA_SLAVE, mask); 272 dma_cap_set(DMA_SLAVE, mask);
254 dma_cap_set(DMA_CYCLIC, mask); 273 dma_cap_set(DMA_CYCLIC, mask);
255 prtd->dma_chan = dma_request_channel(mask, filter_fn, filter_data);
256 274
257 if (!prtd->dma_chan) 275 return dma_request_channel(mask, filter_fn, filter_data);
258 return -ENXIO;
259
260 return 0;
261} 276}
277EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel);
262 278
263/** 279/**
264 * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream 280 * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream
265 * @substream: PCM substream 281 * @substream: PCM substream
266 * @filter_fn: Filter function used to request the DMA channel 282 * @chan: DMA channel to use for data transfers
267 * @filter_data: Data passed to the DMA filter function
268 * 283 *
269 * Returns 0 on success, a negative error code otherwise. 284 * Returns 0 on success, a negative error code otherwise.
270 * 285 *
271 * This function will request a DMA channel using the passed filter function and 286 * The function should usually be called from the pcm open callback. Note that
272 * data. The function should usually be called from the pcm open callback. 287 * this function will use private_data field of the substream's runtime. So it
273 * 288 * is not availabe to your pcm driver implementation.
274 * Note that this function will use private_data field of the substream's
275 * runtime. So it is not availabe to your pcm driver implementation. If you need
276 * to keep additional data attached to a substream use
277 * snd_dmaengine_pcm_{set,get}_data.
278 */ 289 */
279int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, 290int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
280 dma_filter_fn filter_fn, void *filter_data) 291 struct dma_chan *chan)
281{ 292{
282 struct dmaengine_pcm_runtime_data *prtd; 293 struct dmaengine_pcm_runtime_data *prtd;
283 int ret; 294 int ret;
284 295
296 if (!chan)
297 return -ENXIO;
298
285 ret = snd_pcm_hw_constraint_integer(substream->runtime, 299 ret = snd_pcm_hw_constraint_integer(substream->runtime,
286 SNDRV_PCM_HW_PARAM_PERIODS); 300 SNDRV_PCM_HW_PARAM_PERIODS);
287 if (ret < 0) 301 if (ret < 0)
@@ -291,11 +305,7 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
291 if (!prtd) 305 if (!prtd)
292 return -ENOMEM; 306 return -ENOMEM;
293 307
294 ret = dmaengine_pcm_request_channel(prtd, filter_fn, filter_data); 308 prtd->dma_chan = chan;
295 if (ret < 0) {
296 kfree(prtd);
297 return ret;
298 }
299 309
300 substream->runtime->private_data = prtd; 310 substream->runtime->private_data = prtd;
301 311
@@ -304,6 +314,27 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
304EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open); 314EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open);
305 315
306/** 316/**
317 * snd_dmaengine_pcm_open_request_chan - Open a dmaengine based PCM substream and request channel
318 * @substream: PCM substream
319 * @filter_fn: Filter function used to request the DMA channel
320 * @filter_data: Data passed to the DMA filter function
321 *
322 * Returns 0 on success, a negative error code otherwise.
323 *
324 * This function will request a DMA channel using the passed filter function and
325 * data. The function should usually be called from the pcm open callback. Note
326 * that this function will use private_data field of the substream's runtime. So
327 * it is not availabe to your pcm driver implementation.
328 */
329int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
330 dma_filter_fn filter_fn, void *filter_data)
331{
332 return snd_dmaengine_pcm_open(substream,
333 snd_dmaengine_pcm_request_channel(filter_fn, filter_data));
334}
335EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
336
337/**
307 * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream 338 * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
308 * @substream: PCM substream 339 * @substream: PCM substream
309 */ 340 */
@@ -311,11 +342,26 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
311{ 342{
312 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); 343 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
313 344
314 dma_release_channel(prtd->dma_chan);
315 kfree(prtd); 345 kfree(prtd);
316 346
317 return 0; 347 return 0;
318} 348}
319EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close); 349EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
320 350
351/**
352 * snd_dmaengine_pcm_release_chan_close - Close a dmaengine based PCM substream and release channel
353 * @substream: PCM substream
354 *
355 * Releases the DMA channel associated with the PCM substream.
356 */
357int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
358{
359 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
360
361 dma_release_channel(prtd->dma_chan);
362
363 return snd_dmaengine_pcm_close(substream);
364}
365EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
366
321MODULE_LICENSE("GPL"); 367MODULE_LICENSE("GPL");