xref: /OK3568_Linux_fs/kernel/sound/arm/pxa2xx-pcm-lib.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun 
3*4882a593Smuzhiyun #include <linux/slab.h>
4*4882a593Smuzhiyun #include <linux/module.h>
5*4882a593Smuzhiyun #include <linux/dma-mapping.h>
6*4882a593Smuzhiyun #include <linux/dmaengine.h>
7*4882a593Smuzhiyun #include <linux/dma/pxa-dma.h>
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <sound/core.h>
10*4882a593Smuzhiyun #include <sound/pcm.h>
11*4882a593Smuzhiyun #include <sound/pcm_params.h>
12*4882a593Smuzhiyun #include <sound/pxa2xx-lib.h>
13*4882a593Smuzhiyun #include <sound/dmaengine_pcm.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
16*4882a593Smuzhiyun 	.info			= SNDRV_PCM_INFO_MMAP |
17*4882a593Smuzhiyun 				  SNDRV_PCM_INFO_MMAP_VALID |
18*4882a593Smuzhiyun 				  SNDRV_PCM_INFO_INTERLEAVED |
19*4882a593Smuzhiyun 				  SNDRV_PCM_INFO_PAUSE |
20*4882a593Smuzhiyun 				  SNDRV_PCM_INFO_RESUME,
21*4882a593Smuzhiyun 	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
22*4882a593Smuzhiyun 				  SNDRV_PCM_FMTBIT_S24_LE |
23*4882a593Smuzhiyun 				  SNDRV_PCM_FMTBIT_S32_LE,
24*4882a593Smuzhiyun 	.period_bytes_min	= 32,
25*4882a593Smuzhiyun 	.period_bytes_max	= 8192 - 32,
26*4882a593Smuzhiyun 	.periods_min		= 1,
27*4882a593Smuzhiyun 	.periods_max		= 256,
28*4882a593Smuzhiyun 	.buffer_bytes_max	= 128 * 1024,
29*4882a593Smuzhiyun 	.fifo_size		= 32,
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun 
pxa2xx_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)32*4882a593Smuzhiyun int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
33*4882a593Smuzhiyun 			 struct snd_pcm_hw_params *params)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
36*4882a593Smuzhiyun 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
37*4882a593Smuzhiyun 	struct snd_dmaengine_dai_dma_data *dma_params;
38*4882a593Smuzhiyun 	struct dma_slave_config config;
39*4882a593Smuzhiyun 	int ret;
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	dma_params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
42*4882a593Smuzhiyun 	if (!dma_params)
43*4882a593Smuzhiyun 		return 0;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	ret = snd_hwparams_to_dma_slave_config(substream, params, &config);
46*4882a593Smuzhiyun 	if (ret)
47*4882a593Smuzhiyun 		return ret;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	snd_dmaengine_pcm_set_config_from_dai_data(substream,
50*4882a593Smuzhiyun 			snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream),
51*4882a593Smuzhiyun 			&config);
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	ret = dmaengine_slave_config(chan, &config);
54*4882a593Smuzhiyun 	if (ret)
55*4882a593Smuzhiyun 		return ret;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	return 0;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_pcm_hw_params);
62*4882a593Smuzhiyun 
pxa2xx_pcm_hw_free(struct snd_pcm_substream * substream)63*4882a593Smuzhiyun int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	snd_pcm_set_runtime_buffer(substream, NULL);
66*4882a593Smuzhiyun 	return 0;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_pcm_hw_free);
69*4882a593Smuzhiyun 
pxa2xx_pcm_trigger(struct snd_pcm_substream * substream,int cmd)70*4882a593Smuzhiyun int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	return snd_dmaengine_pcm_trigger(substream, cmd);
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_pcm_trigger);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun snd_pcm_uframes_t
pxa2xx_pcm_pointer(struct snd_pcm_substream * substream)77*4882a593Smuzhiyun pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	return snd_dmaengine_pcm_pointer(substream);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_pcm_pointer);
82*4882a593Smuzhiyun 
pxa2xx_pcm_prepare(struct snd_pcm_substream * substream)83*4882a593Smuzhiyun int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun 	return 0;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_pcm_prepare);
88*4882a593Smuzhiyun 
pxa2xx_pcm_open(struct snd_pcm_substream * substream)89*4882a593Smuzhiyun int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
92*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
93*4882a593Smuzhiyun 	struct snd_dmaengine_dai_dma_data *dma_params;
94*4882a593Smuzhiyun 	int ret;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	runtime->hw = pxa2xx_pcm_hardware;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	dma_params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
99*4882a593Smuzhiyun 	if (!dma_params)
100*4882a593Smuzhiyun 		return 0;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	/*
103*4882a593Smuzhiyun 	 * For mysterious reasons (and despite what the manual says)
104*4882a593Smuzhiyun 	 * playback samples are lost if the DMA count is not a multiple
105*4882a593Smuzhiyun 	 * of the DMA burst size.  Let's add a rule to enforce that.
106*4882a593Smuzhiyun 	 */
107*4882a593Smuzhiyun 	ret = snd_pcm_hw_constraint_step(runtime, 0,
108*4882a593Smuzhiyun 		SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
109*4882a593Smuzhiyun 	if (ret)
110*4882a593Smuzhiyun 		return ret;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	ret = snd_pcm_hw_constraint_step(runtime, 0,
113*4882a593Smuzhiyun 		SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
114*4882a593Smuzhiyun 	if (ret)
115*4882a593Smuzhiyun 		return ret;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	ret = snd_pcm_hw_constraint_integer(runtime,
118*4882a593Smuzhiyun 					    SNDRV_PCM_HW_PARAM_PERIODS);
119*4882a593Smuzhiyun 	if (ret < 0)
120*4882a593Smuzhiyun 		return ret;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return snd_dmaengine_pcm_open(
123*4882a593Smuzhiyun 		substream, dma_request_slave_channel(asoc_rtd_to_cpu(rtd, 0)->dev,
124*4882a593Smuzhiyun 						     dma_params->chan_name));
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_pcm_open);
127*4882a593Smuzhiyun 
pxa2xx_pcm_close(struct snd_pcm_substream * substream)128*4882a593Smuzhiyun int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	return snd_dmaengine_pcm_close_release_chan(substream);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_pcm_close);
133*4882a593Smuzhiyun 
pxa2xx_pcm_mmap(struct snd_pcm_substream * substream,struct vm_area_struct * vma)134*4882a593Smuzhiyun int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
135*4882a593Smuzhiyun 	struct vm_area_struct *vma)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
138*4882a593Smuzhiyun 	return dma_mmap_wc(substream->pcm->card->dev, vma, runtime->dma_area,
139*4882a593Smuzhiyun 			   runtime->dma_addr, runtime->dma_bytes);
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_pcm_mmap);
142*4882a593Smuzhiyun 
pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm * pcm,int stream)143*4882a593Smuzhiyun int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun 	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
146*4882a593Smuzhiyun 	struct snd_dma_buffer *buf = &substream->dma_buffer;
147*4882a593Smuzhiyun 	size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
148*4882a593Smuzhiyun 	buf->dev.type = SNDRV_DMA_TYPE_DEV;
149*4882a593Smuzhiyun 	buf->dev.dev = pcm->card->dev;
150*4882a593Smuzhiyun 	buf->private_data = NULL;
151*4882a593Smuzhiyun 	buf->area = dma_alloc_wc(pcm->card->dev, size, &buf->addr, GFP_KERNEL);
152*4882a593Smuzhiyun 	if (!buf->area)
153*4882a593Smuzhiyun 		return -ENOMEM;
154*4882a593Smuzhiyun 	buf->bytes = size;
155*4882a593Smuzhiyun 	return 0;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer);
158*4882a593Smuzhiyun 
pxa2xx_pcm_free_dma_buffers(struct snd_pcm * pcm)159*4882a593Smuzhiyun void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun 	struct snd_pcm_substream *substream;
162*4882a593Smuzhiyun 	struct snd_dma_buffer *buf;
163*4882a593Smuzhiyun 	int stream;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	for (stream = 0; stream < 2; stream++) {
166*4882a593Smuzhiyun 		substream = pcm->streams[stream].substream;
167*4882a593Smuzhiyun 		if (!substream)
168*4882a593Smuzhiyun 			continue;
169*4882a593Smuzhiyun 		buf = &substream->dma_buffer;
170*4882a593Smuzhiyun 		if (!buf->area)
171*4882a593Smuzhiyun 			continue;
172*4882a593Smuzhiyun 		dma_free_wc(pcm->card->dev, buf->bytes, buf->area, buf->addr);
173*4882a593Smuzhiyun 		buf->area = NULL;
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers);
177*4882a593Smuzhiyun 
pxa2xx_soc_pcm_free(struct snd_soc_component * component,struct snd_pcm * pcm)178*4882a593Smuzhiyun void pxa2xx_soc_pcm_free(struct snd_soc_component *component,
179*4882a593Smuzhiyun 			 struct snd_pcm *pcm)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	pxa2xx_pcm_free_dma_buffers(pcm);
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_soc_pcm_free);
184*4882a593Smuzhiyun 
pxa2xx_soc_pcm_new(struct snd_soc_component * component,struct snd_soc_pcm_runtime * rtd)185*4882a593Smuzhiyun int pxa2xx_soc_pcm_new(struct snd_soc_component *component,
186*4882a593Smuzhiyun 		       struct snd_soc_pcm_runtime *rtd)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	struct snd_card *card = rtd->card->snd_card;
189*4882a593Smuzhiyun 	struct snd_pcm *pcm = rtd->pcm;
190*4882a593Smuzhiyun 	int ret;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
193*4882a593Smuzhiyun 	if (ret)
194*4882a593Smuzhiyun 		return ret;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
197*4882a593Smuzhiyun 		ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
198*4882a593Smuzhiyun 			SNDRV_PCM_STREAM_PLAYBACK);
199*4882a593Smuzhiyun 		if (ret)
200*4882a593Smuzhiyun 			goto out;
201*4882a593Smuzhiyun 	}
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
204*4882a593Smuzhiyun 		ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
205*4882a593Smuzhiyun 			SNDRV_PCM_STREAM_CAPTURE);
206*4882a593Smuzhiyun 		if (ret)
207*4882a593Smuzhiyun 			goto out;
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun  out:
210*4882a593Smuzhiyun 	return ret;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_soc_pcm_new);
213*4882a593Smuzhiyun 
pxa2xx_soc_pcm_open(struct snd_soc_component * component,struct snd_pcm_substream * substream)214*4882a593Smuzhiyun int pxa2xx_soc_pcm_open(struct snd_soc_component *component,
215*4882a593Smuzhiyun 			struct snd_pcm_substream *substream)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun 	return pxa2xx_pcm_open(substream);
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_soc_pcm_open);
220*4882a593Smuzhiyun 
pxa2xx_soc_pcm_close(struct snd_soc_component * component,struct snd_pcm_substream * substream)221*4882a593Smuzhiyun int pxa2xx_soc_pcm_close(struct snd_soc_component *component,
222*4882a593Smuzhiyun 			 struct snd_pcm_substream *substream)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	return pxa2xx_pcm_close(substream);
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_soc_pcm_close);
227*4882a593Smuzhiyun 
pxa2xx_soc_pcm_hw_params(struct snd_soc_component * component,struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)228*4882a593Smuzhiyun int pxa2xx_soc_pcm_hw_params(struct snd_soc_component *component,
229*4882a593Smuzhiyun 			     struct snd_pcm_substream *substream,
230*4882a593Smuzhiyun 			     struct snd_pcm_hw_params *params)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 	return pxa2xx_pcm_hw_params(substream, params);
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_params);
235*4882a593Smuzhiyun 
pxa2xx_soc_pcm_hw_free(struct snd_soc_component * component,struct snd_pcm_substream * substream)236*4882a593Smuzhiyun int pxa2xx_soc_pcm_hw_free(struct snd_soc_component *component,
237*4882a593Smuzhiyun 			   struct snd_pcm_substream *substream)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	return pxa2xx_pcm_hw_free(substream);
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_free);
242*4882a593Smuzhiyun 
pxa2xx_soc_pcm_prepare(struct snd_soc_component * component,struct snd_pcm_substream * substream)243*4882a593Smuzhiyun int pxa2xx_soc_pcm_prepare(struct snd_soc_component *component,
244*4882a593Smuzhiyun 			   struct snd_pcm_substream *substream)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	return pxa2xx_pcm_prepare(substream);
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_soc_pcm_prepare);
249*4882a593Smuzhiyun 
pxa2xx_soc_pcm_trigger(struct snd_soc_component * component,struct snd_pcm_substream * substream,int cmd)250*4882a593Smuzhiyun int pxa2xx_soc_pcm_trigger(struct snd_soc_component *component,
251*4882a593Smuzhiyun 			   struct snd_pcm_substream *substream, int cmd)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	return pxa2xx_pcm_trigger(substream, cmd);
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_soc_pcm_trigger);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun snd_pcm_uframes_t
pxa2xx_soc_pcm_pointer(struct snd_soc_component * component,struct snd_pcm_substream * substream)258*4882a593Smuzhiyun pxa2xx_soc_pcm_pointer(struct snd_soc_component *component,
259*4882a593Smuzhiyun 		       struct snd_pcm_substream *substream)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	return pxa2xx_pcm_pointer(substream);
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_soc_pcm_pointer);
264*4882a593Smuzhiyun 
pxa2xx_soc_pcm_mmap(struct snd_soc_component * component,struct snd_pcm_substream * substream,struct vm_area_struct * vma)265*4882a593Smuzhiyun int pxa2xx_soc_pcm_mmap(struct snd_soc_component *component,
266*4882a593Smuzhiyun 			struct snd_pcm_substream *substream,
267*4882a593Smuzhiyun 			struct vm_area_struct *vma)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	return pxa2xx_pcm_mmap(substream, vma);
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun EXPORT_SYMBOL(pxa2xx_soc_pcm_mmap);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun MODULE_AUTHOR("Nicolas Pitre");
274*4882a593Smuzhiyun MODULE_DESCRIPTION("Intel PXA2xx sound library");
275*4882a593Smuzhiyun MODULE_LICENSE("GPL");
276