OSDN Git Service

Merge "input: touchscreen: Fix uninitialized variable usage in Atmel driver"
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / sound / soc / msm / qdsp6v2 / msm-transcode-loopback-q6-v2.c
1 /* Copyright (c) 2017-2018, 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/moduleparam.h>
17 #include <linux/time.h>
18 #include <linux/math64.h>
19 #include <linux/wait.h>
20 #include <linux/platform_device.h>
21 #include <linux/slab.h>
22 #include <linux/msm_audio_ion.h>
23 #include <sound/core.h>
24 #include <sound/soc.h>
25 #include <sound/soc-dapm.h>
26 #include <sound/pcm.h>
27 #include <sound/initval.h>
28 #include <sound/control.h>
29 #include <sound/q6asm-v2.h>
30 #include <sound/q6core.h>
31 #include <sound/q6audio-v2.h>
32 #include <sound/pcm_params.h>
33 #include <sound/timer.h>
34 #include <sound/tlv.h>
35 #include <sound/apr_audio-v2.h>
36 #include <sound/compress_params.h>
37 #include <sound/compress_offload.h>
38 #include <sound/compress_driver.h>
39 #include <linux/msm_audio.h>
40
41 #include "msm-pcm-routing-v2.h"
42 #include "msm-qti-pp-config.h"
43
44 #define LOOPBACK_SESSION_MAX_NUM_STREAMS 2
45 /* Max volume corresponding to 24dB */
46 #define TRANSCODE_LR_VOL_MAX_STEPS 0xFFFF
47
48 #define APP_TYPE_CONFIG_IDX_APP_TYPE 0
49 #define APP_TYPE_CONFIG_IDX_ACDB_ID 1
50 #define APP_TYPE_CONFIG_IDX_SAMPLE_RATE 2
51 #define APP_TYPE_CONFIG_IDX_BE_ID 3
52
53 static DEFINE_MUTEX(transcode_loopback_session_lock);
54
55 struct trans_loopback_pdata {
56         struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX];
57         int32_t ion_fd[MSM_FRONTEND_DAI_MAX];
58         uint32_t master_gain;
59         int perf_mode;
60 };
61
62 struct loopback_stream {
63         struct snd_compr_stream *cstream;
64         uint32_t codec_format;
65         bool start;
66 };
67
68 enum loopback_session_state {
69         /* One or both streams not opened */
70         LOOPBACK_SESSION_CLOSE = 0,
71         /* Loopback streams opened */
72         LOOPBACK_SESSION_READY,
73         /* Loopback streams opened and formats configured */
74         LOOPBACK_SESSION_START,
75         /* Trigger issued on either of streams when in START state */
76         LOOPBACK_SESSION_RUN
77 };
78
79 struct msm_transcode_loopback {
80         struct loopback_stream source;
81         struct loopback_stream sink;
82
83         struct snd_compr_caps source_compr_cap;
84         struct snd_compr_caps sink_compr_cap;
85
86         uint32_t instance;
87         uint32_t num_streams;
88         int session_state;
89
90         struct mutex lock;
91
92         int session_id;
93         struct audio_client *audio_client;
94         int32_t shm_ion_fd;
95         struct ion_client *lib_ion_client;
96         struct ion_client *shm_ion_client;
97         struct ion_handle *lib_ion_handle;
98         struct ion_handle *shm_ion_handle;
99 };
100
101 /* Transcode loopback global info struct */
102 static struct msm_transcode_loopback transcode_info;
103
104 static void loopback_event_handler(uint32_t opcode,
105                 uint32_t token, uint32_t *payload, void *priv)
106 {
107         struct msm_transcode_loopback *trans =
108                         (struct msm_transcode_loopback *)priv;
109         struct snd_soc_pcm_runtime *rtd;
110         struct snd_compr_stream *cstream;
111         struct audio_client *ac;
112         int stream_id;
113         int ret;
114
115         if (!trans || !payload) {
116                 pr_err("%s: rtd or payload is NULL\n", __func__);
117                 return;
118         }
119
120         cstream = trans->sink.cstream;
121         ac = trans->audio_client;
122
123         /*
124          * Token for rest of the compressed commands use to set
125          * session id, stream id, dir etc.
126          */
127         stream_id = q6asm_get_stream_id_from_token(token);
128
129         switch (opcode) {
130         case ASM_STREAM_CMD_ENCDEC_EVENTS:
131         case ASM_IEC_61937_MEDIA_FMT_EVENT:
132                 pr_debug("%s: Handling stream event : 0X%x\n",
133                         __func__, opcode);
134                 rtd = cstream->private_data;
135                 if (!rtd) {
136                         pr_err("%s: rtd is NULL\n", __func__);
137                         return;
138                 }
139
140                 ret = msm_adsp_inform_mixer_ctl(rtd, payload);
141                 if (ret) {
142                         pr_err("%s: failed to inform mixer ctrl. err = %d\n",
143                                 __func__, ret);
144                         return;
145                 }
146                 break;
147         case APR_BASIC_RSP_RESULT: {
148                 switch (payload[0]) {
149                 case ASM_SESSION_CMD_RUN_V2:
150                         pr_debug("%s: ASM_SESSION_CMD_RUN_V2:", __func__);
151                         pr_debug("token 0x%x, stream id %d\n", token,
152                                   stream_id);
153                         break;
154                 case ASM_STREAM_CMD_CLOSE:
155                         pr_debug("%s: ASM_DATA_CMD_CLOSE:", __func__);
156                         pr_debug("token 0x%x, stream id %d\n", token,
157                                   stream_id);
158                         break;
159                 default:
160                         break;
161                 }
162                 break;
163         }
164         default:
165                 pr_debug("%s: Not Supported Event opcode[0x%x]\n",
166                           __func__, opcode);
167                 break;
168         }
169 }
170
171 static void populate_codec_list(struct msm_transcode_loopback *trans,
172                                 struct snd_compr_stream *cstream)
173 {
174         struct snd_compr_caps compr_cap;
175
176         pr_debug("%s\n", __func__);
177
178         memset(&compr_cap, 0, sizeof(struct snd_compr_caps));
179
180         if (cstream->direction == SND_COMPRESS_CAPTURE) {
181                 compr_cap.direction = SND_COMPRESS_CAPTURE;
182                 compr_cap.num_codecs = 3;
183                 compr_cap.codecs[0] = SND_AUDIOCODEC_PCM;
184                 compr_cap.codecs[1] = SND_AUDIOCODEC_AC3;
185                 compr_cap.codecs[2] = SND_AUDIOCODEC_EAC3;
186                 memcpy(&trans->source_compr_cap, &compr_cap,
187                                 sizeof(struct snd_compr_caps));
188         }
189
190         if (cstream->direction == SND_COMPRESS_PLAYBACK) {
191                 compr_cap.direction = SND_COMPRESS_PLAYBACK;
192                 compr_cap.num_codecs = 1;
193                 compr_cap.codecs[0] = SND_AUDIOCODEC_PCM;
194                 memcpy(&trans->sink_compr_cap, &compr_cap,
195                                 sizeof(struct snd_compr_caps));
196         }
197 }
198
199 static int msm_transcode_map_ion_fd(struct msm_transcode_loopback *trans,
200                                     int fd)
201 {
202         ion_phys_addr_t paddr;
203         size_t pa_len = 0;
204         int ret = 0;
205
206         ret = msm_audio_ion_phys_assign("audio_lib_mem_client",
207                                         &trans->lib_ion_client,
208                                         &trans->lib_ion_handle, fd,
209                                         &paddr, &pa_len, HLOS_TO_ADSP);
210         if (ret) {
211                 pr_err("%s: audio lib ION phys failed, rc = %d\n", __func__,
212                         ret);
213                 goto done;
214         }
215
216         ret = q6core_add_remove_pool_pages(paddr, pa_len,
217                                  ADSP_MEMORY_MAP_HLOS_PHYSPOOL, true);
218         if (ret) {
219                 pr_err("%s: add pages failed, rc = %d\n", __func__, ret);
220                 /* Assign back to HLOS if add pages cmd failed */
221                 msm_audio_ion_phys_free(trans->lib_ion_client,
222                                         trans->lib_ion_handle,
223                                         &paddr, &pa_len, ADSP_TO_HLOS);
224         }
225
226 done:
227         return ret;
228 }
229
230 static int msm_transcode_unmap_ion_fd(struct msm_transcode_loopback *trans)
231 {
232         ion_phys_addr_t paddr;
233         size_t pa_len = 0;
234         int ret = 0;
235
236         if (!trans->lib_ion_client || !trans->lib_ion_handle) {
237                 pr_err("%s: ion_client or ion_handle is NULL", __func__);
238                 return -EINVAL;
239         }
240         ret = msm_audio_ion_phys_free(trans->lib_ion_client,
241                                       trans->lib_ion_handle,
242                                       &paddr, &pa_len, ADSP_TO_HLOS);
243         if (ret) {
244                 pr_err("%s: audio lib ION phys failed, rc = %d\n", __func__,
245                         ret);
246                 goto done;
247         }
248
249         ret = q6core_add_remove_pool_pages(paddr, pa_len,
250                                         ADSP_MEMORY_MAP_HLOS_PHYSPOOL, false);
251         if (ret)
252                 pr_err("%s: remove pages failed, rc = %d\n", __func__, ret);
253
254 done:
255         return ret;
256 }
257
258 static int msm_transcode_loopback_open(struct snd_compr_stream *cstream)
259 {
260         int ret = 0;
261         struct snd_compr_runtime *runtime;
262         struct snd_soc_pcm_runtime *rtd;
263         struct msm_transcode_loopback *trans = &transcode_info;
264         struct trans_loopback_pdata *pdata;
265
266         if (cstream == NULL) {
267                 pr_err("%s: Invalid substream\n", __func__);
268                 return -EINVAL;
269         }
270         runtime = cstream->runtime;
271         rtd = snd_pcm_substream_chip(cstream);
272         pdata = snd_soc_platform_get_drvdata(rtd->platform);
273         pdata->cstream[rtd->dai_link->be_id] = cstream;
274
275         mutex_lock(&trans->lock);
276         if (trans->num_streams > LOOPBACK_SESSION_MAX_NUM_STREAMS) {
277                 pr_err("msm_transcode_open failed..invalid stream\n");
278                 ret = -EINVAL;
279                 goto exit;
280         }
281
282         if (cstream->direction == SND_COMPRESS_CAPTURE) {
283                 if (trans->source.cstream == NULL) {
284                         trans->source.cstream = cstream;
285                         trans->num_streams++;
286                 } else {
287                         pr_err("%s: capture stream already opened\n",
288                                 __func__);
289                         ret = -EINVAL;
290                         goto exit;
291                 }
292         } else if (cstream->direction == SND_COMPRESS_PLAYBACK) {
293                 if (trans->sink.cstream == NULL) {
294                         trans->sink.cstream = cstream;
295                         trans->num_streams++;
296                 } else {
297                         pr_debug("%s: playback stream already opened\n",
298                                 __func__);
299                         ret = -EINVAL;
300                         goto exit;
301                 }
302                 msm_adsp_init_mixer_ctl_pp_event_queue(rtd);
303                 if (pdata->ion_fd[rtd->dai_link->be_id] > 0) {
304                         ret = msm_transcode_map_ion_fd(trans,
305                                         pdata->ion_fd[rtd->dai_link->be_id]);
306                         if (ret < 0)
307                                 goto exit;
308                 }
309         }
310
311         pr_debug("%s: num stream%d, stream name %s\n", __func__,
312                  trans->num_streams, cstream->name);
313
314         populate_codec_list(trans, cstream);
315
316         if (trans->num_streams == LOOPBACK_SESSION_MAX_NUM_STREAMS)     {
317                 pr_debug("%s: Moving loopback session to READY state %d\n",
318                          __func__, trans->session_state);
319                 trans->session_state = LOOPBACK_SESSION_READY;
320         }
321
322         runtime->private_data = trans;
323
324 exit:
325         mutex_unlock(&trans->lock);
326         return ret;
327 }
328
329 static void stop_transcoding(struct msm_transcode_loopback *trans)
330 {
331         struct snd_soc_pcm_runtime *soc_pcm_rx;
332         struct snd_soc_pcm_runtime *soc_pcm_tx;
333
334         if (trans->audio_client != NULL) {
335                 q6asm_cmd(trans->audio_client, CMD_CLOSE);
336
337                 if (trans->sink.cstream != NULL) {
338                         soc_pcm_rx = trans->sink.cstream->private_data;
339                         msm_pcm_routing_dereg_phy_stream(
340                                         soc_pcm_rx->dai_link->be_id,
341                                         SND_COMPRESS_PLAYBACK);
342                 }
343                 if (trans->source.cstream != NULL) {
344                         soc_pcm_tx = trans->source.cstream->private_data;
345                         msm_pcm_routing_dereg_phy_stream(
346                                         soc_pcm_tx->dai_link->be_id,
347                                         SND_COMPRESS_CAPTURE);
348                 }
349                 q6asm_audio_client_free(trans->audio_client);
350                 trans->audio_client = NULL;
351         }
352 }
353
354 static int msm_transcode_loopback_free(struct snd_compr_stream *cstream)
355 {
356         struct snd_compr_runtime *runtime = cstream->runtime;
357         struct msm_transcode_loopback *trans = runtime->private_data;
358         struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(cstream);
359         struct trans_loopback_pdata *pdata = snd_soc_platform_get_drvdata(
360                                                                 rtd->platform);
361         int ret = 0;
362         ion_phys_addr_t paddr;
363         size_t pa_len = 0;
364
365         mutex_lock(&trans->lock);
366
367         pr_debug("%s: Transcode loopback end:%d, streams %d\n", __func__,
368                   cstream->direction, trans->num_streams);
369         trans->num_streams--;
370         stop_transcoding(trans);
371
372         if (cstream->direction == SND_COMPRESS_PLAYBACK) {
373                 memset(&trans->sink, 0, sizeof(struct loopback_stream));
374                 msm_adsp_clean_mixer_ctl_pp_event_queue(rtd);
375                 if (trans->shm_ion_fd > 0) {
376                         msm_audio_ion_phys_free(trans->shm_ion_client,
377                                                 trans->shm_ion_handle,
378                                                 &paddr, &pa_len, ADSP_TO_HLOS);
379                         trans->shm_ion_fd = 0;
380                 }
381                 if (pdata->ion_fd[rtd->dai_link->be_id] > 0) {
382                         msm_transcode_unmap_ion_fd(trans);
383                         pdata->ion_fd[rtd->dai_link->be_id] = 0;
384                 }
385         } else if (cstream->direction == SND_COMPRESS_CAPTURE) {
386                 memset(&trans->source, 0, sizeof(struct loopback_stream));
387         }
388
389         trans->session_state = LOOPBACK_SESSION_CLOSE;
390         mutex_unlock(&trans->lock);
391         return ret;
392 }
393
394 static int msm_transcode_loopback_trigger(struct snd_compr_stream *cstream,
395                                           int cmd)
396 {
397         struct snd_compr_runtime *runtime = cstream->runtime;
398         struct msm_transcode_loopback *trans = runtime->private_data;
399
400         switch (cmd) {
401         case SNDRV_PCM_TRIGGER_START:
402         case SNDRV_PCM_TRIGGER_RESUME:
403         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
404
405                 if (trans->session_state == LOOPBACK_SESSION_START) {
406                         pr_debug("%s: Issue Loopback session %d RUN\n",
407                                   __func__, trans->instance);
408                         q6asm_run_nowait(trans->audio_client, 0, 0, 0);
409                         trans->session_state = LOOPBACK_SESSION_RUN;
410                 }
411                 break;
412         case SNDRV_PCM_TRIGGER_SUSPEND:
413         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
414         case SNDRV_PCM_TRIGGER_STOP:
415                 pr_debug("%s: Issue Loopback session %d STOP\n", __func__,
416                           trans->instance);
417                 if (trans->session_state == LOOPBACK_SESSION_RUN)
418                         q6asm_cmd_nowait(trans->audio_client, CMD_PAUSE);
419                 trans->session_state = LOOPBACK_SESSION_START;
420                 break;
421
422         default:
423                 break;
424         }
425         return 0;
426 }
427
428 static int msm_transcode_loopback_set_params(struct snd_compr_stream *cstream,
429                                 struct snd_compr_params *codec_param)
430 {
431
432         struct snd_compr_runtime *runtime = cstream->runtime;
433         struct msm_transcode_loopback *trans = runtime->private_data;
434         struct snd_soc_pcm_runtime *soc_pcm_rx;
435         struct snd_soc_pcm_runtime *soc_pcm_tx;
436         struct snd_soc_pcm_runtime *rtd;
437         struct trans_loopback_pdata *pdata;
438         uint32_t bit_width = 16;
439         int ret = 0;
440
441         if (trans == NULL) {
442                 pr_err("%s: Invalid param\n", __func__);
443                 return -EINVAL;
444         }
445
446         mutex_lock(&trans->lock);
447
448         rtd = snd_pcm_substream_chip(cstream);
449         pdata = snd_soc_platform_get_drvdata(rtd->platform);
450
451         if (cstream->direction == SND_COMPRESS_PLAYBACK) {
452                 if (codec_param->codec.id == SND_AUDIOCODEC_PCM) {
453                         trans->sink.codec_format =
454                                 FORMAT_LINEAR_PCM;
455                         switch (codec_param->codec.format) {
456                         case SNDRV_PCM_FORMAT_S32_LE:
457                                 bit_width = 32;
458                                 break;
459                         case SNDRV_PCM_FORMAT_S24_LE:
460                                 bit_width = 24;
461                                 break;
462                         case SNDRV_PCM_FORMAT_S24_3LE:
463                                 bit_width = 24;
464                                 break;
465                         case SNDRV_PCM_FORMAT_S16_LE:
466                         default:
467                                 bit_width = 16;
468                                 break;
469                         }
470                 } else {
471                         pr_debug("%s: unknown sink codec\n", __func__);
472                         ret = -EINVAL;
473                         goto exit;
474                 }
475                 trans->sink.start = true;
476         }
477
478         if (cstream->direction == SND_COMPRESS_CAPTURE) {
479                 switch (codec_param->codec.id) {
480                 case SND_AUDIOCODEC_PCM:
481                         pr_debug("Source SND_AUDIOCODEC_PCM\n");
482                         trans->source.codec_format =
483                                 FORMAT_LINEAR_PCM;
484                         break;
485                 case SND_AUDIOCODEC_AC3:
486                         pr_debug("Source SND_AUDIOCODEC_AC3\n");
487                         trans->source.codec_format =
488                                 FORMAT_AC3;
489                         break;
490                 case SND_AUDIOCODEC_EAC3:
491                         pr_debug("Source SND_AUDIOCODEC_EAC3\n");
492                         trans->source.codec_format =
493                                 FORMAT_EAC3;
494                         break;
495                 default:
496                         pr_debug("%s: unknown source codec\n", __func__);
497                         ret = -EINVAL;
498                         goto exit;
499                 }
500                 trans->source.start = true;
501         }
502
503         pr_debug("%s: trans->source.start %d trans->sink.start %d trans->source.cstream %pK trans->sink.cstream %pK trans->session_state %d\n",
504                         __func__, trans->source.start, trans->sink.start,
505                         trans->source.cstream, trans->sink.cstream,
506                         trans->session_state);
507
508         if ((trans->session_state == LOOPBACK_SESSION_READY) &&
509                         trans->source.start && trans->sink.start) {
510                 pr_debug("%s: Moving loopback session to start state\n",
511                           __func__);
512                 trans->session_state = LOOPBACK_SESSION_START;
513         }
514
515         if (trans->session_state == LOOPBACK_SESSION_START) {
516                 if (trans->audio_client != NULL) {
517                         pr_debug("%s: ASM client already opened, closing\n",
518                                  __func__);
519                         stop_transcoding(trans);
520                 }
521
522                 trans->audio_client = q6asm_audio_client_alloc(
523                                 (app_cb)loopback_event_handler, trans);
524                 if (!trans->audio_client) {
525                         pr_err("%s: Could not allocate memory\n", __func__);
526                         ret = -EINVAL;
527                         goto exit;
528                 }
529                 pr_debug("%s: ASM client allocated, callback %pK\n", __func__,
530                                                 loopback_event_handler);
531                 trans->session_id = trans->audio_client->session;
532                 trans->audio_client->perf_mode = pdata->perf_mode;
533                 ret = q6asm_open_transcode_loopback(trans->audio_client,
534                                         bit_width,
535                                         trans->source.codec_format,
536                                         trans->sink.codec_format);
537                 if (ret < 0) {
538                         pr_err("%s: Session transcode loopback open failed\n",
539                                 __func__);
540                         q6asm_audio_client_free(trans->audio_client);
541                         trans->audio_client = NULL;
542                         goto exit;
543                 }
544
545                 pr_debug("%s: Starting ADM open for loopback\n", __func__);
546                 soc_pcm_rx = trans->sink.cstream->private_data;
547                 soc_pcm_tx = trans->source.cstream->private_data;
548                 if (trans->source.codec_format != FORMAT_LINEAR_PCM)
549                         msm_pcm_routing_reg_phy_compr_stream(
550                                         soc_pcm_tx->dai_link->be_id,
551                                         false,
552                                         trans->session_id,
553                                         SNDRV_PCM_STREAM_CAPTURE,
554                                         COMPRESSED_PASSTHROUGH_GEN);
555                 else
556                         msm_pcm_routing_reg_phy_stream(
557                                         soc_pcm_tx->dai_link->be_id,
558                                         trans->audio_client->perf_mode,
559                                         trans->session_id,
560                                         SNDRV_PCM_STREAM_CAPTURE);
561                 /* Opening Rx ADM in LOW_LATENCY mode by default */
562                 msm_pcm_routing_reg_phy_stream(
563                                         soc_pcm_rx->dai_link->be_id,
564                                         trans->audio_client->perf_mode,
565                                         trans->session_id,
566                                         SNDRV_PCM_STREAM_PLAYBACK);
567                 pr_debug("%s: Successfully opened ADM sessions\n", __func__);
568         }
569 exit:
570         mutex_unlock(&trans->lock);
571         return ret;
572 }
573
574 static int msm_transcode_loopback_get_caps(struct snd_compr_stream *cstream,
575                                 struct snd_compr_caps *arg)
576 {
577         struct snd_compr_runtime *runtime;
578         struct msm_transcode_loopback *trans;
579
580         if (!arg || !cstream) {
581                 pr_err("%s: Invalid arguments\n", __func__);
582                 return -EINVAL;
583         }
584
585         runtime = cstream->runtime;
586         trans = runtime->private_data;
587         pr_debug("%s\n", __func__);
588         if (cstream->direction == SND_COMPRESS_CAPTURE)
589                 memcpy(arg, &trans->source_compr_cap,
590                        sizeof(struct snd_compr_caps));
591         else
592                 memcpy(arg, &trans->sink_compr_cap,
593                        sizeof(struct snd_compr_caps));
594         return 0;
595 }
596
597 static int msm_transcode_loopback_set_metadata(struct snd_compr_stream *cstream,
598                                 struct snd_compr_metadata *metadata)
599 {
600         struct snd_soc_pcm_runtime *rtd;
601         struct trans_loopback_pdata *pdata;
602
603         if (!metadata || !cstream) {
604                 pr_err("%s: Invalid arguments\n", __func__);
605                 return -EINVAL;
606         }
607
608         rtd = snd_pcm_substream_chip(cstream);
609         pdata = snd_soc_platform_get_drvdata(rtd->platform);
610
611         switch (metadata->key) {
612         case SNDRV_COMPRESS_LATENCY_MODE:
613         {
614                 switch (metadata->value[0]) {
615                 case SNDRV_COMPRESS_LEGACY_LATENCY_MODE:
616                         pdata->perf_mode = LEGACY_PCM_MODE;
617                         break;
618                 case SNDRV_COMPRESS_LOW_LATENCY_MODE:
619                         pdata->perf_mode = LOW_LATENCY_PCM_MODE;
620                         break;
621                 default:
622                         pr_debug("%s: Unsupported latency mode %d, default to Legacy\n",
623                                         __func__, metadata->value[0]);
624                         pdata->perf_mode = LEGACY_PCM_MODE;
625                         break;
626                 }
627         }
628                 break;
629         default:
630                 pr_debug("%s: Unsupported metadata %d\n",
631                                 __func__, metadata->key);
632                 break;
633         }
634         return 0;
635 }
636
637 static int msm_transcode_stream_cmd_put(struct snd_kcontrol *kcontrol,
638                                 struct snd_ctl_elem_value *ucontrol)
639 {
640         struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
641         unsigned long fe_id = kcontrol->private_value;
642         struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *)
643                                 snd_soc_component_get_drvdata(comp);
644         struct snd_compr_stream *cstream = NULL;
645         struct msm_transcode_loopback *prtd;
646         int ret = 0;
647         struct msm_adsp_event_data *event_data = NULL;
648         uint64_t actual_payload_len = 0;
649
650         if (fe_id >= MSM_FRONTEND_DAI_MAX) {
651                 pr_err("%s Received invalid fe_id %lu\n",
652                         __func__, fe_id);
653                 ret = -EINVAL;
654                 goto done;
655         }
656
657         cstream = pdata->cstream[fe_id];
658         if (cstream == NULL) {
659                 pr_err("%s cstream is null.\n", __func__);
660                 ret = -EINVAL;
661                 goto done;
662         }
663
664         prtd = cstream->runtime->private_data;
665         if (!prtd) {
666                 pr_err("%s: prtd is null.\n", __func__);
667                 ret = -EINVAL;
668                 goto done;
669         }
670
671         if (prtd->audio_client == NULL) {
672                 pr_err("%s: audio_client is null.\n", __func__);
673                 ret = -EINVAL;
674                 goto done;
675         }
676
677         event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
678         if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
679             (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
680                 pr_err("%s: invalid event_type=%d",
681                          __func__, event_data->event_type);
682                 ret = -EINVAL;
683                 goto done;
684         }
685
686         actual_payload_len = sizeof(struct msm_adsp_event_data) +
687                 event_data->payload_len;
688         if (actual_payload_len >= U32_MAX) {
689                 pr_err("%s payload length 0x%X  exceeds limit",
690                                 __func__, event_data->payload_len);
691                 ret = -EINVAL;
692                 goto done;
693         }
694
695
696         if ((sizeof(struct msm_adsp_event_data) + event_data->payload_len) >=
697                                         sizeof(ucontrol->value.bytes.data)) {
698                 pr_err("%s param length=%d  exceeds limit",
699                          __func__, event_data->payload_len);
700                 ret = -EINVAL;
701                 goto done;
702         }
703
704         ret = q6asm_send_stream_cmd(prtd->audio_client, event_data);
705         if (ret < 0)
706                 pr_err("%s: failed to send stream event cmd, err = %d\n",
707                         __func__, ret);
708 done:
709         return ret;
710 }
711
712 static int msm_transcode_shm_ion_fd_map_put(struct snd_kcontrol *kcontrol,
713                                     struct snd_ctl_elem_value *ucontrol)
714 {
715         struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
716         unsigned long fe_id = kcontrol->private_value;
717         struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *)
718                                 snd_soc_component_get_drvdata(comp);
719         struct snd_compr_stream *cstream = NULL;
720         struct msm_transcode_loopback *prtd;
721         int ret = 0;
722
723         if (fe_id >= MSM_FRONTEND_DAI_MAX) {
724                 pr_err("%s Received out of bounds invalid fe_id %lu\n",
725                         __func__, fe_id);
726                 ret = -EINVAL;
727                 goto done;
728         }
729
730         cstream = pdata->cstream[fe_id];
731         if (cstream == NULL) {
732                 pr_err("%s cstream is null\n", __func__);
733                 ret = -EINVAL;
734                 goto done;
735         }
736
737         prtd = cstream->runtime->private_data;
738         if (!prtd) {
739                 pr_err("%s: prtd is null\n", __func__);
740                 ret = -EINVAL;
741                 goto done;
742         }
743
744         if (prtd->audio_client == NULL) {
745                 pr_err("%s: audio_client is null\n", __func__);
746                 ret = -EINVAL;
747                 goto done;
748         }
749
750         memcpy(&prtd->shm_ion_fd, ucontrol->value.bytes.data,
751                 sizeof(prtd->shm_ion_fd));
752         ret = q6asm_audio_map_shm_fd(prtd->audio_client,
753                                 &prtd->shm_ion_client,
754                                 &prtd->shm_ion_handle, prtd->shm_ion_fd);
755         if (ret < 0)
756                 pr_err("%s: failed to map shm mem\n", __func__);
757 done:
758         return ret;
759 }
760
761
762 static int msm_transcode_lib_ion_fd_map_put(struct snd_kcontrol *kcontrol,
763                                     struct snd_ctl_elem_value *ucontrol)
764 {
765         struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
766         unsigned long fe_id = kcontrol->private_value;
767         struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *)
768                                 snd_soc_component_get_drvdata(comp);
769         int ret = 0;
770
771         if (fe_id >= MSM_FRONTEND_DAI_MAX) {
772                 pr_err("%s Received out of bounds invalid fe_id %lu\n",
773                         __func__, fe_id);
774                 ret = -EINVAL;
775                 goto done;
776         }
777
778         memcpy(&pdata->ion_fd[fe_id], ucontrol->value.bytes.data,
779                    sizeof(pdata->ion_fd[fe_id]));
780 done:
781         return ret;
782 }
783
784 static int msm_transcode_rtic_event_ack_put(struct snd_kcontrol *kcontrol,
785                                         struct snd_ctl_elem_value *ucontrol)
786 {
787         struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
788         unsigned long fe_id = kcontrol->private_value;
789         struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *)
790                                         snd_soc_component_get_drvdata(comp);
791         struct snd_compr_stream *cstream = NULL;
792         struct msm_transcode_loopback *prtd;
793         int ret = 0;
794         int param_length = 0;
795
796         if (fe_id >= MSM_FRONTEND_DAI_MAX) {
797                 pr_err("%s Received invalid fe_id %lu\n",
798                         __func__, fe_id);
799                 ret = -EINVAL;
800                 goto done;
801         }
802
803         cstream = pdata->cstream[fe_id];
804         if (cstream == NULL) {
805                 pr_err("%s cstream is null\n", __func__);
806                 ret = -EINVAL;
807                 goto done;
808         }
809
810         prtd = cstream->runtime->private_data;
811         if (!prtd) {
812                 pr_err("%s: prtd is null\n", __func__);
813                 ret = -EINVAL;
814                 goto done;
815         }
816
817         if (prtd->audio_client == NULL) {
818                 pr_err("%s: audio_client is null\n", __func__);
819                 ret = -EINVAL;
820                 goto done;
821         }
822
823         memcpy(&param_length, ucontrol->value.bytes.data,
824                 sizeof(param_length));
825         if ((param_length + sizeof(param_length))
826                 >= sizeof(ucontrol->value.bytes.data)) {
827                 pr_err("%s param length=%d  exceeds limit",
828                         __func__, param_length);
829                 ret = -EINVAL;
830                 goto done;
831         }
832
833         ret = q6asm_send_rtic_event_ack(prtd->audio_client,
834                         ucontrol->value.bytes.data + sizeof(param_length),
835                         param_length);
836         if (ret < 0)
837                 pr_err("%s: failed to send rtic event ack, err = %d\n",
838                         __func__, ret);
839 done:
840         return ret;
841 }
842
843 static int msm_transcode_playback_app_type_cfg_put(
844                         struct snd_kcontrol *kcontrol,
845                         struct snd_ctl_elem_value *ucontrol)
846 {
847         u64 fe_id = kcontrol->private_value;
848         int session_type = SESSION_TYPE_RX;
849         int be_id = ucontrol->value.integer.value[APP_TYPE_CONFIG_IDX_BE_ID];
850         struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
851         int ret = 0;
852
853         cfg_data.app_type = ucontrol->value.integer.value[
854                             APP_TYPE_CONFIG_IDX_APP_TYPE];
855         cfg_data.acdb_dev_id = ucontrol->value.integer.value[
856                                APP_TYPE_CONFIG_IDX_ACDB_ID];
857         if (ucontrol->value.integer.value[APP_TYPE_CONFIG_IDX_SAMPLE_RATE] != 0)
858                 cfg_data.sample_rate = ucontrol->value.integer.value[
859                                        APP_TYPE_CONFIG_IDX_SAMPLE_RATE];
860         pr_debug("%s: fe_id %llu session_type %d be_id %d app_type %d acdb_dev_id %d sample_rate- %d\n",
861                 __func__, fe_id, session_type, be_id,
862                 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
863         ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
864                                                       be_id, &cfg_data);
865         if (ret < 0)
866                 pr_err("%s: msm_transcode_playback_stream_app_type_cfg set failed returned %d\n",
867                         __func__, ret);
868
869         return ret;
870 }
871
872 static int msm_transcode_playback_app_type_cfg_get(
873                         struct snd_kcontrol *kcontrol,
874                         struct snd_ctl_elem_value *ucontrol)
875 {
876         u64 fe_id = kcontrol->private_value;
877         int session_type = SESSION_TYPE_RX;
878         int be_id = 0;
879         struct msm_pcm_stream_app_type_cfg cfg_data = {0};
880         int ret = 0;
881
882         ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
883                                                       &be_id, &cfg_data);
884         if (ret < 0) {
885                 pr_err("%s: msm_transcode_playback_stream_app_type_cfg get failed returned %d\n",
886                         __func__, ret);
887                 goto done;
888         }
889
890         ucontrol->value.integer.value[APP_TYPE_CONFIG_IDX_APP_TYPE] =
891                                         cfg_data.app_type;
892         ucontrol->value.integer.value[APP_TYPE_CONFIG_IDX_ACDB_ID] =
893                                         cfg_data.acdb_dev_id;
894         ucontrol->value.integer.value[APP_TYPE_CONFIG_IDX_SAMPLE_RATE] =
895                                         cfg_data.sample_rate;
896         ucontrol->value.integer.value[APP_TYPE_CONFIG_IDX_BE_ID] = be_id;
897         pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
898                 __func__, fe_id, session_type, be_id,
899                 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
900 done:
901         return ret;
902 }
903
904 static int msm_transcode_set_volume(struct snd_compr_stream *cstream,
905                                 uint32_t master_gain)
906 {
907         int rc = 0;
908         struct msm_transcode_loopback *prtd;
909         struct snd_soc_pcm_runtime *rtd;
910
911         pr_debug("%s: master_gain %d\n", __func__, master_gain);
912         if (!cstream || !cstream->runtime) {
913                 pr_err("%s: session not active\n", __func__);
914                 return -EPERM;
915         }
916         rtd = cstream->private_data;
917         prtd = cstream->runtime->private_data;
918
919         if (!rtd || !rtd->platform || !prtd || !prtd->audio_client) {
920                 pr_err("%s: invalid rtd, prtd or audio client", __func__);
921                 return -EINVAL;
922         }
923
924         rc = q6asm_set_volume(prtd->audio_client, master_gain);
925         if (rc < 0)
926                 pr_err("%s: Send vol gain command failed rc=%d\n",
927                        __func__, rc);
928
929         return rc;
930 }
931
932 static int msm_transcode_volume_put(struct snd_kcontrol *kcontrol,
933                                 struct snd_ctl_elem_value *ucontrol)
934 {
935         struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
936         unsigned long fe_id = kcontrol->private_value;
937         struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *)
938                         snd_soc_component_get_drvdata(comp);
939         struct snd_compr_stream *cstream = NULL;
940         uint32_t ret = 0;
941
942         if (fe_id >= MSM_FRONTEND_DAI_MAX) {
943                 pr_err("%s Received out of bounds fe_id %lu\n",
944                         __func__, fe_id);
945                 return -EINVAL;
946         }
947
948         cstream = pdata->cstream[fe_id];
949         pdata->master_gain = ucontrol->value.integer.value[0];
950
951         pr_debug("%s: fe_id %lu master_gain %d\n",
952                  __func__, fe_id, pdata->master_gain);
953         if (cstream)
954                 ret = msm_transcode_set_volume(cstream, pdata->master_gain);
955         return ret;
956 }
957
958 static int msm_transcode_volume_get(struct snd_kcontrol *kcontrol,
959                                 struct snd_ctl_elem_value *ucontrol)
960 {
961         struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
962         unsigned long fe_id = kcontrol->private_value;
963
964         struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *)
965                         snd_soc_component_get_drvdata(comp);
966
967         if (fe_id >= MSM_FRONTEND_DAI_MAX) {
968                 pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id);
969                 return -EINVAL;
970         }
971
972         pr_debug("%s: fe_id %lu\n", __func__, fe_id);
973         ucontrol->value.integer.value[0] = pdata->master_gain;
974
975         return 0;
976 }
977
978 static int msm_transcode_stream_cmd_control(
979                         struct snd_soc_pcm_runtime *rtd)
980 {
981         const char *mixer_ctl_name = DSP_STREAM_CMD;
982         const char *deviceNo = "NN";
983         char *mixer_str = NULL;
984         int ctl_len = 0, ret = 0;
985         struct snd_kcontrol_new fe_loopback_stream_cmd_config_control[1] = {
986                 {
987                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
988                 .name = "?",
989                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
990                 .info = msm_adsp_stream_cmd_info,
991                 .put = msm_transcode_stream_cmd_put,
992                 .private_value = 0,
993                 }
994         };
995
996         if (!rtd) {
997                 pr_err("%s NULL rtd\n", __func__);
998                 ret = -EINVAL;
999                 goto done;
1000         }
1001
1002         ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1003         mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1004         if (!mixer_str) {
1005                 ret = -ENOMEM;
1006                 goto done;
1007         }
1008
1009         snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1010         fe_loopback_stream_cmd_config_control[0].name = mixer_str;
1011         fe_loopback_stream_cmd_config_control[0].private_value =
1012                                 rtd->dai_link->be_id;
1013         pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
1014         ret = snd_soc_add_platform_controls(rtd->platform,
1015                 fe_loopback_stream_cmd_config_control,
1016                 ARRAY_SIZE(fe_loopback_stream_cmd_config_control));
1017         if (ret < 0)
1018                 pr_err("%s: failed to add ctl %s. err = %d\n",
1019                         __func__, mixer_str, ret);
1020
1021         kfree(mixer_str);
1022 done:
1023         return ret;
1024 }
1025
1026 static int msm_transcode_stream_callback_control(
1027                         struct snd_soc_pcm_runtime *rtd)
1028 {
1029         const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
1030         const char *deviceNo = "NN";
1031         char *mixer_str = NULL;
1032         int ctl_len = 0, ret = 0;
1033         struct snd_kcontrol *kctl;
1034
1035         struct snd_kcontrol_new fe_loopback_callback_config_control[1] = {
1036                 {
1037                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1038                 .name = "?",
1039                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1040                 .info = msm_adsp_stream_callback_info,
1041                 .get = msm_adsp_stream_callback_get,
1042                 .private_value = 0,
1043                 }
1044         };
1045
1046         if (!rtd) {
1047                 pr_err("%s: rtd is  NULL\n", __func__);
1048                 ret = -EINVAL;
1049                 goto done;
1050         }
1051
1052         ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1053         mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1054         if (!mixer_str) {
1055                 ret = -ENOMEM;
1056                 goto done;
1057         }
1058
1059         snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1060         fe_loopback_callback_config_control[0].name = mixer_str;
1061         fe_loopback_callback_config_control[0].private_value =
1062                                         rtd->dai_link->be_id;
1063         pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
1064         ret = snd_soc_add_platform_controls(rtd->platform,
1065                         fe_loopback_callback_config_control,
1066                         ARRAY_SIZE(fe_loopback_callback_config_control));
1067         if (ret < 0) {
1068                 pr_err("%s: failed to add ctl %s. err = %d\n",
1069                         __func__, mixer_str, ret);
1070                 ret = -EINVAL;
1071                 goto free_mixer_str;
1072         }
1073
1074         kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
1075         if (!kctl) {
1076                 pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
1077                 ret = -EINVAL;
1078                 goto free_mixer_str;
1079         }
1080
1081         kctl->private_data = NULL;
1082 free_mixer_str:
1083         kfree(mixer_str);
1084 done:
1085         return ret;
1086 }
1087
1088 static int msm_transcode_add_shm_ion_fd_cmd_control(
1089                                         struct snd_soc_pcm_runtime *rtd)
1090 {
1091         const char *mixer_ctl_name = "Playback ION FD";
1092         const char *deviceNo = "NN";
1093         char *mixer_str = NULL;
1094         int ctl_len = 0, ret = 0;
1095         struct snd_kcontrol_new fe_ion_fd_config_control[1] = {
1096                 {
1097                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1098                 .name = "?",
1099                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1100                 .info = msm_adsp_stream_cmd_info,
1101                 .put = msm_transcode_shm_ion_fd_map_put,
1102                 .private_value = 0,
1103                 }
1104         };
1105
1106         if (!rtd) {
1107                 pr_err("%s NULL rtd\n", __func__);
1108                 ret = -EINVAL;
1109                 goto done;
1110         }
1111
1112         ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1113         mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1114         if (!mixer_str) {
1115                 ret = -ENOMEM;
1116                 goto done;
1117         }
1118
1119         snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1120         fe_ion_fd_config_control[0].name = mixer_str;
1121         fe_ion_fd_config_control[0].private_value = rtd->dai_link->be_id;
1122         pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
1123         ret = snd_soc_add_platform_controls(rtd->platform,
1124                                 fe_ion_fd_config_control,
1125                                 ARRAY_SIZE(fe_ion_fd_config_control));
1126         if (ret < 0)
1127                 pr_err("%s: failed to add ctl %s\n", __func__, mixer_str);
1128
1129         kfree(mixer_str);
1130 done:
1131         return ret;
1132 }
1133
1134 static int msm_transcode_add_lib_ion_fd_cmd_control(
1135                                         struct snd_soc_pcm_runtime *rtd)
1136 {
1137         const char *mixer_ctl_name = "Playback ION LIB FD";
1138         const char *deviceNo = "NN";
1139         char *mixer_str = NULL;
1140         int ctl_len = 0, ret = 0;
1141         struct snd_kcontrol_new fe_ion_fd_config_control[1] = {
1142                 {
1143                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1144                 .name = "?",
1145                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1146                 .info = msm_adsp_stream_cmd_info,
1147                 .put = msm_transcode_lib_ion_fd_map_put,
1148                 .private_value = 0,
1149                 }
1150         };
1151
1152         if (!rtd) {
1153                 pr_err("%s NULL rtd\n", __func__);
1154                 ret = -EINVAL;
1155                 goto done;
1156         }
1157
1158         ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1159         mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1160         if (!mixer_str) {
1161                 ret = -ENOMEM;
1162                 goto done;
1163         }
1164
1165         snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1166         fe_ion_fd_config_control[0].name = mixer_str;
1167         fe_ion_fd_config_control[0].private_value = rtd->dai_link->be_id;
1168         pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
1169         ret = snd_soc_add_platform_controls(rtd->platform,
1170                                 fe_ion_fd_config_control,
1171                                 ARRAY_SIZE(fe_ion_fd_config_control));
1172         if (ret < 0)
1173                 pr_err("%s: failed to add ctl %s\n", __func__, mixer_str);
1174
1175         kfree(mixer_str);
1176 done:
1177         return ret;
1178 }
1179
1180 static int msm_transcode_add_event_ack_cmd_control(
1181                                         struct snd_soc_pcm_runtime *rtd)
1182 {
1183         const char *mixer_ctl_name = "Playback Event Ack";
1184         const char *deviceNo = "NN";
1185         char *mixer_str = NULL;
1186         int ctl_len = 0, ret = 0;
1187         struct snd_kcontrol_new fe_event_ack_config_control[1] = {
1188                 {
1189                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1190                 .name = "?",
1191                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1192                 .info = msm_adsp_stream_cmd_info,
1193                 .put = msm_transcode_rtic_event_ack_put,
1194                 .private_value = 0,
1195                 }
1196         };
1197
1198         if (!rtd) {
1199                 pr_err("%s NULL rtd\n", __func__);
1200                 ret = -EINVAL;
1201                 goto done;
1202         }
1203
1204         ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1205         mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1206         if (!mixer_str) {
1207                 ret = -ENOMEM;
1208                 goto done;
1209         }
1210
1211         snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1212         fe_event_ack_config_control[0].name = mixer_str;
1213         fe_event_ack_config_control[0].private_value = rtd->dai_link->be_id;
1214         pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
1215         ret = snd_soc_add_platform_controls(rtd->platform,
1216                                 fe_event_ack_config_control,
1217                                 ARRAY_SIZE(fe_event_ack_config_control));
1218         if (ret < 0)
1219                 pr_err("%s: failed to add ctl %s\n", __func__, mixer_str);
1220
1221         kfree(mixer_str);
1222 done:
1223         return ret;
1224 }
1225
1226 static int msm_transcode_app_type_cfg_info(struct snd_kcontrol *kcontrol,
1227                                        struct snd_ctl_elem_info *uinfo)
1228 {
1229         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1230         uinfo->count = 5;
1231         uinfo->value.integer.min = 0;
1232         uinfo->value.integer.max = 0xFFFFFFFF;
1233         return 0;
1234 }
1235
1236 static int msm_transcode_add_app_type_cfg_control(
1237                         struct snd_soc_pcm_runtime *rtd)
1238 {
1239         char mixer_str[32];
1240         int rc = 0;
1241         struct snd_kcontrol_new fe_app_type_cfg_control[1] = {
1242                 {
1243                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1244                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1245                 .info = msm_transcode_app_type_cfg_info,
1246                 .put = msm_transcode_playback_app_type_cfg_put,
1247                 .get = msm_transcode_playback_app_type_cfg_get,
1248                 .private_value = 0,
1249                 }
1250         };
1251
1252         if (!rtd) {
1253                 pr_err("%s NULL rtd\n", __func__);
1254
1255                 return -EINVAL;
1256         }
1257
1258         if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) {
1259
1260                 snprintf(mixer_str, sizeof(mixer_str),
1261                         "Audio Stream %d App Type Cfg",
1262                          rtd->pcm->device);
1263
1264                 fe_app_type_cfg_control[0].name = mixer_str;
1265                 fe_app_type_cfg_control[0].private_value = rtd->dai_link->be_id;
1266
1267                 fe_app_type_cfg_control[0].put =
1268                                 msm_transcode_playback_app_type_cfg_put;
1269                 fe_app_type_cfg_control[0].get =
1270                                 msm_transcode_playback_app_type_cfg_get;
1271
1272                 pr_debug("Registering new mixer ctl %s", mixer_str);
1273                 snd_soc_add_platform_controls(rtd->platform,
1274                                         fe_app_type_cfg_control,
1275                                         ARRAY_SIZE(fe_app_type_cfg_control));
1276         }
1277
1278         return rc;
1279 }
1280 static int msm_transcode_volume_info(struct snd_kcontrol *kcontrol,
1281                                  struct snd_ctl_elem_info *uinfo)
1282 {
1283         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1284         uinfo->count = 1;
1285         uinfo->value.integer.min = 0;
1286         uinfo->value.integer.max = TRANSCODE_LR_VOL_MAX_STEPS;
1287         return 0;
1288 }
1289
1290 static int msm_transcode_add_volume_control(struct snd_soc_pcm_runtime *rtd)
1291 {
1292         struct snd_kcontrol_new fe_volume_control[1] = {
1293                 {
1294                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1295                 .name = "Transcode Loopback Rx Volume",
1296                 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
1297                           SNDRV_CTL_ELEM_ACCESS_READWRITE,
1298                 .info = msm_transcode_volume_info,
1299                 .get = msm_transcode_volume_get,
1300                 .put = msm_transcode_volume_put,
1301                 .private_value = 0,
1302                 }
1303         };
1304
1305         if (!rtd) {
1306                 pr_err("%s NULL rtd\n", __func__);
1307                 return -EINVAL;
1308         }
1309         if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) {
1310                 fe_volume_control[0].private_value = rtd->dai_link->be_id;
1311                 pr_debug("Registering new mixer ctl %s",
1312                              fe_volume_control[0].name);
1313                 snd_soc_add_platform_controls(rtd->platform, fe_volume_control,
1314                                                 ARRAY_SIZE(fe_volume_control));
1315         }
1316         return 0;
1317 }
1318
1319 static int msm_transcode_loopback_new(struct snd_soc_pcm_runtime *rtd)
1320 {
1321         int rc;
1322
1323         rc = msm_transcode_stream_cmd_control(rtd);
1324         if (rc)
1325                 pr_err("%s: ADSP Stream Cmd Control open failed\n", __func__);
1326
1327         rc = msm_transcode_stream_callback_control(rtd);
1328         if (rc)
1329                 pr_err("%s: ADSP Stream callback Control open failed\n",
1330                         __func__);
1331
1332         rc = msm_transcode_add_shm_ion_fd_cmd_control(rtd);
1333         if (rc)
1334                 pr_err("%s: Could not add transcode shm ion fd Control\n",
1335                         __func__);
1336
1337         rc = msm_transcode_add_lib_ion_fd_cmd_control(rtd);
1338         if (rc)
1339                 pr_err("%s: Could not add transcode lib ion fd Control\n",
1340                         __func__);
1341
1342         rc = msm_transcode_add_event_ack_cmd_control(rtd);
1343         if (rc)
1344                 pr_err("%s: Could not add transcode event ack Control\n",
1345                         __func__);
1346
1347         rc = msm_transcode_add_app_type_cfg_control(rtd);
1348         if (rc)
1349                 pr_err("%s: Could not add Compr App Type Cfg Control\n",
1350                         __func__);
1351
1352         rc = msm_transcode_add_volume_control(rtd);
1353         if (rc)
1354                 pr_err("%s: Could not add transcode volume Control\n",
1355                         __func__);
1356
1357         return 0;
1358 }
1359
1360 static struct snd_compr_ops msm_transcode_loopback_ops = {
1361         .open                   = msm_transcode_loopback_open,
1362         .free                   = msm_transcode_loopback_free,
1363         .trigger                = msm_transcode_loopback_trigger,
1364         .set_params             = msm_transcode_loopback_set_params,
1365         .get_caps               = msm_transcode_loopback_get_caps,
1366         .set_metadata           = msm_transcode_loopback_set_metadata,
1367 };
1368
1369
1370 static int msm_transcode_loopback_probe(struct snd_soc_platform *platform)
1371 {
1372         struct trans_loopback_pdata *pdata = NULL;
1373
1374         pr_debug("%s\n", __func__);
1375         pdata = (struct trans_loopback_pdata *)
1376                         kzalloc(sizeof(struct trans_loopback_pdata),
1377                         GFP_KERNEL);
1378         if (!pdata)
1379                 return -ENOMEM;
1380
1381         pdata->perf_mode = LOW_LATENCY_PCM_MODE;
1382         snd_soc_platform_set_drvdata(platform, pdata);
1383         return 0;
1384 }
1385
1386 static int msm_transcode_loopback_remove(struct snd_soc_platform *platform)
1387 {
1388         struct trans_loopback_pdata *pdata = NULL;
1389
1390         pdata = (struct trans_loopback_pdata *)
1391                         snd_soc_platform_get_drvdata(platform);
1392         kfree(pdata);
1393         return 0;
1394 }
1395
1396 static struct snd_soc_platform_driver msm_soc_platform = {
1397         .probe          = msm_transcode_loopback_probe,
1398         .compr_ops      = &msm_transcode_loopback_ops,
1399         .pcm_new        = msm_transcode_loopback_new,
1400         .remove         = msm_transcode_loopback_remove,
1401 };
1402
1403 static int msm_transcode_dev_probe(struct platform_device *pdev)
1404 {
1405
1406         pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
1407         if (pdev->dev.of_node)
1408                 dev_set_name(&pdev->dev, "%s", "msm-transcode-loopback");
1409
1410         return snd_soc_register_platform(&pdev->dev,
1411                                         &msm_soc_platform);
1412 }
1413
1414 static int msm_transcode_remove(struct platform_device *pdev)
1415 {
1416         snd_soc_unregister_platform(&pdev->dev);
1417         return 0;
1418 }
1419
1420 static const struct of_device_id msm_transcode_loopback_dt_match[] = {
1421         {.compatible = "qcom,msm-transcode-loopback"},
1422         {}
1423 };
1424 MODULE_DEVICE_TABLE(of, msm_transcode_loopback_dt_match);
1425
1426 static struct platform_driver msm_transcode_loopback_driver = {
1427         .driver = {
1428                 .name = "msm-transcode-loopback",
1429                 .owner = THIS_MODULE,
1430                 .of_match_table = msm_transcode_loopback_dt_match,
1431         },
1432         .probe = msm_transcode_dev_probe,
1433         .remove = msm_transcode_remove,
1434 };
1435
1436 static int __init msm_soc_platform_init(void)
1437 {
1438         memset(&transcode_info, 0, sizeof(struct msm_transcode_loopback));
1439         mutex_init(&transcode_info.lock);
1440         return platform_driver_register(&msm_transcode_loopback_driver);
1441 }
1442 module_init(msm_soc_platform_init);
1443
1444 static void __exit msm_soc_platform_exit(void)
1445 {
1446         mutex_destroy(&transcode_info.lock);
1447         platform_driver_unregister(&msm_transcode_loopback_driver);
1448 }
1449 module_exit(msm_soc_platform_exit);
1450
1451 MODULE_DESCRIPTION("Transcode loopback platform driver");
1452 MODULE_LICENSE("GPL v2");