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
= snd_soc_substream_to_rtd(substream
);
37 struct snd_dmaengine_dai_dma_data
*dma_params
;
38 struct dma_slave_config config
;
41 dma_params
= snd_soc_dai_get_dma_data(snd_soc_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(snd_soc_rtd_to_cpu(rtd
, 0), substream
),
53 ret
= dmaengine_slave_config(chan
, &config
);
59 EXPORT_SYMBOL(pxa2xx_pcm_hw_params
);
61 int pxa2xx_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
63 return snd_dmaengine_pcm_trigger(substream
, cmd
);
65 EXPORT_SYMBOL(pxa2xx_pcm_trigger
);
68 pxa2xx_pcm_pointer(struct snd_pcm_substream
*substream
)
70 return snd_dmaengine_pcm_pointer(substream
);
72 EXPORT_SYMBOL(pxa2xx_pcm_pointer
);
74 int pxa2xx_pcm_prepare(struct snd_pcm_substream
*substream
)
78 EXPORT_SYMBOL(pxa2xx_pcm_prepare
);
80 int pxa2xx_pcm_open(struct snd_pcm_substream
*substream
)
82 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
83 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
84 struct snd_dmaengine_dai_dma_data
*dma_params
;
87 runtime
->hw
= pxa2xx_pcm_hardware
;
89 dma_params
= snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd
, 0), substream
);
94 * For mysterious reasons (and despite what the manual says)
95 * playback samples are lost if the DMA count is not a multiple
96 * of the DMA burst size. Let's add a rule to enforce that.
98 ret
= snd_pcm_hw_constraint_step(runtime
, 0,
99 SNDRV_PCM_HW_PARAM_PERIOD_BYTES
, 32);
103 ret
= snd_pcm_hw_constraint_step(runtime
, 0,
104 SNDRV_PCM_HW_PARAM_BUFFER_BYTES
, 32);
108 ret
= snd_pcm_hw_constraint_integer(runtime
,
109 SNDRV_PCM_HW_PARAM_PERIODS
);
113 return snd_dmaengine_pcm_open(
114 substream
, dma_request_slave_channel(snd_soc_rtd_to_cpu(rtd
, 0)->dev
,
115 dma_params
->chan_name
));
117 EXPORT_SYMBOL(pxa2xx_pcm_open
);
119 int pxa2xx_pcm_close(struct snd_pcm_substream
*substream
)
121 return snd_dmaengine_pcm_close_release_chan(substream
);
123 EXPORT_SYMBOL(pxa2xx_pcm_close
);
125 int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm
*pcm
)
127 size_t size
= pxa2xx_pcm_hardware
.buffer_bytes_max
;
129 return snd_pcm_set_fixed_buffer_all(pcm
, SNDRV_DMA_TYPE_DEV_WC
,
130 pcm
->card
->dev
, size
);
132 EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer
);
134 int pxa2xx_soc_pcm_new(struct snd_soc_component
*component
,
135 struct snd_soc_pcm_runtime
*rtd
)
137 struct snd_card
*card
= rtd
->card
->snd_card
;
138 struct snd_pcm
*pcm
= rtd
->pcm
;
141 ret
= dma_coerce_mask_and_coherent(card
->dev
, DMA_BIT_MASK(32));
145 return pxa2xx_pcm_preallocate_dma_buffer(pcm
);
147 EXPORT_SYMBOL(pxa2xx_soc_pcm_new
);
149 int pxa2xx_soc_pcm_open(struct snd_soc_component
*component
,
150 struct snd_pcm_substream
*substream
)
152 return pxa2xx_pcm_open(substream
);
154 EXPORT_SYMBOL(pxa2xx_soc_pcm_open
);
156 int pxa2xx_soc_pcm_close(struct snd_soc_component
*component
,
157 struct snd_pcm_substream
*substream
)
159 return pxa2xx_pcm_close(substream
);
161 EXPORT_SYMBOL(pxa2xx_soc_pcm_close
);
163 int pxa2xx_soc_pcm_hw_params(struct snd_soc_component
*component
,
164 struct snd_pcm_substream
*substream
,
165 struct snd_pcm_hw_params
*params
)
167 return pxa2xx_pcm_hw_params(substream
, params
);
169 EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_params
);
171 int pxa2xx_soc_pcm_prepare(struct snd_soc_component
*component
,
172 struct snd_pcm_substream
*substream
)
174 return pxa2xx_pcm_prepare(substream
);
176 EXPORT_SYMBOL(pxa2xx_soc_pcm_prepare
);
178 int pxa2xx_soc_pcm_trigger(struct snd_soc_component
*component
,
179 struct snd_pcm_substream
*substream
, int cmd
)
181 return pxa2xx_pcm_trigger(substream
, cmd
);
183 EXPORT_SYMBOL(pxa2xx_soc_pcm_trigger
);
186 pxa2xx_soc_pcm_pointer(struct snd_soc_component
*component
,
187 struct snd_pcm_substream
*substream
)
189 return pxa2xx_pcm_pointer(substream
);
191 EXPORT_SYMBOL(pxa2xx_soc_pcm_pointer
);
193 MODULE_AUTHOR("Nicolas Pitre");
194 MODULE_DESCRIPTION("Intel PXA2xx sound library");
195 MODULE_LICENSE("GPL");