1 /*
2  * dma.c  --  ALSA Soc Audio Layer
3  *
4  * (c) 2006 Wolfson Microelectronics PLC.
5  * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
6  *
7  * Copyright 2004-2005 Simtec Electronics
8  *	http://armlinux.simtec.co.uk/
9  *	Ben Dooks <ben@simtec.co.uk>
10  *
11  *  This program is free software; you can redistribute  it and/or modify it
12  *  under  the terms of  the GNU General  Public License as published by the
13  *  Free Software Foundation;  either version 2 of the  License, or (at your
14  *  option) any later version.
15  */
16 
17 #include <linux/slab.h>
18 #include <linux/dma-mapping.h>
19 #include <linux/module.h>
20 
21 #include <sound/soc.h>
22 #include <sound/pcm_params.h>
23 
24 #include <asm/dma.h>
25 #include <mach/hardware.h>
26 #include <mach/dma.h>
27 
28 #include "dma.h"
29 
30 #define ST_RUNNING		(1<<0)
31 #define ST_OPENED		(1<<1)
32 
33 static const struct snd_pcm_hardware dma_hardware = {
34 	.info			= SNDRV_PCM_INFO_INTERLEAVED |
35 				    SNDRV_PCM_INFO_BLOCK_TRANSFER |
36 				    SNDRV_PCM_INFO_MMAP |
37 				    SNDRV_PCM_INFO_MMAP_VALID,
38 	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
39 				    SNDRV_PCM_FMTBIT_U16_LE |
40 				    SNDRV_PCM_FMTBIT_U8 |
41 				    SNDRV_PCM_FMTBIT_S8,
42 	.channels_min		= 2,
43 	.channels_max		= 2,
44 	.buffer_bytes_max	= 128*1024,
45 	.period_bytes_min	= PAGE_SIZE,
46 	.period_bytes_max	= PAGE_SIZE*2,
47 	.periods_min		= 2,
48 	.periods_max		= 128,
49 	.fifo_size		= 32,
50 };
51 
52 struct runtime_data {
53 	spinlock_t lock;
54 	int state;
55 	unsigned int dma_loaded;
56 	unsigned int dma_period;
57 	dma_addr_t dma_start;
58 	dma_addr_t dma_pos;
59 	dma_addr_t dma_end;
60 	struct s3c_dma_params *params;
61 };
62 
63 static void audio_buffdone(void *data);
64 
65 /* dma_enqueue
66  *
67  * place a dma buffer onto the queue for the dma system
68  * to handle.
69  */
dma_enqueue(struct snd_pcm_substream * substream)70 static void dma_enqueue(struct snd_pcm_substream *substream)
71 {
72 	struct runtime_data *prtd = substream->runtime->private_data;
73 	dma_addr_t pos = prtd->dma_pos;
74 	unsigned int limit;
75 	struct samsung_dma_prep_info dma_info;
76 
77 	pr_debug("Entered %s\n", __func__);
78 
79 	limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
80 
81 	pr_debug("%s: loaded %d, limit %d\n",
82 				__func__, prtd->dma_loaded, limit);
83 
84 	dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE);
85 	dma_info.direction =
86 		(substream->stream == SNDRV_PCM_STREAM_PLAYBACK
87 		? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
88 	dma_info.fp = audio_buffdone;
89 	dma_info.fp_param = substream;
90 	dma_info.period = prtd->dma_period;
91 	dma_info.len = prtd->dma_period*limit;
92 
93 	while (prtd->dma_loaded < limit) {
94 		pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
95 
96 		if ((pos + dma_info.period) > prtd->dma_end) {
97 			dma_info.period  = prtd->dma_end - pos;
98 			pr_debug("%s: corrected dma len %ld\n",
99 					__func__, dma_info.period);
100 		}
101 
102 		dma_info.buf = pos;
103 		prtd->params->ops->prepare(prtd->params->ch, &dma_info);
104 
105 		prtd->dma_loaded++;
106 		pos += prtd->dma_period;
107 		if (pos >= prtd->dma_end)
108 			pos = prtd->dma_start;
109 	}
110 
111 	prtd->dma_pos = pos;
112 }
113 
audio_buffdone(void * data)114 static void audio_buffdone(void *data)
115 {
116 	struct snd_pcm_substream *substream = data;
117 	struct runtime_data *prtd = substream->runtime->private_data;
118 
119 	pr_debug("Entered %s\n", __func__);
120 
121 	if (prtd->state & ST_RUNNING) {
122 		prtd->dma_pos += prtd->dma_period;
123 		if (prtd->dma_pos >= prtd->dma_end)
124 			prtd->dma_pos = prtd->dma_start;
125 
126 		if (substream)
127 			snd_pcm_period_elapsed(substream);
128 
129 		spin_lock(&prtd->lock);
130 		if (!samsung_dma_has_circular()) {
131 			prtd->dma_loaded--;
132 			dma_enqueue(substream);
133 		}
134 		spin_unlock(&prtd->lock);
135 	}
136 }
137 
dma_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)138 static int dma_hw_params(struct snd_pcm_substream *substream,
139 	struct snd_pcm_hw_params *params)
140 {
141 	struct snd_pcm_runtime *runtime = substream->runtime;
142 	struct runtime_data *prtd = runtime->private_data;
143 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
144 	unsigned long totbytes = params_buffer_bytes(params);
145 	struct s3c_dma_params *dma =
146 		snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
147 	struct samsung_dma_info dma_info;
148 
149 	pr_debug("Entered %s\n", __func__);
150 
151 	/* return if this is a bufferless transfer e.g.
152 	 * codec <--> BT codec or GSM modem -- lg FIXME */
153 	if (!dma)
154 		return 0;
155 
156 	/* this may get called several times by oss emulation
157 	 * with different params -HW */
158 	if (prtd->params == NULL) {
159 		/* prepare DMA */
160 		prtd->params = dma;
161 
162 		pr_debug("params %p, client %p, channel %d\n", prtd->params,
163 			prtd->params->client, prtd->params->channel);
164 
165 		prtd->params->ops = samsung_dma_get_ops();
166 
167 		dma_info.cap = (samsung_dma_has_circular() ?
168 			DMA_CYCLIC : DMA_SLAVE);
169 		dma_info.client = prtd->params->client;
170 		dma_info.direction =
171 			(substream->stream == SNDRV_PCM_STREAM_PLAYBACK
172 			? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
173 		dma_info.width = prtd->params->dma_size;
174 		dma_info.fifo = prtd->params->dma_addr;
175 		prtd->params->ch = prtd->params->ops->request(
176 				prtd->params->channel, &dma_info);
177 	}
178 
179 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
180 
181 	runtime->dma_bytes = totbytes;
182 
183 	spin_lock_irq(&prtd->lock);
184 	prtd->dma_loaded = 0;
185 	prtd->dma_period = params_period_bytes(params);
186 	prtd->dma_start = runtime->dma_addr;
187 	prtd->dma_pos = prtd->dma_start;
188 	prtd->dma_end = prtd->dma_start + totbytes;
189 	spin_unlock_irq(&prtd->lock);
190 
191 	return 0;
192 }
193 
dma_hw_free(struct snd_pcm_substream * substream)194 static int dma_hw_free(struct snd_pcm_substream *substream)
195 {
196 	struct runtime_data *prtd = substream->runtime->private_data;
197 
198 	pr_debug("Entered %s\n", __func__);
199 
200 	snd_pcm_set_runtime_buffer(substream, NULL);
201 
202 	if (prtd->params) {
203 		prtd->params->ops->flush(prtd->params->ch);
204 		prtd->params->ops->release(prtd->params->ch,
205 					prtd->params->client);
206 		prtd->params = NULL;
207 	}
208 
209 	return 0;
210 }
211 
dma_prepare(struct snd_pcm_substream * substream)212 static int dma_prepare(struct snd_pcm_substream *substream)
213 {
214 	struct runtime_data *prtd = substream->runtime->private_data;
215 	int ret = 0;
216 
217 	pr_debug("Entered %s\n", __func__);
218 
219 	/* return if this is a bufferless transfer e.g.
220 	 * codec <--> BT codec or GSM modem -- lg FIXME */
221 	if (!prtd->params)
222 		return 0;
223 
224 	/* flush the DMA channel */
225 	prtd->params->ops->flush(prtd->params->ch);
226 
227 	prtd->dma_loaded = 0;
228 	prtd->dma_pos = prtd->dma_start;
229 
230 	/* enqueue dma buffers */
231 	dma_enqueue(substream);
232 
233 	return ret;
234 }
235 
dma_trigger(struct snd_pcm_substream * substream,int cmd)236 static int dma_trigger(struct snd_pcm_substream *substream, int cmd)
237 {
238 	struct runtime_data *prtd = substream->runtime->private_data;
239 	int ret = 0;
240 
241 	pr_debug("Entered %s\n", __func__);
242 
243 	spin_lock(&prtd->lock);
244 
245 	switch (cmd) {
246 	case SNDRV_PCM_TRIGGER_START:
247 		prtd->state |= ST_RUNNING;
248 		prtd->params->ops->trigger(prtd->params->ch);
249 		break;
250 
251 	case SNDRV_PCM_TRIGGER_STOP:
252 		prtd->state &= ~ST_RUNNING;
253 		prtd->params->ops->stop(prtd->params->ch);
254 		break;
255 
256 	default:
257 		ret = -EINVAL;
258 		break;
259 	}
260 
261 	spin_unlock(&prtd->lock);
262 
263 	return ret;
264 }
265 
266 static snd_pcm_uframes_t
dma_pointer(struct snd_pcm_substream * substream)267 dma_pointer(struct snd_pcm_substream *substream)
268 {
269 	struct snd_pcm_runtime *runtime = substream->runtime;
270 	struct runtime_data *prtd = runtime->private_data;
271 	unsigned long res;
272 
273 	pr_debug("Entered %s\n", __func__);
274 
275 	res = prtd->dma_pos - prtd->dma_start;
276 
277 	pr_debug("Pointer offset: %lu\n", res);
278 
279 	/* we seem to be getting the odd error from the pcm library due
280 	 * to out-of-bounds pointers. this is maybe due to the dma engine
281 	 * not having loaded the new values for the channel before being
282 	 * called... (todo - fix )
283 	 */
284 
285 	if (res >= snd_pcm_lib_buffer_bytes(substream)) {
286 		if (res == snd_pcm_lib_buffer_bytes(substream))
287 			res = 0;
288 	}
289 
290 	return bytes_to_frames(substream->runtime, res);
291 }
292 
dma_open(struct snd_pcm_substream * substream)293 static int dma_open(struct snd_pcm_substream *substream)
294 {
295 	struct snd_pcm_runtime *runtime = substream->runtime;
296 	struct runtime_data *prtd;
297 
298 	pr_debug("Entered %s\n", __func__);
299 
300 	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
301 	snd_soc_set_runtime_hwparams(substream, &dma_hardware);
302 
303 	prtd = kzalloc(sizeof(struct runtime_data), GFP_KERNEL);
304 	if (prtd == NULL)
305 		return -ENOMEM;
306 
307 	spin_lock_init(&prtd->lock);
308 
309 	runtime->private_data = prtd;
310 	return 0;
311 }
312 
dma_close(struct snd_pcm_substream * substream)313 static int dma_close(struct snd_pcm_substream *substream)
314 {
315 	struct snd_pcm_runtime *runtime = substream->runtime;
316 	struct runtime_data *prtd = runtime->private_data;
317 
318 	pr_debug("Entered %s\n", __func__);
319 
320 	if (!prtd)
321 		pr_debug("dma_close called with prtd == NULL\n");
322 
323 	kfree(prtd);
324 
325 	return 0;
326 }
327 
dma_mmap(struct snd_pcm_substream * substream,struct vm_area_struct * vma)328 static int dma_mmap(struct snd_pcm_substream *substream,
329 	struct vm_area_struct *vma)
330 {
331 	struct snd_pcm_runtime *runtime = substream->runtime;
332 
333 	pr_debug("Entered %s\n", __func__);
334 
335 	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
336 				     runtime->dma_area,
337 				     runtime->dma_addr,
338 				     runtime->dma_bytes);
339 }
340 
341 static struct snd_pcm_ops dma_ops = {
342 	.open		= dma_open,
343 	.close		= dma_close,
344 	.ioctl		= snd_pcm_lib_ioctl,
345 	.hw_params	= dma_hw_params,
346 	.hw_free	= dma_hw_free,
347 	.prepare	= dma_prepare,
348 	.trigger	= dma_trigger,
349 	.pointer	= dma_pointer,
350 	.mmap		= dma_mmap,
351 };
352 
preallocate_dma_buffer(struct snd_pcm * pcm,int stream)353 static int preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
354 {
355 	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
356 	struct snd_dma_buffer *buf = &substream->dma_buffer;
357 	size_t size = dma_hardware.buffer_bytes_max;
358 
359 	pr_debug("Entered %s\n", __func__);
360 
361 	buf->dev.type = SNDRV_DMA_TYPE_DEV;
362 	buf->dev.dev = pcm->card->dev;
363 	buf->private_data = NULL;
364 	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
365 					   &buf->addr, GFP_KERNEL);
366 	if (!buf->area)
367 		return -ENOMEM;
368 	buf->bytes = size;
369 	return 0;
370 }
371 
dma_free_dma_buffers(struct snd_pcm * pcm)372 static void dma_free_dma_buffers(struct snd_pcm *pcm)
373 {
374 	struct snd_pcm_substream *substream;
375 	struct snd_dma_buffer *buf;
376 	int stream;
377 
378 	pr_debug("Entered %s\n", __func__);
379 
380 	for (stream = 0; stream < 2; stream++) {
381 		substream = pcm->streams[stream].substream;
382 		if (!substream)
383 			continue;
384 
385 		buf = &substream->dma_buffer;
386 		if (!buf->area)
387 			continue;
388 
389 		dma_free_writecombine(pcm->card->dev, buf->bytes,
390 				      buf->area, buf->addr);
391 		buf->area = NULL;
392 	}
393 }
394 
395 static u64 dma_mask = DMA_BIT_MASK(32);
396 
dma_new(struct snd_soc_pcm_runtime * rtd)397 static int dma_new(struct snd_soc_pcm_runtime *rtd)
398 {
399 	struct snd_card *card = rtd->card->snd_card;
400 	struct snd_pcm *pcm = rtd->pcm;
401 	int ret = 0;
402 
403 	pr_debug("Entered %s\n", __func__);
404 
405 	if (!card->dev->dma_mask)
406 		card->dev->dma_mask = &dma_mask;
407 	if (!card->dev->coherent_dma_mask)
408 		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
409 
410 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
411 		ret = preallocate_dma_buffer(pcm,
412 			SNDRV_PCM_STREAM_PLAYBACK);
413 		if (ret)
414 			goto out;
415 	}
416 
417 	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
418 		ret = preallocate_dma_buffer(pcm,
419 			SNDRV_PCM_STREAM_CAPTURE);
420 		if (ret)
421 			goto out;
422 	}
423 out:
424 	return ret;
425 }
426 
427 static struct snd_soc_platform_driver samsung_asoc_platform = {
428 	.ops		= &dma_ops,
429 	.pcm_new	= dma_new,
430 	.pcm_free	= dma_free_dma_buffers,
431 };
432 
samsung_asoc_platform_probe(struct platform_device * pdev)433 static int __devinit samsung_asoc_platform_probe(struct platform_device *pdev)
434 {
435 	return snd_soc_register_platform(&pdev->dev, &samsung_asoc_platform);
436 }
437 
samsung_asoc_platform_remove(struct platform_device * pdev)438 static int __devexit samsung_asoc_platform_remove(struct platform_device *pdev)
439 {
440 	snd_soc_unregister_platform(&pdev->dev);
441 	return 0;
442 }
443 
444 static struct platform_driver asoc_dma_driver = {
445 	.driver = {
446 		.name = "samsung-audio",
447 		.owner = THIS_MODULE,
448 	},
449 
450 	.probe = samsung_asoc_platform_probe,
451 	.remove = __devexit_p(samsung_asoc_platform_remove),
452 };
453 
454 module_platform_driver(asoc_dma_driver);
455 
456 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
457 MODULE_DESCRIPTION("Samsung ASoC DMA Driver");
458 MODULE_LICENSE("GPL");
459 MODULE_ALIAS("platform:samsung-audio");
460