mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 12:58:12 -04:00
asoc: support per-stream ec_ref chmix
Per-stream EC Ref mixer controls are added to support stream based channel mixer for ec_ref signal. Signed-off-by: Erin Yan <xinyey@codeaurora.org> Change-Id: I89eb125e9b01b7bcdbb038148ec93d85a19cf3d5
This commit is contained in:
parent
9f0c670400
commit
ed17c8fcb6
5 changed files with 1105 additions and 3 deletions
|
|
@ -67,6 +67,7 @@ struct msm_pcm_pdata {
|
|||
int perf_mode;
|
||||
struct snd_pcm *pcm_device[MSM_FRONTEND_DAI_MM_SIZE];
|
||||
struct msm_pcm_channel_mixer *chmixer_pspd[MSM_FRONTEND_DAI_MM_SIZE][2];
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref[MSM_FRONTEND_DAI_MM_SIZE];
|
||||
};
|
||||
|
||||
static void stop_pcm(struct msm_pcm_loopback *pcm);
|
||||
|
|
@ -1448,6 +1449,459 @@ fail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_cfg_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
/* 2 int values: input_channel, output_channel */
|
||||
uinfo->count = 2;
|
||||
/* Valid range is all positive values to support above controls */
|
||||
uinfo->value.integer.min = 1;
|
||||
uinfo->value.integer.max = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_cfg_ctl_get(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ucontrol->value.integer.value[0] = chmixer_ec_ref->input_channel;
|
||||
ucontrol->value.integer.value[1] = chmixer_ec_ref->output_channel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_cfg_ctl_put(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref->input_channel = ucontrol->value.integer.value[0];
|
||||
chmixer_ec_ref->output_channel = ucontrol->value.integer.value[1];
|
||||
|
||||
if (chmixer_ec_ref->input_channel < 0 ||
|
||||
chmixer_ec_ref->input_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8 ||
|
||||
chmixer_ec_ref->output_channel < 0 ||
|
||||
chmixer_ec_ref->output_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
|
||||
pr_err("%s: Invalid channels, in %d, out %d\n",
|
||||
__func__, chmixer_ec_ref->input_channel,
|
||||
chmixer_ec_ref->output_channel);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* cache value and take effect during adm open stage */
|
||||
msm_pcm_routing_set_stream_ec_ref_chmix_cfg(fe_id, chmixer_ec_ref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_add_chmixer_ec_ref_controls(
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
const char *capture_mixer_ctl_name = "AudStr Cap";
|
||||
const char *suffix = "EC Ref ChMixer Cfg";
|
||||
int session_type = 0, ret = 0, channel = -1;
|
||||
struct msm_pcm_pdata *pdata = NULL;
|
||||
struct snd_soc_component *component = NULL;
|
||||
struct snd_kcontrol_new channel_mixer_cfg_control = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "?",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = msm_pcm_chmixer_ec_ref_cfg_info,
|
||||
.put = msm_pcm_chmixer_ec_ref_cfg_ctl_put,
|
||||
.get = msm_pcm_chmixer_ec_ref_cfg_ctl_get,
|
||||
.private_value = 0,
|
||||
};
|
||||
|
||||
component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
if (!component) {
|
||||
pr_err("%s: component is NULL\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pdata = (struct msm_pcm_pdata *)
|
||||
dev_get_drvdata(component->dev);
|
||||
|
||||
pdata->pcm_device[rtd->dai_link->id] = rtd->pcm;
|
||||
|
||||
/* only apply for TX path */
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
|
||||
session_type = SESSION_TYPE_TX;
|
||||
ret = msm_pcm_add_platform_controls(
|
||||
&channel_mixer_cfg_control,
|
||||
rtd, capture_mixer_ctl_name, suffix,
|
||||
session_type, channel);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
pr_err("%s: failed add platform ctl, err = %d\n",
|
||||
__func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_weight_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
|
||||
/* Valid range: 0 to 0x4000(Unity) gain weightage */
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 0x4000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_weight_ctl_get(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
int channel = (kcontrol->private_value >> 16) & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
|
||||
pr_err("%s: invalid channel %d\n",
|
||||
__func__, channel);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
|
||||
ucontrol->value.integer.value[i] =
|
||||
chmixer_ec_ref->channel_weight[channel-1][i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_weight_ctl_put(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
int channel = (kcontrol->private_value >> 16) & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
|
||||
pr_err("%s: invalid channel %d\n",
|
||||
__func__, channel);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
|
||||
chmixer_ec_ref->channel_weight[channel-1][i] =
|
||||
ucontrol->value.integer.value[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_add_chmixer_ec_ref_weight_controls(
|
||||
struct snd_soc_pcm_runtime *rtd,
|
||||
int channel)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
const char *capture_mixer_ctl_name = "AudStr Cap";
|
||||
const char *suffix = "EC Ref ChMixer Weight Ch";
|
||||
int session_type = 0, ret = 0;
|
||||
struct snd_kcontrol_new channel_mixer_weight_control = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "?",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = msm_pcm_chmixer_ec_ref_weight_info,
|
||||
.put = msm_pcm_chmixer_ec_ref_weight_ctl_put,
|
||||
.get = msm_pcm_chmixer_ec_ref_weight_ctl_get,
|
||||
.private_value = 0,
|
||||
};
|
||||
|
||||
/* only apply for TX path */
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
|
||||
session_type = SESSION_TYPE_TX;
|
||||
ret = msm_pcm_add_platform_controls(
|
||||
&channel_mixer_weight_control,
|
||||
rtd, capture_mixer_ctl_name, suffix,
|
||||
session_type, channel);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
pr_err("%s: failed add platform ctl, err = %d\n",
|
||||
__func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_input_map_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
|
||||
/* Valid channel map value ranges from 1 to 64 */
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 64;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_output_map_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
|
||||
/* Valid channel map value ranges from 1 to 64 */
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 64;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_input_map_ctl_get(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
|
||||
ucontrol->value.integer.value[i] =
|
||||
chmixer_ec_ref->in_ch_map[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_input_map_ctl_put(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref->override_in_ch_map = true;
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
|
||||
chmixer_ec_ref->in_ch_map[i] =
|
||||
ucontrol->value.integer.value[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_output_map_ctl_get(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
|
||||
ucontrol->value.integer.value[i] =
|
||||
chmixer_ec_ref->out_ch_map[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_output_map_ctl_put(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref->override_out_ch_map = true;
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
|
||||
chmixer_ec_ref->out_ch_map[i] =
|
||||
ucontrol->value.integer.value[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_add_chmixer_ec_ref_input_map_controls(
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
const char *capture_mixer_ctl_name = "AudStr Cap";
|
||||
const char *suffix = "EC Ref ChMixer Input Map";
|
||||
int session_type = 0, ret = 0, channel = -1;
|
||||
struct snd_kcontrol_new channel_mixer_input_map_control = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "?",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = msm_pcm_chmixer_ec_ref_input_map_info,
|
||||
.put = msm_pcm_chmixer_ec_ref_input_map_ctl_put,
|
||||
.get = msm_pcm_chmixer_ec_ref_input_map_ctl_get,
|
||||
.private_value = 0,
|
||||
};
|
||||
|
||||
/* only apply for TX path */
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
|
||||
session_type = SESSION_TYPE_TX;
|
||||
ret = msm_pcm_add_platform_controls(
|
||||
&channel_mixer_input_map_control,
|
||||
rtd, capture_mixer_ctl_name,
|
||||
suffix, session_type, channel);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
pr_err("%s: failed add platform ctl, err = %d\n",
|
||||
__func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_pcm_add_chmixer_ec_ref_output_map_controls(
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
const char *capture_mixer_ctl_name = "AudStr Cap";
|
||||
const char *suffix = "EC Ref ChMixer Output Map";
|
||||
int session_type = 0, ret = 0, channel = -1;
|
||||
struct snd_kcontrol_new channel_mixer_output_map_control = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "?",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = msm_pcm_chmixer_ec_ref_output_map_info,
|
||||
.put = msm_pcm_chmixer_ec_ref_output_map_ctl_put,
|
||||
.get = msm_pcm_chmixer_ec_ref_output_map_ctl_get,
|
||||
.private_value = 0,
|
||||
};
|
||||
|
||||
/* only apply for TX path */
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
|
||||
session_type = SESSION_TYPE_TX;
|
||||
ret = msm_pcm_add_platform_controls(
|
||||
&channel_mixer_output_map_control,
|
||||
rtd, capture_mixer_ctl_name,
|
||||
suffix, session_type, channel);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
pr_err("%s: failed add platform ctl, err = %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
|
@ -1494,6 +1948,18 @@ static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
|
|||
}
|
||||
}
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream &&
|
||||
!pdata->chmixer_ec_ref[rtd->dai_link->id]) {
|
||||
pdata->chmixer_ec_ref[rtd->dai_link->id] =
|
||||
kzalloc(sizeof(struct msm_pcm_channel_mixer),
|
||||
GFP_KERNEL);
|
||||
if (!pdata->chmixer_ec_ref[rtd->dai_link->id]) {
|
||||
pr_err("%s: fail to allocate memory\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = msm_pcm_add_channel_mixer_cfg_controls(rtd);
|
||||
if (ret) {
|
||||
pr_err("%s: pcm add channel mixer cfg controls failed:%d\n",
|
||||
|
|
@ -1513,6 +1979,26 @@ static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
ret = msm_pcm_add_chmixer_ec_ref_controls(rtd);
|
||||
if (ret) {
|
||||
pr_err("%s: pcm add ef_ref channel mixer cfg controls failed:%d\n",
|
||||
__func__, ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = msm_pcm_add_chmixer_ec_ref_input_map_controls(rtd);
|
||||
if (ret) {
|
||||
pr_err("%s: pcm add ec_ref channel mixer input map controls failed:%d\n",
|
||||
__func__, ret);
|
||||
goto fail;
|
||||
}
|
||||
ret = msm_pcm_add_chmixer_ec_ref_output_map_controls(rtd);
|
||||
if (ret) {
|
||||
pr_err("%s: pcm add ec_ref channel mixer output map controls failed:%d\n",
|
||||
__func__, ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 1; i <= PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++) {
|
||||
ret = msm_pcm_add_channel_mixer_weight_controls(rtd, i);
|
||||
if (ret) {
|
||||
|
|
@ -1520,6 +2006,13 @@ static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
|
|||
__func__, ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = msm_pcm_add_chmixer_ec_ref_weight_controls(rtd, i);
|
||||
if (ret) {
|
||||
pr_err("%s: pcm add ec_ref channel weight controls failed:%d\n",
|
||||
__func__, ret);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
|
@ -1528,6 +2021,8 @@ fail:
|
|||
kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]);
|
||||
pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] = NULL;
|
||||
pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] = NULL;
|
||||
kfree(pdata->chmixer_ec_ref[rtd->dai_link->id]);
|
||||
pdata->chmixer_ec_ref[rtd->dai_link->id] = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1800,6 +2295,7 @@ static int msm_pcm_remove(struct platform_device *pdev)
|
|||
for (i = 0; i < MSM_FRONTEND_DAI_MM_SIZE; i++) {
|
||||
kfree(pdata->chmixer_pspd[i][SESSION_TYPE_RX]);
|
||||
kfree(pdata->chmixer_pspd[i][SESSION_TYPE_TX]);
|
||||
kfree(pdata->chmixer_ec_ref[i]);
|
||||
}
|
||||
}
|
||||
kfree(pdata);
|
||||
|
|
|
|||
|
|
@ -2829,6 +2829,458 @@ fail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_cfg_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
/* 2 int values: input_channel, output_channel */
|
||||
uinfo->count = 2;
|
||||
/* Valid range is all positive values to support above controls */
|
||||
uinfo->value.integer.min = 1;
|
||||
uinfo->value.integer.max = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_cfg_ctl_get(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ucontrol->value.integer.value[0] = chmixer_ec_ref->input_channel;
|
||||
ucontrol->value.integer.value[1] = chmixer_ec_ref->output_channel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_cfg_ctl_put(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref->input_channel = ucontrol->value.integer.value[0];
|
||||
chmixer_ec_ref->output_channel = ucontrol->value.integer.value[1];
|
||||
|
||||
if (chmixer_ec_ref->input_channel < 0 ||
|
||||
chmixer_ec_ref->input_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8 ||
|
||||
chmixer_ec_ref->output_channel < 0 ||
|
||||
chmixer_ec_ref->output_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
|
||||
pr_err("%s: Invalid channels, in %d, out %d\n",
|
||||
__func__, chmixer_ec_ref->input_channel,
|
||||
chmixer_ec_ref->output_channel);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* cache value and take effect during adm open stage */
|
||||
msm_pcm_routing_set_stream_ec_ref_chmix_cfg(fe_id, chmixer_ec_ref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_add_chmixer_ec_ref_controls(
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
const char *capture_mixer_ctl_name = "AudStr Cap";
|
||||
const char *suffix = "EC Ref ChMixer Cfg";
|
||||
int session_type = 0, ret = 0, channel = -1;
|
||||
struct msm_plat_data *pdata = NULL;
|
||||
struct snd_soc_component *component = NULL;
|
||||
struct snd_kcontrol_new channel_mixer_cfg_control = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "?",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = msm_pcm_chmixer_ec_ref_cfg_info,
|
||||
.put = msm_pcm_chmixer_ec_ref_cfg_ctl_put,
|
||||
.get = msm_pcm_chmixer_ec_ref_cfg_ctl_get,
|
||||
.private_value = 0,
|
||||
};
|
||||
|
||||
component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
if (!component) {
|
||||
pr_err("%s: component is NULL\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pdata = (struct msm_plat_data *)
|
||||
dev_get_drvdata(component->dev);
|
||||
|
||||
pdata->pcm_device[rtd->dai_link->id] = rtd->pcm;
|
||||
|
||||
/* only apply for TX path */
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
|
||||
session_type = SESSION_TYPE_TX;
|
||||
ret = msm_pcm_add_platform_controls(
|
||||
&channel_mixer_cfg_control,
|
||||
rtd, capture_mixer_ctl_name, suffix,
|
||||
session_type, channel);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
pr_err("%s: failed add platform ctl, err = %d\n",
|
||||
__func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_weight_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
|
||||
/* Valid range: 0 to 0x4000(Unity) gain weightage */
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 0x4000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_weight_ctl_get(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
int channel = (kcontrol->private_value >> 16) & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
|
||||
pr_err("%s: invalid channel %d\n",
|
||||
__func__, channel);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
|
||||
ucontrol->value.integer.value[i] =
|
||||
chmixer_ec_ref->channel_weight[channel-1][i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_weight_ctl_put(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
int channel = (kcontrol->private_value >> 16) & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
|
||||
pr_err("%s: invalid channel %d\n",
|
||||
__func__, channel);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
|
||||
chmixer_ec_ref->channel_weight[channel-1][i] =
|
||||
ucontrol->value.integer.value[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_add_chmixer_ec_ref_weight_controls(
|
||||
struct snd_soc_pcm_runtime *rtd,
|
||||
int channel)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
const char *capture_mixer_ctl_name = "AudStr Cap";
|
||||
const char *suffix = "EC Ref ChMixer Weight Ch";
|
||||
int session_type = 0, ret = 0;
|
||||
struct snd_kcontrol_new channel_mixer_weight_control = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "?",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = msm_pcm_chmixer_ec_ref_weight_info,
|
||||
.put = msm_pcm_chmixer_ec_ref_weight_ctl_put,
|
||||
.get = msm_pcm_chmixer_ec_ref_weight_ctl_get,
|
||||
.private_value = 0,
|
||||
};
|
||||
|
||||
/* only apply for TX path */
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
|
||||
session_type = SESSION_TYPE_TX;
|
||||
ret = msm_pcm_add_platform_controls(
|
||||
&channel_mixer_weight_control,
|
||||
rtd, capture_mixer_ctl_name, suffix,
|
||||
session_type, channel);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
pr_err("%s: failed add platform ctl, err = %d\n",
|
||||
__func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_input_map_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
|
||||
/* Valid channel map value ranges from 1 to 64 */
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 64;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_output_map_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
|
||||
/* Valid channel map value ranges from 1 to 64 */
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 64;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_input_map_ctl_get(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
|
||||
ucontrol->value.integer.value[i] =
|
||||
chmixer_ec_ref->in_ch_map[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_input_map_ctl_put(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref->override_in_ch_map = true;
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
|
||||
chmixer_ec_ref->in_ch_map[i] =
|
||||
ucontrol->value.integer.value[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_output_map_ctl_get(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
|
||||
ucontrol->value.integer.value[i] =
|
||||
chmixer_ec_ref->out_ch_map[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmixer_ec_ref_output_map_ctl_put(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u16 fe_id = kcontrol->private_value & 0xFF;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s missing pdata\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref = pdata->chmixer_ec_ref[fe_id];
|
||||
if (!chmixer_ec_ref) {
|
||||
pr_err("%s: invalid chmixer_ec_ref in pdata", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chmixer_ec_ref->override_out_ch_map = true;
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
|
||||
chmixer_ec_ref->out_ch_map[i] =
|
||||
ucontrol->value.integer.value[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_add_chmixer_ec_ref_input_map_controls(
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
const char *capture_mixer_ctl_name = "AudStr Cap";
|
||||
const char *suffix = "EC Ref ChMixer Input Map";
|
||||
int session_type = 0, ret = 0, channel = -1;
|
||||
struct snd_kcontrol_new channel_mixer_input_map_control = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "?",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = msm_pcm_chmixer_ec_ref_input_map_info,
|
||||
.put = msm_pcm_chmixer_ec_ref_input_map_ctl_put,
|
||||
.get = msm_pcm_chmixer_ec_ref_input_map_ctl_get,
|
||||
.private_value = 0,
|
||||
};
|
||||
|
||||
/* only apply for TX path */
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
|
||||
session_type = SESSION_TYPE_TX;
|
||||
ret = msm_pcm_add_platform_controls(
|
||||
&channel_mixer_input_map_control,
|
||||
rtd, capture_mixer_ctl_name,
|
||||
suffix, session_type, channel);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
pr_err("%s: failed add platform ctl, err = %d\n",
|
||||
__func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_pcm_add_chmixer_ec_ref_output_map_controls(
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
const char *capture_mixer_ctl_name = "AudStr Cap";
|
||||
const char *suffix = "EC Ref ChMixer Output Map";
|
||||
int session_type = 0, ret = 0, channel = -1;
|
||||
struct snd_kcontrol_new channel_mixer_output_map_control = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "?",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = msm_pcm_chmixer_ec_ref_output_map_info,
|
||||
.put = msm_pcm_chmixer_ec_ref_output_map_ctl_put,
|
||||
.get = msm_pcm_chmixer_ec_ref_output_map_ctl_get,
|
||||
.private_value = 0,
|
||||
};
|
||||
|
||||
/* only apply for TX path */
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
|
||||
session_type = SESSION_TYPE_TX;
|
||||
ret = msm_pcm_add_platform_controls(
|
||||
&channel_mixer_output_map_control,
|
||||
rtd, capture_mixer_ctl_name,
|
||||
suffix, session_type, channel);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
pr_err("%s: failed add platform ctl, err = %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
|
@ -2875,6 +3327,18 @@ static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
|
|||
}
|
||||
}
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream &&
|
||||
!pdata->chmixer_ec_ref[rtd->dai_link->id]) {
|
||||
pdata->chmixer_ec_ref[rtd->dai_link->id] =
|
||||
kzalloc(sizeof(struct msm_pcm_channel_mixer),
|
||||
GFP_KERNEL);
|
||||
if (!pdata->chmixer_ec_ref[rtd->dai_link->id]) {
|
||||
pr_err("%s: fail to allocate memory\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = msm_pcm_add_channel_mixer_cfg_controls(rtd);
|
||||
if (ret) {
|
||||
pr_err("%s: pcm add channel mixer cfg controls failed:%d\n",
|
||||
|
|
@ -2887,6 +3351,7 @@ static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
|
|||
__func__, ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = msm_pcm_add_channel_mixer_output_map_controls(rtd);
|
||||
if (ret) {
|
||||
pr_err("%s: pcm add channel mixer output map controls failed:%d\n",
|
||||
|
|
@ -2894,6 +3359,26 @@ static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
ret = msm_pcm_add_chmixer_ec_ref_controls(rtd);
|
||||
if (ret) {
|
||||
pr_err("%s: pcm add ef_ref channel mixer cfg controls failed:%d\n",
|
||||
__func__, ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = msm_pcm_add_chmixer_ec_ref_input_map_controls(rtd);
|
||||
if (ret) {
|
||||
pr_err("%s: pcm add ec_ref channel mixer input map controls failed:%d\n",
|
||||
__func__, ret);
|
||||
goto fail;
|
||||
}
|
||||
ret = msm_pcm_add_chmixer_ec_ref_output_map_controls(rtd);
|
||||
if (ret) {
|
||||
pr_err("%s: pcm add ec_ref channel mixer output map controls failed:%d\n",
|
||||
__func__, ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 1; i <= PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++) {
|
||||
ret = msm_pcm_add_channel_mixer_weight_controls(rtd, i);
|
||||
if (ret) {
|
||||
|
|
@ -2901,6 +3386,13 @@ static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
|
|||
__func__, ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = msm_pcm_add_chmixer_ec_ref_weight_controls(rtd, i);
|
||||
if (ret) {
|
||||
pr_err("%s: pcm add ec_ref channel weight controls failed:%d\n",
|
||||
__func__, ret);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
|
@ -2909,6 +3401,8 @@ fail:
|
|||
kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]);
|
||||
pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] = NULL;
|
||||
pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] = NULL;
|
||||
kfree(pdata->chmixer_ec_ref[rtd->dai_link->id]);
|
||||
pdata->chmixer_ec_ref[rtd->dai_link->id] = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -3066,6 +3560,7 @@ static int msm_pcm_remove(struct platform_device *pdev)
|
|||
for (i = 0; i < MSM_FRONTEND_DAI_MM_SIZE; i++) {
|
||||
kfree(pdata->chmixer_pspd[i][SESSION_TYPE_RX]);
|
||||
kfree(pdata->chmixer_pspd[i][SESSION_TYPE_TX]);
|
||||
kfree(pdata->chmixer_ec_ref[i]);
|
||||
}
|
||||
}
|
||||
mutex_destroy(&pdata->lock);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* Copyright (C) 2008 Google, Inc.
|
||||
* Copyright (C) 2008 HTC Corporation
|
||||
* Copyright (c) 2012-2017, 2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2012-2017, 2019, 2021 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_PCM_H
|
||||
|
|
@ -117,6 +117,7 @@ struct msm_plat_data {
|
|||
struct msm_pcm_ch_map *ch_map[MSM_FRONTEND_DAI_MAX];
|
||||
struct snd_pcm *pcm_device[MSM_FRONTEND_DAI_MM_SIZE];
|
||||
struct msm_pcm_channel_mixer *chmixer_pspd[MSM_FRONTEND_DAI_MM_SIZE][2];
|
||||
struct msm_pcm_channel_mixer *chmixer_ec_ref[MSM_FRONTEND_DAI_MM_SIZE];
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ static int num_app_cfg_types;
|
|||
static int msm_ec_ref_port_id;
|
||||
static int afe_loopback_tx_port_index;
|
||||
static int afe_loopback_tx_port_id = -1;
|
||||
static struct msm_pcm_channel_mixer ec_ref_chmix_cfg[MSM_FRONTEND_DAI_MAX];
|
||||
static struct msm_ec_ref_port_cfg ec_ref_port_cfg;
|
||||
|
||||
#define WEIGHT_0_DB 0x4000
|
||||
/* all the FEs which can support channel mixer */
|
||||
|
|
@ -1258,6 +1260,85 @@ int msm_pcm_routing_set_channel_mixer_cfg(
|
|||
}
|
||||
EXPORT_SYMBOL(msm_pcm_routing_set_channel_mixer_cfg);
|
||||
|
||||
|
||||
/**
|
||||
* msm_pcm_routing_set_stream_ec_ref_chmix_cfg
|
||||
*
|
||||
* Receives fedai_id, ec_ref chmix configuration.
|
||||
* Returns 0 on success. On failure returns
|
||||
* -EINVAL and does not alter passed values.
|
||||
*
|
||||
* fedai_id - Passed value, front end ID for which ec_ref config is wanted
|
||||
* cfg_data - Passed value, configuration data used by ec_ref
|
||||
*/
|
||||
int msm_pcm_routing_set_stream_ec_ref_chmix_cfg(
|
||||
int fedai_id, struct msm_pcm_channel_mixer *cfg_data)
|
||||
{
|
||||
int i, j, ret = 0;
|
||||
|
||||
if (cfg_data == NULL) {
|
||||
pr_err("%s: Received NULL pointer for cfg_data\n", __func__);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (cfg_data->input_channel != msm_ec_ref_ch) {
|
||||
pr_err("%s: mismatched input ch %d with port config ch %d\n",
|
||||
__func__, cfg_data->input_channel,
|
||||
msm_ec_ref_ch);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
pr_debug("%s: fedai_id %d, input_channel %d output_channel %d\n",
|
||||
__func__, fedai_id,
|
||||
cfg_data->input_channel, cfg_data->output_channel);
|
||||
|
||||
for (i = 0; i < cfg_data->output_channel; i++)
|
||||
for (j = 0; j < cfg_data->input_channel; j++)
|
||||
pr_debug("%s: ch[%d][%d] weight = %d",
|
||||
__func__, i, j, cfg_data->channel_weight[i][j]);
|
||||
|
||||
if (fedai_id < 0 || fedai_id > MSM_FRONTEND_DAI_MAX) {
|
||||
pr_err("%s: Received out of bounds fedai_id %d\n",
|
||||
__func__, fedai_id);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
mutex_lock(&routing_lock);
|
||||
|
||||
ec_ref_chmix_cfg[fedai_id].input_channel =
|
||||
cfg_data->input_channel;
|
||||
ec_ref_chmix_cfg[fedai_id].output_channel =
|
||||
cfg_data->output_channel;
|
||||
for (i = 0; i < cfg_data->output_channel; i++)
|
||||
for (j = 0; j < cfg_data->input_channel; j++)
|
||||
ec_ref_chmix_cfg[fedai_id].channel_weight[i][j] =
|
||||
cfg_data->channel_weight[i][j];
|
||||
|
||||
ec_ref_chmix_cfg[fedai_id].override_in_ch_map =
|
||||
cfg_data->override_in_ch_map;
|
||||
if (ec_ref_chmix_cfg[fedai_id].override_in_ch_map) {
|
||||
for (i = 0; i < ec_ref_chmix_cfg[fedai_id].input_channel; i++)
|
||||
ec_ref_chmix_cfg[fedai_id].in_ch_map[i] =
|
||||
cfg_data->in_ch_map[i];
|
||||
}
|
||||
|
||||
ec_ref_chmix_cfg[fedai_id].override_out_ch_map =
|
||||
cfg_data->override_out_ch_map;
|
||||
if (ec_ref_chmix_cfg[fedai_id].override_out_ch_map) {
|
||||
for (i = 0; i < ec_ref_chmix_cfg[fedai_id].output_channel; i++)
|
||||
ec_ref_chmix_cfg[fedai_id].out_ch_map[i] =
|
||||
cfg_data->out_ch_map[i];
|
||||
}
|
||||
|
||||
mutex_unlock(&routing_lock);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_pcm_routing_set_stream_ec_ref_chmix_cfg);
|
||||
|
||||
int msm_pcm_routing_reg_stream_app_type_cfg(
|
||||
int fedai_id, int session_type, int be_id,
|
||||
struct msm_pcm_stream_app_type_cfg *cfg_data)
|
||||
|
|
@ -2174,7 +2255,33 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
|
|||
&& be_bit_width == 32)
|
||||
bits_per_sample = msm_routing_get_bit_width(
|
||||
SNDRV_PCM_FORMAT_S32_LE);
|
||||
copp_idx = adm_open(port_id, path_type,
|
||||
if ((session_type == SESSION_TYPE_TX) &&
|
||||
(ec_ref_chmix_cfg[fedai_id].output_channel)) {
|
||||
/* per-session ec_ref configuration */
|
||||
ec_ref_port_cfg.rx = msm_route_ec_ref_rx;
|
||||
ec_ref_port_cfg.port_id = msm_ec_ref_port_id;
|
||||
ec_ref_port_cfg.ch = msm_ec_ref_ch;
|
||||
ec_ref_port_cfg.sampling_rate =
|
||||
msm_ec_ref_sampling_rate;
|
||||
if (msm_ec_ref_bit_format ==
|
||||
SNDRV_PCM_FORMAT_S16_LE)
|
||||
ec_ref_port_cfg.bit_width = 16;
|
||||
else if (msm_ec_ref_bit_format ==
|
||||
SNDRV_PCM_FORMAT_S24_LE)
|
||||
ec_ref_port_cfg.bit_width = 24;
|
||||
|
||||
copp_idx = adm_open_v2(port_id, path_type,
|
||||
sample_rate, channels, topology,
|
||||
perf_mode, bits_per_sample,
|
||||
app_type, acdb_dev_id,
|
||||
session_type, passthr_mode,
|
||||
copp_token,
|
||||
&ec_ref_port_cfg,
|
||||
&ec_ref_chmix_cfg[fedai_id]);
|
||||
/* reset ec_ref config */
|
||||
ec_ref_chmix_cfg[fedai_id].output_channel = 0;
|
||||
} else
|
||||
copp_idx = adm_open(port_id, path_type,
|
||||
sample_rate, channels, topology,
|
||||
perf_mode, bits_per_sample,
|
||||
app_type, acdb_dev_id,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#ifndef _MSM_PCM_ROUTING_H
|
||||
#define _MSM_PCM_ROUTING_H
|
||||
|
|
@ -663,6 +663,9 @@ int msm_pcm_routing_set_channel_mixer_runtime(
|
|||
int session_type,
|
||||
struct msm_pcm_channel_mixer *params);
|
||||
|
||||
int msm_pcm_routing_set_stream_ec_ref_chmix_cfg(
|
||||
int fedai_id, struct msm_pcm_channel_mixer *cfg_data);
|
||||
|
||||
#ifndef SND_PCM_ADD_VOLUME_CTL
|
||||
/* PCM Volume control API
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue