blob: 56b4cf58fad458cf6de275cc4b4801055375abc0 [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;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111
112 uint8_t capture_start;
113 uint8_t playback_start;
114
115 uint8_t playback_instance;
116 uint8_t capture_instance;
117
118 unsigned int play_samp_rate;
119 unsigned int cap_samp_rate;
120
121 unsigned int pcm_size;
122 unsigned int pcm_count;
123 unsigned int pcm_playback_irq_pos; /* IRQ position */
124 unsigned int pcm_playback_buf_pos; /* position in buffer */
125
126 unsigned int pcm_capture_size;
127 unsigned int pcm_capture_count;
128 unsigned int pcm_capture_irq_pos; /* IRQ position */
129 unsigned int pcm_capture_buf_pos; /* position in buffer */
130};
131
Helen Zengb9d00ce2011-10-13 17:25:50 -0700132static int voip_get_media_type(uint32_t mode,
133 unsigned int samp_rate);
134static int voip_get_rate_type(uint32_t mode,
135 uint32_t rate,
136 uint32_t *rate_type);
137static int msm_voip_mode_rate_config_put(struct snd_kcontrol *kcontrol,
138 struct snd_ctl_elem_value *ucontrol);
139static int msm_voip_mode_rate_config_get(struct snd_kcontrol *kcontrol,
140 struct snd_ctl_elem_value *ucontrol);
141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142static struct voip_drv_info voip_info;
143
144static struct snd_pcm_hardware msm_pcm_hardware = {
145 .info = (SNDRV_PCM_INFO_MMAP |
146 SNDRV_PCM_INFO_BLOCK_TRANSFER |
147 SNDRV_PCM_INFO_MMAP_VALID |
148 SNDRV_PCM_INFO_INTERLEAVED),
Helen Zengb9d00ce2011-10-13 17:25:50 -0700149 .formats = SNDRV_PCM_FMTBIT_S16_LE |
150 SNDRV_PCM_FMTBIT_SPECIAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
152 .rate_min = 8000,
153 .rate_max = 16000,
154 .channels_min = 1,
155 .channels_max = 1,
Helen Zengb9d00ce2011-10-13 17:25:50 -0700156 .buffer_bytes_max = sizeof(struct voip_buf_node) * VOIP_MAX_Q_LEN,
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700157 .period_bytes_min = VOIP_MIN_VOC_PKT_SIZE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158 .period_bytes_max = VOIP_MAX_VOC_PKT_SIZE,
159 .periods_min = VOIP_MAX_Q_LEN,
160 .periods_max = VOIP_MAX_Q_LEN,
161 .fifo_size = 0,
162};
163
164
Panneer Arumugambcac6862011-10-27 18:20:44 -0700165static int msm_voip_mute_put(struct snd_kcontrol *kcontrol,
166 struct snd_ctl_elem_value *ucontrol)
167{
168 int mute = ucontrol->value.integer.value[0];
169
170 pr_debug("%s: mute=%d\n", __func__, mute);
171
172 voc_set_tx_mute(voc_get_session_id(VOIP_SESSION_NAME), TX_PATH, mute);
173
174 return 0;
175}
176
177static int msm_voip_mute_get(struct snd_kcontrol *kcontrol,
178 struct snd_ctl_elem_value *ucontrol)
179{
180 ucontrol->value.integer.value[0] = 0;
181 return 0;
182}
183
184static int msm_voip_volume_put(struct snd_kcontrol *kcontrol,
185 struct snd_ctl_elem_value *ucontrol)
186{
187 int volume = ucontrol->value.integer.value[0];
188
189 pr_debug("%s: volume: %d\n", __func__, volume);
190
191 voc_set_rx_vol_index(voc_get_session_id(VOIP_SESSION_NAME),
192 RX_PATH,
193 volume);
194 return 0;
195}
196static int msm_voip_volume_get(struct snd_kcontrol *kcontrol,
197 struct snd_ctl_elem_value *ucontrol)
198{
199 ucontrol->value.integer.value[0] = 0;
200 return 0;
201}
202
203static struct snd_kcontrol_new msm_voip_controls[] = {
204 SOC_SINGLE_EXT("Voip Tx Mute", SND_SOC_NOPM, 0, 1, 0,
205 msm_voip_mute_get, msm_voip_mute_put),
206 SOC_SINGLE_EXT("Voip Rx Volume", SND_SOC_NOPM, 0, 5, 0,
207 msm_voip_volume_get, msm_voip_volume_put),
Helen Zengb9d00ce2011-10-13 17:25:50 -0700208 SOC_SINGLE_MULTI_EXT("Voip Mode Rate Config", SND_SOC_NOPM, 0, 23850,
209 0, 2, msm_voip_mode_rate_config_get,
210 msm_voip_mode_rate_config_put),
Panneer Arumugambcac6862011-10-27 18:20:44 -0700211};
212
213static int msm_pcm_voip_probe(struct snd_soc_platform *platform)
214{
215 snd_soc_add_platform_controls(platform, msm_voip_controls,
216 ARRAY_SIZE(msm_voip_controls));
217
218 return 0;
219}
220
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221/* sample rate supported */
222static unsigned int supported_sample_rates[] = {8000, 16000};
223
224/* capture path */
225static void voip_process_ul_pkt(uint8_t *voc_pkt,
226 uint32_t pkt_len,
227 void *private_data)
228{
229 struct voip_buf_node *buf_node = NULL;
230 struct voip_drv_info *prtd = private_data;
231 unsigned long dsp_flags;
232
233 if (prtd->capture_substream == NULL)
234 return;
235
236 /* Copy up-link packet into out_queue. */
237 spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
238
239 /* discarding UL packets till start is received */
240 if (!list_empty(&prtd->free_out_queue) && prtd->capture_start) {
241 buf_node = list_first_entry(&prtd->free_out_queue,
242 struct voip_buf_node, list);
243 list_del(&buf_node->list);
Helen Zengb9d00ce2011-10-13 17:25:50 -0700244 switch (prtd->mode) {
245 case MODE_AMR_WB:
246 case MODE_AMR: {
247 /* Remove the DSP frame info header. Header format:
248 * Bits 0-3: Frame rate
249 * Bits 4-7: Frame type
250 */
251 buf_node->frame.frame_type = ((*voc_pkt) & 0xF0) >> 4;
252 voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
253 buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
254 memcpy(&buf_node->frame.voc_pkt[0],
255 voc_pkt,
256 buf_node->frame.len);
257 list_add_tail(&buf_node->list, &prtd->out_queue);
258 break;
259 }
260 default: {
261 buf_node->frame.len = pkt_len;
262 memcpy(&buf_node->frame.voc_pkt[0],
263 voc_pkt,
264 buf_node->frame.len);
265 list_add_tail(&buf_node->list, &prtd->out_queue);
266 }
267 }
268 pr_debug("ul_pkt: pkt_len =%d, frame.len=%d\n", pkt_len,
269 buf_node->frame.len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270 prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
271 spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
272 snd_pcm_period_elapsed(prtd->capture_substream);
273 } else {
274 spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
275 pr_err("UL data dropped\n");
276 }
277
278 wake_up(&prtd->out_wait);
279}
280
281/* playback path */
282static void voip_process_dl_pkt(uint8_t *voc_pkt,
283 uint32_t *pkt_len,
284 void *private_data)
285{
286 struct voip_buf_node *buf_node = NULL;
287 struct voip_drv_info *prtd = private_data;
288 unsigned long dsp_flags;
289
290
291 if (prtd->playback_substream == NULL)
292 return;
293
294 spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
295
296 if (!list_empty(&prtd->in_queue) && prtd->playback_start) {
297 buf_node = list_first_entry(&prtd->in_queue,
298 struct voip_buf_node, list);
299 list_del(&buf_node->list);
Helen Zengb9d00ce2011-10-13 17:25:50 -0700300 switch (prtd->mode) {
301 case MODE_AMR:
302 case MODE_AMR_WB: {
303 /* Add the DSP frame info header. Header format:
304 * Bits 0-3: Frame rate
305 * Bits 4-7: Frame type
306 */
307 *voc_pkt = ((buf_node->frame.frame_type & 0x0F) << 4) |
308 (prtd->rate_type & 0x0F);
309 voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
310 *pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
311 memcpy(voc_pkt,
312 &buf_node->frame.voc_pkt[0],
313 buf_node->frame.len);
314 list_add_tail(&buf_node->list, &prtd->free_in_queue);
315 break;
316 }
317 default: {
318 *pkt_len = buf_node->frame.len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319
Helen Zengb9d00ce2011-10-13 17:25:50 -0700320 memcpy(voc_pkt,
321 &buf_node->frame.voc_pkt[0],
322 buf_node->frame.len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323
Helen Zengb9d00ce2011-10-13 17:25:50 -0700324 list_add_tail(&buf_node->list, &prtd->free_in_queue);
325 }
326 }
327 pr_debug("dl_pkt: pkt_len=%d, frame_len=%d\n", *pkt_len,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328 buf_node->frame.len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700329 prtd->pcm_playback_irq_pos += prtd->pcm_count;
330 spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
331 snd_pcm_period_elapsed(prtd->playback_substream);
332 } else {
333 *pkt_len = 0;
334 spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
335 pr_err("DL data not available\n");
336 }
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700337 wake_up(&prtd->in_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700338}
339
340static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
341 .count = ARRAY_SIZE(supported_sample_rates),
342 .list = supported_sample_rates,
343 .mask = 0,
344};
345
346static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
347{
348 struct snd_pcm_runtime *runtime = substream->runtime;
349 struct voip_drv_info *prtd = runtime->private_data;
350
351 prtd->play_samp_rate = runtime->rate;
352 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
353 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
354 prtd->pcm_playback_irq_pos = 0;
355 prtd->pcm_playback_buf_pos = 0;
356
357 return 0;
358}
359
360static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
361{
362 struct snd_pcm_runtime *runtime = substream->runtime;
363 struct voip_drv_info *prtd = runtime->private_data;
364 int ret = 0;
365
366 prtd->cap_samp_rate = runtime->rate;
367 prtd->pcm_capture_size = snd_pcm_lib_buffer_bytes(substream);
368 prtd->pcm_capture_count = snd_pcm_lib_period_bytes(substream);
369 prtd->pcm_capture_irq_pos = 0;
370 prtd->pcm_capture_buf_pos = 0;
371 return ret;
372}
373
374static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
375{
376 int ret = 0;
377 struct snd_pcm_runtime *runtime = substream->runtime;
378 struct voip_drv_info *prtd = runtime->private_data;
379
380 switch (cmd) {
381 case SNDRV_PCM_TRIGGER_START:
382 case SNDRV_PCM_TRIGGER_RESUME:
383 pr_debug("%s: Trigger start\n", __func__);
384 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
385 prtd->capture_start = 1;
386 else
387 prtd->playback_start = 1;
388 break;
389 case SNDRV_PCM_TRIGGER_STOP:
390 pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
391 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
392 prtd->playback_start = 0;
393 else
394 prtd->capture_start = 0;
395 break;
396 default:
397 ret = -EINVAL;
398 break;
399 }
400
401 return ret;
402}
403
404static int msm_pcm_open(struct snd_pcm_substream *substream)
405{
406 struct snd_pcm_runtime *runtime = substream->runtime;
407 struct voip_drv_info *prtd = &voip_info;
408 int ret = 0;
409
410 pr_debug("%s, VoIP\n", __func__);
411 mutex_lock(&prtd->lock);
412
413 runtime->hw = msm_pcm_hardware;
414
415 ret = snd_pcm_hw_constraint_list(runtime, 0,
416 SNDRV_PCM_HW_PARAM_RATE,
417 &constraints_sample_rates);
418 if (ret < 0)
419 pr_debug("snd_pcm_hw_constraint_list failed\n");
420
421 ret = snd_pcm_hw_constraint_integer(runtime,
422 SNDRV_PCM_HW_PARAM_PERIODS);
423 if (ret < 0) {
424 pr_debug("snd_pcm_hw_constraint_integer failed\n");
425 goto err;
426 }
427
428 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
429 prtd->playback_substream = substream;
430 prtd->playback_instance++;
431 } else {
432 prtd->capture_substream = substream;
433 prtd->capture_instance++;
434 }
435 runtime->private_data = prtd;
436err:
437 mutex_unlock(&prtd->lock);
438
439 return ret;
440}
441
442static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
443 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
444{
445 int ret = 0;
446 struct voip_buf_node *buf_node = NULL;
447 struct snd_pcm_runtime *runtime = substream->runtime;
448 struct voip_drv_info *prtd = runtime->private_data;
449
450 int count = frames_to_bytes(runtime, frames);
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700451 pr_debug("%s: count = %d, frames=%d\n", __func__, count, (int)frames);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700452
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700453 ret = wait_event_interruptible_timeout(prtd->in_wait,
454 (!list_empty(&prtd->free_in_queue) ||
455 prtd->state == VOIP_STOPPED),
456 1 * HZ);
457 if (ret > 0) {
458 mutex_lock(&prtd->in_lock);
459 if (count <= VOIP_MAX_VOC_PKT_SIZE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 buf_node =
461 list_first_entry(&prtd->free_in_queue,
462 struct voip_buf_node, list);
463 list_del(&buf_node->list);
Helen Zengb9d00ce2011-10-13 17:25:50 -0700464 if (prtd->mode == MODE_PCM) {
465 ret = copy_from_user(&buf_node->frame.voc_pkt,
466 buf, count);
467 buf_node->frame.len = count;
468 } else
469 ret = copy_from_user(&buf_node->frame,
470 buf, count);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471 list_add_tail(&buf_node->list, &prtd->in_queue);
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700472 } else {
473 pr_err("%s: Write cnt %d is > VOIP_MAX_VOC_PKT_SIZE\n",
474 __func__, count);
475 ret = -ENOMEM;
476 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700478 mutex_unlock(&prtd->in_lock);
479 } else if (ret == 0) {
480 pr_err("%s: No free DL buffs\n", __func__);
481 ret = -ETIMEDOUT;
482 } else {
483 pr_err("%s: playback copy was interrupted\n", __func__);
484 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485
486 return ret;
487}
488static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
489 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
490 snd_pcm_uframes_t frames)
491{
492 int ret = 0;
493 int count = 0;
494 struct voip_buf_node *buf_node = NULL;
495 struct snd_pcm_runtime *runtime = substream->runtime;
496 struct voip_drv_info *prtd = runtime->private_data;
497
498 count = frames_to_bytes(runtime, frames);
499
500 pr_debug("%s: count = %d\n", __func__, count);
501
502 ret = wait_event_interruptible_timeout(prtd->out_wait,
503 (!list_empty(&prtd->out_queue) ||
504 prtd->state == VOIP_STOPPED),
505 1 * HZ);
506
507 if (ret > 0) {
508 mutex_lock(&prtd->out_lock);
509
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700510 if (count <= VOIP_MAX_VOC_PKT_SIZE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511 buf_node = list_first_entry(&prtd->out_queue,
512 struct voip_buf_node, list);
513 list_del(&buf_node->list);
Helen Zengb9d00ce2011-10-13 17:25:50 -0700514 if (prtd->mode == MODE_PCM)
515 ret = copy_to_user(buf,
516 &buf_node->frame.voc_pkt,
517 count);
518 else
519 ret = copy_to_user(buf,
520 &buf_node->frame,
521 count);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522 if (ret) {
523 pr_err("%s: Copy to user retuned %d\n",
524 __func__, ret);
525 ret = -EFAULT;
526 }
527 list_add_tail(&buf_node->list,
528 &prtd->free_out_queue);
529 } else {
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700530 pr_err("%s: Read count %d > VOIP_MAX_VOC_PKT_SIZE\n",
531 __func__, count);
532 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700533 }
534
535 mutex_unlock(&prtd->out_lock);
536
537 } else if (ret == 0) {
538 pr_err("%s: No UL data available\n", __func__);
539 ret = -ETIMEDOUT;
540 } else {
541 pr_err("%s: Read was interrupted\n", __func__);
542 ret = -ERESTARTSYS;
543 }
544 return ret;
545}
546static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
547 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
548{
549 int ret = 0;
550
551 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
552 ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
553 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
554 ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
555
556 return ret;
557}
558
559static int msm_pcm_close(struct snd_pcm_substream *substream)
560{
561 int ret = 0;
562 struct list_head *ptr = NULL;
563 struct list_head *next = NULL;
564 struct voip_buf_node *buf_node = NULL;
565 struct snd_dma_buffer *p_dma_buf, *c_dma_buf;
566 struct snd_pcm_substream *p_substream, *c_substream;
567 struct snd_pcm_runtime *runtime;
568 struct voip_drv_info *prtd;
569
570 if (substream == NULL) {
571 pr_err("substream is NULL\n");
572 return -EINVAL;
573 }
574 runtime = substream->runtime;
575 prtd = runtime->private_data;
576
577 wake_up(&prtd->out_wait);
578
579 mutex_lock(&prtd->lock);
580
581 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
582 prtd->playback_instance--;
583 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
584 prtd->capture_instance--;
585
586 if (!prtd->playback_instance && !prtd->capture_instance) {
587 if (prtd->state == VOIP_STARTED) {
588 prtd->state = VOIP_STOPPED;
Neema Shetty2c07eb52011-08-21 20:33:52 -0700589 voc_end_voice_call(
590 voc_get_session_id(VOIP_SESSION_NAME));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700591 voc_register_mvs_cb(NULL, NULL, prtd);
592 }
593 /* release all buffer */
594 /* release in_queue and free_in_queue */
595 pr_debug("release all buffer\n");
596 p_substream = prtd->playback_substream;
597 if (p_substream == NULL) {
598 pr_debug("p_substream is NULL\n");
599 goto capt;
600 }
601 p_dma_buf = &p_substream->dma_buffer;
602 if (p_dma_buf == NULL) {
603 pr_debug("p_dma_buf is NULL\n");
604 goto capt;
605 }
606 if (p_dma_buf->area != NULL) {
607 mutex_lock(&prtd->in_lock);
608 list_for_each_safe(ptr, next, &prtd->in_queue) {
609 buf_node = list_entry(ptr,
610 struct voip_buf_node, list);
611 list_del(&buf_node->list);
612 }
613 list_for_each_safe(ptr, next, &prtd->free_in_queue) {
614 buf_node = list_entry(ptr,
615 struct voip_buf_node, list);
616 list_del(&buf_node->list);
617 }
618 dma_free_coherent(p_substream->pcm->card->dev,
619 runtime->hw.buffer_bytes_max, p_dma_buf->area,
620 p_dma_buf->addr);
621 p_dma_buf->area = NULL;
622 mutex_unlock(&prtd->in_lock);
623 }
624 /* release out_queue and free_out_queue */
625capt: c_substream = prtd->capture_substream;
626 if (c_substream == NULL) {
627 pr_debug("c_substream is NULL\n");
628 goto done;
629 }
630 c_dma_buf = &c_substream->dma_buffer;
631 if (c_substream == NULL) {
632 pr_debug("c_dma_buf is NULL.\n");
633 goto done;
634 }
635 if (c_dma_buf->area != NULL) {
636 mutex_lock(&prtd->out_lock);
637 list_for_each_safe(ptr, next, &prtd->out_queue) {
638 buf_node = list_entry(ptr,
639 struct voip_buf_node, list);
640 list_del(&buf_node->list);
641 }
642 list_for_each_safe(ptr, next, &prtd->free_out_queue) {
643 buf_node = list_entry(ptr,
644 struct voip_buf_node, list);
645 list_del(&buf_node->list);
646 }
647 dma_free_coherent(c_substream->pcm->card->dev,
648 runtime->hw.buffer_bytes_max, c_dma_buf->area,
649 c_dma_buf->addr);
650 c_dma_buf->area = NULL;
651 mutex_unlock(&prtd->out_lock);
652 }
653done:
654 prtd->capture_substream = NULL;
655 prtd->playback_substream = NULL;
656 }
657 mutex_unlock(&prtd->lock);
658
659 return ret;
660}
661static int msm_pcm_prepare(struct snd_pcm_substream *substream)
662{
663 int ret = 0;
664 struct snd_pcm_runtime *runtime = substream->runtime;
665 struct voip_drv_info *prtd = runtime->private_data;
Helen Zengb9d00ce2011-10-13 17:25:50 -0700666 uint32_t media_type = 0;
667 uint32_t rate_type = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700668
669 mutex_lock(&prtd->lock);
670
671 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
672 ret = msm_pcm_playback_prepare(substream);
673 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
674 ret = msm_pcm_capture_prepare(substream);
675
Helen Zengb9d00ce2011-10-13 17:25:50 -0700676 if ((runtime->format != FORMAT_SPECIAL) &&
677 ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB))) {
678 pr_err("mode:%d and format:%u are not mached\n",
679 prtd->mode, (uint32_t)runtime->format);
680 ret = -EINVAL;
681 goto done;
682 }
683
684 if ((runtime->format != FORMAT_S16_LE) &&
685 (prtd->mode == MODE_PCM)) {
686 pr_err("mode:%d and format:%u are not mached\n",
687 prtd->mode, (uint32_t)runtime->format);
688 ret = -EINVAL;
689 goto done;
690 }
691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700692 if (prtd->playback_instance && prtd->capture_instance
693 && (prtd->state != VOIP_STARTED)) {
694
Helen Zengb9d00ce2011-10-13 17:25:50 -0700695 ret = voip_get_rate_type(prtd->mode,
696 prtd->rate,
697 &rate_type);
698 if (ret < 0) {
699 pr_err("fail at getting rate_type\n");
700 ret = -EINVAL;
701 goto done;
702 }
703 prtd->rate_type = rate_type;
704 media_type = voip_get_media_type(prtd->mode,
705 prtd->play_samp_rate);
706 if (media_type < 0) {
707 pr_err("fail at getting media_type\n");
708 ret = -EINVAL;
709 goto done;
710 }
711 pr_debug(" media_type=%d, rate_type=%d\n", media_type,
712 rate_type);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700713 if ((prtd->play_samp_rate == 8000) &&
714 (prtd->cap_samp_rate == 8000))
Helen Zengb9d00ce2011-10-13 17:25:50 -0700715 voc_config_vocoder(media_type, rate_type,
716 VSS_NETWORK_ID_VOIP_NB);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700717 else if ((prtd->play_samp_rate == 16000) &&
718 (prtd->cap_samp_rate == 16000))
Helen Zengb9d00ce2011-10-13 17:25:50 -0700719 voc_config_vocoder(media_type, rate_type,
720 VSS_NETWORK_ID_VOIP_WB);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700721 else {
Neema Shetty2c07eb52011-08-21 20:33:52 -0700722 pr_debug("%s: Invalid rate playback %d, capture %d\n",
723 __func__, prtd->play_samp_rate,
724 prtd->cap_samp_rate);
725 goto done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700726 }
727 voc_register_mvs_cb(voip_process_ul_pkt,
728 voip_process_dl_pkt, prtd);
Neema Shetty2c07eb52011-08-21 20:33:52 -0700729 voc_start_voice_call(voc_get_session_id(VOIP_SESSION_NAME));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700730
731 prtd->state = VOIP_STARTED;
732 }
Neema Shetty2c07eb52011-08-21 20:33:52 -0700733done:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700734 mutex_unlock(&prtd->lock);
735
736 return ret;
737}
738
739static snd_pcm_uframes_t
740msm_pcm_playback_pointer(struct snd_pcm_substream *substream)
741{
742 struct snd_pcm_runtime *runtime = substream->runtime;
743 struct voip_drv_info *prtd = runtime->private_data;
744
745 pr_debug("%s\n", __func__);
746 if (prtd->pcm_playback_irq_pos >= prtd->pcm_size)
747 prtd->pcm_playback_irq_pos = 0;
748 return bytes_to_frames(runtime, (prtd->pcm_playback_irq_pos));
749}
750
751static snd_pcm_uframes_t
752msm_pcm_capture_pointer(struct snd_pcm_substream *substream)
753{
754 struct snd_pcm_runtime *runtime = substream->runtime;
755 struct voip_drv_info *prtd = runtime->private_data;
756
757 if (prtd->pcm_capture_irq_pos >= prtd->pcm_capture_size)
758 prtd->pcm_capture_irq_pos = 0;
759 return bytes_to_frames(runtime, (prtd->pcm_capture_irq_pos));
760}
761
762static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
763{
764 snd_pcm_uframes_t ret = 0;
765 pr_debug("%s\n", __func__);
766 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
767 ret = msm_pcm_playback_pointer(substream);
768 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
769 ret = msm_pcm_capture_pointer(substream);
770 return ret;
771}
772
773static int msm_pcm_mmap(struct snd_pcm_substream *substream,
774 struct vm_area_struct *vma)
775{
776 struct snd_pcm_runtime *runtime = substream->runtime;
777
778 pr_debug("%s\n", __func__);
779 dma_mmap_coherent(substream->pcm->card->dev, vma,
780 runtime->dma_area,
781 runtime->dma_addr,
782 runtime->dma_bytes);
783 return 0;
784}
785
786static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
787 struct snd_pcm_hw_params *params)
788{
789 struct snd_pcm_runtime *runtime = substream->runtime;
790 struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
791 struct voip_buf_node *buf_node = NULL;
792 int i = 0, offset = 0;
793
794 pr_debug("%s: voip\n", __func__);
795
796 mutex_lock(&voip_info.lock);
797
798 dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
799 dma_buf->dev.dev = substream->pcm->card->dev;
800 dma_buf->private_data = NULL;
801
802 dma_buf->area = dma_alloc_coherent(substream->pcm->card->dev,
803 runtime->hw.buffer_bytes_max,
804 &dma_buf->addr, GFP_KERNEL);
805 if (!dma_buf->area) {
806 pr_err("%s:MSM VOIP dma_alloc failed\n", __func__);
807 return -ENOMEM;
808 }
809
810 dma_buf->bytes = runtime->hw.buffer_bytes_max;
811 memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
812
813 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
814 for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
815 buf_node = (void *)dma_buf->area + offset;
816
817 mutex_lock(&voip_info.in_lock);
818 list_add_tail(&buf_node->list,
819 &voip_info.free_in_queue);
820 mutex_unlock(&voip_info.in_lock);
821 offset = offset + sizeof(struct voip_buf_node);
822 }
823 } else {
824 for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
825 buf_node = (void *) dma_buf->area + offset;
826 mutex_lock(&voip_info.out_lock);
827 list_add_tail(&buf_node->list,
828 &voip_info.free_out_queue);
829 mutex_unlock(&voip_info.out_lock);
830 offset = offset + sizeof(struct voip_buf_node);
831 }
832 }
833
834 mutex_unlock(&voip_info.lock);
835
836 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
837
838 return 0;
839}
840
Helen Zengb9d00ce2011-10-13 17:25:50 -0700841static int msm_voip_mode_rate_config_get(struct snd_kcontrol *kcontrol,
842 struct snd_ctl_elem_value *ucontrol)
843{
844 mutex_lock(&voip_info.lock);
845
846 ucontrol->value.integer.value[0] = voip_info.mode;
847 ucontrol->value.integer.value[1] = voip_info.rate;
848
849 mutex_unlock(&voip_info.lock);
850
851 return 0;
852}
853
854static int msm_voip_mode_rate_config_put(struct snd_kcontrol *kcontrol,
855 struct snd_ctl_elem_value *ucontrol)
856{
857 mutex_lock(&voip_info.lock);
858
859 voip_info.mode = ucontrol->value.integer.value[0];
860 voip_info.rate = ucontrol->value.integer.value[1];
861
862 pr_debug("%s: mode=%d,rate=%d\n", __func__, voip_info.mode,
863 voip_info.rate);
864
865 mutex_unlock(&voip_info.lock);
866
867 return 0;
868}
869
870static int voip_get_rate_type(uint32_t mode, uint32_t rate,
871 uint32_t *rate_type)
872{
873 int ret = 0;
874
875 switch (mode) {
876 case MODE_AMR: {
877 switch (rate) {
878 case 4750:
879 *rate_type = AMR_RATE_4750;
880 break;
881 case 5150:
882 *rate_type = AMR_RATE_5150;
883 break;
884 case 5900:
885 *rate_type = AMR_RATE_5900;
886 break;
887 case 6700:
888 *rate_type = AMR_RATE_6700;
889 break;
890 case 7400:
891 *rate_type = AMR_RATE_7400;
892 break;
893 case 7950:
894 *rate_type = AMR_RATE_7950;
895 break;
896 case 10200:
897 *rate_type = AMR_RATE_10200;
898 break;
899 case 12200:
900 *rate_type = AMR_RATE_12200;
901 break;
902 default:
903 pr_err("wrong rate for AMR NB.\n");
904 ret = -EINVAL;
905 break;
906 }
907 break;
908 }
909 case MODE_AMR_WB: {
910 switch (rate) {
911 case 6600:
912 *rate_type = AMR_RATE_6600 - AMR_RATE_6600;
913 break;
914 case 8850:
915 *rate_type = AMR_RATE_8850 - AMR_RATE_6600;
916 break;
917 case 12650:
918 *rate_type = AMR_RATE_12650 - AMR_RATE_6600;
919 break;
920 case 14250:
921 *rate_type = AMR_RATE_14250 - AMR_RATE_6600;
922 break;
923 case 15850:
924 *rate_type = AMR_RATE_15850 - AMR_RATE_6600;
925 break;
926 case 18250:
927 *rate_type = AMR_RATE_18250 - AMR_RATE_6600;
928 break;
929 case 19850:
930 *rate_type = AMR_RATE_19850 - AMR_RATE_6600;
931 break;
932 case 23050:
933 *rate_type = AMR_RATE_23050 - AMR_RATE_6600;
934 break;
935 case 23850:
936 *rate_type = AMR_RATE_23850 - AMR_RATE_6600;
937 break;
938 default:
939 pr_err("wrong rate for AMR_WB.\n");
940 ret = -EINVAL;
941 break;
942 }
943 break;
944 }
945 case MODE_PCM: {
946 *rate_type = 0;
947 break;
948 }
949 default:
950 pr_err("wrong mode type.\n");
951 ret = -EINVAL;
952 }
953 pr_debug("%s, mode=%d, rate=%u, rate_type=%d\n",
954 __func__, mode, rate, *rate_type);
955 return ret;
956}
957
958static int voip_get_media_type(uint32_t mode,
959 unsigned int samp_rate)
960{
961 uint32_t media_type;
962
963 pr_debug("%s: mode=%d, samp_rate=%d\n", __func__,
964 mode, samp_rate);
965 switch (mode) {
966 case MODE_AMR:
967 media_type = VSS_MEDIA_ID_AMR_NB_MODEM;
968 break;
969 case MODE_AMR_WB:
970 media_type = VSS_MEDIA_ID_AMR_WB_MODEM;
971 break;
972 case MODE_PCM:
973 if (samp_rate == 8000)
974 media_type = VSS_MEDIA_ID_PCM_NB;
975 else
976 media_type = VSS_MEDIA_ID_PCM_WB;
977 break;
978 default:
979 pr_debug(" input mode is not supported\n");
980 media_type = -EINVAL;
981 }
982
983 pr_debug("%s: media_type is 0x%x\n", __func__, media_type);
984
985 return media_type;
986}
987
988
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989static struct snd_pcm_ops msm_pcm_ops = {
990 .open = msm_pcm_open,
991 .copy = msm_pcm_copy,
992 .hw_params = msm_pcm_hw_params,
993 .close = msm_pcm_close,
994 .prepare = msm_pcm_prepare,
995 .trigger = msm_pcm_trigger,
996 .pointer = msm_pcm_pointer,
997 .mmap = msm_pcm_mmap,
998};
999
1000static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
1001{
1002 struct snd_card *card = rtd->card->snd_card;
1003 int ret = 0;
1004
1005 pr_debug("msm_asoc_pcm_new\n");
1006 if (!card->dev->coherent_dma_mask)
1007 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
1008 return ret;
1009}
1010
1011static struct snd_soc_platform_driver msm_soc_platform = {
1012 .ops = &msm_pcm_ops,
1013 .pcm_new = msm_asoc_pcm_new,
Panneer Arumugambcac6862011-10-27 18:20:44 -07001014 .probe = msm_pcm_voip_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001015};
1016
1017static __devinit int msm_pcm_probe(struct platform_device *pdev)
1018{
1019 pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
1020 return snd_soc_register_platform(&pdev->dev,
1021 &msm_soc_platform);
1022}
1023
1024static int msm_pcm_remove(struct platform_device *pdev)
1025{
1026 snd_soc_unregister_platform(&pdev->dev);
1027 return 0;
1028}
1029
1030static struct platform_driver msm_pcm_driver = {
1031 .driver = {
1032 .name = "msm-voip-dsp",
1033 .owner = THIS_MODULE,
1034 },
1035 .probe = msm_pcm_probe,
1036 .remove = __devexit_p(msm_pcm_remove),
1037};
1038
1039static int __init msm_soc_platform_init(void)
1040{
1041 memset(&voip_info, 0, sizeof(voip_info));
Helen Zengb9d00ce2011-10-13 17:25:50 -07001042 voip_info.mode = MODE_PCM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001043 mutex_init(&voip_info.lock);
1044 mutex_init(&voip_info.in_lock);
1045 mutex_init(&voip_info.out_lock);
1046
1047 spin_lock_init(&voip_info.dsp_lock);
1048
1049 init_waitqueue_head(&voip_info.out_wait);
Panneer Arumugam418aa0a2011-10-11 18:44:16 -07001050 init_waitqueue_head(&voip_info.in_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051
1052 INIT_LIST_HEAD(&voip_info.in_queue);
1053 INIT_LIST_HEAD(&voip_info.free_in_queue);
1054 INIT_LIST_HEAD(&voip_info.out_queue);
1055 INIT_LIST_HEAD(&voip_info.free_out_queue);
1056
1057 return platform_driver_register(&msm_pcm_driver);
1058}
1059module_init(msm_soc_platform_init);
1060
1061static void __exit msm_soc_platform_exit(void)
1062{
1063 platform_driver_unregister(&msm_pcm_driver);
1064}
1065module_exit(msm_soc_platform_exit);
1066
1067MODULE_DESCRIPTION("PCM module platform driver");
1068MODULE_LICENSE("GPL v2");