1 // SPDX-License-Identifier: GPL-2.0-only
3 #include <linux/slab.h>
4 #include <linux/module.h>
5 #include <linux/dma-mapping.h>
6 #include <linux/dmaengine.h>
7 #include <linux/dma/pxa-dma.h>
9 #include <sound/core.h>
10 #include <sound/pcm.h>
11 #include <sound/pcm_params.h>
12 #include <sound/pxa2xx-lib.h>
13 #include <sound/dmaengine_pcm.h>
15 static const struct snd_pcm_hardware pxa2xx_pcm_hardware
= {
16 .info
= SNDRV_PCM_INFO_MMAP
|
17 SNDRV_PCM_INFO_MMAP_VALID
|
18 SNDRV_PCM_INFO_INTERLEAVED
|
19 SNDRV_PCM_INFO_PAUSE
|
20 SNDRV_PCM_INFO_RESUME
,
21 .formats
= SNDRV_PCM_FMTBIT_S16_LE
|
22 SNDRV_PCM_FMTBIT_S24_LE
|
23 SNDRV_PCM_FMTBIT_S32_LE
,
24 .period_bytes_min
= 32,
25 .period_bytes_max
= 8192 - 32,
28 .buffer_bytes_max
= 128 * 1024,
32 int pxa2xx_pcm_hw_params(struct snd_pcm_substream
*substream
,
33 struct snd_pcm_hw_params
*params
)
35 struct dma_chan
*chan
= snd_dmaengine_pcm_get_chan(substream
);
36 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
37 struct snd_dmaengine_dai_dma_data
*dma_params
;
38 struct dma_slave_config config
;
41 dma_params
= snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd
, 0), substream
);
45 ret
= snd_hwparams_to_dma_slave_config(substream
, params
, &config
);
49 snd_dmaengine_pcm_set_config_from_dai_data(substream
,
50 snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd
, 0), substream
),
53 ret
= dmaengine_slave_config(chan
, &config
);
57 snd_pcm_set_runtime_buffer(substream
, &substream
->dma_buffer
);
61 EXPORT_SYMBOL(pxa2xx_pcm_hw_params
);
63 int pxa2xx_pcm_hw_free(struct snd_pcm_substream
*substream
)
65 snd_pcm_set_runtime_buffer(substream
, NULL
);
68 EXPORT_SYMBOL(pxa2xx_pcm_hw_free
);
70 int pxa2xx_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
72 return snd_dmaengine_pcm_trigger(substream
, cmd
);
74 EXPORT_SYMBOL(pxa2xx_pcm_trigger
);
77 pxa2xx_pcm_pointer(struct snd_pcm_substream
*substream
)
79 return snd_dmaengine_pcm_pointer(substream
);
81 EXPORT_SYMBOL(pxa2xx_pcm_pointer
);
83 int pxa2xx_pcm_prepare(struct snd_pcm_substream
*substream
)
87 EXPORT_SYMBOL(pxa2xx_pcm_prepare
);
89 int pxa2xx_pcm_open(struct snd_pcm_substream
*substream
)
91 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
92 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
93 struct snd_dmaengine_dai_dma_data
*dma_params
;
96 runtime
->hw
= pxa2xx_pcm_hardware
;
98 dma_params
= snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd
, 0), substream
);
103 * For mysterious reasons (and despite what the manual says)
104 * playback samples are lost if the DMA count is not a multiple
105 * of the DMA burst size. Let's add a rule to enforce that.
107 ret
= snd_pcm_hw_constraint_step(runtime
, 0,
108 SNDRV_PCM_HW_PARAM_PERIOD_BYTES
, 32);
112 ret
= snd_pcm_hw_constraint_step(runtime
, 0,
113 SNDRV_PCM_HW_PARAM_BUFFER_BYTES
, 32);
117 ret
= snd_pcm_hw_constraint_integer(runtime
,
118 SNDRV_PCM_HW_PARAM_PERIODS
);
122 return snd_dmaengine_pcm_open(
123 substream
, dma_request_slave_channel(asoc_rtd_to_cpu(rtd
, 0)->dev
,
124 dma_params
->chan_name
));
126 EXPORT_SYMBOL(pxa2xx_pcm_open
);
128 int pxa2xx_pcm_close(struct snd_pcm_substream
*substream
)
130 return snd_dmaengine_pcm_close_release_chan(substream
);
132 EXPORT_SYMBOL(pxa2xx_pcm_close
);
134 int pxa2xx_pcm_mmap(struct snd_pcm_substream
*substream
,
135 struct vm_area_struct
*vma
)
137 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
138 return dma_mmap_wc(substream
->pcm
->card
->dev
, vma
, runtime
->dma_area
,
139 runtime
->dma_addr
, runtime
->dma_bytes
);
141 EXPORT_SYMBOL(pxa2xx_pcm_mmap
);
143 int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm
*pcm
, int stream
)
145 struct snd_pcm_substream
*substream
= pcm
->streams
[stream
].substream
;
146 struct snd_dma_buffer
*buf
= &substream
->dma_buffer
;
147 size_t size
= pxa2xx_pcm_hardware
.buffer_bytes_max
;
148 buf
->dev
.type
= SNDRV_DMA_TYPE_DEV
;
149 buf
->dev
.dev
= pcm
->card
->dev
;
150 buf
->private_data
= NULL
;
151 buf
->area
= dma_alloc_wc(pcm
->card
->dev
, size
, &buf
->addr
, GFP_KERNEL
);
157 EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer
);
159 void pxa2xx_pcm_free_dma_buffers(struct snd_pcm
*pcm
)
161 struct snd_pcm_substream
*substream
;
162 struct snd_dma_buffer
*buf
;
165 for (stream
= 0; stream
< 2; stream
++) {
166 substream
= pcm
->streams
[stream
].substream
;
169 buf
= &substream
->dma_buffer
;
172 dma_free_wc(pcm
->card
->dev
, buf
->bytes
, buf
->area
, buf
->addr
);
176 EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers
);
178 void pxa2xx_soc_pcm_free(struct snd_soc_component
*component
,
181 pxa2xx_pcm_free_dma_buffers(pcm
);
183 EXPORT_SYMBOL(pxa2xx_soc_pcm_free
);
185 int pxa2xx_soc_pcm_new(struct snd_soc_component
*component
,
186 struct snd_soc_pcm_runtime
*rtd
)
188 struct snd_card
*card
= rtd
->card
->snd_card
;
189 struct snd_pcm
*pcm
= rtd
->pcm
;
192 ret
= dma_coerce_mask_and_coherent(card
->dev
, DMA_BIT_MASK(32));
196 if (pcm
->streams
[SNDRV_PCM_STREAM_PLAYBACK
].substream
) {
197 ret
= pxa2xx_pcm_preallocate_dma_buffer(pcm
,
198 SNDRV_PCM_STREAM_PLAYBACK
);
203 if (pcm
->streams
[SNDRV_PCM_STREAM_CAPTURE
].substream
) {
204 ret
= pxa2xx_pcm_preallocate_dma_buffer(pcm
,
205 SNDRV_PCM_STREAM_CAPTURE
);
212 EXPORT_SYMBOL(pxa2xx_soc_pcm_new
);
214 int pxa2xx_soc_pcm_open(struct snd_soc_component
*component
,
215 struct snd_pcm_substream
*substream
)
217 return pxa2xx_pcm_open(substream
);
219 EXPORT_SYMBOL(pxa2xx_soc_pcm_open
);
221 int pxa2xx_soc_pcm_close(struct snd_soc_component
*component
,
222 struct snd_pcm_substream
*substream
)
224 return pxa2xx_pcm_close(substream
);
226 EXPORT_SYMBOL(pxa2xx_soc_pcm_close
);
228 int pxa2xx_soc_pcm_hw_params(struct snd_soc_component
*component
,
229 struct snd_pcm_substream
*substream
,
230 struct snd_pcm_hw_params
*params
)
232 return pxa2xx_pcm_hw_params(substream
, params
);
234 EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_params
);
236 int pxa2xx_soc_pcm_hw_free(struct snd_soc_component
*component
,
237 struct snd_pcm_substream
*substream
)
239 return pxa2xx_pcm_hw_free(substream
);
241 EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_free
);
243 int pxa2xx_soc_pcm_prepare(struct snd_soc_component
*component
,
244 struct snd_pcm_substream
*substream
)
246 return pxa2xx_pcm_prepare(substream
);
248 EXPORT_SYMBOL(pxa2xx_soc_pcm_prepare
);
250 int pxa2xx_soc_pcm_trigger(struct snd_soc_component
*component
,
251 struct snd_pcm_substream
*substream
, int cmd
)
253 return pxa2xx_pcm_trigger(substream
, cmd
);
255 EXPORT_SYMBOL(pxa2xx_soc_pcm_trigger
);
258 pxa2xx_soc_pcm_pointer(struct snd_soc_component
*component
,
259 struct snd_pcm_substream
*substream
)
261 return pxa2xx_pcm_pointer(substream
);
263 EXPORT_SYMBOL(pxa2xx_soc_pcm_pointer
);
265 int pxa2xx_soc_pcm_mmap(struct snd_soc_component
*component
,
266 struct snd_pcm_substream
*substream
,
267 struct vm_area_struct
*vma
)
269 return pxa2xx_pcm_mmap(substream
, vma
);
271 EXPORT_SYMBOL(pxa2xx_soc_pcm_mmap
);
273 MODULE_AUTHOR("Nicolas Pitre");
274 MODULE_DESCRIPTION("Intel PXA2xx sound library");
275 MODULE_LICENSE("GPL");