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