Merge "asoc: qcs405: fix compilation issue"
diff --git a/asoc/codecs/wcd9335.c b/asoc/codecs/wcd9335.c
index 03958f3..7bc9401 100644
--- a/asoc/codecs/wcd9335.c
+++ b/asoc/codecs/wcd9335.c
@@ -717,6 +717,7 @@
 
 	u32 anc_slot;
 	bool anc_func;
+	bool is_wsa_attach;
 
 	/* Vbat module */
 	struct wcd_vbat vbat;
@@ -9049,17 +9050,6 @@
 	SOC_ENUM_EXT("EAR PA Gain", tasha_ear_pa_gain_enum,
 		tasha_ear_pa_gain_get, tasha_ear_pa_gain_put),
 
-	SOC_ENUM_EXT("EAR SPKR PA Gain", tasha_ear_spkr_pa_gain_enum,
-		     tasha_ear_spkr_pa_gain_get, tasha_ear_spkr_pa_gain_put),
-
-	SOC_ENUM_EXT("SPKR Left Boost Max State", tasha_spkr_boost_stage_enum,
-			tasha_spkr_left_boost_stage_get,
-			tasha_spkr_left_boost_stage_put),
-
-	SOC_ENUM_EXT("SPKR Right Boost Max State", tasha_spkr_boost_stage_enum,
-			tasha_spkr_right_boost_stage_get,
-			tasha_spkr_right_boost_stage_put),
-
 	SOC_SINGLE_TLV("HPHL Volume", WCD9335_HPH_L_EN, 0, 20, 1,
 		line_gain),
 	SOC_SINGLE_TLV("HPHR Volume", WCD9335_HPH_R_EN, 0, 20, 1,
@@ -9087,6 +9077,19 @@
 			analog_gain),
 };
 
+static const struct snd_kcontrol_new tasha_spkr_wsa_controls[] = {
+	SOC_ENUM_EXT("EAR SPKR PA Gain", tasha_ear_spkr_pa_gain_enum,
+		     tasha_ear_spkr_pa_gain_get, tasha_ear_spkr_pa_gain_put),
+
+	SOC_ENUM_EXT("SPKR Left Boost Max State", tasha_spkr_boost_stage_enum,
+			tasha_spkr_left_boost_stage_get,
+			tasha_spkr_left_boost_stage_put),
+
+	SOC_ENUM_EXT("SPKR Right Boost Max State", tasha_spkr_boost_stage_enum,
+			tasha_spkr_right_boost_stage_get,
+			tasha_spkr_right_boost_stage_put),
+};
+
 static const char * const spl_src0_mux_text[] = {
 	"ZERO", "SRC_IN_HPHL", "SRC_IN_LO1",
 };
@@ -13583,6 +13586,10 @@
 	snd_soc_add_codec_controls(codec,
 			tasha_analog_gain_controls,
 			ARRAY_SIZE(tasha_analog_gain_controls));
+	if (tasha->is_wsa_attach)
+		snd_soc_add_codec_controls(codec,
+				tasha_spkr_wsa_controls,
+				ARRAY_SIZE(tasha_wsa_controls));
 	control->num_rx_port = TASHA_RX_MAX;
 	control->rx_chs = ptr;
 	memcpy(control->rx_chs, tasha_rx_chs, sizeof(tasha_rx_chs));
@@ -14053,6 +14060,7 @@
 					__func__, ctrl_num);
 				goto fail_pdev_add;
 			}
+			tasha->is_wsa_attach = true;
 		}
 
 		ret = platform_device_add(pdev);
diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c
index 3e49b29..3ecafbc 100644
--- a/asoc/msm-lsm-client.c
+++ b/asoc/msm-lsm-client.c
@@ -2263,6 +2263,77 @@
 	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 @@
 					__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;