diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c old mode 100644 new mode 100755 index b084c0081f1e..70fc54190027 --- a/asoc/msm-pcm-q6-v2.c +++ b/asoc/msm-pcm-q6-v2.c @@ -129,6 +129,8 @@ static struct snd_pcm_hw_constraint_list constraints_sample_rates = { .mask = 0, }; +static struct asm_softvolume_params soft_params = {0,0,0}; + struct msm_pcm_channel_map *chmap_pspd[MSM_FRONTEND_DAI_MM_SIZE][2]; static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event, @@ -151,6 +153,181 @@ static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event, } } +static int msm_pcm_set_soft_volume_params(struct msm_audio *prtd,struct asm_softvolume_params *soft_vol_params) +{ + int rc = 0; + + switch (prtd->audio_client->topology) { + default: + rc = q6asm_set_softvolume_v2(prtd->audio_client, soft_vol_params, + SOFT_VOLUME_INSTANCE_1); + if (rc < 0) + pr_err("%s: Send SoftVolume Param failed ret=%d\n", + __func__, rc); + + } + return rc; +} + +static int msm_pcm_soft_volume_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_pcm_soft_volume *soft_vol = (struct snd_pcm_soft_volume *) snd_kcontrol_chip(kcontrol); + struct msm_plat_data *pdata = NULL; + struct snd_pcm_substream *substream = NULL; + struct snd_soc_pcm_runtime *soc_prtd = NULL; + struct snd_soc_component *component = NULL; + + pr_debug("%s\n", __func__); + + if (!soft_vol || !soft_vol->pcm) { + pr_err("%s: soft vol is NULL\n", __func__); + return -ENODEV; + } + + substream = soft_vol->pcm->streams[soft_vol->stream].substream; + if (!substream) { + pr_err("%s substream not found\n", __func__); + return -ENODEV; + } + soc_prtd = substream->private_data; + if (!soc_prtd) { + pr_err("%s substream runtime or private_data not found\n", + __func__); + return -ENODEV; + } + + component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME); + if (!component || !component->dev) { + pr_err("%s: component is NULL\n", __func__); + return -ENODEV; + } + + pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev); + if (!pdata) { + pr_err("%s: pdata not found\n", __func__); + return -ENODEV; + } + + mutex_lock(&pdata->lock); + + ucontrol->value.integer.value[0] = soft_params.period; + ucontrol->value.integer.value[1] = soft_params.step; + ucontrol->value.integer.value[2] = soft_params.rampingcurve; + pr_debug("%s: period = %d, step = %d , ramping curve: %d",__func__, + ucontrol->value.integer.value[0], + ucontrol->value.integer.value[1], + ucontrol->value.integer.value[2]); + + mutex_unlock(&pdata->lock); + return 0; +} + +static int msm_pcm_soft_volume_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + struct snd_pcm_soft_volume *soft_vol = (struct snd_pcm_soft_volume *) snd_kcontrol_chip(kcontrol); + struct msm_plat_data *pdata = NULL; + struct snd_soc_pcm_runtime *soc_prtd = NULL; + struct snd_soc_component *component = NULL; + struct snd_pcm_substream *substream = NULL; + + struct msm_audio *prtd; + + if (!soft_vol || !soft_vol->pcm) { + pr_err("%s: soft vol is NULL\n", __func__); + return -ENODEV; + } + + substream = soft_vol->pcm->streams[soft_vol->stream].substream; + if (!substream) { + pr_err("%s: substream not found\n", __func__); + return -ENODEV; + } + + soc_prtd = substream->private_data; + if (!substream->runtime || !soc_prtd) { + pr_err("%s: substream runtime or private_data not found\n", + __func__); + return -ENODEV; + } + + component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME); + if (!component || !component->dev) { + pr_err("%s: component is NULL\n", __func__); + return -ENODEV; + } + + pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev); + if (!pdata) { + pr_err("%s: pdata not found\n", __func__); + return -ENODEV; + } + + mutex_lock(&pdata->lock); + + if (substream->ref_count > 0) { + prtd = substream->runtime->private_data; + + if ( prtd) { + if ((ucontrol->value.integer.value[0] < 0) || (ucontrol->value.integer.value[0] > 15000)) { + pr_err("%s : Ramp period range (0 to 15000), input value is out of range: %d",__func__,soft_params.period); + goto exit; + } else { + soft_params.period = ucontrol->value.integer.value[0]; + } + if ((ucontrol->value.integer.value[1] < 0) || (ucontrol->value.integer.value[1] > 15000000)) { + pr_err("%s : Ramp step range (0 to 15000000), input value is out of range: %d",__func__,soft_params.step); + goto exit; + } else { + soft_params.step = ucontrol->value.integer.value[1]; + } + if ((ucontrol->value.integer.value[2] < 0) || (ucontrol->value.integer.value[2] >= SOFT_VOLUME_CURVE_ENUM_MAX)) { + pr_err("%s : Ramping curve range (0 to 2), input value is out of range: %d",__func__,soft_params.rampingcurve); + goto exit; + } else { + soft_params.rampingcurve = ucontrol->value.integer.value[2]; + } + + pr_debug("%s : soft vol params, period: %d, step: %d, ramp curve: %d",__func__,soft_params.period, + soft_params.step,soft_params.rampingcurve); + rc = msm_pcm_set_soft_volume_params(prtd, &soft_params); + } else { + pr_err("%s: prtd not found\n", __func__); + return -ENODEV; + } + } else { + pr_err("%s: substream ref count is invalid\n", __func__); + return -ENODEV; + } +exit: + mutex_unlock(&pdata->lock); + return rc; +} + +static int msm_pcm_add_soft_volume_params_control(struct snd_soc_pcm_runtime *rtd, int stream) +{ + int ret = 0; + struct snd_pcm *pcm = rtd->pcm; + struct snd_pcm_soft_volume *soft_vol = NULL; + struct snd_kcontrol *kctl = NULL; + + dev_dbg(rtd->dev, "%s, volume control add\n", __func__); + ret = snd_pcm_add_soft_volume_ctls(pcm, stream, + NULL,/* 1,*/ rtd->dai_link->id, + &soft_vol); + if (ret < 0) { + pr_err("%s volume control failed ret %d\n", __func__, ret); + return ret; + } + kctl = soft_vol->kctl; + kctl->put = msm_pcm_soft_volume_ctl_put; + kctl->get = msm_pcm_soft_volume_ctl_get; + return 0; +} + static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv) { @@ -3497,6 +3674,16 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) pr_err("%s: Could not add pcm Volume Control %d\n", __func__, ret); ret = msm_pcm_add_volume_control(rtd, SNDRV_PCM_STREAM_CAPTURE); + if (ret) + pr_err("%s: Could not add pcm Volume Control %d\n", + __func__, ret); + /* adding soft vol module params mixer control command*/ + ret = msm_pcm_add_soft_volume_params_control(rtd, SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + pr_err("%s: Could not add pcm Volume Control %d\n", + __func__, ret); + + ret = msm_pcm_add_soft_volume_params_control(rtd, SNDRV_PCM_STREAM_CAPTURE); if (ret) pr_err("%s: Could not add pcm Volume Control %d\n", __func__, ret); diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c index 5b7fc20a08e4..8d8a5931bbe7 100644 --- a/asoc/msm-pcm-routing-v2.c +++ b/asoc/msm-pcm-routing-v2.c @@ -182,6 +182,81 @@ static int msm_routing_send_device_pp_params(int port_id, int copp_idx, static void msm_routing_load_topology(size_t data_size, void *data); static void msm_routing_unload_topology(uint32_t topology_id); +static int pcm_soft_volume_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = SOFT_VOLUME_CURVE_ENUM_MAX; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = INT_MAX; + return 0; +} + +static void pcm_soft_volume_ctl_private_free(struct snd_kcontrol *kcontrol) +{ + struct snd_pcm_volume *info = snd_kcontrol_chip(kcontrol); + + kfree(info); +} + +int snd_pcm_add_soft_volume_ctls(struct snd_pcm *pcm, int stream, + const struct snd_pcm_soft_vol_usr_elem *soft_vol_params, + unsigned long private_value, + struct snd_pcm_soft_volume **info_ret) +{ + int err = 0; + int size = 0; + struct snd_pcm_soft_volume *info; + struct snd_kcontrol_new knew = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = pcm_soft_volume_ctl_info, + }; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->pcm = pcm; + info->stream = stream; + info->usr_val = soft_vol_params; + size = sizeof("Playback ") + sizeof("Soft Vol Params") + + STRING_LENGTH_OF_INT*sizeof(char) + 1; + knew.name = kzalloc(size, GFP_KERNEL); + if (!knew.name) { + kfree(info); + return -ENOMEM; + } + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + snprintf((char *)knew.name, size, "%s %d %s", + "Playback ", pcm->device, "Soft Vol Params"); + else + snprintf((char *)knew.name, size, "%s %d %s", + "Capture", pcm->device, "Soft Vol Params"); + knew.device = pcm->device; + knew.count = pcm->streams[stream].substream_count; + knew.private_value = private_value; + info->kctl = snd_ctl_new1(&knew, info); + if (!info->kctl) { + kfree(info); + kfree(knew.name); + return -ENOMEM; + } + info->kctl->private_free = pcm_soft_volume_ctl_private_free; + err = snd_ctl_add(pcm->card, info->kctl); + if (err < 0) { + kfree(info); + kfree(knew.name); + return -ENOMEM; + } + if (info_ret) + *info_ret = info; + kfree(knew.name); + + return 0; +} +EXPORT_SYMBOL(snd_pcm_add_soft_volume_ctls); + #ifndef SND_PCM_ADD_VOLUME_CTL static int pcm_volume_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) diff --git a/asoc/msm-pcm-routing-v2.h b/asoc/msm-pcm-routing-v2.h old mode 100644 new mode 100755 index 4a8e4b6eda58..6414d959eb95 --- a/asoc/msm-pcm-routing-v2.h +++ b/asoc/msm-pcm-routing-v2.h @@ -800,6 +800,26 @@ int msm_pcm_routing_set_channel_mixer_runtime( int msm_pcm_routing_set_stream_ec_ref_chmix_cfg( int fedai_id, struct msm_pcm_channel_mixer *cfg_data); + +/* array element of usr elem */ +struct snd_pcm_soft_vol_usr_elem { + int val[3]; +}; + +/* mixer control information; retrieved via snd_kcontrol_chip() */ +struct snd_pcm_soft_volume { + struct snd_pcm *pcm; /* assigned PCM instance */ + int stream; /* PLAYBACK or CAPTURE */ + struct snd_kcontrol *kctl; /* contorl handle*/ + const struct snd_pcm_soft_vol_usr_elem *usr_val; + int max_length; + void *private_data; +}; + +int snd_pcm_add_soft_volume_ctls(struct snd_pcm *pcm, int stream, + const struct snd_pcm_soft_vol_usr_elem *soft_vol_params, + unsigned long private_value, + struct snd_pcm_soft_volume **info_ret); #ifndef SND_PCM_ADD_VOLUME_CTL /* PCM Volume control API */ diff --git a/include/dsp/q6asm-v2.h b/include/dsp/q6asm-v2.h old mode 100644 new mode 100755 index eab3656e5161..37525c57a928 --- a/include/dsp/q6asm-v2.h +++ b/include/dsp/q6asm-v2.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2012-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __Q6_ASM_V2_H__ #define __Q6_ASM_V2_H__ @@ -150,6 +151,7 @@ enum { SOFT_VOLUME_CURVE_LINEAR = 0, SOFT_VOLUME_CURVE_EXP, SOFT_VOLUME_CURVE_LOG, + SOFT_VOLUME_CURVE_ENUM_MAX, }; #define SOFT_VOLUME_INSTANCE_1 1