1
/* linux/sound/soc/msm/qsd8k-pcm.c
2
 *
3
 * Copyright (c) 2009-2010 Code Aurora Forum. All rights reserved.
4
 *
5
 * All source code in this file is licensed under the following license except
6
 * where indicated.
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU General Public License version 2 as published
10
 * by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
 *
16
 * See the GNU General Public License for more details.
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, you can find it at http://www.fsf.org.
19
 */
20
21
#include <linux/init.h>
22
#include <linux/err.h>
23
#include <linux/module.h>
24
#include <linux/moduleparam.h>
25
#include <linux/time.h>
26
#include <linux/wait.h>
27
#include <linux/platform_device.h>
28
#include <linux/slab.h>
29
#include <sound/core.h>
30
#include <sound/soc.h>
31
#include <sound/soc-dapm.h>
32
#include <sound/pcm.h>
33
#include <sound/initval.h>
34
#include <sound/control.h>
35
#include <asm/dma.h>
36
#include <linux/dma-mapping.h>
37
38
#include "qsdv2-pcm.h"
39
40
#define ACDB_ID_HEADSET_PLAYBACK 407
41
42
static void snd_qsd_timer(unsigned long data);
43
44
static void snd_qsd_timer(unsigned long data)
45
{
46
	struct qsd_audio *prtd = (struct qsd_audio *)data;
47
48
	if (!prtd->enabled)
49
		return;
50
	prtd->timerintcnt++;
51
	snd_pcm_period_elapsed(prtd->substream);
52
	if (prtd->enabled)
53
		add_timer(&prtd->timer);
54
}
55
56
static int rc = 1;
57
58
struct audio_client *dummy_ac;
59
60
#define SND_DRIVER        "snd_qsd"
61
#define MAX_PCM_DEVICES	SNDRV_CARDS
62
#define MAX_PCM_SUBSTREAMS 1
63
64
struct snd_qsd {
65
	struct snd_card *card;
66
	struct snd_pcm *pcm;
67
};
68
69
struct qsd_ctl qsd_glb_ctl;
70
EXPORT_SYMBOL(qsd_glb_ctl);
71
struct audio_locks the_locks;
72
EXPORT_SYMBOL(the_locks);
73
74
75
static struct snd_pcm_hardware qsd_pcm_playback_hardware = {
76
	.info = SNDRV_PCM_INFO_INTERLEAVED,
77
	.formats = USE_FORMATS,
78
	.rates = USE_RATE,
79
	.rate_min = USE_RATE_MIN,
80
	.rate_max = USE_RATE_MAX,
81
	.channels_min = USE_CHANNELS_MIN,
82
	.channels_max = USE_CHANNELS_MAX,
83
	.buffer_bytes_max = MAX_BUFFER_SIZE,
84
	.period_bytes_min = MIN_PERIOD_SIZE,
85
	.period_bytes_max = MAX_PERIOD_SIZE,
86
	.periods_min = USE_PERIODS_MIN,
87
	.periods_max = USE_PERIODS_MAX,
88
	.fifo_size = 0,
89
};
90
91
static struct snd_pcm_hardware qsd_pcm_capture_hardware = {
92
	.info = SNDRV_PCM_INFO_INTERLEAVED,
93
	.formats = USE_FORMATS,
94
	.rates = USE_RATE,
95
	.rate_min = USE_RATE_MIN,
96
	.rate_max = USE_RATE_MAX,
97
	.channels_min = USE_CHANNELS_MIN,
98
	.channels_max = USE_CHANNELS_MAX,
99
	.buffer_bytes_max = MAX_BUFFER_SIZE,
100
	.period_bytes_min = MIN_PERIOD_SIZE,
101
	.period_bytes_max = MAX_PERIOD_SIZE,
102
	.periods_min = USE_PERIODS_MIN,
103
	.periods_max = USE_PERIODS_MAX,
104
	.fifo_size = 0,
105
};
106
107
int qsd_audio_volume_update(struct qsd_audio *prtd)
108
{
109
	int rc = 0;
110
111
	return rc;
112
}
113
114
void qsd_pcm_playback_eos_cb(void *data)
115
{
116
	struct qsd_audio *prtd = data;
117
118
	prtd->eos_ack = 1;
119
	wake_up(&the_locks.eos_wait);
120
}
121
122
void qsd_pcm_playback_buf_done_cb(void *data)
123
{
124
	struct qsd_audio *prtd = data;
125
126
	prtd->intcnt++;
127
	prtd->pcm_irq_pos += prtd->pcm_count;
128
}
129
130
void qsd_pcm_capture_eos_cb(void *data)
131
{
132
}
133
134
void qsd_pcm_capture_buf_done_cb(void *data)
135
{
136
}
137
138
static int qsd_pcm_playback_prepare(struct snd_pcm_substream *substream)
139
{
140
	struct snd_pcm_runtime *runtime = substream->runtime;
141
	struct qsd_audio *prtd = runtime->private_data;
142
	unsigned long expiry = 0;
143
144
	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
145
	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
146
	prtd->out_sample_rate = runtime->rate;
147
	prtd->out_channel_mode = runtime->channels;
148
	prtd->pcm_irq_pos = 0;
149
	prtd->pcm_buf_pos = 0;
150
	atomic_set(&prtd->copy_count, 0);
151
152
	if (prtd->enabled)
153
		return 0;
154
155
	prtd->dsp_handle = q6audio_open_pcm(prtd->pcm_count,
156
					prtd->out_sample_rate,
157
					prtd->out_channel_mode,
158
					AUDIO_FLAG_WRITE,ACDB_ID_HEADSET_PLAYBACK);
159
160
	if (!prtd->dsp_handle)
161
		return -EAGAIN;
162
163
	prtd->dsp_handle->playback_eos_cb = qsd_pcm_playback_eos_cb;
164
	prtd->dsp_handle->playback_eos_data = prtd;
165
166
	prtd->dsp_handle->playback_buf_done_cb = qsd_pcm_playback_buf_done_cb;
167
	prtd->dsp_handle->playback_buf_done_data = prtd;
168
169
	prtd->enabled = 1;
170
	expiry = ((unsigned long)((prtd->pcm_count * 1000)
171
		/(runtime->rate * runtime->channels * 2)));
172
	prtd->timer.expires = jiffies + msecs_to_jiffies(expiry);
173
	setup_timer(&prtd->timer, snd_qsd_timer, (unsigned long)prtd);
174
	add_timer(&prtd->timer);
175
176
	return rc;
177
}
178
179
static int qsd_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
180
{
181
	int ret = 0;
182
183
	switch (cmd) {
184
	case SNDRV_PCM_TRIGGER_START:
185
		break;
186
	case SNDRV_PCM_TRIGGER_RESUME:
187
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
188
		break;
189
	case SNDRV_PCM_TRIGGER_STOP:
190
	case SNDRV_PCM_TRIGGER_SUSPEND:
191
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
192
		break;
193
	default:
194
		ret = -EINVAL;
195
	}
196
197
	return ret;
198
}
199
200
static snd_pcm_uframes_t
201
qsd_pcm_playback_pointer(struct snd_pcm_substream *substream)
202
{
203
	struct snd_pcm_runtime *runtime = substream->runtime;
204
	struct qsd_audio *prtd = runtime->private_data;
205
206
	if (prtd->pcm_irq_pos >= prtd->pcm_size)
207
		prtd->pcm_irq_pos = 0;
208
	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
209
}
210
211
static int qsd_pcm_open(struct snd_pcm_substream *substream)
212
{
213
	struct snd_pcm_runtime *runtime = substream->runtime;
214
	struct qsd_audio *prtd;
215
	int ret = 0;
216
217
	prtd = kzalloc(sizeof(struct qsd_audio), GFP_KERNEL);
218
	if (prtd == NULL) {
219
		ret = -ENOMEM;
220
		return ret;
221
	}
222
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
223
		printk(KERN_INFO "Stream = SNDRV_PCM_STREAM_PLAYBACK\n");
224
		runtime->hw = qsd_pcm_playback_hardware;
225
		prtd->dir = SNDRV_PCM_STREAM_PLAYBACK;
226
	} else {
227
		printk(KERN_INFO "Stream = SNDRV_PCM_STREAM_CAPTURE\n");
228
		runtime->hw = qsd_pcm_capture_hardware;
229
		prtd->dir = SNDRV_PCM_STREAM_CAPTURE;
230
	}
231
	prtd->substream = substream;
232
233
	dummy_ac = q6audio_open(AUDIO_FLAG_WRITE, 8192);
234
235
	/* Ensure that buffer size is a multiple of period size */
236
	ret = snd_pcm_hw_constraint_integer(runtime,
237
					    SNDRV_PCM_HW_PARAM_PERIODS);
238
	if (ret < 0) {
239
		kfree(prtd);
240
		return ret;
241
	}
242
243
	runtime->private_data = prtd;
244
245
	prtd->enabled = 0;
246
247
	return 0;
248
}
249
250
static int qsd_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
251
				 snd_pcm_uframes_t hwoff, void __user *buf,
252
				 snd_pcm_uframes_t frames)
253
{
254
	struct snd_pcm_runtime *runtime = substream->runtime;
255
	struct qsd_audio *prtd = runtime->private_data;
256
	struct audio_client *ac = prtd->dsp_handle;
257
	struct audio_buffer *ab;
258
	int fbytes = 0;
259
	size_t xfer;
260
	int count;
261
	int rc;
262
263
	printk(KERN_DEBUG"%s:%i\n", __func__, __LINE__);
264
265
	fbytes = frames_to_bytes(runtime, frames);
266
	count = fbytes;
267
	printk(KERN_DEBUG"%s:%i\n", __func__, __LINE__);
268
269
	while (count > 0) {
270
		ab = ac->buf + ac->cpu_buf;
271
272
		if (ab->used)
273
			wait_event(ac->wait, (ab->used == 0));
274
275
		xfer = count;
276
		if (xfer > ab->size)
277
			xfer = ab->size;
278
		printk(KERN_DEBUG"%s:%i\n", __func__, __LINE__);
279
280
		if (copy_from_user(ab->data, buf, xfer))
281
			return -EFAULT;
282
283
		buf += xfer;
284
		count -= xfer;
285
286
		ab->used = xfer;
287
288
		q6audio_write(ac, ab);
289
290
291
		printk(KERN_DEBUG"%s:%i\n", __func__, __LINE__);
292
293
		ac->cpu_buf ^= 1;
294
	}
295
	printk(KERN_DEBUG"%s:%i\n", __func__, __LINE__);
296
297
	prtd->pcm_buf_pos += fbytes;
298
299
	prtd->buffer_cnt++;
300
	printk(KERN_DEBUG"%s:%i\n", __func__, __LINE__);
301
302
	mutex_lock(&the_locks.mixer_lock);
303
	if (qsd_glb_ctl.update) {
304
		rc = qsd_audio_volume_update(prtd);
305
		qsd_glb_ctl.update = 0;
306
	}
307
	mutex_unlock(&the_locks.mixer_lock);
308
	printk(KERN_DEBUG"%s:%i\n", __func__, __LINE__);
309
310
	return fbytes;
311
}
312
313
static int qsd_pcm_playback_close(struct snd_pcm_substream *substream)
314
{
315
	struct snd_pcm_runtime *runtime = substream->runtime;
316
	struct qsd_audio *prtd = runtime->private_data;
317
	int ret = 0;
318
319
	if (prtd->enabled) {
320
		q6audio_command(prtd->dsp_handle,
321
			ADSP_AUDIO_IOCTL_CMD_STREAM_EOS);
322
323
		q6audio_close(prtd->dsp_handle);
324
325
		ret = wait_event_interruptible(the_locks.eos_wait,
326
					prtd->eos_ack);
327
328
		if (!prtd->eos_ack)
329
			pr_err("EOS Failed\n");
330
	}
331
332
	prtd->enabled = 0;
333
	del_timer_sync(&prtd->timer);
334
	prtd->eos_ack = 0;
335
336
	/*
337
	 * TODO: Deregister the async callback handler.
338
	 */
339
	kfree(prtd);
340
341
	kfree(dummy_ac);
342
343
	return ret;
344
}
345
346
static int qsd_pcm_capture_copy(struct snd_pcm_substream *substream, int a,
347
				 snd_pcm_uframes_t hwoff, void __user *buf,
348
				 snd_pcm_uframes_t frames)
349
{
350
	struct snd_pcm_runtime *runtime = substream->runtime;
351
	struct qsd_audio *prtd = runtime->private_data;
352
	struct audio_client *ac = prtd->dsp_handle;
353
	struct audio_buffer *ab;
354
	int fbytes = 0;
355
	size_t xfer = 0;
356
	int count;
357
	int rc = 0;
358
359
	/* pr_err("+%s:\n", __func__); */
360
	fbytes = frames_to_bytes(runtime, frames);
361
	count = fbytes;
362
363
	while (count > 0) {
364
		ab = ac->buf + ac->cpu_buf;
365
366
		if (ab->used)
367
			wait_event(ac->wait, (ab->used == 0));
368
369
		xfer = count;
370
		if (xfer > ab->size)
371
			xfer = ab->size;
372
373
		if (copy_to_user(buf, ab->data, xfer))
374
			return -EFAULT;
375
376
		buf += xfer;
377
		count -= xfer;
378
379
		ab->used = 1;
380
		q6audio_read(ac, ab);
381
		ac->cpu_buf ^= 1;
382
	}
383
384
	prtd->pcm_buf_pos += fbytes;
385
	if (xfer < fbytes)
386
		return -EIO;
387
388
	/* pr_err("+%s:\n", __func__); */
389
390
	return rc;
391
}
392
393
static snd_pcm_uframes_t
394
qsd_pcm_capture_pointer(struct snd_pcm_substream *substream)
395
{
396
	struct snd_pcm_runtime *runtime = substream->runtime;
397
	struct qsd_audio *prtd = runtime->private_data;
398
399
	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
400
}
401
402
static int qsd_pcm_capture_close(struct snd_pcm_substream *substream)
403
{
404
	struct snd_pcm_runtime *runtime = substream->runtime;
405
	struct qsd_audio *prtd = runtime->private_data;
406
407
	prtd->enabled = 0;
408
	del_timer_sync(&prtd->timer);
409
410
	/*
411
	 * TODO: Deregister the async callback handler.
412
	 */
413
414
	if (prtd->enabled)
415
		q6audio_close(prtd->dsp_handle);
416
417
	kfree(prtd);
418
419
	return 0;
420
}
421
422
static int qsd_pcm_capture_prepare(struct snd_pcm_substream *substream)
423
{
424
	struct snd_pcm_runtime *runtime = substream->runtime;
425
	struct qsd_audio *prtd = runtime->private_data;
426
	int rc = 0;
427
	unsigned long expiry = 0;
428
429
	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
430
	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
431
	prtd->out_sample_rate = runtime->rate;
432
	prtd->out_channel_mode = runtime->channels;
433
	prtd->pcm_irq_pos = 0;
434
	prtd->pcm_buf_pos = 0;
435
436
	if (prtd->enabled)
437
		return 0;
438
439
	prtd->dsp_handle = q6audio_open_pcm(prtd->pcm_count,
440
						prtd->out_sample_rate,
441
						prtd->out_channel_mode,
442
						AUDIO_FLAG_READ,ACDB_ID_HEADSET_PLAYBACK);
443
	if (!prtd->dsp_handle)
444
		return -EAGAIN;
445
446
447
	prtd->dsp_handle->capture_eos_cb = qsd_pcm_capture_eos_cb;
448
	prtd->dsp_handle->capture_eos_data = prtd;
449
450
	prtd->dsp_handle->capture_buf_done_cb = qsd_pcm_capture_buf_done_cb;
451
	prtd->dsp_handle->capture_buf_done_data = prtd;
452
453
454
	prtd->enabled = 1;
455
	expiry = ((unsigned long)((prtd->pcm_count * 1000)
456
		/(runtime->rate * runtime->channels * 2)));
457
	prtd->timer.expires = jiffies + msecs_to_jiffies(expiry);
458
	setup_timer(&prtd->timer, snd_qsd_timer, (unsigned long)prtd);
459
	add_timer(&prtd->timer);
460
461
	return rc;
462
}
463
464
465
static int qsd_pcm_copy(struct snd_pcm_substream *substream, int a,
466
			snd_pcm_uframes_t hwoff, void __user *buf,
467
			snd_pcm_uframes_t frames)
468
{
469
	int ret = 0;
470
471
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
472
		ret = qsd_pcm_playback_copy(substream, a, hwoff, buf, frames);
473
	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
474
		ret = qsd_pcm_capture_copy(substream, a, hwoff, buf, frames);
475
	return ret;
476
}
477
478
static int qsd_pcm_close(struct snd_pcm_substream *substream)
479
{
480
	int ret = 0;
481
482
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
483
		ret = qsd_pcm_playback_close(substream);
484
	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
485
		ret = qsd_pcm_capture_close(substream);
486
	return ret;
487
}
488
static int qsd_pcm_prepare(struct snd_pcm_substream *substream)
489
{
490
	int ret = 0;
491
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
492
		ret = qsd_pcm_playback_prepare(substream);
493
	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
494
		ret = qsd_pcm_capture_prepare(substream);
495
	return ret;
496
}
497
498
static snd_pcm_uframes_t qsd_pcm_pointer(struct snd_pcm_substream *substream)
499
{
500
	snd_pcm_uframes_t ret = 0;
501
502
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
503
		ret = qsd_pcm_playback_pointer(substream);
504
	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
505
		ret = qsd_pcm_capture_pointer(substream);
506
	return ret;
507
}
508
509
int qsd_pcm_hw_params(struct snd_pcm_substream *substream,
510
		      struct snd_pcm_hw_params *params)
511
{
512
	struct snd_pcm_runtime *runtime = substream->runtime;
513
514
	if (substream->pcm->device & 1) {
515
		runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
516
		runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
517
	}
518
	return 0;
519
}
520
521
struct snd_pcm_ops qsd_pcm_ops = {
522
	.open = qsd_pcm_open,
523
	.copy = qsd_pcm_copy,
524
	.hw_params = qsd_pcm_hw_params,
525
	.close = qsd_pcm_close,
526
	.ioctl = snd_pcm_lib_ioctl,
527
	.prepare = qsd_pcm_prepare,
528
	.trigger = qsd_pcm_trigger,
529
	.pointer = qsd_pcm_pointer,
530
};
531
EXPORT_SYMBOL_GPL(qsd_pcm_ops);
532
533
static int qsd_pcm_remove(struct platform_device *devptr)
534
{
535
	struct snd_soc_device *socdev = platform_get_drvdata(devptr);
536
	snd_soc_free_pcms(socdev);
537
	kfree(socdev->card->codec);
538
	platform_set_drvdata(devptr, NULL);
539
	return 0;
540
}
541
542
static int qsd_pcm_new(struct snd_card *card,
543
			struct snd_soc_dai *codec_dai,
544
			struct snd_pcm *pcm)
545
{
546
	int ret;
547
	if (!card->dev->coherent_dma_mask)
548
		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
549
550
	ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK,
551
				PLAYBACK_STREAMS);
552
	if (ret)
553
		return ret;
554
	ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE,
555
				CAPTURE_STREAMS);
556
	if (ret)
557
		return ret;
558
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &qsd_pcm_ops);
559
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &qsd_pcm_ops);
560
	return ret;
561
}
562
563
struct snd_soc_platform qsd_soc_platform = {
564
	.name		= "qsd-audio",
565
	.remove         = qsd_pcm_remove,
566
	.pcm_ops 	= &qsd_pcm_ops,
567
	.pcm_new	= qsd_pcm_new,
568
};
569
EXPORT_SYMBOL(qsd_soc_platform);
570
571
static int __init qsd_soc_platform_init(void)
572
{
573
	return snd_soc_register_platform(&qsd_soc_platform);
574
}
575
module_init(qsd_soc_platform_init);
576
577
static void __exit qsd_soc_platform_exit(void)
578
{
579
	snd_soc_unregister_platform(&qsd_soc_platform);
580
}
581
module_exit(qsd_soc_platform_exit);
582
583
MODULE_DESCRIPTION("PCM module platform driver");
584
MODULE_LICENSE("GPL v2");