1 /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
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.
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.
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>
41 #include "msm-pcm-routing-v2.h"
42 #include "msm-qti-pp-config.h"
44 #define LOOPBACK_SESSION_MAX_NUM_STREAMS 2
45 /* Max volume corresponding to 24dB */
46 #define TRANSCODE_LR_VOL_MAX_STEPS 0xFFFF
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
53 static DEFINE_MUTEX(transcode_loopback_session_lock);
55 struct trans_loopback_pdata {
56 struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX];
57 int32_t ion_fd[MSM_FRONTEND_DAI_MAX];
62 struct loopback_stream {
63 struct snd_compr_stream *cstream;
64 uint32_t codec_format;
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 */
79 struct msm_transcode_loopback {
80 struct loopback_stream source;
81 struct loopback_stream sink;
83 struct snd_compr_caps source_compr_cap;
84 struct snd_compr_caps sink_compr_cap;
93 struct audio_client *audio_client;
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;
101 /* Transcode loopback global info struct */
102 static struct msm_transcode_loopback transcode_info;
104 static void loopback_event_handler(uint32_t opcode,
105 uint32_t token, uint32_t *payload, void *priv)
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;
115 if (!trans || !payload) {
116 pr_err("%s: rtd or payload is NULL\n", __func__);
120 cstream = trans->sink.cstream;
121 ac = trans->audio_client;
124 * Token for rest of the compressed commands use to set
125 * session id, stream id, dir etc.
127 stream_id = q6asm_get_stream_id_from_token(token);
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",
134 rtd = cstream->private_data;
136 pr_err("%s: rtd is NULL\n", __func__);
140 ret = msm_adsp_inform_mixer_ctl(rtd, payload);
142 pr_err("%s: failed to inform mixer ctrl. err = %d\n",
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,
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,
165 pr_debug("%s: Not Supported Event opcode[0x%x]\n",
171 static void populate_codec_list(struct msm_transcode_loopback *trans,
172 struct snd_compr_stream *cstream)
174 struct snd_compr_caps compr_cap;
176 pr_debug("%s\n", __func__);
178 memset(&compr_cap, 0, sizeof(struct snd_compr_caps));
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));
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));
199 static int msm_transcode_map_ion_fd(struct msm_transcode_loopback *trans,
202 ion_phys_addr_t paddr;
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);
211 pr_err("%s: audio lib ION phys failed, rc = %d\n", __func__,
216 ret = q6core_add_remove_pool_pages(paddr, pa_len,
217 ADSP_MEMORY_MAP_HLOS_PHYSPOOL, true);
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);
230 static int msm_transcode_unmap_ion_fd(struct msm_transcode_loopback *trans)
232 ion_phys_addr_t paddr;
236 if (!trans->lib_ion_client || !trans->lib_ion_handle) {
237 pr_err("%s: ion_client or ion_handle is NULL", __func__);
240 ret = msm_audio_ion_phys_free(trans->lib_ion_client,
241 trans->lib_ion_handle,
242 &paddr, &pa_len, ADSP_TO_HLOS);
244 pr_err("%s: audio lib ION phys failed, rc = %d\n", __func__,
249 ret = q6core_add_remove_pool_pages(paddr, pa_len,
250 ADSP_MEMORY_MAP_HLOS_PHYSPOOL, false);
252 pr_err("%s: remove pages failed, rc = %d\n", __func__, ret);
258 static int msm_transcode_loopback_open(struct snd_compr_stream *cstream)
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;
266 if (cstream == NULL) {
267 pr_err("%s: Invalid substream\n", __func__);
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;
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");
282 if (cstream->direction == SND_COMPRESS_CAPTURE) {
283 if (trans->source.cstream == NULL) {
284 trans->source.cstream = cstream;
285 trans->num_streams++;
287 pr_err("%s: capture stream already opened\n",
292 } else if (cstream->direction == SND_COMPRESS_PLAYBACK) {
293 if (trans->sink.cstream == NULL) {
294 trans->sink.cstream = cstream;
295 trans->num_streams++;
297 pr_debug("%s: playback stream already opened\n",
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]);
311 pr_debug("%s: num stream%d, stream name %s\n", __func__,
312 trans->num_streams, cstream->name);
314 populate_codec_list(trans, cstream);
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;
322 runtime->private_data = trans;
325 mutex_unlock(&trans->lock);
329 static void stop_transcoding(struct msm_transcode_loopback *trans)
331 struct snd_soc_pcm_runtime *soc_pcm_rx;
332 struct snd_soc_pcm_runtime *soc_pcm_tx;
334 if (trans->audio_client != NULL) {
335 q6asm_cmd(trans->audio_client, CMD_CLOSE);
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);
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);
349 q6asm_audio_client_free(trans->audio_client);
350 trans->audio_client = NULL;
354 static int msm_transcode_loopback_free(struct snd_compr_stream *cstream)
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(
362 ion_phys_addr_t paddr;
365 mutex_lock(&trans->lock);
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);
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;
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;
385 } else if (cstream->direction == SND_COMPRESS_CAPTURE) {
386 memset(&trans->source, 0, sizeof(struct loopback_stream));
389 trans->session_state = LOOPBACK_SESSION_CLOSE;
390 mutex_unlock(&trans->lock);
394 static int msm_transcode_loopback_trigger(struct snd_compr_stream *cstream,
397 struct snd_compr_runtime *runtime = cstream->runtime;
398 struct msm_transcode_loopback *trans = runtime->private_data;
401 case SNDRV_PCM_TRIGGER_START:
402 case SNDRV_PCM_TRIGGER_RESUME:
403 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
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;
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__,
417 if (trans->session_state == LOOPBACK_SESSION_RUN)
418 q6asm_cmd_nowait(trans->audio_client, CMD_PAUSE);
419 trans->session_state = LOOPBACK_SESSION_START;
428 static int msm_transcode_loopback_set_params(struct snd_compr_stream *cstream,
429 struct snd_compr_params *codec_param)
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;
442 pr_err("%s: Invalid param\n", __func__);
446 mutex_lock(&trans->lock);
448 rtd = snd_pcm_substream_chip(cstream);
449 pdata = snd_soc_platform_get_drvdata(rtd->platform);
451 if (cstream->direction == SND_COMPRESS_PLAYBACK) {
452 if (codec_param->codec.id == SND_AUDIOCODEC_PCM) {
453 trans->sink.codec_format =
455 switch (codec_param->codec.format) {
456 case SNDRV_PCM_FORMAT_S32_LE:
459 case SNDRV_PCM_FORMAT_S24_LE:
462 case SNDRV_PCM_FORMAT_S24_3LE:
465 case SNDRV_PCM_FORMAT_S16_LE:
471 pr_debug("%s: unknown sink codec\n", __func__);
475 trans->sink.start = true;
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 =
485 case SND_AUDIOCODEC_AC3:
486 pr_debug("Source SND_AUDIOCODEC_AC3\n");
487 trans->source.codec_format =
490 case SND_AUDIOCODEC_EAC3:
491 pr_debug("Source SND_AUDIOCODEC_EAC3\n");
492 trans->source.codec_format =
496 pr_debug("%s: unknown source codec\n", __func__);
500 trans->source.start = true;
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);
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",
512 trans->session_state = LOOPBACK_SESSION_START;
515 if (trans->session_state == LOOPBACK_SESSION_START) {
516 if (trans->audio_client != NULL) {
517 pr_debug("%s: ASM client already opened, closing\n",
519 stop_transcoding(trans);
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__);
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,
535 trans->source.codec_format,
536 trans->sink.codec_format);
538 pr_err("%s: Session transcode loopback open failed\n",
540 q6asm_audio_client_free(trans->audio_client);
541 trans->audio_client = NULL;
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,
553 SNDRV_PCM_STREAM_CAPTURE,
554 COMPRESSED_PASSTHROUGH_GEN);
556 msm_pcm_routing_reg_phy_stream(
557 soc_pcm_tx->dai_link->be_id,
558 trans->audio_client->perf_mode,
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,
566 SNDRV_PCM_STREAM_PLAYBACK);
567 pr_debug("%s: Successfully opened ADM sessions\n", __func__);
570 mutex_unlock(&trans->lock);
574 static int msm_transcode_loopback_get_caps(struct snd_compr_stream *cstream,
575 struct snd_compr_caps *arg)
577 struct snd_compr_runtime *runtime;
578 struct msm_transcode_loopback *trans;
580 if (!arg || !cstream) {
581 pr_err("%s: Invalid arguments\n", __func__);
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));
592 memcpy(arg, &trans->sink_compr_cap,
593 sizeof(struct snd_compr_caps));
597 static int msm_transcode_loopback_set_metadata(struct snd_compr_stream *cstream,
598 struct snd_compr_metadata *metadata)
600 struct snd_soc_pcm_runtime *rtd;
601 struct trans_loopback_pdata *pdata;
603 if (!metadata || !cstream) {
604 pr_err("%s: Invalid arguments\n", __func__);
608 rtd = snd_pcm_substream_chip(cstream);
609 pdata = snd_soc_platform_get_drvdata(rtd->platform);
611 switch (metadata->key) {
612 case SNDRV_COMPRESS_LATENCY_MODE:
614 switch (metadata->value[0]) {
615 case SNDRV_COMPRESS_LEGACY_LATENCY_MODE:
616 pdata->perf_mode = LEGACY_PCM_MODE;
618 case SNDRV_COMPRESS_LOW_LATENCY_MODE:
619 pdata->perf_mode = LOW_LATENCY_PCM_MODE;
622 pr_debug("%s: Unsupported latency mode %d, default to Legacy\n",
623 __func__, metadata->value[0]);
624 pdata->perf_mode = LEGACY_PCM_MODE;
630 pr_debug("%s: Unsupported metadata %d\n",
631 __func__, metadata->key);
637 static int msm_transcode_stream_cmd_put(struct snd_kcontrol *kcontrol,
638 struct snd_ctl_elem_value *ucontrol)
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;
647 struct msm_adsp_event_data *event_data = NULL;
648 uint64_t actual_payload_len = 0;
650 if (fe_id >= MSM_FRONTEND_DAI_MAX) {
651 pr_err("%s Received invalid fe_id %lu\n",
657 cstream = pdata->cstream[fe_id];
658 if (cstream == NULL) {
659 pr_err("%s cstream is null.\n", __func__);
664 prtd = cstream->runtime->private_data;
666 pr_err("%s: prtd is null.\n", __func__);
671 if (prtd->audio_client == NULL) {
672 pr_err("%s: audio_client is null.\n", __func__);
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);
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);
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);
704 ret = q6asm_send_stream_cmd(prtd->audio_client, event_data);
706 pr_err("%s: failed to send stream event cmd, err = %d\n",
712 static int msm_transcode_shm_ion_fd_map_put(struct snd_kcontrol *kcontrol,
713 struct snd_ctl_elem_value *ucontrol)
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;
723 if (fe_id >= MSM_FRONTEND_DAI_MAX) {
724 pr_err("%s Received out of bounds invalid fe_id %lu\n",
730 cstream = pdata->cstream[fe_id];
731 if (cstream == NULL) {
732 pr_err("%s cstream is null\n", __func__);
737 prtd = cstream->runtime->private_data;
739 pr_err("%s: prtd is null\n", __func__);
744 if (prtd->audio_client == NULL) {
745 pr_err("%s: audio_client is null\n", __func__);
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);
756 pr_err("%s: failed to map shm mem\n", __func__);
762 static int msm_transcode_lib_ion_fd_map_put(struct snd_kcontrol *kcontrol,
763 struct snd_ctl_elem_value *ucontrol)
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);
771 if (fe_id >= MSM_FRONTEND_DAI_MAX) {
772 pr_err("%s Received out of bounds invalid fe_id %lu\n",
778 memcpy(&pdata->ion_fd[fe_id], ucontrol->value.bytes.data,
779 sizeof(pdata->ion_fd[fe_id]));
784 static int msm_transcode_rtic_event_ack_put(struct snd_kcontrol *kcontrol,
785 struct snd_ctl_elem_value *ucontrol)
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;
794 int param_length = 0;
796 if (fe_id >= MSM_FRONTEND_DAI_MAX) {
797 pr_err("%s Received invalid fe_id %lu\n",
803 cstream = pdata->cstream[fe_id];
804 if (cstream == NULL) {
805 pr_err("%s cstream is null\n", __func__);
810 prtd = cstream->runtime->private_data;
812 pr_err("%s: prtd is null\n", __func__);
817 if (prtd->audio_client == NULL) {
818 pr_err("%s: audio_client is null\n", __func__);
823 memcpy(¶m_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);
833 ret = q6asm_send_rtic_event_ack(prtd->audio_client,
834 ucontrol->value.bytes.data + sizeof(param_length),
837 pr_err("%s: failed to send rtic event ack, err = %d\n",
843 static int msm_transcode_playback_app_type_cfg_put(
844 struct snd_kcontrol *kcontrol,
845 struct snd_ctl_elem_value *ucontrol)
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};
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,
866 pr_err("%s: msm_transcode_playback_stream_app_type_cfg set failed returned %d\n",
872 static int msm_transcode_playback_app_type_cfg_get(
873 struct snd_kcontrol *kcontrol,
874 struct snd_ctl_elem_value *ucontrol)
876 u64 fe_id = kcontrol->private_value;
877 int session_type = SESSION_TYPE_RX;
879 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
882 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
885 pr_err("%s: msm_transcode_playback_stream_app_type_cfg get failed returned %d\n",
890 ucontrol->value.integer.value[APP_TYPE_CONFIG_IDX_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);
904 static int msm_transcode_set_volume(struct snd_compr_stream *cstream,
905 uint32_t master_gain)
908 struct msm_transcode_loopback *prtd;
909 struct snd_soc_pcm_runtime *rtd;
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__);
916 rtd = cstream->private_data;
917 prtd = cstream->runtime->private_data;
919 if (!rtd || !rtd->platform || !prtd || !prtd->audio_client) {
920 pr_err("%s: invalid rtd, prtd or audio client", __func__);
924 rc = q6asm_set_volume(prtd->audio_client, master_gain);
926 pr_err("%s: Send vol gain command failed rc=%d\n",
932 static int msm_transcode_volume_put(struct snd_kcontrol *kcontrol,
933 struct snd_ctl_elem_value *ucontrol)
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;
942 if (fe_id >= MSM_FRONTEND_DAI_MAX) {
943 pr_err("%s Received out of bounds fe_id %lu\n",
948 cstream = pdata->cstream[fe_id];
949 pdata->master_gain = ucontrol->value.integer.value[0];
951 pr_debug("%s: fe_id %lu master_gain %d\n",
952 __func__, fe_id, pdata->master_gain);
954 ret = msm_transcode_set_volume(cstream, pdata->master_gain);
958 static int msm_transcode_volume_get(struct snd_kcontrol *kcontrol,
959 struct snd_ctl_elem_value *ucontrol)
961 struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
962 unsigned long fe_id = kcontrol->private_value;
964 struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *)
965 snd_soc_component_get_drvdata(comp);
967 if (fe_id >= MSM_FRONTEND_DAI_MAX) {
968 pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id);
972 pr_debug("%s: fe_id %lu\n", __func__, fe_id);
973 ucontrol->value.integer.value[0] = pdata->master_gain;
978 static int msm_transcode_stream_cmd_control(
979 struct snd_soc_pcm_runtime *rtd)
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] = {
987 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
989 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
990 .info = msm_adsp_stream_cmd_info,
991 .put = msm_transcode_stream_cmd_put,
997 pr_err("%s NULL rtd\n", __func__);
1002 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1003 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
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));
1018 pr_err("%s: failed to add ctl %s. err = %d\n",
1019 __func__, mixer_str, ret);
1026 static int msm_transcode_stream_callback_control(
1027 struct snd_soc_pcm_runtime *rtd)
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;
1035 struct snd_kcontrol_new fe_loopback_callback_config_control[1] = {
1037 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1039 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1040 .info = msm_adsp_stream_callback_info,
1041 .get = msm_adsp_stream_callback_get,
1047 pr_err("%s: rtd is NULL\n", __func__);
1052 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1053 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
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));
1068 pr_err("%s: failed to add ctl %s. err = %d\n",
1069 __func__, mixer_str, ret);
1071 goto free_mixer_str;
1074 kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
1076 pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
1078 goto free_mixer_str;
1081 kctl->private_data = NULL;
1088 static int msm_transcode_add_shm_ion_fd_cmd_control(
1089 struct snd_soc_pcm_runtime *rtd)
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] = {
1097 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1099 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1100 .info = msm_adsp_stream_cmd_info,
1101 .put = msm_transcode_shm_ion_fd_map_put,
1107 pr_err("%s NULL rtd\n", __func__);
1112 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1113 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
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));
1127 pr_err("%s: failed to add ctl %s\n", __func__, mixer_str);
1134 static int msm_transcode_add_lib_ion_fd_cmd_control(
1135 struct snd_soc_pcm_runtime *rtd)
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] = {
1143 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1145 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1146 .info = msm_adsp_stream_cmd_info,
1147 .put = msm_transcode_lib_ion_fd_map_put,
1153 pr_err("%s NULL rtd\n", __func__);
1158 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1159 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
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));
1173 pr_err("%s: failed to add ctl %s\n", __func__, mixer_str);
1180 static int msm_transcode_add_event_ack_cmd_control(
1181 struct snd_soc_pcm_runtime *rtd)
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] = {
1189 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1191 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1192 .info = msm_adsp_stream_cmd_info,
1193 .put = msm_transcode_rtic_event_ack_put,
1199 pr_err("%s NULL rtd\n", __func__);
1204 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1205 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
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));
1219 pr_err("%s: failed to add ctl %s\n", __func__, mixer_str);
1226 static int msm_transcode_app_type_cfg_info(struct snd_kcontrol *kcontrol,
1227 struct snd_ctl_elem_info *uinfo)
1229 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1231 uinfo->value.integer.min = 0;
1232 uinfo->value.integer.max = 0xFFFFFFFF;
1236 static int msm_transcode_add_app_type_cfg_control(
1237 struct snd_soc_pcm_runtime *rtd)
1241 struct snd_kcontrol_new fe_app_type_cfg_control[1] = {
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,
1253 pr_err("%s NULL rtd\n", __func__);
1258 if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) {
1260 snprintf(mixer_str, sizeof(mixer_str),
1261 "Audio Stream %d App Type Cfg",
1264 fe_app_type_cfg_control[0].name = mixer_str;
1265 fe_app_type_cfg_control[0].private_value = rtd->dai_link->be_id;
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;
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));
1280 static int msm_transcode_volume_info(struct snd_kcontrol *kcontrol,
1281 struct snd_ctl_elem_info *uinfo)
1283 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1285 uinfo->value.integer.min = 0;
1286 uinfo->value.integer.max = TRANSCODE_LR_VOL_MAX_STEPS;
1290 static int msm_transcode_add_volume_control(struct snd_soc_pcm_runtime *rtd)
1292 struct snd_kcontrol_new fe_volume_control[1] = {
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,
1306 pr_err("%s NULL rtd\n", __func__);
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));
1319 static int msm_transcode_loopback_new(struct snd_soc_pcm_runtime *rtd)
1323 rc = msm_transcode_stream_cmd_control(rtd);
1325 pr_err("%s: ADSP Stream Cmd Control open failed\n", __func__);
1327 rc = msm_transcode_stream_callback_control(rtd);
1329 pr_err("%s: ADSP Stream callback Control open failed\n",
1332 rc = msm_transcode_add_shm_ion_fd_cmd_control(rtd);
1334 pr_err("%s: Could not add transcode shm ion fd Control\n",
1337 rc = msm_transcode_add_lib_ion_fd_cmd_control(rtd);
1339 pr_err("%s: Could not add transcode lib ion fd Control\n",
1342 rc = msm_transcode_add_event_ack_cmd_control(rtd);
1344 pr_err("%s: Could not add transcode event ack Control\n",
1347 rc = msm_transcode_add_app_type_cfg_control(rtd);
1349 pr_err("%s: Could not add Compr App Type Cfg Control\n",
1352 rc = msm_transcode_add_volume_control(rtd);
1354 pr_err("%s: Could not add transcode volume Control\n",
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,
1370 static int msm_transcode_loopback_probe(struct snd_soc_platform *platform)
1372 struct trans_loopback_pdata *pdata = NULL;
1374 pr_debug("%s\n", __func__);
1375 pdata = (struct trans_loopback_pdata *)
1376 kzalloc(sizeof(struct trans_loopback_pdata),
1381 pdata->perf_mode = LOW_LATENCY_PCM_MODE;
1382 snd_soc_platform_set_drvdata(platform, pdata);
1386 static int msm_transcode_loopback_remove(struct snd_soc_platform *platform)
1388 struct trans_loopback_pdata *pdata = NULL;
1390 pdata = (struct trans_loopback_pdata *)
1391 snd_soc_platform_get_drvdata(platform);
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,
1403 static int msm_transcode_dev_probe(struct platform_device *pdev)
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");
1410 return snd_soc_register_platform(&pdev->dev,
1414 static int msm_transcode_remove(struct platform_device *pdev)
1416 snd_soc_unregister_platform(&pdev->dev);
1420 static const struct of_device_id msm_transcode_loopback_dt_match[] = {
1421 {.compatible = "qcom,msm-transcode-loopback"},
1424 MODULE_DEVICE_TABLE(of, msm_transcode_loopback_dt_match);
1426 static struct platform_driver msm_transcode_loopback_driver = {
1428 .name = "msm-transcode-loopback",
1429 .owner = THIS_MODULE,
1430 .of_match_table = msm_transcode_loopback_dt_match,
1432 .probe = msm_transcode_dev_probe,
1433 .remove = msm_transcode_remove,
1436 static int __init msm_soc_platform_init(void)
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);
1442 module_init(msm_soc_platform_init);
1444 static void __exit msm_soc_platform_exit(void)
1446 mutex_destroy(&transcode_info.lock);
1447 platform_driver_unregister(&msm_transcode_loopback_driver);
1449 module_exit(msm_soc_platform_exit);
1451 MODULE_DESCRIPTION("Transcode loopback platform driver");
1452 MODULE_LICENSE("GPL v2");