diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c index 3e49b295a4a3..3ecafbccec65 100644 --- a/asoc/msm-lsm-client.c +++ b/asoc/msm-lsm-client.c @@ -2263,6 +2263,77 @@ static int msm_lsm_open(struct snd_pcm_substream *substream) return 0; } +static int msm_lsm_send_ch_mix_config(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct lsm_priv *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd; + struct lsm_hw_params *in_params; + int pp_ch_cnt; + int *ch_wght_coeff; + int ret = 0, i, idx; + + /* + * The output channels from channel mixer is the input to LSM (stream) + * side and is read from in_params->num_chs. + * + * The input channels to channel mixer are the output channels from + * the device side (routing) and is obtained by reading the + * pp_ch_cnt. + * + * For LSM to be functional, only unity channel mixing is allowed. + */ + + in_params = &prtd->lsm_client->in_hw_params; + rtd = prtd->substream->private_data; + pp_ch_cnt = msm_pcm_routing_get_pp_ch_cnt(rtd->dai_link->id, + SESSION_TYPE_TX); + if (pp_ch_cnt < 0 || + pp_ch_cnt > LSM_V3P0_MAX_NUM_CHANNELS || + in_params->num_chs > LSM_V3P0_MAX_NUM_CHANNELS) { + dev_err(rtd->dev, + "%s: invalid ch cnt, pp_ch_cnt %d in_ch_cnt %d\n", + __func__, pp_ch_cnt, in_params->num_chs); + return -EINVAL; + } + + if (!pp_ch_cnt || + (pp_ch_cnt == in_params->num_chs)) { + dev_dbg(rtd->dev, + "%s: Skip ch mixing, pp_ch_cnt %d in_ch_cnt %d\n", + __func__, pp_ch_cnt, in_params->num_chs); + return 0; + } + + ch_wght_coeff = kzalloc(in_params->num_chs * pp_ch_cnt * sizeof(int), + GFP_KERNEL); + if (!ch_wght_coeff) + return -ENOMEM; + + /* + * channel weight co-efficients is a m X n array, where + * m = number of input channels to ch mixer (pp_ch_cnt) + * n = number of output channels from ch mixer (in_params->num_chs) + */ + for (i = 0; i < in_params->num_chs; i++) { + idx = (i * pp_ch_cnt) + i; + ch_wght_coeff[idx] = 1; + } + + ret = msm_pcm_routing_send_chmix_cfg(rtd->dai_link->id, + pp_ch_cnt, in_params->num_chs, + ch_wght_coeff, + SESSION_TYPE_TX, STREAM_TYPE_LSM); + if (ret) + dev_err(rtd->dev, + "%s: Failed to configure channel mixer err %d\n", + __func__, ret); + + kfree(ch_wght_coeff); + + return ret; +} + static int msm_lsm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -2300,6 +2371,13 @@ static int msm_lsm_prepare(struct snd_pcm_substream *substream) __func__, ret); return ret; } + + ret = msm_lsm_send_ch_mix_config(substream); + if (ret) { + msm_pcm_routing_dereg_phy_stream(rtd->dai_link->id, + SNDRV_PCM_STREAM_CAPTURE); + return ret; + } } prtd->lsm_client->session_state = RUNNING;