2 * Copyright (C) 2013, Analog Devices Inc.
3 * Author: Lars-Peter Clausen <lars@metafoo.de>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/dmaengine.h>
18 #include <linux/slab.h>
19 #include <sound/pcm.h>
20 #include <sound/pcm_params.h>
21 #include <sound/soc.h>
22 #include <linux/dma-mapping.h>
25 #include <sound/dmaengine_pcm.h>
28 * The platforms dmaengine driver does not support reporting the amount of
29 * bytes that are still left to transfer.
31 #define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(31)
33 struct dmaengine_pcm
{
34 struct dma_chan
*chan
[SNDRV_PCM_STREAM_LAST
+ 1];
35 const struct snd_dmaengine_pcm_config
*config
;
36 struct snd_soc_platform platform
;
40 static struct dmaengine_pcm
*soc_platform_to_pcm(struct snd_soc_platform
*p
)
42 return container_of(p
, struct dmaengine_pcm
, platform
);
45 static struct device
*dmaengine_dma_dev(struct dmaengine_pcm
*pcm
,
46 struct snd_pcm_substream
*substream
)
48 if (!pcm
->chan
[substream
->stream
])
51 return pcm
->chan
[substream
->stream
]->device
->dev
;
55 * snd_dmaengine_pcm_prepare_slave_config() - Generic prepare_slave_config callback
56 * @substream: PCM substream
58 * @slave_config: DMA slave config to prepare
60 * This function can be used as a generic prepare_slave_config callback for
61 * platforms which make use of the snd_dmaengine_dai_dma_data struct for their
62 * DAI DMA data. Internally the function will first call
63 * snd_hwparams_to_dma_slave_config to fill in the slave config based on the
64 * hw_params, followed by snd_dmaengine_set_config_from_dai_data to fill in the
65 * remaining fields based on the DAI DMA data.
67 int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream
*substream
,
68 struct snd_pcm_hw_params
*params
, struct dma_slave_config
*slave_config
)
70 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
71 struct snd_dmaengine_dai_dma_data
*dma_data
;
74 dma_data
= snd_soc_dai_get_dma_data(rtd
->cpu_dai
, substream
);
76 ret
= snd_hwparams_to_dma_slave_config(substream
, params
, slave_config
);
80 snd_dmaengine_pcm_set_config_from_dai_data(substream
, dma_data
,
85 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_prepare_slave_config
);
87 static int dmaengine_pcm_hw_params(struct snd_pcm_substream
*substream
,
88 struct snd_pcm_hw_params
*params
)
90 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
91 struct dmaengine_pcm
*pcm
= soc_platform_to_pcm(rtd
->platform
);
92 struct dma_chan
*chan
= snd_dmaengine_pcm_get_chan(substream
);
93 int (*prepare_slave_config
)(struct snd_pcm_substream
*substream
,
94 struct snd_pcm_hw_params
*params
,
95 struct dma_slave_config
*slave_config
);
96 struct dma_slave_config slave_config
;
99 memset(&slave_config
, 0, sizeof(slave_config
));
102 prepare_slave_config
= snd_dmaengine_pcm_prepare_slave_config
;
104 prepare_slave_config
= pcm
->config
->prepare_slave_config
;
106 if (prepare_slave_config
) {
107 ret
= prepare_slave_config(substream
, params
, &slave_config
);
111 ret
= dmaengine_slave_config(chan
, &slave_config
);
116 return snd_pcm_lib_malloc_pages(substream
, params_buffer_bytes(params
));
119 static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream
*substream
)
121 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
122 struct dmaengine_pcm
*pcm
= soc_platform_to_pcm(rtd
->platform
);
123 struct device
*dma_dev
= dmaengine_dma_dev(pcm
, substream
);
124 struct dma_chan
*chan
= pcm
->chan
[substream
->stream
];
125 struct snd_dmaengine_dai_dma_data
*dma_data
;
126 struct dma_slave_caps dma_caps
;
127 struct snd_pcm_hardware hw
;
128 u32 addr_widths
= BIT(DMA_SLAVE_BUSWIDTH_1_BYTE
) |
129 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES
) |
130 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES
);
133 if (pcm
->config
&& pcm
->config
->pcm_hardware
)
134 return snd_soc_set_runtime_hwparams(substream
,
135 pcm
->config
->pcm_hardware
);
137 dma_data
= snd_soc_dai_get_dma_data(rtd
->cpu_dai
, substream
);
139 memset(&hw
, 0, sizeof(hw
));
140 hw
.info
= SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID
|
141 SNDRV_PCM_INFO_INTERLEAVED
;
143 hw
.periods_max
= UINT_MAX
;
144 hw
.period_bytes_min
= 256;
145 hw
.period_bytes_max
= dma_get_max_seg_size(dma_dev
);
146 hw
.buffer_bytes_max
= SIZE_MAX
;
147 hw
.fifo_size
= dma_data
->fifo_size
;
149 if (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_NO_RESIDUE
)
150 hw
.info
|= SNDRV_PCM_INFO_BATCH
;
152 ret
= dma_get_slave_caps(chan
, &dma_caps
);
154 if (dma_caps
.cmd_pause
)
155 hw
.info
|= SNDRV_PCM_INFO_PAUSE
| SNDRV_PCM_INFO_RESUME
;
156 if (dma_caps
.residue_granularity
<= DMA_RESIDUE_GRANULARITY_SEGMENT
)
157 hw
.info
|= SNDRV_PCM_INFO_BATCH
;
159 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
160 addr_widths
= dma_caps
.dst_addr_widths
;
162 addr_widths
= dma_caps
.src_addr_widths
;
166 * If SND_DMAENGINE_PCM_DAI_FLAG_PACK is set keep
167 * hw.formats set to 0, meaning no restrictions are in place.
168 * In this case it's the responsibility of the DAI driver to
169 * provide the supported format information.
171 if (!(dma_data
->flags
& SND_DMAENGINE_PCM_DAI_FLAG_PACK
))
173 * Prepare formats mask for valid/allowed sample types. If the
174 * dma does not have support for the given physical word size,
175 * it needs to be masked out so user space can not use the
176 * format which produces corrupted audio.
177 * In case the dma driver does not implement the slave_caps the
178 * default assumption is that it supports 1, 2 and 4 bytes
181 for (i
= 0; i
<= SNDRV_PCM_FORMAT_LAST
; i
++) {
182 int bits
= snd_pcm_format_physical_width(i
);
185 * Enable only samples with DMA supported physical
194 if (addr_widths
& (1 << (bits
/ 8)))
195 hw
.formats
|= (1LL << i
);
198 /* Unsupported types */
203 return snd_soc_set_runtime_hwparams(substream
, &hw
);
206 static int dmaengine_pcm_open(struct snd_pcm_substream
*substream
)
208 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
209 struct dmaengine_pcm
*pcm
= soc_platform_to_pcm(rtd
->platform
);
210 struct dma_chan
*chan
= pcm
->chan
[substream
->stream
];
213 ret
= dmaengine_pcm_set_runtime_hwparams(substream
);
217 return snd_dmaengine_pcm_open(substream
, chan
);
220 static struct dma_chan
*dmaengine_pcm_compat_request_channel(
221 struct snd_soc_pcm_runtime
*rtd
,
222 struct snd_pcm_substream
*substream
)
224 struct dmaengine_pcm
*pcm
= soc_platform_to_pcm(rtd
->platform
);
225 struct snd_dmaengine_dai_dma_data
*dma_data
;
226 dma_filter_fn fn
= NULL
;
228 dma_data
= snd_soc_dai_get_dma_data(rtd
->cpu_dai
, substream
);
230 if ((pcm
->flags
& SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX
) && pcm
->chan
[0])
233 if (pcm
->config
&& pcm
->config
->compat_request_channel
)
234 return pcm
->config
->compat_request_channel(rtd
, substream
);
237 fn
= pcm
->config
->compat_filter_fn
;
239 return snd_dmaengine_pcm_request_channel(fn
, dma_data
->filter_data
);
242 static bool dmaengine_pcm_can_report_residue(struct device
*dev
,
243 struct dma_chan
*chan
)
245 struct dma_slave_caps dma_caps
;
248 ret
= dma_get_slave_caps(chan
, &dma_caps
);
250 dev_warn(dev
, "Failed to get DMA channel capabilities, falling back to period counting: %d\n",
255 if (dma_caps
.residue_granularity
== DMA_RESIDUE_GRANULARITY_DESCRIPTOR
)
261 static int dmaengine_pcm_new(struct snd_soc_pcm_runtime
*rtd
)
263 struct dmaengine_pcm
*pcm
= soc_platform_to_pcm(rtd
->platform
);
264 const struct snd_dmaengine_pcm_config
*config
= pcm
->config
;
265 struct device
*dev
= rtd
->platform
->dev
;
266 struct snd_pcm_substream
*substream
;
267 size_t prealloc_buffer_size
;
268 size_t max_buffer_size
;
272 if (config
&& config
->prealloc_buffer_size
) {
273 prealloc_buffer_size
= config
->prealloc_buffer_size
;
274 max_buffer_size
= config
->pcm_hardware
->buffer_bytes_max
;
276 prealloc_buffer_size
= 512 * 1024;
277 max_buffer_size
= SIZE_MAX
;
280 for (i
= SNDRV_PCM_STREAM_PLAYBACK
; i
<= SNDRV_PCM_STREAM_CAPTURE
; i
++) {
281 substream
= rtd
->pcm
->streams
[i
].substream
;
285 if (!pcm
->chan
[i
] && (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_COMPAT
)) {
286 pcm
->chan
[i
] = dmaengine_pcm_compat_request_channel(rtd
,
291 dev_err(rtd
->platform
->dev
,
292 "Missing dma channel for stream: %d\n", i
);
296 ret
= snd_pcm_lib_preallocate_pages(substream
,
297 SNDRV_DMA_TYPE_DEV_IRAM
,
298 dmaengine_dma_dev(pcm
, substream
),
299 prealloc_buffer_size
,
304 if (!dmaengine_pcm_can_report_residue(dev
, pcm
->chan
[i
]))
305 pcm
->flags
|= SND_DMAENGINE_PCM_FLAG_NO_RESIDUE
;
311 static snd_pcm_uframes_t
dmaengine_pcm_pointer(
312 struct snd_pcm_substream
*substream
)
314 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
315 struct dmaengine_pcm
*pcm
= soc_platform_to_pcm(rtd
->platform
);
317 if (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_NO_RESIDUE
)
318 return snd_dmaengine_pcm_pointer_no_residue(substream
);
320 return snd_dmaengine_pcm_pointer(substream
);
323 static const struct snd_pcm_ops dmaengine_pcm_ops
= {
324 .open
= dmaengine_pcm_open
,
325 .close
= snd_dmaengine_pcm_close
,
326 .ioctl
= snd_pcm_lib_ioctl
,
327 .hw_params
= dmaengine_pcm_hw_params
,
328 .hw_free
= snd_pcm_lib_free_pages
,
329 .trigger
= snd_dmaengine_pcm_trigger
,
330 .pointer
= dmaengine_pcm_pointer
,
333 static const struct snd_soc_platform_driver dmaengine_pcm_platform
= {
334 .component_driver
= {
335 .probe_order
= SND_SOC_COMP_ORDER_LATE
,
337 .ops
= &dmaengine_pcm_ops
,
338 .pcm_new
= dmaengine_pcm_new
,
341 static const char * const dmaengine_pcm_dma_channel_names
[] = {
342 [SNDRV_PCM_STREAM_PLAYBACK
] = "tx",
343 [SNDRV_PCM_STREAM_CAPTURE
] = "rx",
346 static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm
*pcm
,
347 struct device
*dev
, const struct snd_dmaengine_pcm_config
*config
)
351 struct dma_chan
*chan
;
353 if ((pcm
->flags
& SND_DMAENGINE_PCM_FLAG_NO_DT
) || !dev
->of_node
)
356 if (config
&& config
->dma_dev
) {
358 * If this warning is seen, it probably means that your Linux
359 * device structure does not match your HW device structure.
360 * It would be best to refactor the Linux device structure to
361 * correctly match the HW structure.
363 dev_warn(dev
, "DMA channels sourced from device %s",
364 dev_name(config
->dma_dev
));
365 dev
= config
->dma_dev
;
368 for (i
= SNDRV_PCM_STREAM_PLAYBACK
; i
<= SNDRV_PCM_STREAM_CAPTURE
;
370 if (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX
)
373 name
= dmaengine_pcm_dma_channel_names
[i
];
374 if (config
&& config
->chan_names
[i
])
375 name
= config
->chan_names
[i
];
376 chan
= dma_request_slave_channel_reason(dev
, name
);
378 if (PTR_ERR(chan
) == -EPROBE_DEFER
)
379 return -EPROBE_DEFER
;
384 if (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX
)
388 if (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX
)
389 pcm
->chan
[1] = pcm
->chan
[0];
394 static void dmaengine_pcm_release_chan(struct dmaengine_pcm
*pcm
)
398 for (i
= SNDRV_PCM_STREAM_PLAYBACK
; i
<= SNDRV_PCM_STREAM_CAPTURE
;
402 dma_release_channel(pcm
->chan
[i
]);
403 if (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX
)
409 * snd_dmaengine_pcm_register - Register a dmaengine based PCM device
410 * @dev: The parent device for the PCM device
411 * @config: Platform specific PCM configuration
412 * @flags: Platform specific quirks
414 int snd_dmaengine_pcm_register(struct device
*dev
,
415 const struct snd_dmaengine_pcm_config
*config
, unsigned int flags
)
417 struct dmaengine_pcm
*pcm
;
420 pcm
= kzalloc(sizeof(*pcm
), GFP_KERNEL
);
424 pcm
->config
= config
;
427 ret
= dmaengine_pcm_request_chan_of(pcm
, dev
, config
);
431 ret
= snd_soc_add_platform(dev
, &pcm
->platform
,
432 &dmaengine_pcm_platform
);
439 dmaengine_pcm_release_chan(pcm
);
443 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register
);
446 * snd_dmaengine_pcm_unregister - Removes a dmaengine based PCM device
447 * @dev: Parent device the PCM was register with
449 * Removes a dmaengine based PCM device previously registered with
450 * snd_dmaengine_pcm_register.
452 void snd_dmaengine_pcm_unregister(struct device
*dev
)
454 struct snd_soc_platform
*platform
;
455 struct dmaengine_pcm
*pcm
;
457 platform
= snd_soc_lookup_platform(dev
);
461 pcm
= soc_platform_to_pcm(platform
);
463 snd_soc_remove_platform(platform
);
464 dmaengine_pcm_release_chan(pcm
);
467 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_unregister
);
469 MODULE_LICENSE("GPL");