Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed17c8fc authored by Erin Yan's avatar Erin Yan Committed by Gerrit - the friendly Code Review server
Browse files

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: default avatarErin Yan <xinyey@codeaurora.org>
Change-Id: I89eb125e9b01b7bcdbb038148ec93d85a19cf3d5
parent 9f0c6704
Loading
Loading
Loading
Loading
+496 −0
Original line number Diff line number Diff line
@@ -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 @@ static int msm_pcm_add_channel_mixer_weight_controls(
	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 @@ static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
	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);
+495 −0

File changed.

Preview size limit exceeded, changes collapsed.

+2 −1
Original line number Diff line number Diff line
@@ -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;
};

+108 −1
Original line number Diff line number Diff line
@@ -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,6 +2255,32 @@ 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);
			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,
+4 −1
Original line number Diff line number Diff line
/* 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
 */