diff options
Diffstat (limited to 'sound/soc/soc-dmaengine-pcm.c')
-rw-r--r-- | sound/soc/soc-dmaengine-pcm.c | 150 |
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 | ||
40 | static inline struct dmaengine_pcm_runtime_data *substream_to_prtd( | 38 | static 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 | */ | ||
51 | void 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 | } | ||
57 | EXPORT_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 | */ | ||
65 | void *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 | } | ||
71 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_data); | ||
72 | |||
73 | struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) | 44 | struct 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 | } |
123 | EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config); | 96 | EXPORT_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 | */ | ||
114 | void 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 | } | ||
133 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data); | ||
134 | |||
125 | static void dmaengine_pcm_dma_complete(void *arg) | 135 | static 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 | } |
245 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); | 255 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); |
246 | 256 | ||
247 | static 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 | */ | ||
266 | struct 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 | } |
277 | EXPORT_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 | */ |
279 | int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, | 290 | int 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, | |||
304 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open); | 314 | EXPORT_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 | */ | ||
329 | int 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 | } | ||
335 | EXPORT_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 | } |
319 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close); | 349 | EXPORT_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 | */ | ||
357 | int 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 | } | ||
365 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan); | ||
366 | |||
321 | MODULE_LICENSE("GPL"); | 367 | MODULE_LICENSE("GPL"); |