blob: fd771df5d3d4b0372582549302b53126b9e7ecb1 [file] [log] [blame]
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301/* Copyright (c) 2013-2017, The Linux Foundation. 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>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053028#include <dsp/msm_audio_ion.h>
29#include <dsp/q6voice.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053030
31#define HPCM_MAX_Q_LEN 2
32#define HPCM_MIN_VOC_PKT_SIZE 320
33#define HPCM_MAX_VOC_PKT_SIZE 640
34#define VHPCM_BLOCK_SIZE 4096
35#define CACHE_ALIGNMENT_SIZE 128
36#define CACHE_ALIGNMENT_MASK 0xFFFFFF80
37
38#define VOICE_TX_CAPTURE_DAI_ID "CS-VOICE HOST TX CAPTURE"
39#define VOICE_TX_PLAYBACK_DAI_ID "CS-VOICE HOST TX PLAYBACK"
40#define VOICE_RX_CAPTURE_DAI_ID "CS-VOICE HOST RX CAPTURE"
41#define VOICE_RX_PLAYBACK_DAI_ID "CS-VOICE HOST RX PLAYBACK"
42
43#define VOLTE_TX_CAPTURE_DAI_ID "VOLTE HOST TX CAPTURE"
44#define VOLTE_TX_PLAYBACK_DAI_ID "VOLTE HOST TX PLAYBACK"
45#define VOLTE_RX_CAPTURE_DAI_ID "VOLTE HOST RX CAPTURE"
46#define VOLTE_RX_PLAYBACK_DAI_ID "VOLTE HOST RX PLAYBACK"
47
48
49#define VoMMode1_TX_CAPTURE_DAI_ID "VoiceMMode1 HOST TX CAPTURE"
50#define VoMMode1_TX_PLAYBACK_DAI_ID "VoiceMMode1 HOST TX PLAYBACK"
51#define VoMMode1_RX_CAPTURE_DAI_ID "VoiceMMode1 HOST RX CAPTURE"
52#define VoMMode1_RX_PLAYBACK_DAI_ID "VoiceMMode1 HOST RX PLAYBACK"
53
54#define VoMMode2_TX_CAPTURE_DAI_ID "VoiceMMode2 HOST TX CAPTURE"
55#define VoMMode2_TX_PLAYBACK_DAI_ID "VoiceMMode2 HOST TX PLAYBACK"
56#define VoMMode2_RX_CAPTURE_DAI_ID "VoiceMMode2 HOST RX CAPTURE"
57#define VoMMode2_RX_PLAYBACK_DAI_ID "VoiceMMode2 HOST RX PLAYBACK"
58
59enum {
60 RX = 1,
61 TX,
62};
63
64enum {
65 VOICE_INDEX = 0,
66 VOLTE_INDEX,
67 VOMMODE1_INDEX,
68 VOMMODE2_INDEX,
69 MAX_SESSION
70};
71
72enum hpcm_state {
73 HPCM_STOPPED = 1,
74 HPCM_CLOSED,
75 HPCM_PREPARED,
76 HPCM_STARTED,
77};
78
79struct hpcm_frame {
80 uint32_t len;
81 uint8_t voc_pkt[HPCM_MAX_VOC_PKT_SIZE];
82};
83
84struct hpcm_buf_node {
85 struct list_head list;
86 struct hpcm_frame frame;
87};
88
89struct vocpcm_ion_buffer {
90 /* Physical address */
91 phys_addr_t paddr;
92 /* Kernel virtual address */
93 void *kvaddr;
94};
95
96struct dai_data {
97 enum hpcm_state state;
98 struct snd_pcm_substream *substream;
99 struct list_head filled_queue;
100 struct list_head free_queue;
101 wait_queue_head_t queue_wait;
102 spinlock_t dsp_lock;
103 uint32_t pcm_size;
104 uint32_t pcm_count;
105 /* IRQ position */
106 uint32_t pcm_irq_pos;
107 /* Position in buffer */
108 uint32_t pcm_buf_pos;
109 struct vocpcm_ion_buffer vocpcm_ion_buffer;
110};
111
112struct tap_point {
113 struct dai_data playback_dai_data;
114 struct dai_data capture_dai_data;
115};
116
117struct session {
118 struct tap_point tx_tap_point;
119 struct tap_point rx_tap_point;
120 phys_addr_t sess_paddr;
121 void *sess_kvaddr;
122 struct ion_handle *ion_handle;
123 struct mem_map_table tp_mem_table;
124};
125
126struct tappnt_mxr_data {
127 bool enable;
128 uint16_t direction;
129 uint16_t sample_rate;
130};
131
132/* Values from mixer ctl are cached in this structure */
133struct mixer_conf {
134 int8_t sess_indx;
135 struct tappnt_mxr_data rx;
136 struct tappnt_mxr_data tx;
137};
138
139struct start_cmd {
140 struct vss_ivpcm_tap_point tap_pnt[2];
141 uint32_t no_of_tapoints;
142};
143
144struct hpcm_drv {
145 struct mutex lock;
146 struct session session[MAX_SESSION];
147 struct mixer_conf mixer_conf;
148 struct ion_client *ion_client;
149 struct start_cmd start_cmd;
150};
151
152static struct hpcm_drv hpcm_drv;
153
154static struct snd_pcm_hardware msm_pcm_hardware = {
155 .info = (SNDRV_PCM_INFO_MMAP |
156 SNDRV_PCM_INFO_BLOCK_TRANSFER |
157 SNDRV_PCM_INFO_MMAP_VALID |
158 SNDRV_PCM_INFO_INTERLEAVED),
159 .formats = SNDRV_PCM_FMTBIT_S16_LE |
160 SNDRV_PCM_FMTBIT_SPECIAL,
161 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
162 .rate_min = 8000,
163 .rate_max = 16000,
164 .channels_min = 1,
165 .channels_max = 1,
166 .buffer_bytes_max = sizeof(struct hpcm_buf_node) * HPCM_MAX_Q_LEN,
167 .period_bytes_min = HPCM_MIN_VOC_PKT_SIZE,
168 .period_bytes_max = HPCM_MAX_VOC_PKT_SIZE,
169 .periods_min = HPCM_MAX_Q_LEN,
170 .periods_max = HPCM_MAX_Q_LEN,
171 .fifo_size = 0,
172};
173
174static char *hpcm_get_sess_name(int sess_indx)
175{
176 char *sess_name = NULL;
177
178 if (sess_indx == VOICE_INDEX)
179 sess_name = VOICE_SESSION_NAME;
180 else if (sess_indx == VOLTE_INDEX)
181 sess_name = VOLTE_SESSION_NAME;
182 else if (sess_indx == VOMMODE1_INDEX)
183 sess_name = VOICEMMODE1_NAME;
184 else if (sess_indx == VOMMODE2_INDEX)
185 sess_name = VOICEMMODE2_NAME;
186 else
187 pr_err("%s:, Invalid sess_index\n", __func__);
188
189 return sess_name;
190}
191
192static void hpcm_reset_mixer_config(struct hpcm_drv *prtd)
193{
194 prtd->mixer_conf.sess_indx = -1;
195 prtd->mixer_conf.rx.enable = false;
196 prtd->mixer_conf.rx.direction = -1;
197 prtd->mixer_conf.rx.sample_rate = 0;
198
199 prtd->mixer_conf.tx.enable = false;
200 prtd->mixer_conf.tx.direction = -1;
201 prtd->mixer_conf.tx.sample_rate = 0;
202}
203
204/* Check for valid mixer control values */
205static bool hpcm_is_valid_config(int sess_indx, int tap_point,
206 uint16_t direction, uint16_t samplerate)
207{
208 if (sess_indx < VOICE_INDEX || sess_indx > VOMMODE2_INDEX) {
209 pr_err("%s: invalid sess_indx :%d\n", __func__, sess_indx);
210 goto error;
211 }
212
213 if (samplerate != VSS_IVPCM_SAMPLING_RATE_8K &&
214 samplerate != VSS_IVPCM_SAMPLING_RATE_16K) {
215 pr_err("%s: invalid sample rate :%d\n", __func__, samplerate);
216 goto error;
217 }
218
219 if ((tap_point != RX) && (tap_point != TX)) {
220 pr_err("%s: invalid tappoint :%d\n", __func__, tap_point);
221 goto error;
222 }
223
224 if ((direction != VSS_IVPCM_TAP_POINT_DIR_IN) &&
225 (direction != VSS_IVPCM_TAP_POINT_DIR_OUT) &&
226 (direction != VSS_IVPCM_TAP_POINT_DIR_OUT_IN)) {
227 pr_err("%s: invalid direction :%d\n", __func__, direction);
228 goto error;
229 }
230
231 return true;
232
233error:
234 return false;
235}
236
237
238static struct dai_data *hpcm_get_dai_data(char *pcm_id, struct hpcm_drv *prtd)
239{
240 struct dai_data *dai_data = NULL;
241 size_t size = 0;
242
243 if (pcm_id) {
244 size = strlen(pcm_id);
245 /* Check for Voice DAI */
246 if (strnstr(pcm_id, VOICE_TX_CAPTURE_DAI_ID, size)) {
247 dai_data =
248 &prtd->session[VOICE_INDEX].tx_tap_point.capture_dai_data;
249 } else if (strnstr(pcm_id, VOICE_TX_PLAYBACK_DAI_ID, size)) {
250 dai_data =
251 &prtd->session[VOICE_INDEX].tx_tap_point.playback_dai_data;
252 } else if (strnstr(pcm_id, VOICE_RX_CAPTURE_DAI_ID, size)) {
253 dai_data =
254 &prtd->session[VOICE_INDEX].rx_tap_point.capture_dai_data;
255 } else if (strnstr(pcm_id, VOICE_RX_PLAYBACK_DAI_ID, size)) {
256 dai_data =
257 &prtd->session[VOICE_INDEX].rx_tap_point.playback_dai_data;
258 /* Check for VoLTE DAI */
259 } else if (strnstr(pcm_id, VOLTE_TX_CAPTURE_DAI_ID, size)) {
260 dai_data =
261 &prtd->session[VOLTE_INDEX].tx_tap_point.capture_dai_data;
262 } else if (strnstr(pcm_id, VOLTE_TX_PLAYBACK_DAI_ID, size)) {
263 dai_data =
264 &prtd->session[VOLTE_INDEX].tx_tap_point.playback_dai_data;
265 } else if (strnstr(pcm_id, VOLTE_RX_CAPTURE_DAI_ID, size)) {
266 dai_data =
267 &prtd->session[VOLTE_INDEX].rx_tap_point.capture_dai_data;
268 } else if (strnstr(pcm_id, VOLTE_RX_PLAYBACK_DAI_ID, size)) {
269 dai_data =
270 &prtd->session[VOLTE_INDEX].rx_tap_point.playback_dai_data;
271 /* check for VoiceMMode1 DAI */
272 } else if (strnstr(pcm_id, VoMMode1_TX_CAPTURE_DAI_ID, size)) {
273 dai_data =
274 &prtd->session[VOMMODE1_INDEX].tx_tap_point.capture_dai_data;
275 } else if (strnstr(pcm_id, VoMMode1_TX_PLAYBACK_DAI_ID, size)) {
276 dai_data =
277 &prtd->session[VOMMODE1_INDEX].tx_tap_point.playback_dai_data;
278 } else if (strnstr(pcm_id, VoMMode1_RX_CAPTURE_DAI_ID, size)) {
279 dai_data =
280 &prtd->session[VOMMODE1_INDEX].rx_tap_point.capture_dai_data;
281 } else if (strnstr(pcm_id, VoMMode1_RX_PLAYBACK_DAI_ID, size)) {
282 dai_data =
283 &prtd->session[VOMMODE1_INDEX].rx_tap_point.playback_dai_data;
284 /* check for VOiceMMode2 DAI */
285 } else if (strnstr(pcm_id, VoMMode2_TX_CAPTURE_DAI_ID, size)) {
286 dai_data =
287 &prtd->session[VOMMODE2_INDEX].tx_tap_point.capture_dai_data;
288 } else if (strnstr(pcm_id, VoMMode2_TX_PLAYBACK_DAI_ID, size)) {
289 dai_data =
290 &prtd->session[VOMMODE2_INDEX].tx_tap_point.playback_dai_data;
291 } else if (strnstr(pcm_id, VoMMode2_RX_CAPTURE_DAI_ID, size)) {
292 dai_data =
293 &prtd->session[VOMMODE2_INDEX].rx_tap_point.capture_dai_data;
294 } else if (strnstr(pcm_id, VoMMode2_RX_PLAYBACK_DAI_ID, size)) {
295 dai_data =
296 &prtd->session[VOMMODE2_INDEX].rx_tap_point.playback_dai_data;
297
298 } else {
299 pr_err("%s: Wrong dai id\n", __func__);
300 }
301 }
302
303 return dai_data;
304}
305
306static struct tap_point *hpcm_get_tappoint_data(char *pcm_id,
307 struct hpcm_drv *prtd)
308{
309 struct tap_point *tp = NULL;
310 size_t size = 0;
311
312 if (pcm_id) {
313 size = strlen(pcm_id);
314 /* Check for Voice DAI */
315 if (strnstr(pcm_id, VOICE_TX_CAPTURE_DAI_ID, size)) {
316 tp = &prtd->session[VOICE_INDEX].tx_tap_point;
317 } else if (strnstr(pcm_id, VOICE_TX_PLAYBACK_DAI_ID, size)) {
318 tp = &prtd->session[VOICE_INDEX].tx_tap_point;
319 } else if (strnstr(pcm_id, VOICE_RX_CAPTURE_DAI_ID, size)) {
320 tp = &prtd->session[VOICE_INDEX].rx_tap_point;
321 } else if (strnstr(pcm_id, VOICE_RX_PLAYBACK_DAI_ID, size)) {
322 tp = &prtd->session[VOICE_INDEX].rx_tap_point;
323 /* Check for VoLTE DAI */
324 } else if (strnstr(pcm_id, VOLTE_TX_CAPTURE_DAI_ID, size)) {
325 tp = &prtd->session[VOLTE_INDEX].tx_tap_point;
326 } else if (strnstr(pcm_id, VOLTE_TX_PLAYBACK_DAI_ID, size)) {
327 tp = &prtd->session[VOLTE_INDEX].tx_tap_point;
328 } else if (strnstr(pcm_id, VOLTE_RX_CAPTURE_DAI_ID, size)) {
329 tp = &prtd->session[VOLTE_INDEX].rx_tap_point;
330 } else if (strnstr(pcm_id, VOLTE_RX_PLAYBACK_DAI_ID, size)) {
331 tp = &prtd->session[VOLTE_INDEX].rx_tap_point;
332 /* check for VoiceMMode1 */
333 } else if (strnstr(pcm_id, VoMMode1_TX_CAPTURE_DAI_ID, size)) {
334 tp = &prtd->session[VOMMODE1_INDEX].tx_tap_point;
335 } else if (strnstr(pcm_id, VoMMode1_TX_PLAYBACK_DAI_ID, size)) {
336 tp = &prtd->session[VOMMODE1_INDEX].tx_tap_point;
337 } else if (strnstr(pcm_id, VoMMode1_RX_CAPTURE_DAI_ID, size)) {
338 tp = &prtd->session[VOMMODE1_INDEX].rx_tap_point;
339 } else if (strnstr(pcm_id, VoMMode1_RX_PLAYBACK_DAI_ID, size)) {
340 tp = &prtd->session[VOMMODE1_INDEX].rx_tap_point;
341 /* check for VoiceMMode2 */
342 } else if (strnstr(pcm_id, VoMMode2_TX_CAPTURE_DAI_ID, size)) {
343 tp = &prtd->session[VOMMODE2_INDEX].tx_tap_point;
344 } else if (strnstr(pcm_id, VoMMode2_TX_PLAYBACK_DAI_ID, size)) {
345 tp = &prtd->session[VOMMODE2_INDEX].tx_tap_point;
346 } else if (strnstr(pcm_id, VoMMode2_RX_CAPTURE_DAI_ID, size)) {
347 tp = &prtd->session[VOMMODE2_INDEX].rx_tap_point;
348 } else if (strnstr(pcm_id, VoMMode2_RX_PLAYBACK_DAI_ID, size)) {
349 tp = &prtd->session[VOMMODE2_INDEX].rx_tap_point;
350 } else {
351 pr_err("%s: wrong dai id\n", __func__);
352 }
353 }
354
355 return tp;
356}
357
358static struct tappnt_mxr_data *hpcm_get_tappnt_mixer_data(char *pcm_id,
359 struct hpcm_drv *prtd)
360{
361
362 if (strnstr(pcm_id, VOICE_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
363 strnstr(pcm_id, VOICE_TX_PLAYBACK_DAI_ID, strlen(pcm_id)) ||
364 strnstr(pcm_id, VOLTE_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
365 strnstr(pcm_id, VOLTE_TX_PLAYBACK_DAI_ID, strlen(pcm_id)) ||
366 strnstr(pcm_id, VoMMode1_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
367 strnstr(pcm_id, VoMMode1_TX_PLAYBACK_DAI_ID, strlen(pcm_id)) ||
368 strnstr(pcm_id, VoMMode2_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
369 strnstr(pcm_id, VoMMode2_TX_PLAYBACK_DAI_ID, strlen(pcm_id))) {
370 return &prtd->mixer_conf.tx;
371 } else {
372 return &prtd->mixer_conf.rx;
373 }
374}
375
376static int get_tappnt_value(char *pcm_id)
377{
378
379 if (strnstr(pcm_id, VOICE_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
380 strnstr(pcm_id, VOICE_TX_PLAYBACK_DAI_ID, strlen(pcm_id)) ||
381 strnstr(pcm_id, VOLTE_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
382 strnstr(pcm_id, VOLTE_TX_PLAYBACK_DAI_ID, strlen(pcm_id)) ||
383 strnstr(pcm_id, VoMMode1_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
384 strnstr(pcm_id, VoMMode1_TX_PLAYBACK_DAI_ID, strlen(pcm_id)) ||
385 strnstr(pcm_id, VoMMode2_TX_CAPTURE_DAI_ID, strlen(pcm_id)) ||
386 strnstr(pcm_id, VoMMode2_TX_PLAYBACK_DAI_ID, strlen(pcm_id))) {
387 return TX;
388 } else {
389 return RX;
390 }
391}
392
393static bool hpcm_all_dais_are_ready(uint16_t direction, struct tap_point *tp,
394 enum hpcm_state state)
395{
396 bool dais_started = false;
397
398 /*
399 * Based on the direction set per tap point in the mixer control,
400 * all the dais per tap point should meet the required state for the
401 * commands such as vpcm_map_memory/vpcm_start to be executed.
402 */
403 switch (direction) {
404 case VSS_IVPCM_TAP_POINT_DIR_OUT_IN:
405 if ((tp->playback_dai_data.state >= state) &&
406 (tp->capture_dai_data.state >= state)) {
407 dais_started = true;
408 }
409 break;
410
411 case VSS_IVPCM_TAP_POINT_DIR_IN:
412 if (tp->playback_dai_data.state >= state)
413 dais_started = true;
414 break;
415
416 case VSS_IVPCM_TAP_POINT_DIR_OUT:
417 if (tp->capture_dai_data.state >= state)
418 dais_started = true;
419 break;
420
421 default:
422 pr_err("invalid direction\n");
423 }
424
425 return dais_started;
426}
427
428static void hpcm_create_free_queue(struct snd_dma_buffer *dma_buf,
429 struct dai_data *dai_data)
430{
431 struct hpcm_buf_node *buf_node = NULL;
432 int i = 0, offset = 0;
433
434 for (i = 0; i < HPCM_MAX_Q_LEN; i++) {
435 buf_node = (void *)dma_buf->area + offset;
436 list_add_tail(&buf_node->list,
437 &dai_data->free_queue);
438 offset = offset + sizeof(struct hpcm_buf_node);
439 }
440}
441
442static void hpcm_free_allocated_mem(struct hpcm_drv *prtd)
443{
444 phys_addr_t paddr = 0;
445 struct tap_point *txtp = NULL;
446 struct tap_point *rxtp = NULL;
447 struct session *sess = NULL;
448
449 sess = &prtd->session[prtd->mixer_conf.sess_indx];
450 txtp = &sess->tx_tap_point;
451 rxtp = &sess->rx_tap_point;
452 paddr = sess->sess_paddr;
453
454 if (paddr) {
455 msm_audio_ion_free(prtd->ion_client, sess->ion_handle);
456 prtd->ion_client = NULL;
457 sess->ion_handle = NULL;
458 msm_audio_ion_free(sess->tp_mem_table.client,
459 sess->tp_mem_table.handle);
460 sess->tp_mem_table.client = NULL;
461 sess->tp_mem_table.handle = NULL;
462 sess->sess_paddr = 0;
463 sess->sess_kvaddr = 0;
464 sess->ion_handle = 0;
465 prtd->ion_client = 0;
466 sess->tp_mem_table.client = 0;
467 sess->tp_mem_table.handle = 0;
468
469 txtp->capture_dai_data.vocpcm_ion_buffer.paddr = 0;
470 txtp->capture_dai_data.vocpcm_ion_buffer.kvaddr = 0;
471
472 txtp->playback_dai_data.vocpcm_ion_buffer.paddr = 0;
473 txtp->playback_dai_data.vocpcm_ion_buffer.kvaddr = 0;
474
475 rxtp->capture_dai_data.vocpcm_ion_buffer.paddr = 0;
476 rxtp->capture_dai_data.vocpcm_ion_buffer.kvaddr = 0;
477
478 rxtp->playback_dai_data.vocpcm_ion_buffer.paddr = 0;
479 rxtp->playback_dai_data.vocpcm_ion_buffer.kvaddr = 0;
480 } else {
481 pr_debug("%s, paddr = 0, nothing to free\n", __func__);
482 }
483}
484
485static void hpcm_unmap_and_free_shared_memory(struct hpcm_drv *prtd)
486
487{
488 phys_addr_t paddr = 0;
489 char *sess_name = hpcm_get_sess_name(prtd->mixer_conf.sess_indx);
490
491 if (prtd->mixer_conf.sess_indx >= 0)
492 paddr = prtd->session[prtd->mixer_conf.sess_indx].sess_paddr;
493 else
494 paddr = 0;
495
496 if (paddr) {
497 voc_send_cvp_unmap_vocpcm_memory(voc_get_session_id(sess_name));
498 hpcm_free_allocated_mem(prtd);
499 } else {
500 pr_debug("%s, paddr = 0, nothing to unmap/free\n", __func__);
501 }
502}
503
504static int hpcm_map_vocpcm_memory(struct hpcm_drv *prtd)
505{
506 int ret = 0;
507 char *sess_name = hpcm_get_sess_name(prtd->mixer_conf.sess_indx);
508 struct session *sess = NULL;
509
510 sess = &prtd->session[prtd->mixer_conf.sess_indx];
511
512 ret = voc_send_cvp_map_vocpcm_memory(voc_get_session_id(sess_name),
513 &sess->tp_mem_table,
514 sess->sess_paddr,
515 VHPCM_BLOCK_SIZE);
516
517 return ret;
518}
519
520static int hpcm_allocate_shared_memory(struct hpcm_drv *prtd)
521{
522 int result;
523 int ret = 0;
524 size_t mem_len;
525 size_t len;
526 struct tap_point *txtp = NULL;
527 struct tap_point *rxtp = NULL;
528 struct session *sess = NULL;
529
530 sess = &prtd->session[prtd->mixer_conf.sess_indx];
531 txtp = &sess->tx_tap_point;
532 rxtp = &sess->rx_tap_point;
533
534 result = msm_audio_ion_alloc("host_pcm_buffer",
535 &prtd->ion_client,
536 &sess->ion_handle,
537 VHPCM_BLOCK_SIZE,
538 &sess->sess_paddr,
539 &mem_len,
540 &sess->sess_kvaddr);
541 if (result) {
542 pr_err("%s: msm_audio_ion_alloc error, rc = %d\n",
543 __func__, result);
544 sess->sess_paddr = 0;
545 sess->sess_kvaddr = 0;
546 ret = -ENOMEM;
547 goto done;
548 }
549 pr_debug("%s: Host PCM memory block allocated\n", __func__);
550
551 /* Allocate mem_map_table for tap point */
552 result = msm_audio_ion_alloc("host_pcm_table",
553 &sess->tp_mem_table.client,
554 &sess->tp_mem_table.handle,
555 sizeof(struct vss_imemory_table_t),
556 &sess->tp_mem_table.phys,
557 &len,
558 &sess->tp_mem_table.data);
559
560 if (result) {
561 pr_err("%s: msm_audio_ion_alloc error, rc = %d\n",
562 __func__, result);
563 msm_audio_ion_free(prtd->ion_client, sess->ion_handle);
564 prtd->ion_client = NULL;
565 sess->ion_handle = NULL;
566 sess->sess_paddr = 0;
567 sess->sess_kvaddr = 0;
568 ret = -ENOMEM;
569 goto done;
570 }
571 pr_debug("%s: Host PCM memory table allocated\n", __func__);
572
573 memset(sess->tp_mem_table.data, 0,
574 sizeof(struct vss_imemory_table_t));
575
576 sess->tp_mem_table.size = sizeof(struct vss_imemory_table_t);
577
578 pr_debug("%s: data %pK phys %pK\n", __func__,
579 sess->tp_mem_table.data, &sess->tp_mem_table.phys);
580
581 /* Split 4096 block into four 1024 byte blocks for each dai */
582 txtp->capture_dai_data.vocpcm_ion_buffer.paddr =
583 sess->sess_paddr;
584 txtp->capture_dai_data.vocpcm_ion_buffer.kvaddr =
585 sess->sess_kvaddr;
586
587 txtp->playback_dai_data.vocpcm_ion_buffer.paddr =
588 sess->sess_paddr + VHPCM_BLOCK_SIZE/4;
589 txtp->playback_dai_data.vocpcm_ion_buffer.kvaddr =
590 sess->sess_kvaddr + VHPCM_BLOCK_SIZE/4;
591
592 rxtp->capture_dai_data.vocpcm_ion_buffer.paddr =
593 sess->sess_paddr + (VHPCM_BLOCK_SIZE/4) * 2;
594 rxtp->capture_dai_data.vocpcm_ion_buffer.kvaddr =
595 sess->sess_kvaddr + (VHPCM_BLOCK_SIZE/4) * 2;
596
597 rxtp->playback_dai_data.vocpcm_ion_buffer.paddr =
598 sess->sess_paddr + (VHPCM_BLOCK_SIZE/4) * 3;
599 rxtp->playback_dai_data.vocpcm_ion_buffer.kvaddr =
600 sess->sess_kvaddr + (VHPCM_BLOCK_SIZE/4) * 3;
601
602done:
603 return ret;
604}
605
606static int hpcm_start_vocpcm(char *pcm_id, struct hpcm_drv *prtd,
607 struct tap_point *tp)
608{
609 int indx = prtd->mixer_conf.sess_indx;
610 uint32_t *no_of_tp = &prtd->start_cmd.no_of_tapoints;
611 struct vss_ivpcm_tap_point *tap_pnt = &prtd->start_cmd.tap_pnt[0];
612 uint32_t no_of_tp_req = 0;
613 char *sess_name = hpcm_get_sess_name(indx);
614
615 if (prtd->mixer_conf.rx.enable)
616 no_of_tp_req++;
617 if (prtd->mixer_conf.tx.enable)
618 no_of_tp_req++;
619
620 if (prtd->mixer_conf.rx.enable && (get_tappnt_value(pcm_id) == RX)) {
621 if (hpcm_all_dais_are_ready(prtd->mixer_conf.rx.direction,
622 tp, HPCM_PREPARED)) {
623 pr_debug("%s: RX conditions met\n", __func__);
624 tap_pnt[*no_of_tp].tap_point =
625 VSS_IVPCM_TAP_POINT_RX_DEFAULT;
626 tap_pnt[*no_of_tp].direction =
627 prtd->mixer_conf.rx.direction;
628 tap_pnt[*no_of_tp].sampling_rate =
629 prtd->mixer_conf.rx.sample_rate;
630 (*no_of_tp)++;
631 }
632 }
633
634 if (prtd->mixer_conf.tx.enable && (get_tappnt_value(pcm_id) == TX)) {
635 if (hpcm_all_dais_are_ready(prtd->mixer_conf.tx.direction,
636 tp, HPCM_PREPARED)) {
637 pr_debug("%s: TX conditions met\n", __func__);
638 tap_pnt[*no_of_tp].tap_point =
639 VSS_IVPCM_TAP_POINT_TX_DEFAULT;
640 tap_pnt[*no_of_tp].direction =
641 prtd->mixer_conf.tx.direction;
642 tap_pnt[*no_of_tp].sampling_rate =
643 prtd->mixer_conf.tx.sample_rate;
644 (*no_of_tp)++;
645 }
646 }
647
648 if ((prtd->mixer_conf.tx.enable || prtd->mixer_conf.rx.enable) &&
649 *no_of_tp == no_of_tp_req) {
650 voc_send_cvp_start_vocpcm(voc_get_session_id(sess_name),
651 tap_pnt, *no_of_tp);
652 /* Reset the start command so that it is not called twice */
653 memset(&prtd->start_cmd, 0, sizeof(struct start_cmd));
654 } else {
655 pr_debug("%s: required pcm handles not opened yet\n", __func__);
656 }
657
658 return 0;
659}
660
661/* Playback path*/
662static void hpcm_copy_playback_data_from_queue(struct dai_data *dai_data,
663 uint32_t *len)
664{
665 struct hpcm_buf_node *buf_node = NULL;
666 unsigned long dsp_flags;
667
668 if (dai_data->substream == NULL)
669 return;
670
671 spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
672
673 if (!list_empty(&dai_data->filled_queue)) {
674 buf_node = list_first_entry(&dai_data->filled_queue,
675 struct hpcm_buf_node, list);
676 list_del(&buf_node->list);
677 *len = buf_node->frame.len;
678 memcpy((u8 *)dai_data->vocpcm_ion_buffer.kvaddr,
679 &buf_node->frame.voc_pkt[0],
680 buf_node->frame.len);
681
682 list_add_tail(&buf_node->list, &dai_data->free_queue);
683 dai_data->pcm_irq_pos += dai_data->pcm_count;
684 spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
685 snd_pcm_period_elapsed(dai_data->substream);
686 } else {
687 *len = 0;
688 spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
689 pr_err("IN data not available\n");
690 }
691
692 wake_up(&dai_data->queue_wait);
693}
694
695/* Capture path*/
696static void hpcm_copy_capture_data_to_queue(struct dai_data *dai_data,
697 uint32_t len)
698{
699 struct hpcm_buf_node *buf_node = NULL;
700 unsigned long dsp_flags;
701
702 if (dai_data->substream == NULL)
703 return;
704
705 /* Copy out buffer packet into free_queue */
706 spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
707
708 if (!list_empty(&dai_data->free_queue)) {
709 buf_node = list_first_entry(&dai_data->free_queue,
710 struct hpcm_buf_node, list);
711 list_del(&buf_node->list);
712 buf_node->frame.len = len;
713 memcpy(&buf_node->frame.voc_pkt[0],
714 (uint8_t *)dai_data->vocpcm_ion_buffer.kvaddr,
715 buf_node->frame.len);
716 list_add_tail(&buf_node->list, &dai_data->filled_queue);
717 dai_data->pcm_irq_pos += dai_data->pcm_count;
718 spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
719 snd_pcm_period_elapsed(dai_data->substream);
720 } else {
721 spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
722 pr_err("OUTPUT data dropped\n");
723 }
724
725 wake_up(&dai_data->queue_wait);
726}
727
728void hpcm_notify_evt_processing(uint8_t *data, char *session,
729 void *private_data)
730{
731 struct hpcm_drv *prtd = (struct hpcm_drv *)private_data;
732 struct vss_ivpcm_evt_notify_v2_t *notify_evt =
733 (struct vss_ivpcm_evt_notify_v2_t *)data;
734 struct vss_ivpcm_evt_push_buffer_v2_t push_buff_event;
735 struct tap_point *tp = NULL;
736 int in_buf_len = 0;
737 struct tappnt_mxr_data *tmd = NULL;
738 char *sess_name = hpcm_get_sess_name(prtd->mixer_conf.sess_indx);
739
740 /* If it's not a timetick, it's a error notification, drop the event */
741 if ((notify_evt->notify_mask & VSS_IVPCM_NOTIFY_MASK_TIMETICK) == 0) {
742 pr_err("%s: Error notification. mask=%d\n", __func__,
743 notify_evt->notify_mask);
744 return;
745 }
746
747 if (notify_evt->tap_point == VSS_IVPCM_TAP_POINT_TX_DEFAULT) {
748 tp = &prtd->session[prtd->mixer_conf.sess_indx].tx_tap_point;
749 tmd = &prtd->mixer_conf.tx;
750 } else if (notify_evt->tap_point == VSS_IVPCM_TAP_POINT_RX_DEFAULT) {
751 tp = &prtd->session[prtd->mixer_conf.sess_indx].rx_tap_point;
752 tmd = &prtd->mixer_conf.rx;
753 }
754
755 if (tp == NULL || tmd == NULL) {
756 pr_err("%s: tp = %pK or tmd = %pK is null\n", __func__,
757 tp, tmd);
758
759 return;
760 }
761
762 if (notify_evt->notify_mask & VSS_IVPCM_NOTIFY_MASK_OUTPUT_BUFFER) {
763 hpcm_copy_capture_data_to_queue(&tp->capture_dai_data,
764 notify_evt->filled_out_size);
765 }
766
767 if (notify_evt->notify_mask & VSS_IVPCM_NOTIFY_MASK_INPUT_BUFFER) {
768 hpcm_copy_playback_data_from_queue(&tp->playback_dai_data,
769 &in_buf_len);
770 }
771
772 switch (tmd->direction) {
773 /*
774 * When the dir is OUT_IN, for the first notify mask, pushbuf mask
775 * should be set to VSS_IVPCM_PUSH_BUFFER_MASK_OUTPUT_BUFFER since we
776 * atleast need one buffer's worth data before we can send IN buffer.
777 * For the consecutive notify evts, the push buf mask will set for both
778 * VSS_IVPCM_PUSH_BUFFER_MASK_OUTPUT_BUFFER and
779 * VSS_IVPCM_PUSH_BUFFER_MASK_IN_BUFFER.
780 */
781 case VSS_IVPCM_TAP_POINT_DIR_OUT_IN:
782 if (notify_evt->notify_mask ==
783 VSS_IVPCM_NOTIFY_MASK_TIMETICK) {
784 push_buff_event.push_buf_mask =
785 VSS_IVPCM_PUSH_BUFFER_MASK_OUTPUT_BUFFER;
786 } else {
787 push_buff_event.push_buf_mask =
788 VSS_IVPCM_PUSH_BUFFER_MASK_OUTPUT_BUFFER |
789 VSS_IVPCM_PUSH_BUFFER_MASK_INPUT_BUFFER;
790 }
791 break;
792
793 case VSS_IVPCM_TAP_POINT_DIR_IN:
794 push_buff_event.push_buf_mask =
795 VSS_IVPCM_PUSH_BUFFER_MASK_INPUT_BUFFER;
796 break;
797
798 case VSS_IVPCM_TAP_POINT_DIR_OUT:
799 push_buff_event.push_buf_mask =
800 VSS_IVPCM_PUSH_BUFFER_MASK_OUTPUT_BUFFER;
801 break;
802 }
803
804 push_buff_event.tap_point = notify_evt->tap_point;
805 push_buff_event.out_buf_mem_address =
806 tp->capture_dai_data.vocpcm_ion_buffer.paddr;
807 push_buff_event.in_buf_mem_address =
808 tp->playback_dai_data.vocpcm_ion_buffer.paddr;
809 push_buff_event.sampling_rate = notify_evt->sampling_rate;
810 push_buff_event.num_in_channels = 1;
811
812 /*
813 * ADSP must read and write from a cache aligned (128 byte) location,
814 * and in blocks of the cache alignment size. The 128 byte cache
815 * alignment requirement is guaranteed due to 4096 byte memory
816 * alignment requirement during memory allocation/mapping. The output
817 * buffer (ADSP write) size mask ensures that a 128 byte multiple
818 * worth of will be written. Internally, the input buffer (ADSP read)
819 * size will also be a multiple of 128 bytes. However it is the
820 * application's responsibility to ensure no other data is written in
821 * the specified length of memory.
822 */
823 push_buff_event.out_buf_mem_size = ((notify_evt->request_buf_size) +
824 CACHE_ALIGNMENT_SIZE) & CACHE_ALIGNMENT_MASK;
825 push_buff_event.in_buf_mem_size = in_buf_len;
826
827 voc_send_cvp_vocpcm_push_buf_evt(voc_get_session_id(sess_name),
828 &push_buff_event);
829}
830
831static int msm_hpcm_configure_voice_put(struct snd_kcontrol *kcontrol,
832 struct snd_ctl_elem_value *ucontrol)
833{
834
835 int tap_point = ucontrol->value.integer.value[0];
836 uint16_t direction = ucontrol->value.integer.value[1];
837 uint16_t sample_rate = ucontrol->value.integer.value[2];
838 struct tappnt_mxr_data *tmd = NULL;
839 int ret = 0;
840
841 mutex_lock(&hpcm_drv.lock);
842 pr_debug("%s: tap_point = %d direction = %d sample_rate = %d\n",
843 __func__, tap_point, direction, sample_rate);
844
845 if (!hpcm_is_valid_config(VOICE_INDEX, tap_point, direction,
846 sample_rate)) {
847 pr_err("Invalid vpcm mixer control voice values\n");
848 ret = -EINVAL;
849 goto done;
850 }
851
852 if (tap_point == RX)
853 tmd = &hpcm_drv.mixer_conf.rx;
854 else
855 tmd = &hpcm_drv.mixer_conf.tx;
856
857 tmd->enable = true;
858 tmd->direction = direction;
859 tmd->sample_rate = sample_rate;
860 hpcm_drv.mixer_conf.sess_indx = VOICE_INDEX;
861
862done:
863 mutex_unlock(&hpcm_drv.lock);
864 return ret;
865}
866
867static int msm_hpcm_configure_vmmode1_put(struct snd_kcontrol *kcontrol,
868 struct snd_ctl_elem_value *ucontrol)
869{
870
871 int tap_point = ucontrol->value.integer.value[0];
872 uint16_t direction = ucontrol->value.integer.value[1];
873 uint16_t sample_rate = ucontrol->value.integer.value[2];
874 struct tappnt_mxr_data *tmd = NULL;
875 int ret = 0;
876
877 mutex_lock(&hpcm_drv.lock);
878 pr_debug("%s: tap_point = %d direction = %d sample_rate = %d\n",
879 __func__, tap_point, direction, sample_rate);
880
881 if (!hpcm_is_valid_config(VOMMODE1_INDEX, tap_point, direction,
882 sample_rate)) {
883 pr_err("Invalid vpcm mixer control voice values\n");
884 ret = -EINVAL;
885 goto done;
886 }
887
888 if (tap_point == RX)
889 tmd = &hpcm_drv.mixer_conf.rx;
890 else
891 tmd = &hpcm_drv.mixer_conf.tx;
892
893 tmd->enable = true;
894 tmd->direction = direction;
895 tmd->sample_rate = sample_rate;
896 hpcm_drv.mixer_conf.sess_indx = VOMMODE1_INDEX;
897
898done:
899 mutex_unlock(&hpcm_drv.lock);
900 return ret;
901}
902
903static int msm_hpcm_configure_vmmode2_put(struct snd_kcontrol *kcontrol,
904 struct snd_ctl_elem_value *ucontrol)
905{
906
907 int tap_point = ucontrol->value.integer.value[0];
908 uint16_t direction = ucontrol->value.integer.value[1];
909 uint16_t sample_rate = ucontrol->value.integer.value[2];
910 struct tappnt_mxr_data *tmd = NULL;
911 int ret = 0;
912
913 mutex_lock(&hpcm_drv.lock);
914 pr_debug("%s: tap_point = %d direction = %d sample_rate = %d\n",
915 __func__, tap_point, direction, sample_rate);
916
917 if (!hpcm_is_valid_config(VOMMODE2_INDEX, tap_point, direction,
918 sample_rate)) {
919 pr_err("Invalid vpcm mixer control voice values\n");
920 ret = -EINVAL;
921 goto done;
922 }
923
924 if (tap_point == RX)
925 tmd = &hpcm_drv.mixer_conf.rx;
926 else
927 tmd = &hpcm_drv.mixer_conf.tx;
928
929 tmd->enable = true;
930 tmd->direction = direction;
931 tmd->sample_rate = sample_rate;
932 hpcm_drv.mixer_conf.sess_indx = VOMMODE2_INDEX;
933
934done:
935 mutex_unlock(&hpcm_drv.lock);
936 return ret;
937}
938
939static int msm_hpcm_configure_volte_put(struct snd_kcontrol *kcontrol,
940 struct snd_ctl_elem_value *ucontrol)
941{
942
943 int tap_point = ucontrol->value.integer.value[0];
944 uint16_t direction = ucontrol->value.integer.value[1];
945 uint16_t sample_rate = ucontrol->value.integer.value[2];
946 struct tappnt_mxr_data *tmd = NULL;
947 int ret = 0;
948
949 mutex_lock(&hpcm_drv.lock);
950 pr_debug("%s: tap_point=%d direction=%d sample_rate=%d\n",
951 __func__, tap_point, direction, sample_rate);
952
953 if (!hpcm_is_valid_config(VOLTE_INDEX, tap_point, direction,
954 sample_rate)) {
955 pr_err("Invalid vpcm mixer control volte values\n");
956 ret = -EINVAL;
957 goto done;
958 }
959
960 if (tap_point == RX)
961 tmd = &hpcm_drv.mixer_conf.rx;
962 else
963 tmd = &hpcm_drv.mixer_conf.tx;
964
965 tmd->enable = true;
966 tmd->direction = direction;
967 tmd->sample_rate = sample_rate;
968 hpcm_drv.mixer_conf.sess_indx = VOLTE_INDEX;
969
970done:
971 mutex_unlock(&hpcm_drv.lock);
972 return ret;
973
974}
975
976static struct snd_kcontrol_new msm_hpcm_controls[] = {
977 SOC_SINGLE_MULTI_EXT("HPCM_Voice tappoint direction samplerate",
978 SND_SOC_NOPM, 0, 16000, 0, 3,
979 NULL, msm_hpcm_configure_voice_put),
980 SOC_SINGLE_MULTI_EXT("HPCM_VoLTE tappoint direction samplerate",
981 SND_SOC_NOPM, 0, 16000, 0, 3,
982 NULL, msm_hpcm_configure_volte_put),
983 SOC_SINGLE_MULTI_EXT("HPCM_VMMode1 tappoint direction samplerate",
984 SND_SOC_NOPM, 0, 16000, 0, 3,
985 NULL, msm_hpcm_configure_vmmode1_put),
986 SOC_SINGLE_MULTI_EXT("HPCM_VMMode2 tappoint direction samplerate",
987 SND_SOC_NOPM, 0, 16000, 0, 3,
988 NULL, msm_hpcm_configure_vmmode2_put),
989};
990
991/* Sample rates supported */
992static unsigned int supported_sample_rates[] = {8000, 16000};
993
994static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
995 .count = ARRAY_SIZE(supported_sample_rates),
996 .list = supported_sample_rates,
997 .mask = 0,
998};
999
1000static int msm_pcm_close(struct snd_pcm_substream *substream)
1001{
1002 int ret = 0;
1003 struct list_head *ptr = NULL;
1004 struct list_head *next = NULL;
1005 struct hpcm_buf_node *buf_node = NULL;
1006 struct snd_dma_buffer *dma_buf;
1007 struct snd_pcm_runtime *runtime;
1008 struct hpcm_drv *prtd;
1009 unsigned long dsp_flags;
1010 struct dai_data *dai_data = NULL;
1011 struct tap_point *tp = NULL;
1012 struct tappnt_mxr_data *tmd = NULL;
1013 char *sess_name = NULL;
1014
1015 if (substream == NULL) {
1016 pr_err("substream is NULL\n");
1017 return -EINVAL;
1018 }
1019
1020 pr_debug("%s, %s\n", __func__, substream->pcm->id);
1021 runtime = substream->runtime;
1022 prtd = runtime->private_data;
1023 sess_name = hpcm_get_sess_name(prtd->mixer_conf.sess_indx);
1024 dai_data = hpcm_get_dai_data(substream->pcm->id, prtd);
1025
1026 if (dai_data == NULL) {
1027 pr_err("%s, dai_data is NULL\n", __func__);
1028
1029 ret = -EINVAL;
1030 goto done;
1031 }
1032
1033 wake_up(&dai_data->queue_wait);
1034 mutex_lock(&prtd->lock);
1035
1036 tmd = hpcm_get_tappnt_mixer_data(substream->pcm->id, prtd);
1037
1038 tp = hpcm_get_tappoint_data(substream->pcm->id, prtd);
1039 /* Send stop command */
1040 voc_send_cvp_stop_vocpcm(voc_get_session_id(sess_name));
1041 /* Memory unmap/free takes place only when called the first time */
1042 hpcm_unmap_and_free_shared_memory(prtd);
1043 /* Unregister host PCM event callback function */
1044 voc_deregister_hpcm_evt_cb();
1045 /* Reset the cached start cmd */
1046 memset(&prtd->start_cmd, 0, sizeof(struct start_cmd));
1047 /* Release all buffer */
1048 pr_debug("%s: Release all buffer\n", __func__);
1049 substream = dai_data->substream;
1050 if (substream == NULL) {
1051 pr_debug("%s: substream is NULL\n", __func__);
1052 goto done;
1053 }
1054 dma_buf = &substream->dma_buffer;
1055 if (dma_buf == NULL) {
1056 pr_debug("%s: dma_buf is NULL\n", __func__);
1057 goto done;
1058 }
1059 if (dma_buf->area != NULL) {
1060 spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
1061 list_for_each_safe(ptr, next, &dai_data->filled_queue) {
1062 buf_node = list_entry(ptr,
1063 struct hpcm_buf_node, list);
1064 list_del(&buf_node->list);
1065 }
1066 list_for_each_safe(ptr, next, &dai_data->free_queue) {
1067 buf_node = list_entry(ptr,
1068 struct hpcm_buf_node, list);
1069 list_del(&buf_node->list);
1070 }
1071 spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
1072 dma_free_coherent(substream->pcm->card->dev,
1073 runtime->hw.buffer_bytes_max, dma_buf->area,
1074 dma_buf->addr);
1075 dma_buf->area = NULL;
1076 }
1077 dai_data->substream = NULL;
1078 dai_data->pcm_buf_pos = 0;
1079 dai_data->pcm_count = 0;
1080 dai_data->pcm_irq_pos = 0;
1081 dai_data->pcm_size = 0;
1082 dai_data->state = HPCM_CLOSED;
1083 hpcm_reset_mixer_config(prtd);
1084
1085done:
1086 mutex_unlock(&prtd->lock);
1087 return ret;
1088}
1089
1090static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
1091 snd_pcm_uframes_t hwoff, void __user *buf,
1092 snd_pcm_uframes_t frames)
1093{
1094 int ret = 0;
1095 struct hpcm_buf_node *buf_node = NULL;
1096 struct snd_pcm_runtime *runtime = substream->runtime;
1097 struct hpcm_drv *prtd = runtime->private_data;
1098 struct dai_data *dai_data = hpcm_get_dai_data(substream->pcm->id, prtd);
1099 unsigned long dsp_flags;
1100
1101 int count = frames_to_bytes(runtime, frames);
1102
1103 if (dai_data == NULL) {
1104 pr_err("%s, dai_data is null\n", __func__);
1105
1106 ret = -EINVAL;
1107 goto done;
1108 }
1109
1110 ret = wait_event_interruptible_timeout(dai_data->queue_wait,
1111 (!list_empty(&dai_data->free_queue) ||
1112 dai_data->state == HPCM_STOPPED),
1113 1 * HZ);
1114 if (ret > 0) {
1115 if (count <= HPCM_MAX_VOC_PKT_SIZE) {
1116 spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
1117 buf_node =
1118 list_first_entry(&dai_data->free_queue,
1119 struct hpcm_buf_node, list);
1120 list_del(&buf_node->list);
1121 spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
1122 ret = copy_from_user(&buf_node->frame.voc_pkt, buf,
1123 count);
1124 buf_node->frame.len = count;
1125 spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
1126 list_add_tail(&buf_node->list, &dai_data->filled_queue);
1127 spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
1128 } else {
1129 pr_err("%s: Write cnt %d is > HPCM_MAX_VOC_PKT_SIZE\n",
1130 __func__, count);
1131 ret = -ENOMEM;
1132 }
1133 } else if (ret == 0) {
1134 pr_err("%s: No free Playback buffer\n", __func__);
1135 ret = -ETIMEDOUT;
1136 } else {
1137 pr_err("%s: playback copy was interrupted\n", __func__);
1138 }
1139
1140done:
1141 return ret;
1142}
1143
1144static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
1145 int channel, snd_pcm_uframes_t hwoff,
1146 void __user *buf, snd_pcm_uframes_t frames)
1147{
1148 int ret = 0;
1149 int count = 0;
1150 struct hpcm_buf_node *buf_node = NULL;
1151 struct snd_pcm_runtime *runtime = substream->runtime;
1152 struct hpcm_drv *prtd = runtime->private_data;
1153 struct dai_data *dai_data = hpcm_get_dai_data(substream->pcm->id, prtd);
1154 unsigned long dsp_flags;
1155
1156 if (dai_data == NULL) {
1157 pr_err("%s, dai_data is null\n", __func__);
1158
1159 ret = -EINVAL;
1160 goto done;
1161 }
1162
1163 count = frames_to_bytes(runtime, frames);
1164
1165 ret = wait_event_interruptible_timeout(dai_data->queue_wait,
1166 (!list_empty(&dai_data->filled_queue) ||
1167 dai_data->state == HPCM_STOPPED),
1168 1 * HZ);
1169
1170 if (ret > 0) {
1171 if (count <= HPCM_MAX_VOC_PKT_SIZE) {
1172 spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
1173 buf_node = list_first_entry(&dai_data->filled_queue,
1174 struct hpcm_buf_node, list);
1175 list_del(&buf_node->list);
1176 spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
1177 ret = copy_to_user(buf, &buf_node->frame.voc_pkt,
1178 buf_node->frame.len);
1179 if (ret) {
1180 pr_err("%s: Copy to user returned %d\n",
1181 __func__, ret);
1182 ret = -EFAULT;
1183 }
1184 spin_lock_irqsave(&dai_data->dsp_lock, dsp_flags);
1185 list_add_tail(&buf_node->list, &dai_data->free_queue);
1186 spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
1187
1188 } else {
1189 pr_err("%s: Read count %d > HPCM_MAX_VOC_PKT_SIZE\n",
1190 __func__, count);
1191 ret = -ENOMEM;
1192 }
1193
1194 } else if (ret == 0) {
1195 pr_err("%s: No Caputre data available\n", __func__);
1196 ret = -ETIMEDOUT;
1197 } else {
1198 pr_err("%s: Read was interrupted\n", __func__);
1199 ret = -ERESTARTSYS;
1200 }
1201
1202done:
1203 return ret;
1204}
1205
1206static int msm_pcm_copy(struct snd_pcm_substream *substream, int channel,
1207 snd_pcm_uframes_t hwoff, void __user *buf,
1208 snd_pcm_uframes_t frames)
1209{
1210 int ret = 0;
1211
1212 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1213 ret = msm_pcm_playback_copy(substream, channel,
1214 hwoff, buf, frames);
1215 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1216 ret = msm_pcm_capture_copy(substream, channel,
1217 hwoff, buf, frames);
1218
1219 return ret;
1220}
1221
1222static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
1223{
1224 struct dai_data *dai_data = NULL;
1225 struct snd_pcm_runtime *runtime = substream->runtime;
1226 struct hpcm_drv *prtd = runtime->private_data;
1227 snd_pcm_uframes_t ret;
1228
1229 dai_data = hpcm_get_dai_data(substream->pcm->id, prtd);
1230
1231 if (dai_data == NULL) {
1232 pr_err("%s, dai_data is null\n", __func__);
1233
1234 ret = 0;
1235 goto done;
1236 }
1237
1238 if (dai_data->pcm_irq_pos >= dai_data->pcm_size)
1239 dai_data->pcm_irq_pos = 0;
1240
1241 ret = bytes_to_frames(runtime, (dai_data->pcm_irq_pos));
1242
1243done:
1244 return ret;
1245}
1246
1247static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1248{
1249 int ret = 0;
1250 struct snd_pcm_runtime *runtime = substream->runtime;
1251 struct hpcm_drv *prtd = runtime->private_data;
1252 struct dai_data *dai_data =
1253 hpcm_get_dai_data(substream->pcm->id, prtd);
1254
1255 if (dai_data == NULL) {
1256 pr_err("%s, dai_data is null\n", __func__);
1257
1258 ret = -EINVAL;
1259 goto done;
1260 }
1261
1262 pr_debug("%s, %s\n", __func__, substream->pcm->id);
1263
1264 switch (cmd) {
1265 case SNDRV_PCM_TRIGGER_START:
1266 pr_debug("SNDRV_PCM_TRIGGER_START\n");
1267 dai_data->state = HPCM_STARTED;
1268 break;
1269
1270 case SNDRV_PCM_TRIGGER_STOP:
1271 pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
1272 dai_data->state = HPCM_STOPPED;
1273 break;
1274
1275 default:
1276 ret = -EINVAL;
1277 break;
1278 }
1279
1280done:
1281 return ret;
1282}
1283
1284static int msm_pcm_prepare(struct snd_pcm_substream *substream)
1285{
1286 int ret = 0;
1287 struct snd_pcm_runtime *runtime = substream->runtime;
1288 struct hpcm_drv *prtd = runtime->private_data;
1289 struct dai_data *dai_data = NULL;
1290 struct tap_point *tp = NULL;
1291
1292 pr_debug("%s, %s\n", __func__, substream->pcm->id);
1293 mutex_lock(&prtd->lock);
1294
1295 dai_data = hpcm_get_dai_data(substream->pcm->id, prtd);
1296
1297 if (dai_data == NULL) {
1298 pr_err("%s, dai_data is null\n", __func__);
1299
1300 ret = -EINVAL;
1301 goto done;
1302 }
1303
1304 dai_data->pcm_size = snd_pcm_lib_buffer_bytes(substream);
1305 dai_data->pcm_count = snd_pcm_lib_period_bytes(substream);
1306 dai_data->pcm_irq_pos = 0;
1307 dai_data->pcm_buf_pos = 0;
1308 dai_data->state = HPCM_PREPARED;
1309
1310 /* Register event notify processing callback in prepare instead of
1311 * init() as q6voice module's init() can be called at a later point
1312 */
1313 voc_register_hpcm_evt_cb(hpcm_notify_evt_processing, &hpcm_drv);
1314
1315 tp = hpcm_get_tappoint_data(substream->pcm->id, prtd);
1316 if (tp != NULL) {
1317 ret = hpcm_start_vocpcm(substream->pcm->id, prtd, tp);
1318 if (ret) {
1319 pr_err("error sending start cmd err=%d\n", ret);
1320 goto done;
1321 }
1322 } else {
1323 pr_err("%s tp is NULL\n", __func__);
1324 }
1325done:
1326 mutex_unlock(&prtd->lock);
1327 return ret;
1328}
1329
1330static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
1331 struct snd_pcm_hw_params *params)
1332{
1333 struct snd_pcm_runtime *runtime = substream->runtime;
1334 struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
1335 struct hpcm_drv *prtd = (struct hpcm_drv *)runtime->private_data;
1336 int ret = 0;
1337
1338 pr_debug("%s: %s\n", __func__, substream->pcm->id);
1339 mutex_lock(&prtd->lock);
1340
1341 /* Allocate and map voice host PCM ion buffer */
1342 if (prtd->session[prtd->mixer_conf.sess_indx].sess_paddr == 0) {
1343 ret = hpcm_allocate_shared_memory(prtd);
1344 if (ret) {
1345 pr_err("error creating shared memory err=%d\n", ret);
1346 goto done;
1347 }
1348
1349 ret = hpcm_map_vocpcm_memory(prtd);
1350 if (ret) {
1351 pr_err("error mapping shared memory err=%d\n", ret);
1352 hpcm_free_allocated_mem(prtd);
1353 goto done;
1354 }
1355 } else {
1356 pr_debug("%s, VHPCM memory allocation/mapping not performed\n"
1357 , __func__);
1358 }
1359
1360 dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
1361 dma_buf->dev.dev = substream->pcm->card->dev;
1362 dma_buf->private_data = NULL;
1363
1364 dma_buf->area = dma_alloc_coherent(substream->pcm->card->dev,
1365 runtime->hw.buffer_bytes_max,
1366 &dma_buf->addr, GFP_KERNEL);
1367
1368 if (!dma_buf->area) {
1369 pr_err("%s:MSM dma_alloc failed\n", __func__);
1370 ret = -ENOMEM;
1371 goto done;
1372 }
1373
1374 dma_buf->bytes = runtime->hw.buffer_bytes_max;
1375 memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
1376
1377 hpcm_create_free_queue(dma_buf,
1378 hpcm_get_dai_data(substream->pcm->id, prtd));
1379
1380 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
1381
1382done:
1383 mutex_unlock(&prtd->lock);
1384 return ret;
1385}
1386
1387static int msm_pcm_open(struct snd_pcm_substream *substream)
1388{
1389 struct snd_pcm_runtime *runtime = substream->runtime;
1390 struct hpcm_drv *prtd = &hpcm_drv;
1391 struct tappnt_mxr_data *tmd = NULL;
1392 struct dai_data *dai_data = NULL;
1393 int ret = 0;
1394 int tp_val = 0;
1395
1396 pr_debug("%s, %s\n", __func__, substream->pcm->id);
1397 mutex_lock(&prtd->lock);
1398
1399 dai_data = hpcm_get_dai_data(substream->pcm->id, prtd);
1400
1401 if (dai_data == NULL) {
1402 pr_err("%s, dai_data is null\n", __func__);
1403
1404 ret = -EINVAL;
1405 goto done;
1406 }
1407
1408 runtime->hw = msm_pcm_hardware;
1409
1410 ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
1411 &constraints_sample_rates);
1412 if (ret < 0)
1413 pr_debug("snd_pcm_hw_constraint_list failed\n");
1414
1415 ret = snd_pcm_hw_constraint_integer(runtime,
1416 SNDRV_PCM_HW_PARAM_PERIODS);
1417 if (ret < 0) {
1418 pr_debug("snd_pcm_hw_constraint_integer failed\n");
1419 goto done;
1420 }
1421
1422 tp_val = get_tappnt_value(substream->pcm->id);
1423 tmd = hpcm_get_tappnt_mixer_data(substream->pcm->id, prtd);
1424
1425 /* Check wheather the kcontrol values set are valid */
1426 if (!tmd ||
1427 !(tmd->enable) ||
1428 !hpcm_is_valid_config(prtd->mixer_conf.sess_indx,
1429 tp_val, tmd->direction,
1430 tmd->sample_rate)) {
1431 ret = -EINVAL;
1432 goto done;
1433 }
1434
1435 dai_data->substream = substream;
1436 runtime->private_data = prtd;
1437
1438done:
1439 mutex_unlock(&prtd->lock);
1440 return ret;
1441}
1442
1443static const struct snd_pcm_ops msm_pcm_ops = {
1444 .open = msm_pcm_open,
1445 .hw_params = msm_pcm_hw_params,
1446 .prepare = msm_pcm_prepare,
1447 .trigger = msm_pcm_trigger,
1448 .pointer = msm_pcm_pointer,
1449 .copy = msm_pcm_copy,
1450 .close = msm_pcm_close,
1451};
1452
1453static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
1454{
1455 struct snd_card *card = rtd->card->snd_card;
1456
1457 pr_debug("%s:\n", __func__);
1458 if (!card->dev->coherent_dma_mask)
1459 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
1460
1461 return 0;
1462}
1463
1464static int msm_pcm_hpcm_probe(struct snd_soc_platform *platform)
1465{
1466 snd_soc_add_platform_controls(platform, msm_hpcm_controls,
1467 ARRAY_SIZE(msm_hpcm_controls));
1468
1469 return 0;
1470}
1471
1472static struct snd_soc_platform_driver msm_soc_platform = {
1473 .ops = &msm_pcm_ops,
1474 .pcm_new = msm_asoc_pcm_new,
1475 .probe = msm_pcm_hpcm_probe,
1476};
1477
1478static int msm_pcm_probe(struct platform_device *pdev)
1479{
1480
1481 pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
1482 return snd_soc_register_platform(&pdev->dev, &msm_soc_platform);
1483}
1484
1485static int msm_pcm_remove(struct platform_device *pdev)
1486{
1487 snd_soc_unregister_platform(&pdev->dev);
1488 return 0;
1489}
1490
1491static const struct of_device_id msm_voice_host_pcm_dt_match[] = {
1492 {.compatible = "qcom,msm-voice-host-pcm"},
1493 {}
1494};
1495MODULE_DEVICE_TABLE(of, msm_voice_host_pcm_dt_match);
1496
1497static struct platform_driver msm_pcm_driver = {
1498 .driver = {
1499 .name = "msm-voice-host-pcm",
1500 .owner = THIS_MODULE,
1501 .of_match_table = msm_voice_host_pcm_dt_match,
1502 },
1503 .probe = msm_pcm_probe,
1504 .remove = msm_pcm_remove,
1505};
1506
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301507int __init msm_voice_host_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301508{
1509 int i = 0;
1510 struct session *s = NULL;
1511
1512 memset(&hpcm_drv, 0, sizeof(hpcm_drv));
1513 mutex_init(&hpcm_drv.lock);
1514
1515 for (i = 0; i < MAX_SESSION; i++) {
1516 s = &hpcm_drv.session[i];
1517 spin_lock_init(&s->rx_tap_point.capture_dai_data.dsp_lock);
1518 spin_lock_init(&s->rx_tap_point.playback_dai_data.dsp_lock);
1519 spin_lock_init(&s->tx_tap_point.capture_dai_data.dsp_lock);
1520 spin_lock_init(&s->tx_tap_point.playback_dai_data.dsp_lock);
1521
1522 init_waitqueue_head(
1523 &s->rx_tap_point.capture_dai_data.queue_wait);
1524 init_waitqueue_head(
1525 &s->rx_tap_point.playback_dai_data.queue_wait);
1526 init_waitqueue_head(
1527 &s->tx_tap_point.capture_dai_data.queue_wait);
1528 init_waitqueue_head(
1529 &s->tx_tap_point.playback_dai_data.queue_wait);
1530
1531 INIT_LIST_HEAD(&s->rx_tap_point.capture_dai_data.filled_queue);
1532 INIT_LIST_HEAD(&s->rx_tap_point.capture_dai_data.free_queue);
1533 INIT_LIST_HEAD(&s->rx_tap_point.playback_dai_data.filled_queue);
1534 INIT_LIST_HEAD(&s->rx_tap_point.playback_dai_data.free_queue);
1535
1536 INIT_LIST_HEAD(&s->tx_tap_point.capture_dai_data.filled_queue);
1537 INIT_LIST_HEAD(&s->tx_tap_point.capture_dai_data.free_queue);
1538 INIT_LIST_HEAD(&s->tx_tap_point.playback_dai_data.filled_queue);
1539 INIT_LIST_HEAD(&s->tx_tap_point.playback_dai_data.free_queue);
1540 }
1541
1542 return platform_driver_register(&msm_pcm_driver);
1543}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301544
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05301545void msm_voice_host_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301546{
1547 platform_driver_unregister(&msm_pcm_driver);
1548}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301549
1550MODULE_DESCRIPTION("PCM module platform driver");
1551MODULE_LICENSE("GPL v2");