diff --git a/asoc/msm-transcode-loopback-q6-v2.c b/asoc/msm-transcode-loopback-q6-v2.c index fb70f6cb7a..f44e87d44d 100644 --- a/asoc/msm-transcode-loopback-q6-v2.c +++ b/asoc/msm-transcode-loopback-q6-v2.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include #include +#include #include "msm-pcm-routing-v2.h" #include "msm-qti-pp-config.h" @@ -50,10 +52,20 @@ static DEFINE_MUTEX(transcode_loopback_session_lock); +struct msm_transcode_audio_effects { + struct bass_boost_params bass_boost; + struct pbe_params pbe; + struct virtualizer_params virtualizer; + struct reverb_params reverb; + struct eq_params equalizer; + struct soft_volume_params volume; +}; + struct trans_loopback_pdata { struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX]; uint32_t master_gain; int perf_mode; + struct msm_transcode_audio_effects *audio_effects[MSM_FRONTEND_DAI_MAX]; }; struct loopback_stream { @@ -204,6 +216,13 @@ static int msm_transcode_loopback_open(struct snd_compr_stream *cstream) rtd = snd_pcm_substream_chip(cstream); pdata = snd_soc_platform_get_drvdata(rtd->platform); pdata->cstream[rtd->dai_link->id] = cstream; + pdata->audio_effects[rtd->dai_link->id] = + kzalloc(sizeof(struct msm_transcode_audio_effects), GFP_KERNEL); + + if (pdata->audio_effects[rtd->dai_link->id] == NULL) { + ret = -ENOMEM; + goto effect_error; + } mutex_lock(&trans->lock); if (trans->num_streams > LOOPBACK_SESSION_MAX_NUM_STREAMS) { @@ -250,6 +269,11 @@ static int msm_transcode_loopback_open(struct snd_compr_stream *cstream) exit: mutex_unlock(&trans->lock); + if ((pdata->audio_effects[rtd->dai_link->id] != NULL) && (ret < 0)) { + kfree(pdata->audio_effects[rtd->dai_link->id]); + pdata->audio_effects[rtd->dai_link->id] = NULL; + } +effect_error: return ret; } @@ -283,10 +307,18 @@ static int msm_transcode_loopback_free(struct snd_compr_stream *cstream) struct snd_compr_runtime *runtime = cstream->runtime; struct msm_transcode_loopback *trans = runtime->private_data; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(cstream); + struct trans_loopback_pdata *pdata; int ret = 0; + pdata = snd_soc_platform_get_drvdata(rtd->platform); + mutex_lock(&trans->lock); + if (pdata->audio_effects[rtd->dai_link->id] != NULL) { + kfree(pdata->audio_effects[rtd->dai_link->id]); + pdata->audio_effects[rtd->dai_link->id] = NULL; + } + pr_debug("%s: Transcode loopback end:%d, streams %d\n", __func__, cstream->direction, trans->num_streams); trans->num_streams--; @@ -338,6 +370,39 @@ static int msm_transcode_loopback_trigger(struct snd_compr_stream *cstream, return 0; } +static int msm_transcode_set_render_window(struct audio_client *ac, + uint32_t ws_lsw, uint32_t ws_msw, + uint32_t we_lsw, uint32_t we_msw) +{ + int ret = -EINVAL; + struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window; + uint32_t param_id; + + pr_debug("%s, ws_lsw 0x%x ws_msw 0x%x we_lsw 0x%x we_msw 0x%x\n", + __func__, ws_lsw, ws_msw, we_lsw, we_msw); + + memset(&asm_mtmx_strtr_window, 0, + sizeof(struct asm_session_mtmx_strtr_param_window_v2_t)); + asm_mtmx_strtr_window.window_lsw = ws_lsw; + asm_mtmx_strtr_window.window_msw = ws_msw; + param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_START_V2; + ret = q6asm_send_mtmx_strtr_window(ac, &asm_mtmx_strtr_window, param_id); + if (ret) { + pr_err("%s, start window can't be set error %d\n", __func__, ret); + goto exit; + } + + asm_mtmx_strtr_window.window_lsw = we_lsw; + asm_mtmx_strtr_window.window_msw = we_msw; + param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_END_V2; + ret = q6asm_send_mtmx_strtr_window(ac, &asm_mtmx_strtr_window, param_id); + if (ret) + pr_err("%s, end window can't be set error %d\n", __func__, ret); + +exit: + return ret; +} + static int msm_transcode_loopback_set_params(struct snd_compr_stream *cstream, struct snd_compr_params *codec_param) { @@ -512,6 +577,8 @@ static int msm_transcode_loopback_set_metadata(struct snd_compr_stream *cstream, { struct snd_soc_pcm_runtime *rtd; struct trans_loopback_pdata *pdata; + struct msm_transcode_loopback *prtd = NULL; + struct audio_client *ac = NULL; if (!metadata || !cstream) { pr_err("%s: Invalid arguments\n", __func__); @@ -521,6 +588,15 @@ static int msm_transcode_loopback_set_metadata(struct snd_compr_stream *cstream, rtd = snd_pcm_substream_chip(cstream); pdata = snd_soc_platform_get_drvdata(rtd->platform); + prtd = cstream->runtime->private_data; + + if (!prtd || !prtd->audio_client) { + pr_err("%s: prtd or audio client is NULL\n", __func__); + return -EINVAL; + } + + ac = prtd->audio_client; + switch (metadata->key) { case SNDRV_COMPRESS_LATENCY_MODE: { @@ -537,8 +613,17 @@ static int msm_transcode_loopback_set_metadata(struct snd_compr_stream *cstream, pdata->perf_mode = LEGACY_PCM_MODE; break; } - } break; + } + case SNDRV_COMPRESS_RENDER_WINDOW: + { + return msm_transcode_set_render_window( + ac, + metadata->value[0], + metadata->value[1], + metadata->value[2], + metadata->value[3]); + } default: pr_debug("%s: Unsupported metadata %d\n", __func__, metadata->key); @@ -852,6 +937,192 @@ static int msm_transcode_volume_get(struct snd_kcontrol *kcontrol, return 0; } +static int msm_transcode_audio_effects_config_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = MAX_PP_PARAMS_SZ; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xFFFFFFFF; + return 0; +} + +static int msm_transcode_audio_effects_config_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + unsigned long fe_id = kcontrol->private_value; + struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *) + snd_soc_component_get_drvdata(comp); + struct msm_transcode_audio_effects *audio_effects = NULL; + struct snd_compr_stream *cstream = NULL; + + pr_debug("%s: fe_id: %lu\n", __func__, fe_id); + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received out of bounds fe_id %lu\n", + __func__, fe_id); + return -EINVAL; + } + cstream = pdata->cstream[fe_id]; + audio_effects = pdata->audio_effects[fe_id]; + if (!cstream || !audio_effects) { + pr_err("%s: stream or effects inactive\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int msm_transcode_audio_effects_config_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + unsigned long fe_id = kcontrol->private_value; + struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *) + snd_soc_component_get_drvdata(comp); + struct msm_transcode_audio_effects *audio_effects = NULL; + struct snd_compr_stream *cstream = NULL; + struct msm_transcode_loopback *prtd = NULL; + long *values = &(ucontrol->value.integer.value[0]); + int effects_module; + int ret = 0; + + pr_debug("%s: fe_id: %lu\n", __func__, fe_id); + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received out of bounds fe_id %lu\n", + __func__, fe_id); + ret = -EINVAL; + goto exit; + } + cstream = pdata->cstream[fe_id]; + audio_effects = pdata->audio_effects[fe_id]; + if (!cstream || !audio_effects) { + pr_err("%s: stream or effects inactive\n", __func__); + ret = -EINVAL; + goto exit; + } + prtd = cstream->runtime->private_data; + if (!prtd) { + pr_err("%s: cannot set audio effects\n", __func__); + ret = -EINVAL; + goto exit; + } + + effects_module = *values++; + switch (effects_module) { + case VIRTUALIZER_MODULE: + pr_debug("%s: VIRTUALIZER_MODULE\n", __func__); + if (msm_audio_effects_is_effmodule_supp_in_top(effects_module, + prtd->audio_client->topology)) + ret = msm_audio_effects_virtualizer_handler( + prtd->audio_client, + &(audio_effects->virtualizer), + values); + break; + case REVERB_MODULE: + pr_debug("%s: REVERB_MODULE\n", __func__); + if (msm_audio_effects_is_effmodule_supp_in_top(effects_module, + prtd->audio_client->topology)) + ret = msm_audio_effects_reverb_handler(prtd->audio_client, + &(audio_effects->reverb), + values); + break; + case BASS_BOOST_MODULE: + pr_debug("%s: BASS_BOOST_MODULE\n", __func__); + if (msm_audio_effects_is_effmodule_supp_in_top(effects_module, + prtd->audio_client->topology)) + ret = msm_audio_effects_bass_boost_handler(prtd->audio_client, + &(audio_effects->bass_boost), + values); + break; + case PBE_MODULE: + pr_debug("%s: PBE_MODULE\n", __func__); + if (msm_audio_effects_is_effmodule_supp_in_top(effects_module, + prtd->audio_client->topology)) + ret = msm_audio_effects_pbe_handler(prtd->audio_client, + &(audio_effects->pbe), + values); + break; + case EQ_MODULE: + pr_debug("%s: EQ_MODULE\n", __func__); + if (msm_audio_effects_is_effmodule_supp_in_top(effects_module, + prtd->audio_client->topology)) + ret = msm_audio_effects_popless_eq_handler(prtd->audio_client, + &(audio_effects->equalizer), + values); + break; + case SOFT_VOLUME_MODULE: + pr_debug("%s: SOFT_VOLUME_MODULE\n", __func__); + break; + case SOFT_VOLUME2_MODULE: + pr_debug("%s: SOFT_VOLUME2_MODULE\n", __func__); + if (msm_audio_effects_is_effmodule_supp_in_top(effects_module, + prtd->audio_client->topology)) + ret = msm_audio_effects_volume_handler_v2(prtd->audio_client, + &(audio_effects->volume), + values, SOFT_VOLUME_INSTANCE_2); + break; + default: + pr_err("%s Invalid effects config module\n", __func__); + ret = -EINVAL; + } + +exit: + return ret; +} + +static int msm_transcode_add_audio_effects_control(struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = "Audio Effects Config"; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0; + int ret = 0; + struct snd_kcontrol_new fe_audio_effects_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_transcode_audio_effects_config_info, + .get = msm_transcode_audio_effects_config_get, + .put = msm_transcode_audio_effects_config_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s NULL rtd\n", __func__); + ret = -EINVAL; + goto done; + } + + pr_debug("%s: added new compr FE with name %s, id %d, cpu dai %s, device no %d\n", __func__, + rtd->dai_link->name, rtd->dai_link->id, + rtd->dai_link->cpu_dai_name, rtd->pcm->device); + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + + fe_audio_effects_config_control[0].name = mixer_str; + fe_audio_effects_config_control[0].private_value = rtd->dai_link->id; + ret = snd_soc_add_platform_controls(rtd->platform, + fe_audio_effects_config_control, + ARRAY_SIZE(fe_audio_effects_config_control)); + if (ret < 0) + pr_err("%s: failed to add ctl %s. err = %d\n", __func__, mixer_str, ret); + + kfree(mixer_str); +done: + return ret; +} + static int msm_transcode_stream_cmd_control( struct snd_soc_pcm_runtime *rtd) { @@ -1147,6 +1418,11 @@ static int msm_transcode_loopback_new(struct snd_soc_pcm_runtime *rtd) { int rc; + rc = msm_transcode_add_audio_effects_control(rtd); + if (rc) + pr_err("%s: Could not add Compr Audio Effects Control\n", + __func__); + rc = msm_transcode_stream_cmd_control(rtd); if (rc) pr_err("%s: ADSP Stream Cmd Control open failed\n", __func__); @@ -1192,6 +1468,7 @@ static struct snd_compr_ops msm_transcode_loopback_ops = { static int msm_transcode_loopback_probe(struct snd_soc_platform *platform) { struct trans_loopback_pdata *pdata = NULL; + int i; pr_debug("%s\n", __func__); pdata = (struct trans_loopback_pdata *) @@ -1201,6 +1478,9 @@ static int msm_transcode_loopback_probe(struct snd_soc_platform *platform) return -ENOMEM; pdata->perf_mode = LOW_LATENCY_PCM_MODE; + for (i = 0; i < MSM_FRONTEND_DAI_MAX; i++) + pdata->audio_effects[i] = NULL; + snd_soc_platform_set_drvdata(platform, pdata); return 0; }