1 // SPDX-License-Identifier: GPL-2.0+
3 // Copyright (C) 2013, Analog Devices Inc.
4 // Author: Lars-Peter Clausen <lars@metafoo.de>
6 #include <linux/module.h>
7 #include <linux/init.h>
8 #include <linux/dmaengine.h>
9 #include <linux/slab.h>
10 #include <sound/pcm.h>
11 #include <sound/pcm_params.h>
12 #include <sound/soc.h>
13 #include <linux/dma-mapping.h>
16 #include <sound/dmaengine_pcm.h>
19 * The platforms dmaengine driver does not support reporting the amount of
20 * bytes that are still left to transfer.
22 #define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(31)
24 struct dmaengine_pcm
{
25 struct dma_chan
*chan
[SNDRV_PCM_STREAM_LAST
+ 1];
26 const struct snd_dmaengine_pcm_config
*config
;
27 struct snd_soc_component component
;
31 static struct dmaengine_pcm
*soc_component_to_pcm(struct snd_soc_component
*p
)
33 return container_of(p
, struct dmaengine_pcm
, component
);
36 static struct device
*dmaengine_dma_dev(struct dmaengine_pcm
*pcm
,
37 struct snd_pcm_substream
*substream
)
39 if (!pcm
->chan
[substream
->stream
])
42 return pcm
->chan
[substream
->stream
]->device
->dev
;
46 * snd_dmaengine_pcm_prepare_slave_config() - Generic prepare_slave_config callback
47 * @substream: PCM substream
49 * @slave_config: DMA slave config to prepare
51 * This function can be used as a generic prepare_slave_config callback for
52 * platforms which make use of the snd_dmaengine_dai_dma_data struct for their
53 * DAI DMA data. Internally the function will first call
54 * snd_hwparams_to_dma_slave_config to fill in the slave config based on the
55 * hw_params, followed by snd_dmaengine_set_config_from_dai_data to fill in the
56 * remaining fields based on the DAI DMA data.
58 int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream
*substream
,
59 struct snd_pcm_hw_params
*params
, struct dma_slave_config
*slave_config
)
61 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
62 struct snd_dmaengine_dai_dma_data
*dma_data
;
65 dma_data
= snd_soc_dai_get_dma_data(rtd
->cpu_dai
, substream
);
67 ret
= snd_hwparams_to_dma_slave_config(substream
, params
, slave_config
);
71 snd_dmaengine_pcm_set_config_from_dai_data(substream
, dma_data
,
76 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_prepare_slave_config
);
78 static int dmaengine_pcm_hw_params(struct snd_soc_component
*component
,
79 struct snd_pcm_substream
*substream
,
80 struct snd_pcm_hw_params
*params
)
82 struct dmaengine_pcm
*pcm
= soc_component_to_pcm(component
);
83 struct dma_chan
*chan
= snd_dmaengine_pcm_get_chan(substream
);
84 int (*prepare_slave_config
)(struct snd_pcm_substream
*substream
,
85 struct snd_pcm_hw_params
*params
,
86 struct dma_slave_config
*slave_config
);
87 struct dma_slave_config slave_config
;
90 memset(&slave_config
, 0, sizeof(slave_config
));
93 prepare_slave_config
= snd_dmaengine_pcm_prepare_slave_config
;
95 prepare_slave_config
= pcm
->config
->prepare_slave_config
;
97 if (prepare_slave_config
) {
98 ret
= prepare_slave_config(substream
, params
, &slave_config
);
102 ret
= dmaengine_slave_config(chan
, &slave_config
);
111 dmaengine_pcm_set_runtime_hwparams(struct snd_soc_component
*component
,
112 struct snd_pcm_substream
*substream
)
114 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
115 struct dmaengine_pcm
*pcm
= soc_component_to_pcm(component
);
116 struct device
*dma_dev
= dmaengine_dma_dev(pcm
, substream
);
117 struct dma_chan
*chan
= pcm
->chan
[substream
->stream
];
118 struct snd_dmaengine_dai_dma_data
*dma_data
;
119 struct snd_pcm_hardware hw
;
121 if (pcm
->config
&& pcm
->config
->pcm_hardware
)
122 return snd_soc_set_runtime_hwparams(substream
,
123 pcm
->config
->pcm_hardware
);
125 dma_data
= snd_soc_dai_get_dma_data(rtd
->cpu_dai
, substream
);
127 memset(&hw
, 0, sizeof(hw
));
128 hw
.info
= SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID
|
129 SNDRV_PCM_INFO_INTERLEAVED
;
131 hw
.periods_max
= UINT_MAX
;
132 hw
.period_bytes_min
= 256;
133 hw
.period_bytes_max
= dma_get_max_seg_size(dma_dev
);
134 hw
.buffer_bytes_max
= SIZE_MAX
;
135 hw
.fifo_size
= dma_data
->fifo_size
;
137 if (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_NO_RESIDUE
)
138 hw
.info
|= SNDRV_PCM_INFO_BATCH
;
141 * FIXME: Remove the return value check to align with the code
142 * before adding snd_dmaengine_pcm_refine_runtime_hwparams
145 snd_dmaengine_pcm_refine_runtime_hwparams(substream
,
150 return snd_soc_set_runtime_hwparams(substream
, &hw
);
153 static int dmaengine_pcm_open(struct snd_soc_component
*component
,
154 struct snd_pcm_substream
*substream
)
156 struct dmaengine_pcm
*pcm
= soc_component_to_pcm(component
);
157 struct dma_chan
*chan
= pcm
->chan
[substream
->stream
];
160 ret
= dmaengine_pcm_set_runtime_hwparams(component
, substream
);
164 return snd_dmaengine_pcm_open(substream
, chan
);
167 static int dmaengine_pcm_close(struct snd_soc_component
*component
,
168 struct snd_pcm_substream
*substream
)
170 return snd_dmaengine_pcm_close(substream
);
173 static int dmaengine_pcm_trigger(struct snd_soc_component
*component
,
174 struct snd_pcm_substream
*substream
, int cmd
)
176 return snd_dmaengine_pcm_trigger(substream
, cmd
);
179 static struct dma_chan
*dmaengine_pcm_compat_request_channel(
180 struct snd_soc_component
*component
,
181 struct snd_soc_pcm_runtime
*rtd
,
182 struct snd_pcm_substream
*substream
)
184 struct dmaengine_pcm
*pcm
= soc_component_to_pcm(component
);
185 struct snd_dmaengine_dai_dma_data
*dma_data
;
186 dma_filter_fn fn
= NULL
;
188 dma_data
= snd_soc_dai_get_dma_data(rtd
->cpu_dai
, substream
);
190 if ((pcm
->flags
& SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX
) && pcm
->chan
[0])
193 if (pcm
->config
&& pcm
->config
->compat_request_channel
)
194 return pcm
->config
->compat_request_channel(rtd
, substream
);
197 fn
= pcm
->config
->compat_filter_fn
;
199 return snd_dmaengine_pcm_request_channel(fn
, dma_data
->filter_data
);
202 static bool dmaengine_pcm_can_report_residue(struct device
*dev
,
203 struct dma_chan
*chan
)
205 struct dma_slave_caps dma_caps
;
208 ret
= dma_get_slave_caps(chan
, &dma_caps
);
210 dev_warn(dev
, "Failed to get DMA channel capabilities, falling back to period counting: %d\n",
215 if (dma_caps
.residue_granularity
== DMA_RESIDUE_GRANULARITY_DESCRIPTOR
)
221 static int dmaengine_pcm_new(struct snd_soc_component
*component
,
222 struct snd_soc_pcm_runtime
*rtd
)
224 struct dmaengine_pcm
*pcm
= soc_component_to_pcm(component
);
225 const struct snd_dmaengine_pcm_config
*config
= pcm
->config
;
226 struct device
*dev
= component
->dev
;
227 struct snd_pcm_substream
*substream
;
228 size_t prealloc_buffer_size
;
229 size_t max_buffer_size
;
232 if (config
&& config
->prealloc_buffer_size
) {
233 prealloc_buffer_size
= config
->prealloc_buffer_size
;
234 max_buffer_size
= config
->pcm_hardware
->buffer_bytes_max
;
236 prealloc_buffer_size
= 512 * 1024;
237 max_buffer_size
= SIZE_MAX
;
240 for (i
= SNDRV_PCM_STREAM_PLAYBACK
; i
<= SNDRV_PCM_STREAM_CAPTURE
; i
++) {
241 substream
= rtd
->pcm
->streams
[i
].substream
;
245 if (!pcm
->chan
[i
] && config
&& config
->chan_names
[i
])
246 pcm
->chan
[i
] = dma_request_slave_channel(dev
,
247 config
->chan_names
[i
]);
249 if (!pcm
->chan
[i
] && (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_COMPAT
)) {
250 pcm
->chan
[i
] = dmaengine_pcm_compat_request_channel(
251 component
, rtd
, substream
);
255 dev_err(component
->dev
,
256 "Missing dma channel for stream: %d\n", i
);
260 snd_pcm_set_managed_buffer(substream
,
261 SNDRV_DMA_TYPE_DEV_IRAM
,
262 dmaengine_dma_dev(pcm
, substream
),
263 prealloc_buffer_size
,
266 if (!dmaengine_pcm_can_report_residue(dev
, pcm
->chan
[i
]))
267 pcm
->flags
|= SND_DMAENGINE_PCM_FLAG_NO_RESIDUE
;
269 if (rtd
->pcm
->streams
[i
].pcm
->name
[0] == '\0') {
270 strscpy_pad(rtd
->pcm
->streams
[i
].pcm
->name
,
271 rtd
->pcm
->streams
[i
].pcm
->id
,
272 sizeof(rtd
->pcm
->streams
[i
].pcm
->name
));
279 static snd_pcm_uframes_t
dmaengine_pcm_pointer(
280 struct snd_soc_component
*component
,
281 struct snd_pcm_substream
*substream
)
283 struct dmaengine_pcm
*pcm
= soc_component_to_pcm(component
);
285 if (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_NO_RESIDUE
)
286 return snd_dmaengine_pcm_pointer_no_residue(substream
);
288 return snd_dmaengine_pcm_pointer(substream
);
291 static int dmaengine_copy_user(struct snd_soc_component
*component
,
292 struct snd_pcm_substream
*substream
,
293 int channel
, unsigned long hwoff
,
294 void __user
*buf
, unsigned long bytes
)
296 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
297 struct dmaengine_pcm
*pcm
= soc_component_to_pcm(component
);
298 int (*process
)(struct snd_pcm_substream
*substream
,
299 int channel
, unsigned long hwoff
,
300 void *buf
, unsigned long bytes
) = pcm
->config
->process
;
301 bool is_playback
= substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
;
302 void *dma_ptr
= runtime
->dma_area
+ hwoff
+
303 channel
* (runtime
->dma_bytes
/ runtime
->channels
);
307 if (copy_from_user(dma_ptr
, buf
, bytes
))
311 ret
= process(substream
, channel
, hwoff
, (__force
void *)buf
, bytes
);
317 if (copy_to_user(buf
, dma_ptr
, bytes
))
323 static const struct snd_soc_component_driver dmaengine_pcm_component
= {
324 .name
= SND_DMAENGINE_PCM_DRV_NAME
,
325 .probe_order
= SND_SOC_COMP_ORDER_LATE
,
326 .open
= dmaengine_pcm_open
,
327 .close
= dmaengine_pcm_close
,
328 .hw_params
= dmaengine_pcm_hw_params
,
329 .trigger
= dmaengine_pcm_trigger
,
330 .pointer
= dmaengine_pcm_pointer
,
331 .pcm_construct
= dmaengine_pcm_new
,
334 static const struct snd_soc_component_driver dmaengine_pcm_component_process
= {
335 .name
= SND_DMAENGINE_PCM_DRV_NAME
,
336 .probe_order
= SND_SOC_COMP_ORDER_LATE
,
337 .open
= dmaengine_pcm_open
,
338 .close
= dmaengine_pcm_close
,
339 .hw_params
= dmaengine_pcm_hw_params
,
340 .trigger
= dmaengine_pcm_trigger
,
341 .pointer
= dmaengine_pcm_pointer
,
342 .copy_user
= dmaengine_copy_user
,
343 .pcm_construct
= dmaengine_pcm_new
,
346 static const char * const dmaengine_pcm_dma_channel_names
[] = {
347 [SNDRV_PCM_STREAM_PLAYBACK
] = "tx",
348 [SNDRV_PCM_STREAM_CAPTURE
] = "rx",
351 static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm
*pcm
,
352 struct device
*dev
, const struct snd_dmaengine_pcm_config
*config
)
356 struct dma_chan
*chan
;
358 if ((pcm
->flags
& SND_DMAENGINE_PCM_FLAG_NO_DT
) || (!dev
->of_node
&&
359 !(config
&& config
->dma_dev
&& config
->dma_dev
->of_node
)))
362 if (config
&& config
->dma_dev
) {
364 * If this warning is seen, it probably means that your Linux
365 * device structure does not match your HW device structure.
366 * It would be best to refactor the Linux device structure to
367 * correctly match the HW structure.
369 dev_warn(dev
, "DMA channels sourced from device %s",
370 dev_name(config
->dma_dev
));
371 dev
= config
->dma_dev
;
374 for (i
= SNDRV_PCM_STREAM_PLAYBACK
; i
<= SNDRV_PCM_STREAM_CAPTURE
;
376 if (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX
)
379 name
= dmaengine_pcm_dma_channel_names
[i
];
380 if (config
&& config
->chan_names
[i
])
381 name
= config
->chan_names
[i
];
382 chan
= dma_request_chan(dev
, name
);
384 if (PTR_ERR(chan
) == -EPROBE_DEFER
)
385 return -EPROBE_DEFER
;
390 if (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX
)
394 if (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX
)
395 pcm
->chan
[1] = pcm
->chan
[0];
400 static void dmaengine_pcm_release_chan(struct dmaengine_pcm
*pcm
)
404 for (i
= SNDRV_PCM_STREAM_PLAYBACK
; i
<= SNDRV_PCM_STREAM_CAPTURE
;
408 dma_release_channel(pcm
->chan
[i
]);
409 if (pcm
->flags
& SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX
)
415 * snd_dmaengine_pcm_register - Register a dmaengine based PCM device
416 * @dev: The parent device for the PCM device
417 * @config: Platform specific PCM configuration
418 * @flags: Platform specific quirks
420 int snd_dmaengine_pcm_register(struct device
*dev
,
421 const struct snd_dmaengine_pcm_config
*config
, unsigned int flags
)
423 struct dmaengine_pcm
*pcm
;
426 pcm
= kzalloc(sizeof(*pcm
), GFP_KERNEL
);
430 #ifdef CONFIG_DEBUG_FS
431 pcm
->component
.debugfs_prefix
= "dma";
433 pcm
->config
= config
;
436 ret
= dmaengine_pcm_request_chan_of(pcm
, dev
, config
);
440 if (config
&& config
->process
)
441 ret
= snd_soc_add_component(dev
, &pcm
->component
,
442 &dmaengine_pcm_component_process
,
445 ret
= snd_soc_add_component(dev
, &pcm
->component
,
446 &dmaengine_pcm_component
, NULL
, 0);
453 dmaengine_pcm_release_chan(pcm
);
457 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register
);
460 * snd_dmaengine_pcm_unregister - Removes a dmaengine based PCM device
461 * @dev: Parent device the PCM was register with
463 * Removes a dmaengine based PCM device previously registered with
464 * snd_dmaengine_pcm_register.
466 void snd_dmaengine_pcm_unregister(struct device
*dev
)
468 struct snd_soc_component
*component
;
469 struct dmaengine_pcm
*pcm
;
471 component
= snd_soc_lookup_component(dev
, SND_DMAENGINE_PCM_DRV_NAME
);
475 pcm
= soc_component_to_pcm(component
);
477 snd_soc_unregister_component(dev
);
478 dmaengine_pcm_release_chan(pcm
);
481 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_unregister
);
483 MODULE_LICENSE("GPL");