1 /*
2  * omap-pcm.c  --  ALSA PCM interface for the OMAP SoC
3  *
4  * Copyright (C) 2008 Nokia Corporation
5  *
6  * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
7  *          Peter Ujfalusi <peter.ujfalusi@ti.com>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * version 2 as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24 
25 #include <linux/dma-mapping.h>
26 #include <linux/slab.h>
27 #include <linux/module.h>
28 #include <sound/core.h>
29 #include <sound/pcm.h>
30 #include <sound/pcm_params.h>
31 #include <sound/soc.h>
32 
33 #include <plat/dma.h>
34 #include "omap-pcm.h"
35 
36 static const struct snd_pcm_hardware omap_pcm_hardware = {
37 	.info			= SNDRV_PCM_INFO_MMAP |
38 				  SNDRV_PCM_INFO_MMAP_VALID |
39 				  SNDRV_PCM_INFO_INTERLEAVED |
40 				  SNDRV_PCM_INFO_PAUSE |
41 				  SNDRV_PCM_INFO_RESUME |
42 				  SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
43 	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
44 				  SNDRV_PCM_FMTBIT_S32_LE,
45 	.period_bytes_min	= 32,
46 	.period_bytes_max	= 64 * 1024,
47 	.periods_min		= 2,
48 	.periods_max		= 255,
49 	.buffer_bytes_max	= 128 * 1024,
50 };
51 
52 struct omap_runtime_data {
53 	spinlock_t			lock;
54 	struct omap_pcm_dma_data	*dma_data;
55 	int				dma_ch;
56 	int				period_index;
57 };
58 
omap_pcm_dma_irq(int ch,u16 stat,void * data)59 static void omap_pcm_dma_irq(int ch, u16 stat, void *data)
60 {
61 	struct snd_pcm_substream *substream = data;
62 	struct snd_pcm_runtime *runtime = substream->runtime;
63 	struct omap_runtime_data *prtd = runtime->private_data;
64 	unsigned long flags;
65 
66 	if ((cpu_is_omap1510())) {
67 		/*
68 		 * OMAP1510 doesn't fully support DMA progress counter
69 		 * and there is no software emulation implemented yet,
70 		 * so have to maintain our own progress counters
71 		 * that can be used by omap_pcm_pointer() instead.
72 		 */
73 		spin_lock_irqsave(&prtd->lock, flags);
74 		if ((stat == OMAP_DMA_LAST_IRQ) &&
75 				(prtd->period_index == runtime->periods - 1)) {
76 			/* we are in sync, do nothing */
77 			spin_unlock_irqrestore(&prtd->lock, flags);
78 			return;
79 		}
80 		if (prtd->period_index >= 0) {
81 			if (stat & OMAP_DMA_BLOCK_IRQ) {
82 				/* end of buffer reached, loop back */
83 				prtd->period_index = 0;
84 			} else if (stat & OMAP_DMA_LAST_IRQ) {
85 				/* update the counter for the last period */
86 				prtd->period_index = runtime->periods - 1;
87 			} else if (++prtd->period_index >= runtime->periods) {
88 				/* end of buffer missed? loop back */
89 				prtd->period_index = 0;
90 			}
91 		}
92 		spin_unlock_irqrestore(&prtd->lock, flags);
93 	}
94 
95 	snd_pcm_period_elapsed(substream);
96 }
97 
98 /* this may get called several times by oss emulation */
omap_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)99 static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
100 			      struct snd_pcm_hw_params *params)
101 {
102 	struct snd_pcm_runtime *runtime = substream->runtime;
103 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
104 	struct omap_runtime_data *prtd = runtime->private_data;
105 	struct omap_pcm_dma_data *dma_data;
106 
107 	int err = 0;
108 
109 	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
110 
111 	/* return if this is a bufferless transfer e.g.
112 	 * codec <--> BT codec or GSM modem -- lg FIXME */
113 	if (!dma_data)
114 		return 0;
115 
116 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
117 	runtime->dma_bytes = params_buffer_bytes(params);
118 
119 	if (prtd->dma_data)
120 		return 0;
121 	prtd->dma_data = dma_data;
122 	err = omap_request_dma(dma_data->dma_req, dma_data->name,
123 			       omap_pcm_dma_irq, substream, &prtd->dma_ch);
124 	if (!err) {
125 		/*
126 		 * Link channel with itself so DMA doesn't need any
127 		 * reprogramming while looping the buffer
128 		 */
129 		omap_dma_link_lch(prtd->dma_ch, prtd->dma_ch);
130 	}
131 
132 	return err;
133 }
134 
omap_pcm_hw_free(struct snd_pcm_substream * substream)135 static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
136 {
137 	struct snd_pcm_runtime *runtime = substream->runtime;
138 	struct omap_runtime_data *prtd = runtime->private_data;
139 
140 	if (prtd->dma_data == NULL)
141 		return 0;
142 
143 	omap_dma_unlink_lch(prtd->dma_ch, prtd->dma_ch);
144 	omap_free_dma(prtd->dma_ch);
145 	prtd->dma_data = NULL;
146 
147 	snd_pcm_set_runtime_buffer(substream, NULL);
148 
149 	return 0;
150 }
151 
omap_pcm_prepare(struct snd_pcm_substream * substream)152 static int omap_pcm_prepare(struct snd_pcm_substream *substream)
153 {
154 	struct snd_pcm_runtime *runtime = substream->runtime;
155 	struct omap_runtime_data *prtd = runtime->private_data;
156 	struct omap_pcm_dma_data *dma_data = prtd->dma_data;
157 	struct omap_dma_channel_params dma_params;
158 	int bytes;
159 
160 	/* return if this is a bufferless transfer e.g.
161 	 * codec <--> BT codec or GSM modem -- lg FIXME */
162 	if (!prtd->dma_data)
163 		return 0;
164 
165 	memset(&dma_params, 0, sizeof(dma_params));
166 	dma_params.data_type			= dma_data->data_type;
167 	dma_params.trigger			= dma_data->dma_req;
168 	dma_params.sync_mode			= dma_data->sync_mode;
169 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
170 		dma_params.src_amode		= OMAP_DMA_AMODE_POST_INC;
171 		dma_params.dst_amode		= OMAP_DMA_AMODE_CONSTANT;
172 		dma_params.src_or_dst_synch	= OMAP_DMA_DST_SYNC;
173 		dma_params.src_start		= runtime->dma_addr;
174 		dma_params.dst_start		= dma_data->port_addr;
175 		dma_params.dst_port		= OMAP_DMA_PORT_MPUI;
176 		dma_params.dst_fi		= dma_data->packet_size;
177 	} else {
178 		dma_params.src_amode		= OMAP_DMA_AMODE_CONSTANT;
179 		dma_params.dst_amode		= OMAP_DMA_AMODE_POST_INC;
180 		dma_params.src_or_dst_synch	= OMAP_DMA_SRC_SYNC;
181 		dma_params.src_start		= dma_data->port_addr;
182 		dma_params.dst_start		= runtime->dma_addr;
183 		dma_params.src_port		= OMAP_DMA_PORT_MPUI;
184 		dma_params.src_fi		= dma_data->packet_size;
185 	}
186 	/*
187 	 * Set DMA transfer frame size equal to ALSA period size and frame
188 	 * count as no. of ALSA periods. Then with DMA frame interrupt enabled,
189 	 * we can transfer the whole ALSA buffer with single DMA transfer but
190 	 * still can get an interrupt at each period bounary
191 	 */
192 	bytes = snd_pcm_lib_period_bytes(substream);
193 	dma_params.elem_count	= bytes >> dma_data->data_type;
194 	dma_params.frame_count	= runtime->periods;
195 	omap_set_dma_params(prtd->dma_ch, &dma_params);
196 
197 	if ((cpu_is_omap1510()))
198 		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ |
199 			      OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ);
200 	else if (!substream->runtime->no_period_wakeup)
201 		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
202 	else {
203 		/*
204 		 * No period wakeup:
205 		 * we need to disable BLOCK_IRQ, which is enabled by the omap
206 		 * dma core at request dma time.
207 		 */
208 		omap_disable_dma_irq(prtd->dma_ch, OMAP_DMA_BLOCK_IRQ);
209 	}
210 
211 	if (!(cpu_class_is_omap1())) {
212 		omap_set_dma_src_burst_mode(prtd->dma_ch,
213 						OMAP_DMA_DATA_BURST_16);
214 		omap_set_dma_dest_burst_mode(prtd->dma_ch,
215 						OMAP_DMA_DATA_BURST_16);
216 	}
217 
218 	return 0;
219 }
220 
omap_pcm_trigger(struct snd_pcm_substream * substream,int cmd)221 static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
222 {
223 	struct snd_pcm_runtime *runtime = substream->runtime;
224 	struct omap_runtime_data *prtd = runtime->private_data;
225 	struct omap_pcm_dma_data *dma_data = prtd->dma_data;
226 	unsigned long flags;
227 	int ret = 0;
228 
229 	spin_lock_irqsave(&prtd->lock, flags);
230 	switch (cmd) {
231 	case SNDRV_PCM_TRIGGER_START:
232 	case SNDRV_PCM_TRIGGER_RESUME:
233 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
234 		prtd->period_index = 0;
235 		/* Configure McBSP internal buffer usage */
236 		if (dma_data->set_threshold)
237 			dma_data->set_threshold(substream);
238 
239 		omap_start_dma(prtd->dma_ch);
240 		break;
241 
242 	case SNDRV_PCM_TRIGGER_STOP:
243 	case SNDRV_PCM_TRIGGER_SUSPEND:
244 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
245 		prtd->period_index = -1;
246 		omap_stop_dma(prtd->dma_ch);
247 		break;
248 	default:
249 		ret = -EINVAL;
250 	}
251 	spin_unlock_irqrestore(&prtd->lock, flags);
252 
253 	return ret;
254 }
255 
omap_pcm_pointer(struct snd_pcm_substream * substream)256 static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
257 {
258 	struct snd_pcm_runtime *runtime = substream->runtime;
259 	struct omap_runtime_data *prtd = runtime->private_data;
260 	dma_addr_t ptr;
261 	snd_pcm_uframes_t offset;
262 
263 	if (cpu_is_omap1510()) {
264 		offset = prtd->period_index * runtime->period_size;
265 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
266 		ptr = omap_get_dma_dst_pos(prtd->dma_ch);
267 		offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
268 	} else {
269 		ptr = omap_get_dma_src_pos(prtd->dma_ch);
270 		offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
271 	}
272 
273 	if (offset >= runtime->buffer_size)
274 		offset = 0;
275 
276 	return offset;
277 }
278 
omap_pcm_open(struct snd_pcm_substream * substream)279 static int omap_pcm_open(struct snd_pcm_substream *substream)
280 {
281 	struct snd_pcm_runtime *runtime = substream->runtime;
282 	struct omap_runtime_data *prtd;
283 	int ret;
284 
285 	snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
286 
287 	/* Ensure that buffer size is a multiple of period size */
288 	ret = snd_pcm_hw_constraint_integer(runtime,
289 					    SNDRV_PCM_HW_PARAM_PERIODS);
290 	if (ret < 0)
291 		goto out;
292 
293 	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
294 	if (prtd == NULL) {
295 		ret = -ENOMEM;
296 		goto out;
297 	}
298 	spin_lock_init(&prtd->lock);
299 	runtime->private_data = prtd;
300 
301 out:
302 	return ret;
303 }
304 
omap_pcm_close(struct snd_pcm_substream * substream)305 static int omap_pcm_close(struct snd_pcm_substream *substream)
306 {
307 	struct snd_pcm_runtime *runtime = substream->runtime;
308 
309 	kfree(runtime->private_data);
310 	return 0;
311 }
312 
omap_pcm_mmap(struct snd_pcm_substream * substream,struct vm_area_struct * vma)313 static int omap_pcm_mmap(struct snd_pcm_substream *substream,
314 	struct vm_area_struct *vma)
315 {
316 	struct snd_pcm_runtime *runtime = substream->runtime;
317 
318 	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
319 				     runtime->dma_area,
320 				     runtime->dma_addr,
321 				     runtime->dma_bytes);
322 }
323 
324 static struct snd_pcm_ops omap_pcm_ops = {
325 	.open		= omap_pcm_open,
326 	.close		= omap_pcm_close,
327 	.ioctl		= snd_pcm_lib_ioctl,
328 	.hw_params	= omap_pcm_hw_params,
329 	.hw_free	= omap_pcm_hw_free,
330 	.prepare	= omap_pcm_prepare,
331 	.trigger	= omap_pcm_trigger,
332 	.pointer	= omap_pcm_pointer,
333 	.mmap		= omap_pcm_mmap,
334 };
335 
336 static u64 omap_pcm_dmamask = DMA_BIT_MASK(64);
337 
omap_pcm_preallocate_dma_buffer(struct snd_pcm * pcm,int stream)338 static int omap_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
339 	int stream)
340 {
341 	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
342 	struct snd_dma_buffer *buf = &substream->dma_buffer;
343 	size_t size = omap_pcm_hardware.buffer_bytes_max;
344 
345 	buf->dev.type = SNDRV_DMA_TYPE_DEV;
346 	buf->dev.dev = pcm->card->dev;
347 	buf->private_data = NULL;
348 	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
349 					   &buf->addr, GFP_KERNEL);
350 	if (!buf->area)
351 		return -ENOMEM;
352 
353 	buf->bytes = size;
354 	return 0;
355 }
356 
omap_pcm_free_dma_buffers(struct snd_pcm * pcm)357 static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm)
358 {
359 	struct snd_pcm_substream *substream;
360 	struct snd_dma_buffer *buf;
361 	int stream;
362 
363 	for (stream = 0; stream < 2; stream++) {
364 		substream = pcm->streams[stream].substream;
365 		if (!substream)
366 			continue;
367 
368 		buf = &substream->dma_buffer;
369 		if (!buf->area)
370 			continue;
371 
372 		dma_free_writecombine(pcm->card->dev, buf->bytes,
373 				      buf->area, buf->addr);
374 		buf->area = NULL;
375 	}
376 }
377 
omap_pcm_new(struct snd_soc_pcm_runtime * rtd)378 static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
379 {
380 	struct snd_card *card = rtd->card->snd_card;
381 	struct snd_pcm *pcm = rtd->pcm;
382 	int ret = 0;
383 
384 	if (!card->dev->dma_mask)
385 		card->dev->dma_mask = &omap_pcm_dmamask;
386 	if (!card->dev->coherent_dma_mask)
387 		card->dev->coherent_dma_mask = DMA_BIT_MASK(64);
388 
389 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
390 		ret = omap_pcm_preallocate_dma_buffer(pcm,
391 			SNDRV_PCM_STREAM_PLAYBACK);
392 		if (ret)
393 			goto out;
394 	}
395 
396 	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
397 		ret = omap_pcm_preallocate_dma_buffer(pcm,
398 			SNDRV_PCM_STREAM_CAPTURE);
399 		if (ret)
400 			goto out;
401 	}
402 
403 out:
404 	return ret;
405 }
406 
407 static struct snd_soc_platform_driver omap_soc_platform = {
408 	.ops		= &omap_pcm_ops,
409 	.pcm_new	= omap_pcm_new,
410 	.pcm_free	= omap_pcm_free_dma_buffers,
411 };
412 
omap_pcm_probe(struct platform_device * pdev)413 static __devinit int omap_pcm_probe(struct platform_device *pdev)
414 {
415 	return snd_soc_register_platform(&pdev->dev,
416 			&omap_soc_platform);
417 }
418 
omap_pcm_remove(struct platform_device * pdev)419 static int __devexit omap_pcm_remove(struct platform_device *pdev)
420 {
421 	snd_soc_unregister_platform(&pdev->dev);
422 	return 0;
423 }
424 
425 static struct platform_driver omap_pcm_driver = {
426 	.driver = {
427 			.name = "omap-pcm-audio",
428 			.owner = THIS_MODULE,
429 	},
430 
431 	.probe = omap_pcm_probe,
432 	.remove = __devexit_p(omap_pcm_remove),
433 };
434 
435 module_platform_driver(omap_pcm_driver);
436 
437 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
438 MODULE_DESCRIPTION("OMAP PCM DMA module");
439 MODULE_LICENSE("GPL");
440