blob: 230147200fc628caabce6e603059c2aac2e72715 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/init.h>
14#include <linux/err.h>
15#include <linux/module.h>
16#include <linux/time.h>
17#include <linux/wait.h>
18#include <linux/platform_device.h>
19#include <linux/slab.h>
20#include <linux/dma-mapping.h>
21#include <sound/core.h>
22#include <sound/soc.h>
23#include <sound/soc-dapm.h>
24#include <sound/pcm.h>
25#include <sound/initval.h>
26#include <sound/control.h>
27#include <asm/dma.h>
28
29#include "msm-pcm-q6.h"
30#include "msm-pcm-routing.h"
31#include "qdsp6/q6voice.h"
32
33#define VOIP_MAX_Q_LEN 10
Helen Zengb62d92a2011-08-23 17:51:17 -070034#define VOIP_MAX_VOC_PKT_SIZE 640
Panneer Arumugam418aa0a2011-10-11 18:44:16 -070035#define VOIP_MIN_VOC_PKT_SIZE 320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036
Helen Zengb9d00ce2011-10-13 17:25:50 -070037/* Length of the DSP frame info header added to the voc packet. */
38#define DSP_FRAME_HDR_LEN 1
39
40#define MODE_AMR 0x5
41#define MODE_AMR_WB 0xD
42#define MODE_PCM 0xC
43
44enum format {
45 FORMAT_S16_LE = 2,
46 FORMAT_SPECIAL = 31,
47};
48
49
50enum amr_rate_type {
51 AMR_RATE_4750, /* AMR 4.75 kbps */
52 AMR_RATE_5150, /* AMR 5.15 kbps */
53 AMR_RATE_5900, /* AMR 5.90 kbps */
54 AMR_RATE_6700, /* AMR 6.70 kbps */
55 AMR_RATE_7400, /* AMR 7.40 kbps */
56 AMR_RATE_7950, /* AMR 7.95 kbps */
57 AMR_RATE_10200, /* AMR 10.20 kbps */
58 AMR_RATE_12200, /* AMR 12.20 kbps */
59 AMR_RATE_6600, /* AMR-WB 6.60 kbps */
60 AMR_RATE_8850, /* AMR-WB 8.85 kbps */
61 AMR_RATE_12650, /* AMR-WB 12.65 kbps */
62 AMR_RATE_14250, /* AMR-WB 14.25 kbps */
63 AMR_RATE_15850, /* AMR-WB 15.85 kbps */
64 AMR_RATE_18250, /* AMR-WB 18.25 kbps */
65 AMR_RATE_19850, /* AMR-WB 19.85 kbps */
66 AMR_RATE_23050, /* AMR-WB 23.05 kbps */
67 AMR_RATE_23850, /* AMR-WB 23.85 kbps */
68 AMR_RATE_UNDEF
69};
70
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071enum voip_state {
72 VOIP_STOPPED,
73 VOIP_STARTED,
74};
75
76struct voip_frame {
Helen Zengb9d00ce2011-10-13 17:25:50 -070077 uint32_t frame_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070078 uint32_t len;
79 uint8_t voc_pkt[VOIP_MAX_VOC_PKT_SIZE];
80};
81
82struct voip_buf_node {
83 struct list_head list;
84 struct voip_frame frame;
85};
86
87struct voip_drv_info {
88 enum voip_state state;
89
90 struct snd_pcm_substream *playback_substream;
91 struct snd_pcm_substream *capture_substream;
92
93 struct list_head in_queue;
94 struct list_head free_in_queue;
95
96 struct list_head out_queue;
97 struct list_head free_out_queue;
98
99 wait_queue_head_t out_wait;
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700100 wait_queue_head_t in_wait;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700101
102 struct mutex lock;
103 struct mutex in_lock;
104 struct mutex out_lock;
105
106 spinlock_t dsp_lock;
107
Helen Zengb9d00ce2011-10-13 17:25:50 -0700108 uint32_t mode;
109 uint32_t rate_type;
110 uint32_t rate;
Helen Zengff97bec2012-02-20 14:30:50 -0800111 uint32_t dtx_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112
113 uint8_t capture_start;
114 uint8_t playback_start;
115
116 uint8_t playback_instance;
117 uint8_t capture_instance;
118
119 unsigned int play_samp_rate;
120 unsigned int cap_samp_rate;
121
122 unsigned int pcm_size;
123 unsigned int pcm_count;
124 unsigned int pcm_playback_irq_pos; /* IRQ position */
125 unsigned int pcm_playback_buf_pos; /* position in buffer */
126
127 unsigned int pcm_capture_size;
128 unsigned int pcm_capture_count;
129 unsigned int pcm_capture_irq_pos; /* IRQ position */
130 unsigned int pcm_capture_buf_pos; /* position in buffer */
131};
132
Helen Zengb9d00ce2011-10-13 17:25:50 -0700133static int voip_get_media_type(uint32_t mode,
134 unsigned int samp_rate);
135static int voip_get_rate_type(uint32_t mode,
136 uint32_t rate,
137 uint32_t *rate_type);
138static int msm_voip_mode_rate_config_put(struct snd_kcontrol *kcontrol,
139 struct snd_ctl_elem_value *ucontrol);
140static int msm_voip_mode_rate_config_get(struct snd_kcontrol *kcontrol,
141 struct snd_ctl_elem_value *ucontrol);
142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143static struct voip_drv_info voip_info;
144
145static struct snd_pcm_hardware msm_pcm_hardware = {
146 .info = (SNDRV_PCM_INFO_MMAP |
147 SNDRV_PCM_INFO_BLOCK_TRANSFER |
148 SNDRV_PCM_INFO_MMAP_VALID |
149 SNDRV_PCM_INFO_INTERLEAVED),
Helen Zengb9d00ce2011-10-13 17:25:50 -0700150 .formats = SNDRV_PCM_FMTBIT_S16_LE |
151 SNDRV_PCM_FMTBIT_SPECIAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
153 .rate_min = 8000,
154 .rate_max = 16000,
155 .channels_min = 1,
156 .channels_max = 1,
Helen Zengb9d00ce2011-10-13 17:25:50 -0700157 .buffer_bytes_max = sizeof(struct voip_buf_node) * VOIP_MAX_Q_LEN,
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700158 .period_bytes_min = VOIP_MIN_VOC_PKT_SIZE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 .period_bytes_max = VOIP_MAX_VOC_PKT_SIZE,
160 .periods_min = VOIP_MAX_Q_LEN,
161 .periods_max = VOIP_MAX_Q_LEN,
162 .fifo_size = 0,
163};
164
165
Panneer Arumugambcac6862011-10-27 18:20:44 -0700166static int msm_voip_mute_put(struct snd_kcontrol *kcontrol,
167 struct snd_ctl_elem_value *ucontrol)
168{
169 int mute = ucontrol->value.integer.value[0];
170
171 pr_debug("%s: mute=%d\n", __func__, mute);
172
173 voc_set_tx_mute(voc_get_session_id(VOIP_SESSION_NAME), TX_PATH, mute);
174
175 return 0;
176}
177
178static int msm_voip_mute_get(struct snd_kcontrol *kcontrol,
179 struct snd_ctl_elem_value *ucontrol)
180{
181 ucontrol->value.integer.value[0] = 0;
182 return 0;
183}
184
185static int msm_voip_volume_put(struct snd_kcontrol *kcontrol,
186 struct snd_ctl_elem_value *ucontrol)
187{
188 int volume = ucontrol->value.integer.value[0];
189
190 pr_debug("%s: volume: %d\n", __func__, volume);
191
192 voc_set_rx_vol_index(voc_get_session_id(VOIP_SESSION_NAME),
193 RX_PATH,
194 volume);
195 return 0;
196}
197static int msm_voip_volume_get(struct snd_kcontrol *kcontrol,
198 struct snd_ctl_elem_value *ucontrol)
199{
200 ucontrol->value.integer.value[0] = 0;
201 return 0;
202}
203
Helen Zengff97bec2012-02-20 14:30:50 -0800204static int msm_voip_dtx_mode_put(struct snd_kcontrol *kcontrol,
205 struct snd_ctl_elem_value *ucontrol)
206{
207 mutex_lock(&voip_info.lock);
208
209 voip_info.dtx_mode = ucontrol->value.integer.value[0];
210
211 pr_debug("%s: dtx: %d\n", __func__, voip_info.dtx_mode);
212
213 mutex_unlock(&voip_info.lock);
214
215 return 0;
216}
217static int msm_voip_dtx_mode_get(struct snd_kcontrol *kcontrol,
218 struct snd_ctl_elem_value *ucontrol)
219{
220 mutex_lock(&voip_info.lock);
221
222 ucontrol->value.integer.value[0] = voip_info.dtx_mode;
223
224 mutex_unlock(&voip_info.lock);
225
226 return 0;
227}
228
Panneer Arumugambcac6862011-10-27 18:20:44 -0700229static struct snd_kcontrol_new msm_voip_controls[] = {
230 SOC_SINGLE_EXT("Voip Tx Mute", SND_SOC_NOPM, 0, 1, 0,
231 msm_voip_mute_get, msm_voip_mute_put),
232 SOC_SINGLE_EXT("Voip Rx Volume", SND_SOC_NOPM, 0, 5, 0,
233 msm_voip_volume_get, msm_voip_volume_put),
Helen Zengb9d00ce2011-10-13 17:25:50 -0700234 SOC_SINGLE_MULTI_EXT("Voip Mode Rate Config", SND_SOC_NOPM, 0, 23850,
235 0, 2, msm_voip_mode_rate_config_get,
236 msm_voip_mode_rate_config_put),
Helen Zengff97bec2012-02-20 14:30:50 -0800237 SOC_SINGLE_EXT("Voip Dtx Mode", SND_SOC_NOPM, 0, 1, 0,
238 msm_voip_dtx_mode_get, msm_voip_dtx_mode_put),
Panneer Arumugambcac6862011-10-27 18:20:44 -0700239};
240
241static int msm_pcm_voip_probe(struct snd_soc_platform *platform)
242{
243 snd_soc_add_platform_controls(platform, msm_voip_controls,
244 ARRAY_SIZE(msm_voip_controls));
245
246 return 0;
247}
248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249/* sample rate supported */
250static unsigned int supported_sample_rates[] = {8000, 16000};
251
252/* capture path */
253static void voip_process_ul_pkt(uint8_t *voc_pkt,
254 uint32_t pkt_len,
255 void *private_data)
256{
257 struct voip_buf_node *buf_node = NULL;
258 struct voip_drv_info *prtd = private_data;
259 unsigned long dsp_flags;
260
261 if (prtd->capture_substream == NULL)
262 return;
263
264 /* Copy up-link packet into out_queue. */
265 spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
266
267 /* discarding UL packets till start is received */
268 if (!list_empty(&prtd->free_out_queue) && prtd->capture_start) {
269 buf_node = list_first_entry(&prtd->free_out_queue,
270 struct voip_buf_node, list);
271 list_del(&buf_node->list);
Helen Zengb9d00ce2011-10-13 17:25:50 -0700272 switch (prtd->mode) {
273 case MODE_AMR_WB:
274 case MODE_AMR: {
275 /* Remove the DSP frame info header. Header format:
276 * Bits 0-3: Frame rate
277 * Bits 4-7: Frame type
278 */
279 buf_node->frame.frame_type = ((*voc_pkt) & 0xF0) >> 4;
280 voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
281 buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
282 memcpy(&buf_node->frame.voc_pkt[0],
283 voc_pkt,
284 buf_node->frame.len);
285 list_add_tail(&buf_node->list, &prtd->out_queue);
286 break;
287 }
288 default: {
289 buf_node->frame.len = pkt_len;
290 memcpy(&buf_node->frame.voc_pkt[0],
291 voc_pkt,
292 buf_node->frame.len);
293 list_add_tail(&buf_node->list, &prtd->out_queue);
294 }
295 }
296 pr_debug("ul_pkt: pkt_len =%d, frame.len=%d\n", pkt_len,
297 buf_node->frame.len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
299 spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
300 snd_pcm_period_elapsed(prtd->capture_substream);
301 } else {
302 spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
303 pr_err("UL data dropped\n");
304 }
305
306 wake_up(&prtd->out_wait);
307}
308
309/* playback path */
310static void voip_process_dl_pkt(uint8_t *voc_pkt,
311 uint32_t *pkt_len,
312 void *private_data)
313{
314 struct voip_buf_node *buf_node = NULL;
315 struct voip_drv_info *prtd = private_data;
316 unsigned long dsp_flags;
317
318
319 if (prtd->playback_substream == NULL)
320 return;
321
322 spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
323
324 if (!list_empty(&prtd->in_queue) && prtd->playback_start) {
325 buf_node = list_first_entry(&prtd->in_queue,
326 struct voip_buf_node, list);
327 list_del(&buf_node->list);
Helen Zengb9d00ce2011-10-13 17:25:50 -0700328 switch (prtd->mode) {
329 case MODE_AMR:
330 case MODE_AMR_WB: {
331 /* Add the DSP frame info header. Header format:
332 * Bits 0-3: Frame rate
333 * Bits 4-7: Frame type
334 */
335 *voc_pkt = ((buf_node->frame.frame_type & 0x0F) << 4) |
336 (prtd->rate_type & 0x0F);
337 voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
338 *pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
339 memcpy(voc_pkt,
340 &buf_node->frame.voc_pkt[0],
341 buf_node->frame.len);
342 list_add_tail(&buf_node->list, &prtd->free_in_queue);
343 break;
344 }
345 default: {
346 *pkt_len = buf_node->frame.len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347
Helen Zengb9d00ce2011-10-13 17:25:50 -0700348 memcpy(voc_pkt,
349 &buf_node->frame.voc_pkt[0],
350 buf_node->frame.len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351
Helen Zengb9d00ce2011-10-13 17:25:50 -0700352 list_add_tail(&buf_node->list, &prtd->free_in_queue);
353 }
354 }
355 pr_debug("dl_pkt: pkt_len=%d, frame_len=%d\n", *pkt_len,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700356 buf_node->frame.len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700357 prtd->pcm_playback_irq_pos += prtd->pcm_count;
358 spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
359 snd_pcm_period_elapsed(prtd->playback_substream);
360 } else {
361 *pkt_len = 0;
362 spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
363 pr_err("DL data not available\n");
364 }
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700365 wake_up(&prtd->in_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700366}
367
368static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
369 .count = ARRAY_SIZE(supported_sample_rates),
370 .list = supported_sample_rates,
371 .mask = 0,
372};
373
374static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
375{
376 struct snd_pcm_runtime *runtime = substream->runtime;
377 struct voip_drv_info *prtd = runtime->private_data;
378
379 prtd->play_samp_rate = runtime->rate;
380 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
381 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
382 prtd->pcm_playback_irq_pos = 0;
383 prtd->pcm_playback_buf_pos = 0;
384
385 return 0;
386}
387
388static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
389{
390 struct snd_pcm_runtime *runtime = substream->runtime;
391 struct voip_drv_info *prtd = runtime->private_data;
392 int ret = 0;
393
394 prtd->cap_samp_rate = runtime->rate;
395 prtd->pcm_capture_size = snd_pcm_lib_buffer_bytes(substream);
396 prtd->pcm_capture_count = snd_pcm_lib_period_bytes(substream);
397 prtd->pcm_capture_irq_pos = 0;
398 prtd->pcm_capture_buf_pos = 0;
399 return ret;
400}
401
402static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
403{
404 int ret = 0;
405 struct snd_pcm_runtime *runtime = substream->runtime;
406 struct voip_drv_info *prtd = runtime->private_data;
407
408 switch (cmd) {
409 case SNDRV_PCM_TRIGGER_START:
410 case SNDRV_PCM_TRIGGER_RESUME:
411 pr_debug("%s: Trigger start\n", __func__);
412 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
413 prtd->capture_start = 1;
414 else
415 prtd->playback_start = 1;
416 break;
417 case SNDRV_PCM_TRIGGER_STOP:
418 pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
419 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
420 prtd->playback_start = 0;
421 else
422 prtd->capture_start = 0;
423 break;
424 default:
425 ret = -EINVAL;
426 break;
427 }
428
429 return ret;
430}
431
432static int msm_pcm_open(struct snd_pcm_substream *substream)
433{
434 struct snd_pcm_runtime *runtime = substream->runtime;
435 struct voip_drv_info *prtd = &voip_info;
436 int ret = 0;
437
438 pr_debug("%s, VoIP\n", __func__);
439 mutex_lock(&prtd->lock);
440
441 runtime->hw = msm_pcm_hardware;
442
443 ret = snd_pcm_hw_constraint_list(runtime, 0,
444 SNDRV_PCM_HW_PARAM_RATE,
445 &constraints_sample_rates);
446 if (ret < 0)
447 pr_debug("snd_pcm_hw_constraint_list failed\n");
448
449 ret = snd_pcm_hw_constraint_integer(runtime,
450 SNDRV_PCM_HW_PARAM_PERIODS);
451 if (ret < 0) {
452 pr_debug("snd_pcm_hw_constraint_integer failed\n");
453 goto err;
454 }
455
456 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
457 prtd->playback_substream = substream;
458 prtd->playback_instance++;
459 } else {
460 prtd->capture_substream = substream;
461 prtd->capture_instance++;
462 }
463 runtime->private_data = prtd;
464err:
465 mutex_unlock(&prtd->lock);
466
467 return ret;
468}
469
470static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
471 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
472{
473 int ret = 0;
474 struct voip_buf_node *buf_node = NULL;
475 struct snd_pcm_runtime *runtime = substream->runtime;
476 struct voip_drv_info *prtd = runtime->private_data;
477
478 int count = frames_to_bytes(runtime, frames);
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700479 pr_debug("%s: count = %d, frames=%d\n", __func__, count, (int)frames);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700481 ret = wait_event_interruptible_timeout(prtd->in_wait,
482 (!list_empty(&prtd->free_in_queue) ||
483 prtd->state == VOIP_STOPPED),
484 1 * HZ);
485 if (ret > 0) {
486 mutex_lock(&prtd->in_lock);
487 if (count <= VOIP_MAX_VOC_PKT_SIZE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 buf_node =
489 list_first_entry(&prtd->free_in_queue,
490 struct voip_buf_node, list);
491 list_del(&buf_node->list);
Helen Zengb9d00ce2011-10-13 17:25:50 -0700492 if (prtd->mode == MODE_PCM) {
493 ret = copy_from_user(&buf_node->frame.voc_pkt,
494 buf, count);
495 buf_node->frame.len = count;
496 } else
497 ret = copy_from_user(&buf_node->frame,
498 buf, count);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499 list_add_tail(&buf_node->list, &prtd->in_queue);
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700500 } else {
501 pr_err("%s: Write cnt %d is > VOIP_MAX_VOC_PKT_SIZE\n",
502 __func__, count);
503 ret = -ENOMEM;
504 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700505
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700506 mutex_unlock(&prtd->in_lock);
507 } else if (ret == 0) {
508 pr_err("%s: No free DL buffs\n", __func__);
509 ret = -ETIMEDOUT;
510 } else {
511 pr_err("%s: playback copy was interrupted\n", __func__);
512 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513
514 return ret;
515}
516static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
517 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
518 snd_pcm_uframes_t frames)
519{
520 int ret = 0;
521 int count = 0;
522 struct voip_buf_node *buf_node = NULL;
523 struct snd_pcm_runtime *runtime = substream->runtime;
524 struct voip_drv_info *prtd = runtime->private_data;
525
526 count = frames_to_bytes(runtime, frames);
527
528 pr_debug("%s: count = %d\n", __func__, count);
529
530 ret = wait_event_interruptible_timeout(prtd->out_wait,
531 (!list_empty(&prtd->out_queue) ||
532 prtd->state == VOIP_STOPPED),
533 1 * HZ);
534
535 if (ret > 0) {
536 mutex_lock(&prtd->out_lock);
537
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700538 if (count <= VOIP_MAX_VOC_PKT_SIZE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700539 buf_node = list_first_entry(&prtd->out_queue,
540 struct voip_buf_node, list);
541 list_del(&buf_node->list);
Helen Zengb9d00ce2011-10-13 17:25:50 -0700542 if (prtd->mode == MODE_PCM)
543 ret = copy_to_user(buf,
544 &buf_node->frame.voc_pkt,
545 count);
546 else
547 ret = copy_to_user(buf,
548 &buf_node->frame,
549 count);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550 if (ret) {
551 pr_err("%s: Copy to user retuned %d\n",
552 __func__, ret);
553 ret = -EFAULT;
554 }
555 list_add_tail(&buf_node->list,
556 &prtd->free_out_queue);
557 } else {
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700558 pr_err("%s: Read count %d > VOIP_MAX_VOC_PKT_SIZE\n",
559 __func__, count);
560 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561 }
562
563 mutex_unlock(&prtd->out_lock);
564
565 } else if (ret == 0) {
566 pr_err("%s: No UL data available\n", __func__);
567 ret = -ETIMEDOUT;
568 } else {
569 pr_err("%s: Read was interrupted\n", __func__);
570 ret = -ERESTARTSYS;
571 }
572 return ret;
573}
574static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
575 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
576{
577 int ret = 0;
578
579 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
580 ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
581 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
582 ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
583
584 return ret;
585}
586
587static int msm_pcm_close(struct snd_pcm_substream *substream)
588{
589 int ret = 0;
590 struct list_head *ptr = NULL;
591 struct list_head *next = NULL;
592 struct voip_buf_node *buf_node = NULL;
593 struct snd_dma_buffer *p_dma_buf, *c_dma_buf;
594 struct snd_pcm_substream *p_substream, *c_substream;
595 struct snd_pcm_runtime *runtime;
596 struct voip_drv_info *prtd;
597
598 if (substream == NULL) {
599 pr_err("substream is NULL\n");
600 return -EINVAL;
601 }
602 runtime = substream->runtime;
603 prtd = runtime->private_data;
604
605 wake_up(&prtd->out_wait);
606
607 mutex_lock(&prtd->lock);
608
609 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
610 prtd->playback_instance--;
611 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
612 prtd->capture_instance--;
613
614 if (!prtd->playback_instance && !prtd->capture_instance) {
615 if (prtd->state == VOIP_STARTED) {
616 prtd->state = VOIP_STOPPED;
Neema Shetty2c07eb52011-08-21 20:33:52 -0700617 voc_end_voice_call(
618 voc_get_session_id(VOIP_SESSION_NAME));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 voc_register_mvs_cb(NULL, NULL, prtd);
620 }
621 /* release all buffer */
622 /* release in_queue and free_in_queue */
623 pr_debug("release all buffer\n");
624 p_substream = prtd->playback_substream;
625 if (p_substream == NULL) {
626 pr_debug("p_substream is NULL\n");
627 goto capt;
628 }
629 p_dma_buf = &p_substream->dma_buffer;
630 if (p_dma_buf == NULL) {
631 pr_debug("p_dma_buf is NULL\n");
632 goto capt;
633 }
634 if (p_dma_buf->area != NULL) {
635 mutex_lock(&prtd->in_lock);
636 list_for_each_safe(ptr, next, &prtd->in_queue) {
637 buf_node = list_entry(ptr,
638 struct voip_buf_node, list);
639 list_del(&buf_node->list);
640 }
641 list_for_each_safe(ptr, next, &prtd->free_in_queue) {
642 buf_node = list_entry(ptr,
643 struct voip_buf_node, list);
644 list_del(&buf_node->list);
645 }
646 dma_free_coherent(p_substream->pcm->card->dev,
647 runtime->hw.buffer_bytes_max, p_dma_buf->area,
648 p_dma_buf->addr);
649 p_dma_buf->area = NULL;
650 mutex_unlock(&prtd->in_lock);
651 }
652 /* release out_queue and free_out_queue */
653capt: c_substream = prtd->capture_substream;
654 if (c_substream == NULL) {
655 pr_debug("c_substream is NULL\n");
656 goto done;
657 }
658 c_dma_buf = &c_substream->dma_buffer;
659 if (c_substream == NULL) {
660 pr_debug("c_dma_buf is NULL.\n");
661 goto done;
662 }
663 if (c_dma_buf->area != NULL) {
664 mutex_lock(&prtd->out_lock);
665 list_for_each_safe(ptr, next, &prtd->out_queue) {
666 buf_node = list_entry(ptr,
667 struct voip_buf_node, list);
668 list_del(&buf_node->list);
669 }
670 list_for_each_safe(ptr, next, &prtd->free_out_queue) {
671 buf_node = list_entry(ptr,
672 struct voip_buf_node, list);
673 list_del(&buf_node->list);
674 }
675 dma_free_coherent(c_substream->pcm->card->dev,
676 runtime->hw.buffer_bytes_max, c_dma_buf->area,
677 c_dma_buf->addr);
678 c_dma_buf->area = NULL;
679 mutex_unlock(&prtd->out_lock);
680 }
681done:
682 prtd->capture_substream = NULL;
683 prtd->playback_substream = NULL;
684 }
685 mutex_unlock(&prtd->lock);
686
687 return ret;
688}
689static int msm_pcm_prepare(struct snd_pcm_substream *substream)
690{
691 int ret = 0;
692 struct snd_pcm_runtime *runtime = substream->runtime;
693 struct voip_drv_info *prtd = runtime->private_data;
Helen Zengb9d00ce2011-10-13 17:25:50 -0700694 uint32_t media_type = 0;
695 uint32_t rate_type = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696
697 mutex_lock(&prtd->lock);
698
699 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
700 ret = msm_pcm_playback_prepare(substream);
701 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
702 ret = msm_pcm_capture_prepare(substream);
703
Helen Zengb9d00ce2011-10-13 17:25:50 -0700704 if ((runtime->format != FORMAT_SPECIAL) &&
705 ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB))) {
706 pr_err("mode:%d and format:%u are not mached\n",
707 prtd->mode, (uint32_t)runtime->format);
708 ret = -EINVAL;
709 goto done;
710 }
711
712 if ((runtime->format != FORMAT_S16_LE) &&
713 (prtd->mode == MODE_PCM)) {
714 pr_err("mode:%d and format:%u are not mached\n",
715 prtd->mode, (uint32_t)runtime->format);
716 ret = -EINVAL;
717 goto done;
718 }
719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720 if (prtd->playback_instance && prtd->capture_instance
721 && (prtd->state != VOIP_STARTED)) {
722
Helen Zengb9d00ce2011-10-13 17:25:50 -0700723 ret = voip_get_rate_type(prtd->mode,
724 prtd->rate,
725 &rate_type);
726 if (ret < 0) {
727 pr_err("fail at getting rate_type\n");
728 ret = -EINVAL;
729 goto done;
730 }
731 prtd->rate_type = rate_type;
732 media_type = voip_get_media_type(prtd->mode,
733 prtd->play_samp_rate);
734 if (media_type < 0) {
735 pr_err("fail at getting media_type\n");
736 ret = -EINVAL;
737 goto done;
738 }
739 pr_debug(" media_type=%d, rate_type=%d\n", media_type,
740 rate_type);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741 if ((prtd->play_samp_rate == 8000) &&
742 (prtd->cap_samp_rate == 8000))
Helen Zengb9d00ce2011-10-13 17:25:50 -0700743 voc_config_vocoder(media_type, rate_type,
Helen Zengff97bec2012-02-20 14:30:50 -0800744 VSS_NETWORK_ID_VOIP_NB,
745 voip_info.dtx_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746 else if ((prtd->play_samp_rate == 16000) &&
747 (prtd->cap_samp_rate == 16000))
Helen Zengb9d00ce2011-10-13 17:25:50 -0700748 voc_config_vocoder(media_type, rate_type,
Helen Zengff97bec2012-02-20 14:30:50 -0800749 VSS_NETWORK_ID_VOIP_WB,
750 voip_info.dtx_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700751 else {
Neema Shetty2c07eb52011-08-21 20:33:52 -0700752 pr_debug("%s: Invalid rate playback %d, capture %d\n",
753 __func__, prtd->play_samp_rate,
754 prtd->cap_samp_rate);
755 goto done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700756 }
757 voc_register_mvs_cb(voip_process_ul_pkt,
758 voip_process_dl_pkt, prtd);
Neema Shetty2c07eb52011-08-21 20:33:52 -0700759 voc_start_voice_call(voc_get_session_id(VOIP_SESSION_NAME));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700760
761 prtd->state = VOIP_STARTED;
762 }
Neema Shetty2c07eb52011-08-21 20:33:52 -0700763done:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700764 mutex_unlock(&prtd->lock);
765
766 return ret;
767}
768
769static snd_pcm_uframes_t
770msm_pcm_playback_pointer(struct snd_pcm_substream *substream)
771{
772 struct snd_pcm_runtime *runtime = substream->runtime;
773 struct voip_drv_info *prtd = runtime->private_data;
774
775 pr_debug("%s\n", __func__);
776 if (prtd->pcm_playback_irq_pos >= prtd->pcm_size)
777 prtd->pcm_playback_irq_pos = 0;
778 return bytes_to_frames(runtime, (prtd->pcm_playback_irq_pos));
779}
780
781static snd_pcm_uframes_t
782msm_pcm_capture_pointer(struct snd_pcm_substream *substream)
783{
784 struct snd_pcm_runtime *runtime = substream->runtime;
785 struct voip_drv_info *prtd = runtime->private_data;
786
787 if (prtd->pcm_capture_irq_pos >= prtd->pcm_capture_size)
788 prtd->pcm_capture_irq_pos = 0;
789 return bytes_to_frames(runtime, (prtd->pcm_capture_irq_pos));
790}
791
792static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
793{
794 snd_pcm_uframes_t ret = 0;
795 pr_debug("%s\n", __func__);
796 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
797 ret = msm_pcm_playback_pointer(substream);
798 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
799 ret = msm_pcm_capture_pointer(substream);
800 return ret;
801}
802
803static int msm_pcm_mmap(struct snd_pcm_substream *substream,
804 struct vm_area_struct *vma)
805{
806 struct snd_pcm_runtime *runtime = substream->runtime;
807
808 pr_debug("%s\n", __func__);
809 dma_mmap_coherent(substream->pcm->card->dev, vma,
810 runtime->dma_area,
811 runtime->dma_addr,
812 runtime->dma_bytes);
813 return 0;
814}
815
816static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
817 struct snd_pcm_hw_params *params)
818{
819 struct snd_pcm_runtime *runtime = substream->runtime;
820 struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
821 struct voip_buf_node *buf_node = NULL;
822 int i = 0, offset = 0;
823
824 pr_debug("%s: voip\n", __func__);
825
826 mutex_lock(&voip_info.lock);
827
828 dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
829 dma_buf->dev.dev = substream->pcm->card->dev;
830 dma_buf->private_data = NULL;
831
832 dma_buf->area = dma_alloc_coherent(substream->pcm->card->dev,
833 runtime->hw.buffer_bytes_max,
834 &dma_buf->addr, GFP_KERNEL);
835 if (!dma_buf->area) {
836 pr_err("%s:MSM VOIP dma_alloc failed\n", __func__);
837 return -ENOMEM;
838 }
839
840 dma_buf->bytes = runtime->hw.buffer_bytes_max;
841 memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
842
843 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
844 for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
845 buf_node = (void *)dma_buf->area + offset;
846
847 mutex_lock(&voip_info.in_lock);
848 list_add_tail(&buf_node->list,
849 &voip_info.free_in_queue);
850 mutex_unlock(&voip_info.in_lock);
851 offset = offset + sizeof(struct voip_buf_node);
852 }
853 } else {
854 for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
855 buf_node = (void *) dma_buf->area + offset;
856 mutex_lock(&voip_info.out_lock);
857 list_add_tail(&buf_node->list,
858 &voip_info.free_out_queue);
859 mutex_unlock(&voip_info.out_lock);
860 offset = offset + sizeof(struct voip_buf_node);
861 }
862 }
863
864 mutex_unlock(&voip_info.lock);
865
866 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
867
868 return 0;
869}
870
Helen Zengb9d00ce2011-10-13 17:25:50 -0700871static int msm_voip_mode_rate_config_get(struct snd_kcontrol *kcontrol,
872 struct snd_ctl_elem_value *ucontrol)
873{
874 mutex_lock(&voip_info.lock);
875
876 ucontrol->value.integer.value[0] = voip_info.mode;
877 ucontrol->value.integer.value[1] = voip_info.rate;
878
879 mutex_unlock(&voip_info.lock);
880
881 return 0;
882}
883
884static int msm_voip_mode_rate_config_put(struct snd_kcontrol *kcontrol,
885 struct snd_ctl_elem_value *ucontrol)
886{
887 mutex_lock(&voip_info.lock);
888
889 voip_info.mode = ucontrol->value.integer.value[0];
890 voip_info.rate = ucontrol->value.integer.value[1];
891
892 pr_debug("%s: mode=%d,rate=%d\n", __func__, voip_info.mode,
893 voip_info.rate);
894
895 mutex_unlock(&voip_info.lock);
896
897 return 0;
898}
899
900static int voip_get_rate_type(uint32_t mode, uint32_t rate,
901 uint32_t *rate_type)
902{
903 int ret = 0;
904
905 switch (mode) {
906 case MODE_AMR: {
907 switch (rate) {
908 case 4750:
909 *rate_type = AMR_RATE_4750;
910 break;
911 case 5150:
912 *rate_type = AMR_RATE_5150;
913 break;
914 case 5900:
915 *rate_type = AMR_RATE_5900;
916 break;
917 case 6700:
918 *rate_type = AMR_RATE_6700;
919 break;
920 case 7400:
921 *rate_type = AMR_RATE_7400;
922 break;
923 case 7950:
924 *rate_type = AMR_RATE_7950;
925 break;
926 case 10200:
927 *rate_type = AMR_RATE_10200;
928 break;
929 case 12200:
930 *rate_type = AMR_RATE_12200;
931 break;
932 default:
933 pr_err("wrong rate for AMR NB.\n");
934 ret = -EINVAL;
935 break;
936 }
937 break;
938 }
939 case MODE_AMR_WB: {
940 switch (rate) {
941 case 6600:
942 *rate_type = AMR_RATE_6600 - AMR_RATE_6600;
943 break;
944 case 8850:
945 *rate_type = AMR_RATE_8850 - AMR_RATE_6600;
946 break;
947 case 12650:
948 *rate_type = AMR_RATE_12650 - AMR_RATE_6600;
949 break;
950 case 14250:
951 *rate_type = AMR_RATE_14250 - AMR_RATE_6600;
952 break;
953 case 15850:
954 *rate_type = AMR_RATE_15850 - AMR_RATE_6600;
955 break;
956 case 18250:
957 *rate_type = AMR_RATE_18250 - AMR_RATE_6600;
958 break;
959 case 19850:
960 *rate_type = AMR_RATE_19850 - AMR_RATE_6600;
961 break;
962 case 23050:
963 *rate_type = AMR_RATE_23050 - AMR_RATE_6600;
964 break;
965 case 23850:
966 *rate_type = AMR_RATE_23850 - AMR_RATE_6600;
967 break;
968 default:
969 pr_err("wrong rate for AMR_WB.\n");
970 ret = -EINVAL;
971 break;
972 }
973 break;
974 }
975 case MODE_PCM: {
976 *rate_type = 0;
977 break;
978 }
979 default:
980 pr_err("wrong mode type.\n");
981 ret = -EINVAL;
982 }
983 pr_debug("%s, mode=%d, rate=%u, rate_type=%d\n",
984 __func__, mode, rate, *rate_type);
985 return ret;
986}
987
988static int voip_get_media_type(uint32_t mode,
989 unsigned int samp_rate)
990{
991 uint32_t media_type;
992
993 pr_debug("%s: mode=%d, samp_rate=%d\n", __func__,
994 mode, samp_rate);
995 switch (mode) {
996 case MODE_AMR:
997 media_type = VSS_MEDIA_ID_AMR_NB_MODEM;
998 break;
999 case MODE_AMR_WB:
1000 media_type = VSS_MEDIA_ID_AMR_WB_MODEM;
1001 break;
1002 case MODE_PCM:
1003 if (samp_rate == 8000)
1004 media_type = VSS_MEDIA_ID_PCM_NB;
1005 else
1006 media_type = VSS_MEDIA_ID_PCM_WB;
1007 break;
1008 default:
1009 pr_debug(" input mode is not supported\n");
1010 media_type = -EINVAL;
1011 }
1012
1013 pr_debug("%s: media_type is 0x%x\n", __func__, media_type);
1014
1015 return media_type;
1016}
1017
1018
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001019static struct snd_pcm_ops msm_pcm_ops = {
1020 .open = msm_pcm_open,
1021 .copy = msm_pcm_copy,
1022 .hw_params = msm_pcm_hw_params,
1023 .close = msm_pcm_close,
1024 .prepare = msm_pcm_prepare,
1025 .trigger = msm_pcm_trigger,
1026 .pointer = msm_pcm_pointer,
1027 .mmap = msm_pcm_mmap,
1028};
1029
1030static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
1031{
1032 struct snd_card *card = rtd->card->snd_card;
1033 int ret = 0;
1034
1035 pr_debug("msm_asoc_pcm_new\n");
1036 if (!card->dev->coherent_dma_mask)
1037 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
1038 return ret;
1039}
1040
1041static struct snd_soc_platform_driver msm_soc_platform = {
1042 .ops = &msm_pcm_ops,
1043 .pcm_new = msm_asoc_pcm_new,
Panneer Arumugambcac6862011-10-27 18:20:44 -07001044 .probe = msm_pcm_voip_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001045};
1046
1047static __devinit int msm_pcm_probe(struct platform_device *pdev)
1048{
1049 pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
1050 return snd_soc_register_platform(&pdev->dev,
1051 &msm_soc_platform);
1052}
1053
1054static int msm_pcm_remove(struct platform_device *pdev)
1055{
1056 snd_soc_unregister_platform(&pdev->dev);
1057 return 0;
1058}
1059
1060static struct platform_driver msm_pcm_driver = {
1061 .driver = {
1062 .name = "msm-voip-dsp",
1063 .owner = THIS_MODULE,
1064 },
1065 .probe = msm_pcm_probe,
1066 .remove = __devexit_p(msm_pcm_remove),
1067};
1068
1069static int __init msm_soc_platform_init(void)
1070{
1071 memset(&voip_info, 0, sizeof(voip_info));
Helen Zengb9d00ce2011-10-13 17:25:50 -07001072 voip_info.mode = MODE_PCM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073 mutex_init(&voip_info.lock);
1074 mutex_init(&voip_info.in_lock);
1075 mutex_init(&voip_info.out_lock);
1076
1077 spin_lock_init(&voip_info.dsp_lock);
1078
1079 init_waitqueue_head(&voip_info.out_wait);
Panneer Arumugam418aa0a2011-10-11 18:44:16 -07001080 init_waitqueue_head(&voip_info.in_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081
1082 INIT_LIST_HEAD(&voip_info.in_queue);
1083 INIT_LIST_HEAD(&voip_info.free_in_queue);
1084 INIT_LIST_HEAD(&voip_info.out_queue);
1085 INIT_LIST_HEAD(&voip_info.free_out_queue);
1086
1087 return platform_driver_register(&msm_pcm_driver);
1088}
1089module_init(msm_soc_platform_init);
1090
1091static void __exit msm_soc_platform_exit(void)
1092{
1093 platform_driver_unregister(&msm_pcm_driver);
1094}
1095module_exit(msm_soc_platform_exit);
1096
1097MODULE_DESCRIPTION("PCM module platform driver");
1098MODULE_LICENSE("GPL v2");