Merge ce9731f4349bfced5826abd4c71ba4205c6e98b8 on remote branch

Change-Id: I95d515e20765a5e048a2ea9d9135b776037b2ac4
diff --git a/asoc/codecs/sdm660_cdc/msm-analog-cdc.c b/asoc/codecs/sdm660_cdc/msm-analog-cdc.c
index de112bc..9553b39 100644
--- a/asoc/codecs/sdm660_cdc/msm-analog-cdc.c
+++ b/asoc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -2260,10 +2260,6 @@
 				snd_soc_update_bits(codec,
 					MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
 					0xEF, 0xEF);
-			else
-				snd_soc_update_bits(codec,
-					MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
-					0x10, 0x00);
 			break;
 		case BOOST_ALWAYS:
 		case BOOST_ON_FOREVER:
@@ -2272,8 +2268,6 @@
 				0xEF, 0xEF);
 			break;
 		case BYPASS_ALWAYS:
-			snd_soc_update_bits(codec,
-				MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x00);
 			break;
 		default:
 			dev_err(codec->dev,
@@ -2281,6 +2275,8 @@
 				sdm660_cdc->boost_option);
 			break;
 		}
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+				    0x10, 0x00);
 		msm_anlg_cdc_dig_notifier_call(codec,
 					       DIG_CDC_EVENT_RX3_MUTE_OFF);
 		snd_soc_update_bits(codec, w->reg, 0x80, 0x80);
diff --git a/asoc/codecs/wsa881x.c b/asoc/codecs/wsa881x.c
index 2ef9e0a..d2a3938 100644
--- a/asoc/codecs/wsa881x.c
+++ b/asoc/codecs/wsa881x.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -76,6 +76,7 @@
 enum {
 	WSA881X_DEV_DOWN,
 	WSA881X_DEV_UP,
+	WSA881X_DEV_READY,
 };
 
 /*
@@ -99,6 +100,7 @@
 	int version;
 	struct mutex bg_lock;
 	struct mutex res_lock;
+	struct mutex temp_lock;
 	struct snd_info_entry *entry;
 	struct snd_info_entry *version_entry;
 	int state;
@@ -491,6 +493,17 @@
 	.read = codec_debug_read,
 };
 
+static void wsa881x_regcache_sync(struct wsa881x_priv *wsa881x)
+{
+	mutex_lock(&wsa881x->res_lock);
+	if (wsa881x->state != WSA881X_DEV_READY) {
+		regcache_mark_dirty(wsa881x->regmap);
+		regcache_sync(wsa881x->regmap);
+		wsa881x->state = WSA881X_DEV_READY;
+	}
+	mutex_unlock(&wsa881x->res_lock);
+}
+
 static const struct reg_sequence wsa881x_pre_pmu_pa[] = {
 	{WSA881X_SPKR_DRV_GAIN, 0x41, 0},
 	{WSA881X_SPKR_MISC_CTL1, 0x01, 0},
@@ -850,7 +863,9 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		mutex_lock(&wsa881x->temp_lock);
 		wsa881x_resource_acquire(codec, ENABLE);
+		mutex_unlock(&wsa881x->temp_lock);
 		wsa881x_boost_ctrl(codec, ENABLE);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
@@ -858,7 +873,9 @@
 					    wsa881x->swr_slave->dev_num,
 					    false);
 		wsa881x_boost_ctrl(codec, DISABLE);
+		mutex_lock(&wsa881x->temp_lock);
 		wsa881x_resource_acquire(codec, DISABLE);
+		mutex_unlock(&wsa881x->temp_lock);
 		break;
 	}
 	return 0;
@@ -1103,13 +1120,8 @@
 			return -EINVAL;
 		}
 	}
-	mutex_lock(&wsa881x->res_lock);
-	if (!wsa881x->clk_cnt) {
-		regcache_mark_dirty(wsa881x->regmap);
-		regcache_sync(wsa881x->regmap);
-	}
-	mutex_unlock(&wsa881x->res_lock);
-
+	wsa881x_regcache_sync(wsa881x);
+	mutex_lock(&wsa881x->temp_lock);
 	wsa881x_resource_acquire(codec, ENABLE);
 
 	snd_soc_update_bits(codec, WSA881X_TADC_VALUE_CTL, 0x01, 0x00);
@@ -1122,6 +1134,7 @@
 	wsa_temp_reg->d2_lsb = snd_soc_read(codec, WSA881X_OTP_REG_4);
 
 	wsa881x_resource_acquire(codec, DISABLE);
+	mutex_unlock(&wsa881x->temp_lock);
 
 	return 0;
 }
@@ -1137,7 +1150,6 @@
 	dev = wsa881x->swr_slave;
 	wsa881x->codec = codec;
 	mutex_init(&wsa881x->bg_lock);
-	mutex_init(&wsa881x->res_lock);
 	wsa881x_init(codec);
 	snprintf(wsa881x->tz_pdata.name, sizeof(wsa881x->tz_pdata.name),
 		"%s.%x", "wsatz", (u8)dev->addr);
@@ -1159,7 +1171,6 @@
 	if (wsa881x->tz_pdata.tz_dev)
 		wsa881x_deinit_thermal(wsa881x->tz_pdata.tz_dev);
 	mutex_destroy(&wsa881x->bg_lock);
-	mutex_destroy(&wsa881x->res_lock);
 
 	return 0;
 }
@@ -1342,6 +1353,8 @@
 			__func__);
 		goto dev_err;
 	}
+	mutex_init(&wsa881x->res_lock);
+	mutex_init(&wsa881x->temp_lock);
 
 	return 0;
 
@@ -1364,6 +1377,8 @@
 	}
 	debugfs_remove_recursive(debugfs_wsa881x_dent);
 	debugfs_wsa881x_dent = NULL;
+	mutex_destroy(&wsa881x->res_lock);
+	mutex_destroy(&wsa881x->temp_lock);
 	snd_soc_unregister_codec(&pdev->dev);
 	if (wsa881x->pd_gpio)
 		gpio_free(wsa881x->pd_gpio);
@@ -1422,6 +1437,11 @@
 		dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
 		return -EINVAL;
 	}
+	if (wsa881x->state == WSA881X_DEV_READY) {
+		dev_dbg(&pdev->dev, "%s: device already active\n", __func__);
+		return 0;
+	}
+
 	wsa881x->bg_cnt = 0;
 	wsa881x->clk_cnt = 0;
 	while (swr_get_logical_dev_num(pdev, pdev->addr, &devnum) && retry--) {
@@ -1429,8 +1449,8 @@
 		usleep_range(1000, 1100);
 	}
 	pdev->dev_num = devnum;
-	regcache_mark_dirty(wsa881x->regmap);
-	regcache_sync(wsa881x->regmap);
+	wsa881x_regcache_sync(wsa881x);
+
 	return 0;
 }
 
diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c
index c98c1cf..5dc1ad2 100644
--- a/asoc/msm-compress-q6-v2.c
+++ b/asoc/msm-compress-q6-v2.c
@@ -3894,6 +3894,16 @@
 	return 0;
 }
 
+static int msm_compr_chmix_cfg_ctl_info(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 128;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xFFFFFFFF;
+	return 0;
+}
+
 static int msm_compr_volume_info(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_info *uinfo)
 {
@@ -4317,6 +4327,112 @@
 	return 0;
 }
 
+static int msm_compr_chmix_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+				snd_soc_component_get_drvdata(comp);
+	struct snd_compr_stream *cstream = NULL;
+	struct snd_soc_pcm_runtime *rtd = NULL;
+	u64 fe_id = kcontrol->private_value;
+	int ip_channel_cnt, op_channel_cnt;
+	int i, index = 0;
+	int ch_coeff[PCM_FORMAT_MAX_NUM_CHANNEL * PCM_FORMAT_MAX_NUM_CHANNEL];
+	bool use_default_chmap = true;
+	char *chmap = NULL;
+
+	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s: Received out of bounds fe_id %llu\n",
+			__func__, fe_id);
+		return -EINVAL;
+	}
+	cstream = pdata->cstream[fe_id];
+	if (!cstream) {
+		pr_err("%s: stream inactive\n", __func__);
+		return -EINVAL;
+	}
+	rtd = cstream->private_data;
+	if (!rtd) {
+		pr_err("%s: stream inactive\n", __func__);
+		return -EINVAL;
+	}
+
+	use_default_chmap = !(pdata->ch_map[rtd->dai_link->id]->set_ch_map);
+	chmap = pdata->ch_map[rtd->dai_link->id]->channel_map;
+
+	ip_channel_cnt = ucontrol->value.integer.value[index++];
+	op_channel_cnt = ucontrol->value.integer.value[index++];
+	/*
+	 * wght coeff of first out channel corresponding to each in channel
+	 * are sent followed by second out channel for each in channel etc.
+	 */
+	memset(ch_coeff, 0, sizeof(ch_coeff));
+	for (i = 0; i < op_channel_cnt * ip_channel_cnt; i++) {
+		ch_coeff[i] =
+			ucontrol->value.integer.value[index++];
+	}
+
+	msm_pcm_routing_send_chmix_cfg(fe_id, ip_channel_cnt, op_channel_cnt,
+			ch_coeff, SESSION_TYPE_RX, use_default_chmap, chmap);
+
+	return 0;
+}
+
+static int msm_compr_chmix_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	return 0;
+}
+
+static int msm_compr_add_chmix_cfg_controls(struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = "Audio Stream";
+	const char *deviceNo       = "NN";
+	const char *suffix         = "Channel Mix Cfg";
+	int ctl_len;
+	char *mixer_str = NULL;
+	struct snd_kcontrol_new chmix_cfg_controls[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_compr_chmix_cfg_ctl_info,
+		.get = msm_compr_chmix_cfg_ctl_get,
+		.put = msm_compr_chmix_cfg_ctl_put,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s NULL rtd\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: added new compr FE with name %s, id %d, cpu dai %s, device no %d\n",
+		 __func__, rtd->dai_link->name, rtd->dai_link->id,
+		 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 +
+		  strlen(suffix) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str)
+		return -ENOMEM;
+
+	snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name,
+		 rtd->pcm->device, suffix);
+
+	chmix_cfg_controls[0].name = mixer_str;
+	chmix_cfg_controls[0].private_value = rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s", __func__, mixer_str);
+	snd_soc_add_platform_controls(rtd->platform,
+				      chmix_cfg_controls,
+				      ARRAY_SIZE(chmix_cfg_controls));
+	kfree(mixer_str);
+	return 0;
+}
+
 static int msm_compr_add_channel_map_control(struct snd_soc_pcm_runtime *rtd)
 {
 	const char *mixer_ctl_name = "Playback Channel Map";
@@ -4513,6 +4629,9 @@
 	if (rc)
 		pr_err("%s: Could not add Compr Channel Map Control\n",
 			__func__);
+	rc = msm_compr_add_chmix_cfg_controls(rtd);
+	if (rc)
+		pr_err("%s: add chmix cfg controls failed:%d\n", __func__, rc);
 	return 0;
 }
 
diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c
index 4c9215f..3792021 100644
--- a/asoc/msm-pcm-q6-v2.c
+++ b/asoc/msm-pcm-q6-v2.c
@@ -1753,6 +1753,150 @@
 	return 0;
 }
 
+static int msm_pcm_chmix_cfg_ctl_info(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 128;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xFFFFFFFF;
+	return 0;
+}
+
+static int msm_pcm_chmix_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *usr_info = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_platform *platform;
+	struct msm_plat_data *pdata;
+	struct snd_pcm_substream *substream;
+	struct msm_audio *prtd;
+	u64 fe_id = kcontrol->private_value;
+	int ip_channel_cnt, op_channel_cnt;
+	int i, index = 0, ret = 0;
+	int ch_coeff[PCM_FORMAT_MAX_NUM_CHANNEL * PCM_FORMAT_MAX_NUM_CHANNEL];
+	bool use_default_chmap = true;
+	char *ch_map = NULL;
+
+	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s: Received out of bounds fe_id %llu\n",
+			__func__, fe_id);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (!usr_info) {
+		pr_err("%s: usr_info is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+	platform = snd_soc_component_to_platform(usr_info);
+	if (!platform) {
+		pr_err("%s: platform is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+	pdata = dev_get_drvdata(platform->dev);
+	if (!pdata) {
+		pr_err("%s: pdata is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+	substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+
+	if (!substream) {
+		pr_err("%s substream not found\n", __func__);
+		return -ENODEV;
+	}
+	if (!substream->runtime) {
+		pr_err("%s substream runtime not found\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+	prtd = substream->runtime->private_data;
+	if (!prtd) {
+		pr_err("%s: stream inactive\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+	use_default_chmap = !prtd->set_channel_map;
+	ch_map = prtd->channel_map;
+	ip_channel_cnt = ucontrol->value.integer.value[index++];
+	op_channel_cnt = ucontrol->value.integer.value[index++];
+	/*
+	 * wght coeff of first out channel corresponding to each in channel
+	 * are sent followed by second out channel for each in channel etc.
+	 */
+	memset(ch_coeff, 0, sizeof(ch_coeff));
+	for (i = 0; i < op_channel_cnt * ip_channel_cnt; i++) {
+		ch_coeff[i] =
+			ucontrol->value.integer.value[index++];
+	}
+
+	msm_pcm_routing_send_chmix_cfg(fe_id, ip_channel_cnt, op_channel_cnt,
+			ch_coeff, SESSION_TYPE_RX, use_default_chmap, ch_map);
+done:
+	return ret;
+}
+
+static int msm_pcm_chmix_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	return 0;
+}
+
+static int msm_pcm_add_chmix_cfg_controls(struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = "Audio Stream";
+	const char *deviceNo       = "NN";
+	const char *suffix         = "Channel Mix Cfg";
+	char *mixer_str = NULL;
+	int ctl_len = 0;
+	struct msm_plat_data *pdata;
+	struct snd_kcontrol_new chmix_cfg_controls[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_pcm_chmix_cfg_ctl_info,
+		.get = msm_pcm_chmix_cfg_ctl_get,
+		.put = msm_pcm_chmix_cfg_ctl_put,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s: NULL rtd\n", __func__);
+		return -EINVAL;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + 1 +
+		  strlen(deviceNo) + 1 + strlen(suffix) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str)
+		return -ENOMEM;
+
+	snprintf(mixer_str, ctl_len, "%s %d %s",
+		 mixer_ctl_name, rtd->pcm->device, suffix);
+	chmix_cfg_controls[0].name = mixer_str;
+	chmix_cfg_controls[0].private_value = rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+	pdata = dev_get_drvdata(rtd->platform->dev);
+	if (pdata) {
+		if (!pdata->pcm)
+			pdata->pcm = rtd->pcm;
+		snd_soc_add_platform_controls(rtd->platform,
+					      chmix_cfg_controls,
+					      ARRAY_SIZE(chmix_cfg_controls));
+	} else {
+		pr_err("%s: NULL pdata\n", __func__);
+		return -EINVAL;
+	}
+	kfree(mixer_str);
+	return 0;
+}
+
 static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
 {
 	int ret = 0;
@@ -1765,6 +1909,9 @@
 	if (ret)
 		pr_err("%s: pcm add app type controls failed:%d\n",
 			__func__, ret);
+	ret = msm_pcm_add_chmix_cfg_controls(rtd);
+	if (ret)
+		pr_err("%s: add chmix cfg controls failed:%d\n", __func__, ret);
 	return ret;
 }
 
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index e821717..35b2bdb 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -792,6 +792,79 @@
 	return rc;
 }
 
+/*
+ * msm_pcm_routing_send_chmix_cfg
+ *
+ * Receives fe_id, ip_channel_cnt, op_channel_cnt, channel weight, session_type
+ * use_default_chmap and channel map to map in channel mixer and send to
+ * adm programmable matrix.
+ *
+ * fe_id - Passed value, frontend id which is wanted
+ * ip_channel_cnt - Passed value, number of input channels
+ * op_channel_cnt - Passed value, number of output channels
+ * ch_wght_coeff - Passed reference, weights for each output channel
+ * session_type - Passed value, session_type for RX or TX
+ * use_default_chmap - true if default channel map  to be used
+ * ch_map - input/output channel map for playback/capture session respectively
+ */
+
+int msm_pcm_routing_send_chmix_cfg(int fe_id, int ip_channel_cnt,
+				   int op_channel_cnt, int *ch_wght_coeff,
+				   int session_type, bool use_default_chmap,
+				   char *channel_map)
+{
+	int rc = 0, idx = 0, i, j;
+	int be_index = 0, port_id, index = 0;
+	unsigned int session_id = 0;
+
+	pr_debug("%s: fe_id[%d] ip_ch[%d] op_ch[%d] sess_type [%d]\n",
+		 __func__, fe_id, ip_channel_cnt, op_channel_cnt, session_type);
+
+	if (!use_default_chmap && (channel_map == NULL)) {
+		pr_err("%s: No valid chan map and can't use default\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if ((ch_wght_coeff == NULL) || (op_channel_cnt > ADM_MAX_CHANNELS) ||
+	     (ip_channel_cnt > ADM_MAX_CHANNELS)) {
+		pr_err("%s: Invalid channels or null coefficients\n", __func__);
+		return -EINVAL;
+	}
+
+	for (be_index = 0; be_index < MSM_BACKEND_DAI_MAX; be_index++) {
+		port_id = msm_bedais[be_index].port_id;
+		if (!msm_bedais[be_index].active ||
+			!test_bit(fe_id, &msm_bedais[be_index].fe_sessions[0]))
+			continue;
+
+		session_id = fe_dai_map[fe_id][session_type].strm_id;
+		channel_mixer[fe_id].input_channels[0] = ip_channel_cnt;
+		channel_mixer[fe_id].output_channel = op_channel_cnt;
+		channel_mixer[fe_id].rule = 0;
+
+		for (j = 0; j < op_channel_cnt; j++) {
+			for (i = 0; i < ip_channel_cnt; i++)
+				channel_mixer[fe_id].channel_weight[j][i] =
+						ch_wght_coeff[index++];
+		}
+		for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
+			unsigned long copp =
+				session_copp_map[fe_id][session_type][be_index];
+			if (!test_bit(idx, &copp))
+				continue;
+			rc = adm_programable_channel_mixer(port_id,
+					idx, session_id, session_type,
+					channel_mixer + fe_id, 0,
+					use_default_chmap, channel_map);
+			if (rc < 0)
+				pr_err("%s: err setting channel mix config\n",
+					__func__);
+		}
+	}
+	return 0;
+}
+
 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)
@@ -1326,6 +1399,8 @@
 	int sess_type = 0;
 	int i = 0, j = 0, be_id;
 	int ret = 0;
+	bool use_default_chmap = true;
+	char *ch_map = NULL;
 
 	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
 		pr_err("%s: invalid FE %d\n", __func__, fe_id);
@@ -1368,7 +1443,8 @@
 			ret = adm_programable_channel_mixer(
 					msm_bedais[be_id].port_id,
 					copp_idx, dspst_id, sess_type,
-					channel_mixer + fe_id, i);
+					channel_mixer + fe_id, i,
+					use_default_chmap, ch_map);
 		}
 	}
 
@@ -3693,6 +3769,10 @@
 		msm_route_ec_ref_rx = 23;
 		ec_ref_port_id = AFE_PORT_ID_HDMI_OVER_DP_RX;
 		break;
+	case 24:
+		msm_route_ec_ref_rx = 24;
+		ec_ref_port_id = AFE_PORT_ID_PRIMARY_TDM_RX_1;
+		break;
 	default:
 		msm_route_ec_ref_rx = 0; /* NONE */
 		pr_err("%s EC ref rx %ld not valid\n",
@@ -3716,7 +3796,8 @@
 	"SLIM_5_RX", "SLIM_1_TX", "QUAT_TDM_TX_1",
 	"QUAT_TDM_RX_0", "QUAT_TDM_RX_1", "QUAT_TDM_RX_2", "SLIM_6_RX",
 	"TERT_MI2S_RX", "QUAT_MI2S_RX", "TERT_TDM_TX_0", "USB_AUDIO_RX",
-	"INT0_MI2S_RX", "INT4_MI2S_RX", "INT3_MI2S_TX", "DISPLAY_PORT"};
+	"INT0_MI2S_RX", "INT4_MI2S_RX", "INT3_MI2S_TX", "DISPLAY_PORT",
+	"PRI_TDM_RX_1"};
 
 static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ec_ref_rx), ec_ref_rx),
@@ -15670,6 +15751,7 @@
 	{"AUDIO_REF_EC_UL1 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
 	{"AUDIO_REF_EC_UL1 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
 	{"AUDIO_REF_EC_UL1 MUX", "SLIM_1_TX", "SLIMBUS_1_TX"},
+	{"AUDIO_REF_EC_UL1 MUX", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
 	{"AUDIO_REF_EC_UL1 MUX", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
 	{"AUDIO_REF_EC_UL1 MUX", "QUAT_TDM_RX_0", "QUAT_TDM_RX_0"},
 	{"AUDIO_REF_EC_UL1 MUX", "QUAT_TDM_RX_1", "QUAT_TDM_RX_1"},
@@ -15705,6 +15787,7 @@
 	{"AUDIO_REF_EC_UL8 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
 	{"AUDIO_REF_EC_UL8 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
 	{"AUDIO_REF_EC_UL8 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL8 MUX", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
 
 	{"AUDIO_REF_EC_UL9 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"AUDIO_REF_EC_UL9 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
diff --git a/asoc/msm-pcm-routing-v2.h b/asoc/msm-pcm-routing-v2.h
index c2422d6..93f6ceb 100644
--- a/asoc/msm-pcm-routing-v2.h
+++ b/asoc/msm-pcm-routing-v2.h
@@ -525,4 +525,8 @@
 int msm_pcm_routing_get_stream_app_type_cfg(
 	int fedai_id, int session_type, int *be_id,
 	struct msm_pcm_stream_app_type_cfg *cfg_data);
+int msm_pcm_routing_send_chmix_cfg(int fe_id, int ip_channel_cnt,
+				int op_channel_cnt, int *ch_wght_coeff,
+				int session_type, bool use_default_chmap,
+				char *channel_map);
 #endif /*_MSM_PCM_H*/
diff --git a/asoc/msm-pcm-voice-v2.c b/asoc/msm-pcm-voice-v2.c
index 7447d0c..10e1207 100644
--- a/asoc/msm-pcm-voice-v2.c
+++ b/asoc/msm-pcm-voice-v2.c
@@ -720,7 +720,9 @@
 {
 	int rc;
 	bool destroy_cvd = false;
+	bool vote_bms = false;
 	const char *is_destroy_cvd = "qcom,destroy-cvd";
+	const char *is_vote_bms = "qcom,vote-bms";
 
 	if (!is_voc_initialized()) {
 		pr_debug("%s: voice module not initialized yet, deferring probe()\n",
@@ -747,6 +749,10 @@
 						is_destroy_cvd);
 	voc_set_destroy_cvd_flag(destroy_cvd);
 
+	vote_bms = of_property_read_bool(pdev->dev.of_node,
+					 is_vote_bms);
+	voc_set_vote_bms_flag(vote_bms);
+
 	rc = snd_soc_register_platform(&pdev->dev,
 				       &msm_soc_platform);
 
diff --git a/asoc/sdm660-common.h b/asoc/sdm660-common.h
index 65f9d5b..3df6bf8 100644
--- a/asoc/sdm660-common.h
+++ b/asoc/sdm660-common.h
@@ -122,6 +122,10 @@
 	struct mutex cdc_int_mclk0_mutex;
 	struct delayed_work disable_int_mclk0_work;
 	struct afe_clk_set digital_cdc_core_clk;
+	int gpio_linein_det;
+	int gpio_lineout_det;
+	int linein_det_swh;
+	int lineout_det_swh;
 };
 
 int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
diff --git a/asoc/sdm660-ext-dai-links.c b/asoc/sdm660-ext-dai-links.c
index 91554f7..3568ebb 100644
--- a/asoc/sdm660-ext-dai-links.c
+++ b/asoc/sdm660-ext-dai-links.c
@@ -2000,6 +2000,23 @@
 	},
 };
 
+static struct snd_soc_dai_link msm_afe_rxtx_lb_be_dai_link[] = {
+	{
+		.name = LPASS_BE_AFE_LOOPBACK_TX,
+		.stream_name = "AFE Loopback Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.24577",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.id = MSM_BACKEND_DAI_AFE_LOOPBACK_TX,
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+};
+
+
 static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
 	{
 		.name = LPASS_BE_SLIMBUS_7_RX,
@@ -2079,7 +2096,8 @@
 ARRAY_SIZE(msm_mi2s_be_dai_links) +
 ARRAY_SIZE(msm_auxpcm_be_dai_links) +
 ARRAY_SIZE(msm_wcn_be_dai_links) +
-ARRAY_SIZE(ext_disp_be_dai_link)];
+ARRAY_SIZE(ext_disp_be_dai_link) +
+ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link)];
 
 static struct snd_soc_dai_link msm_ext_tavil_dai_links[
 ARRAY_SIZE(msm_ext_common_fe_dai) +
@@ -2090,7 +2108,8 @@
 ARRAY_SIZE(msm_mi2s_be_dai_links) +
 ARRAY_SIZE(msm_auxpcm_be_dai_links) +
 ARRAY_SIZE(msm_wcn_be_dai_links) +
-ARRAY_SIZE(ext_disp_be_dai_link)];
+ARRAY_SIZE(ext_disp_be_dai_link) +
+ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link)];
 
 /**
  * populate_snd_card_dailinks - prepares dailink array and initializes card.
@@ -2182,6 +2201,14 @@
 				sizeof(ext_disp_be_dai_link));
 			len5 += ARRAY_SIZE(ext_disp_be_dai_link);
 		}
+		if (of_property_read_bool(dev->of_node, "qcom,afe-rxtx-lb")) {
+			dev_dbg(dev, "%s(): AFE RX to TX loopback supported\n",
+					__func__);
+			memcpy(msm_ext_tasha_dai_links + len5,
+				msm_afe_rxtx_lb_be_dai_link,
+				sizeof(msm_afe_rxtx_lb_be_dai_link));
+			len5 += ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link);
+		}
 		msm_ext_dai_links = msm_ext_tasha_dai_links;
 	} else if (strnstr(card->name, "tavil", strlen(card->name))) {
 		len1 = ARRAY_SIZE(msm_ext_common_fe_dai);
@@ -2231,6 +2258,14 @@
 				sizeof(ext_disp_be_dai_link));
 			len5 += ARRAY_SIZE(ext_disp_be_dai_link);
 		}
+		if (of_property_read_bool(dev->of_node, "qcom,afe-rxtx-lb")) {
+			dev_dbg(dev, "%s(): AFE RX to TX loopback supported\n",
+					__func__);
+			memcpy(msm_ext_tavil_dai_links + len5,
+				msm_afe_rxtx_lb_be_dai_link,
+				sizeof(msm_afe_rxtx_lb_be_dai_link));
+			len5 += ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link);
+		}
 		msm_ext_dai_links = msm_ext_tavil_dai_links;
 	} else {
 		dev_err(dev, "%s: failing as no matching card name\n",
diff --git a/asoc/sdm660-external.c b/asoc/sdm660-external.c
index 91accff..ca1d2aa 100644
--- a/asoc/sdm660-external.c
+++ b/asoc/sdm660-external.c
@@ -22,6 +22,7 @@
 #include "msm-pcm-routing-v2.h"
 #include "sdm660-common.h"
 #include "sdm660-external.h"
+#include "codecs/msm-cdc-pinctrl.h"
 #include "codecs/wcd9335.h"
 #include "codecs/wcd934x/wcd934x.h"
 #include "codecs/wcd934x/wcd934x-mbhc.h"
@@ -37,6 +38,8 @@
 #define WSA8810_NAME_1 "wsa881x.20170211"
 #define WSA8810_NAME_2 "wsa881x.20170212"
 
+#define MSM_HIFI_ON 1
+
 static int msm_ext_spk_control = 1;
 static struct wcd_mbhc_config *wcd_mbhc_cfg_ptr;
 
@@ -48,6 +51,7 @@
 
 static struct msm_asoc_wcd93xx_codec msm_codec_fn;
 static struct platform_device *spdev;
+static int msm_hifi_control;
 
 static bool is_initial_boot;
 
@@ -108,8 +112,40 @@
 	[SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
 };
 
+static struct snd_soc_jack linein_jack;
+
+static struct snd_soc_jack_pin linein_jack_pins[] = {
+	{
+		.pin = "Linein",
+		.mask = SND_JACK_LINEIN,
+	},
+};
+
+static struct snd_soc_jack_gpio linein_jack_gpio = {
+	.name = "Linein detection",
+	.report = SND_JACK_LINEIN,
+	.debounce_time = 800,
+};
+
+static struct snd_soc_jack lineout_jack;
+
+static struct snd_soc_jack_pin lineout_jack_pins[] = {
+	{
+		.pin = "Lineout",
+		.mask = SND_JACK_LINEOUT,
+	},
+};
+
+static struct snd_soc_jack_gpio lineout_jack_gpio = {
+	.name = "Lineout detection",
+	.report = SND_JACK_LINEOUT,
+	.debounce_time = 800,
+};
+
 static int msm_vi_feed_tx_ch = 2;
-static const char *const slim_rx_ch_text[] = {"One", "Two"};
+static const char *const slim_rx_ch_text[] = {"One", "Two", "Three", "Four",
+						"Five", "Six", "Seven",
+						"Eight"};
 static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four",
 						"Five", "Six", "Seven",
 						"Eight"};
@@ -130,6 +166,8 @@
 static char const *bt_sample_rate_tx_text[] = {"KHZ_8", "KHZ_16",
 					"KHZ_44P1", "KHZ_48",
 					"KHZ_88P2", "KHZ_96"};
+static const char *const hifi_text[] = {"Off", "On"};
+
 static SOC_ENUM_SINGLE_EXT_DECL(spk_func_en, spk_function_text);
 static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text);
@@ -150,6 +188,7 @@
 static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_rx, bt_sample_rate_rx_text);
 static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_tx, bt_sample_rate_tx_text);
+static SOC_ENUM_SINGLE_EXT_DECL(hifi_function, hifi_text);
 
 static int slim_get_sample_rate_val(int sample_rate)
 {
@@ -738,6 +777,56 @@
 	return 1;
 }
 
+static int msm_hifi_ctrl(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_card *card = codec->component.card;
+	struct msm_asoc_mach_data *pdata =
+				snd_soc_card_get_drvdata(card);
+
+	pr_debug("%s: msm_hifi_control = %d\n", __func__,
+		 msm_hifi_control);
+
+	if (!pdata || !pdata->hph_en1_gpio_p) {
+		pr_err("%s: hph_en1_gpio is invalid\n", __func__);
+		return -EINVAL;
+	}
+	if (msm_hifi_control == MSM_HIFI_ON) {
+		msm_cdc_pinctrl_select_active_state(pdata->hph_en1_gpio_p);
+		/* 5msec delay needed as per HW requirement */
+		usleep_range(5000, 5010);
+	} else {
+		msm_cdc_pinctrl_select_sleep_state(pdata->hph_en1_gpio_p);
+	}
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static int msm_hifi_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_hifi_control = %d\n",
+		 __func__, msm_hifi_control);
+	ucontrol->value.integer.value[0] = msm_hifi_control;
+
+	return 0;
+}
+
+static int msm_hifi_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+
+	pr_debug("%s() ucontrol->value.integer.value[0] = %ld\n",
+		 __func__, ucontrol->value.integer.value[0]);
+
+	msm_hifi_control = ucontrol->value.integer.value[0];
+	msm_hifi_ctrl(codec);
+
+	return 0;
+}
+
 static void *def_ext_mbhc_cal(void)
 {
 	void *wcd_mbhc_cal;
@@ -887,6 +976,8 @@
 	SOC_ENUM_EXT("BT SampleRate TX", bt_sample_rate_tx,
 			msm_bt_sample_rate_tx_get,
 			msm_bt_sample_rate_tx_put),
+	SOC_ENUM_EXT("HiFi Function", hifi_function, msm_hifi_get,
+			msm_hifi_put),
 };
 
 static int msm_slim_get_ch_from_beid(int32_t id)
@@ -1536,6 +1627,39 @@
 	return 0;
 }
 
+static int msm_hifi_ctrl_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *k, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_card *card = codec->component.card;
+	struct msm_asoc_mach_data *pdata =
+				snd_soc_card_get_drvdata(card);
+
+	pr_debug("%s: msm_hifi_control = %d\n", __func__, msm_hifi_control);
+
+	if (!pdata || !pdata->hph_en0_gpio_p) {
+		pr_err("%s: hph_en0_gpio is invalid\n", __func__);
+		return -EINVAL;
+	}
+
+	if (msm_hifi_control != MSM_HIFI_ON) {
+		pr_debug("%s: HiFi mixer control is not set\n",
+			 __func__);
+		return 0;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		msm_cdc_pinctrl_select_active_state(pdata->hph_en0_gpio_p);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		msm_cdc_pinctrl_select_sleep_state(pdata->hph_en0_gpio_p);
+		break;
+	}
+
+	return 0;
+}
+
 static int msm_ext_prepare_hifi(struct msm_asoc_mach_data *pdata)
 {
 	int ret = 0;
@@ -1575,6 +1699,7 @@
 	SND_SOC_DAPM_SPK("Lineout_3 amp", NULL),
 	SND_SOC_DAPM_SPK("Lineout_2 amp", NULL),
 	SND_SOC_DAPM_SPK("Lineout_4 amp", NULL),
+	SND_SOC_DAPM_SPK("hifi amp", msm_hifi_ctrl_event),
 	SND_SOC_DAPM_MIC("Handset Mic", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
 	SND_SOC_DAPM_MIC("Secondary Mic", NULL),
@@ -1592,6 +1717,8 @@
 	SND_SOC_DAPM_MIC("Digital Mic4", NULL),
 	SND_SOC_DAPM_MIC("Digital Mic5", NULL),
 	SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+	SND_SOC_DAPM_HP("Lineout", NULL),
+	SND_SOC_DAPM_MIC("Linein", NULL),
 };
 
 static struct snd_soc_dapm_route wcd_audio_paths_tasha[] = {
@@ -1929,6 +2056,26 @@
 		tasha_codec_info_create_codec_entry(pdata->codec_root, codec);
 		tasha_mbhc_zdet_gpio_ctrl(msm_config_hph_en0_gpio, rtd->codec);
 	}
+
+	if (gpio_is_valid(pdata->gpio_linein_det)) {
+		snd_soc_card_jack_new(rtd->card, "Linein", SND_JACK_LINEIN,
+				      &linein_jack, linein_jack_pins,
+				      ARRAY_SIZE(linein_jack_pins));
+
+		linein_jack_gpio.invert = pdata->linein_det_swh;
+		linein_jack_gpio.gpio = pdata->gpio_linein_det;
+		snd_soc_jack_add_gpios(&linein_jack, 1, &linein_jack_gpio);
+	}
+
+	if (gpio_is_valid(pdata->gpio_lineout_det)) {
+		snd_soc_card_jack_new(rtd->card, "Lineout", SND_JACK_LINEOUT,
+				      &lineout_jack, lineout_jack_pins,
+				      ARRAY_SIZE(lineout_jack_pins));
+
+		lineout_jack_gpio.invert = pdata->lineout_det_swh;
+		lineout_jack_gpio.gpio = pdata->gpio_lineout_det;
+		snd_soc_jack_add_gpios(&lineout_jack, 1, &lineout_jack_gpio);
+	}
 done:
 	msm_set_codec_reg_done(true);
 	return 0;
@@ -2007,6 +2154,34 @@
 			"qcom,hph-en0-gpio", pdev->dev.of_node->full_name);
 	}
 
+	ret = of_property_read_u32(pdev->dev.of_node, "qcom,linein-det-swh",
+				   &pdata->linein_det_swh);
+	if (ret) {
+		dev_dbg(&pdev->dev, "%s: missing %s in dt node\n",
+			 __func__, "qcom,linein-det-swh");
+	}
+
+	ret = of_property_read_u32(pdev->dev.of_node, "qcom,lineout-det-swh",
+				   &pdata->lineout_det_swh);
+	if (ret) {
+		dev_dbg(&pdev->dev, "%s: missing %s in dt node\n",
+			 __func__, "qcom,lineout-det-swh");
+	}
+
+	pdata->gpio_linein_det = of_get_named_gpio(pdev->dev.of_node,
+						   "qcom,linein-det-gpio", 0);
+	if (pdata->gpio_linein_det < 0) {
+		dev_dbg(&pdev->dev, "property %s not detected in node %s\n",
+			"qcom,linein-det-gpio", pdev->dev.of_node->full_name);
+	}
+
+	pdata->gpio_lineout_det = of_get_named_gpio(pdev->dev.of_node,
+						  "qcom,lineout-det-gpio", 0);
+	if (pdata->gpio_lineout_det < 0) {
+		dev_dbg(&pdev->dev, "property %s not detected in node %s\n",
+			"qcom,lineout-det-gpio", pdev->dev.of_node->full_name);
+	}
+
 	ret = msm_ext_prepare_hifi(pdata);
 	if (ret) {
 		dev_dbg(&pdev->dev, "msm_ext_prepare_hifi failed (%d)\n",
diff --git a/dsp/audio_cal_utils.c b/dsp/audio_cal_utils.c
index ad1dc3d..c6449dd 100644
--- a/dsp/audio_cal_utils.c
+++ b/dsp/audio_cal_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -63,6 +63,7 @@
 		break;
 	case ADM_AUDPROC_CAL_TYPE:
 	case ADM_LSM_AUDPROC_CAL_TYPE:
+	case ADM_LSM_AUDPROC_PERSISTENT_CAL_TYPE:
 		size = sizeof(struct audio_cal_info_audproc);
 		break;
 	case ADM_AUDVOL_CAL_TYPE:
@@ -213,6 +214,7 @@
 		break;
 	case ADM_AUDPROC_CAL_TYPE:
 	case ADM_LSM_AUDPROC_CAL_TYPE:
+	case ADM_LSM_AUDPROC_PERSISTENT_CAL_TYPE:
 		size = sizeof(struct audio_cal_type_audproc);
 		break;
 	case ADM_AUDVOL_CAL_TYPE:
diff --git a/dsp/codecs/audio_aac.c b/dsp/codecs/audio_aac.c
index c742f72..44444ef 100644
--- a/dsp/codecs/audio_aac.c
+++ b/dsp/codecs/audio_aac.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2018, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -230,7 +230,7 @@
 		pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
 		rc = audio->codec_ioctl(file, cmd, arg);
 		if (rc)
-			pr_err("%s[%pK]:Failed in utils_ioctl: %d\n",
+			pr_err_ratelimited("%s[%pK]:Failed in utils_ioctl: %d\n",
 				__func__, audio, rc);
 	}
 	}
@@ -339,7 +339,7 @@
 		pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
 		rc = audio->codec_compat_ioctl(file, cmd, arg);
 		if (rc)
-			pr_err("%s[%pK]:Failed in utils_ioctl: %d\n",
+			pr_err_ratelimited("%s[%pK]:Failed in utils_ioctl: %d\n",
 				__func__, audio, rc);
 	}
 	}
diff --git a/dsp/codecs/audio_alac.c b/dsp/codecs/audio_alac.c
index cfb3087..975a1e9 100644
--- a/dsp/codecs/audio_alac.c
+++ b/dsp/codecs/audio_alac.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -151,7 +151,7 @@
 	default: {
 		rc = audio->codec_ioctl(file, cmd, arg);
 		if (rc)
-			pr_err("Failed in utils_ioctl: %d\n", rc);
+			pr_err_ratelimited("Failed in utils_ioctl: %d\n", rc);
 		break;
 	}
 	}
@@ -253,7 +253,7 @@
 	default: {
 		rc = audio->codec_compat_ioctl(file, cmd, arg);
 		if (rc)
-			pr_err("Failed in utils_ioctl: %d\n", rc);
+			pr_err_ratelimited("Failed in utils_ioctl: %d\n", rc);
 		break;
 	}
 	}
diff --git a/dsp/codecs/audio_ape.c b/dsp/codecs/audio_ape.c
index 3df6347..f2a6bf7 100644
--- a/dsp/codecs/audio_ape.c
+++ b/dsp/codecs/audio_ape.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -137,7 +137,7 @@
 		pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
 		rc = audio->codec_ioctl(file, cmd, arg);
 		if (rc)
-			pr_err("Failed in utils_ioctl: %d\n", rc);
+			pr_err_ratelimited("Failed in utils_ioctl: %d\n", rc);
 		break;
 	}
 	}
@@ -235,7 +235,7 @@
 		pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
 		rc = audio->codec_compat_ioctl(file, cmd, arg);
 		if (rc)
-			pr_err("Failed in utils_ioctl: %d\n", rc);
+			pr_err_ratelimited("Failed in utils_ioctl: %d\n", rc);
 		break;
 	}
 	}
diff --git a/dsp/codecs/audio_utils.c b/dsp/codecs/audio_utils.c
index 15ee9f5..e559678 100644
--- a/dsp/codecs/audio_utils.c
+++ b/dsp/codecs/audio_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -760,6 +760,10 @@
 				}
 				bytes_to_copy =
 					(size + audio->out_frame_info[idx][1]);
+				if (bytes_to_copy == 0) {
+					rc = 0;
+					break;
+				}
 				/* Number of frames information copied */
 				buf += sizeof(unsigned char);
 				count -= sizeof(unsigned char);
@@ -793,8 +797,10 @@
 
 	pr_debug("%s:session id %d: read: %zd bytes\n", __func__,
 			audio->ac->session, (buf-start));
-	if (buf > start)
-		return buf - start;
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
 	return rc;
 }
 
diff --git a/dsp/codecs/audio_utils_aio.c b/dsp/codecs/audio_utils_aio.c
index e8f22e7..9c8b3b8 100644
--- a/dsp/codecs/audio_utils_aio.c
+++ b/dsp/codecs/audio_utils_aio.c
@@ -1,6 +1,6 @@
 /* Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2018, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -201,17 +201,17 @@
 	if (audio->enabled) {
 		rc = q6asm_cmd(audio->ac, CMD_PAUSE);
 		if (rc < 0)
-			pr_err("%s[%pK]: pause cmd failed rc=%d\n",
+			pr_err_ratelimited("%s[%pK]: pause cmd failed rc=%d\n",
 				__func__, audio, rc);
 
 		if (rc == 0) {
 			/* Send suspend only if pause was successful */
 			rc = q6asm_cmd(audio->ac, CMD_SUSPEND);
 			if (rc < 0)
-				pr_err("%s[%pK]: suspend cmd failed rc=%d\n",
+				pr_err_ratelimited("%s[%pK]: suspend cmd failed rc=%d\n",
 					__func__, audio, rc);
 		} else
-			pr_err("%s[%pK]: not sending suspend since pause failed\n",
+			pr_err_ratelimited("%s[%pK]: not sending suspend since pause failed\n",
 				__func__, audio);
 
 	} else
@@ -230,7 +230,7 @@
 		if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
 			rc = audio_aio_pause(audio);
 			if (rc < 0)
-				pr_err("%s[%pK}: pause cmd failed rc=%d\n",
+				pr_err_ratelimited("%s[%pK}: pause cmd failed rc=%d\n",
 					__func__, audio,
 					rc);
 			else
@@ -238,13 +238,13 @@
 		}
 		rc = q6asm_cmd(audio->ac, CMD_FLUSH);
 		if (rc < 0)
-			pr_err("%s[%pK]: flush cmd failed rc=%d\n",
+			pr_err_ratelimited("%s[%pK]: flush cmd failed rc=%d\n",
 				__func__, audio, rc);
 		/* Not in stop state, reenable the stream */
 		if (audio->stopped == 0) {
 			rc = audio_aio_enable(audio);
 			if (rc)
-				pr_err("%s[%pK]:audio re-enable failed\n",
+				pr_err_ratelimited("%s[%pK]:audio re-enable failed\n",
 					__func__, audio);
 			else {
 				audio->enabled = 1;
@@ -268,7 +268,7 @@
 
 	rc = q6asm_cmd(audio->ac, CMD_OUT_FLUSH);
 	if (rc < 0)
-		pr_err("%s[%pK}: output port flush cmd failed rc=%d\n",
+		pr_err_ratelimited("%s[%pK}: output port flush cmd failed rc=%d\n",
 			__func__, audio, rc);
 	return rc;
 }
@@ -402,7 +402,7 @@
 		/* Close the session */
 		rc = q6asm_cmd(audio->ac, CMD_CLOSE);
 		if (rc < 0)
-			pr_err("%s[%pK]:Failed to close the session rc=%d\n",
+			pr_err_ratelimited("%s[%pK]:Failed to close the session rc=%d\n",
 				__func__, audio, rc);
 		audio->stopped = 1;
 		wake_up(&audio->write_wait);
@@ -677,7 +677,7 @@
 	pr_debug("%s[%pK]: EOS cmd sent to DSP\n", __func__, audio);
 
 	if (rc < 0)
-		pr_err("%s[%pK]: q6asm_cmd failed, rc = %d",
+		pr_err_ratelimited("%s[%pK]: q6asm_cmd failed, rc = %d",
 			__func__, audio, rc);
 
 	pr_debug("%s[%pK]: wait for RENDERED_EOS from DSP\n"
@@ -1422,7 +1422,7 @@
 		mutex_lock(&audio->read_lock);
 		rc = audio_aio_outport_flush(audio);
 		if (rc < 0) {
-			pr_err("%s[%pK]: AUDIO_OUTPORT_FLUSH failed\n",
+			pr_err_ratelimited("%s[%pK]: AUDIO_OUTPORT_FLUSH failed\n",
 				__func__, audio);
 			rc = -EINTR;
 		}
@@ -1436,7 +1436,7 @@
 		audio->stopped = 1;
 		rc = audio_aio_flush(audio);
 		if (rc < 0) {
-			pr_err("%s[%pK]:Audio Stop procedure failed rc=%d\n",
+			pr_err_ratelimited("%s[%pK]:Audio Stop procedure failed rc=%d\n",
 				__func__, audio, rc);
 			mutex_unlock(&audio->lock);
 			break;
@@ -1457,7 +1457,7 @@
 		if (arg == 1) {
 			rc = audio_aio_pause(audio);
 			if (rc < 0) {
-				pr_err("%s[%pK]: pause FAILED rc=%d\n",
+				pr_err_ratelimited("%s[%pK]: pause FAILED rc=%d\n",
 					__func__, audio, rc);
 				mutex_unlock(&audio->lock);
 				break;
@@ -1467,7 +1467,7 @@
 			if (audio->drv_status & ADRV_STATUS_PAUSE) {
 				rc = audio_aio_enable(audio);
 				if (rc)
-					pr_err("%s[%pK]: audio enable failed\n",
+					pr_err_ratelimited("%s[%pK]: audio enable failed\n",
 					__func__, audio);
 				else {
 					audio->drv_status &= ~ADRV_STATUS_PAUSE;
@@ -1494,7 +1494,7 @@
 		/* Flush input / Output buffer in software*/
 		audio_aio_ioport_reset(audio);
 		if (rc < 0) {
-			pr_err("%s[%pK]:AUDIO_FLUSH interrupted\n",
+			pr_err_ratelimited("%s[%pK]:AUDIO_FLUSH interrupted\n",
 				__func__, audio);
 			rc = -EINTR;
 		} else {
@@ -1514,7 +1514,7 @@
 		mutex_lock(&audio->lock);
 		if (copy_to_user((void *)arg, &audio->ac->session,
 			sizeof(u16))) {
-			pr_err("%s: copy_to_user for AUDIO_GET_SESSION_ID failed\n",
+			pr_err_ratelimited("%s: copy_to_user for AUDIO_GET_SESSION_ID failed\n",
 				__func__);
 			rc = -EFAULT;
 		}
@@ -1524,7 +1524,7 @@
 	case AUDIO_PM_AWAKE: {
 		if ((audio->audio_ws_mgr ==  NULL) ||
 				(audio->miscdevice == NULL)) {
-			pr_err("%s[%pK]: invalid ws_mgr or miscdevice",
+			pr_err_ratelimited("%s[%pK]: invalid ws_mgr or miscdevice",
 					__func__, audio);
 			rc = -EACCES;
 			break;
@@ -1544,7 +1544,7 @@
 	case AUDIO_PM_RELAX: {
 		if ((audio->audio_ws_mgr ==  NULL) ||
 				(audio->miscdevice == NULL)) {
-			pr_err("%s[%pK]: invalid ws_mgr or miscdevice",
+			pr_err_ratelimited("%s[%pK]: invalid ws_mgr or miscdevice",
 					__func__, audio);
 			rc = -EACCES;
 			break;
diff --git a/dsp/codecs/audio_wma.c b/dsp/codecs/audio_wma.c
index ef9c8c6..0e8341e 100644
--- a/dsp/codecs/audio_wma.c
+++ b/dsp/codecs/audio_wma.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2018, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -126,7 +126,7 @@
 		pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
 		rc = audio->codec_ioctl(file, cmd, arg);
 		if (rc)
-			pr_err("Failed in utils_ioctl: %d\n", rc);
+			pr_err_ratelimited("Failed in utils_ioctl: %d\n", rc);
 		break;
 	}
 	}
@@ -215,7 +215,7 @@
 		pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
 		rc = audio->codec_compat_ioctl(file, cmd, arg);
 		if (rc)
-			pr_err("Failed in utils_ioctl: %d\n", rc);
+			pr_err_ratelimited("Failed in utils_ioctl: %d\n", rc);
 		break;
 	}
 	}
diff --git a/dsp/codecs/audio_wmapro.c b/dsp/codecs/audio_wmapro.c
index 2182618..6b1e46f 100644
--- a/dsp/codecs/audio_wmapro.c
+++ b/dsp/codecs/audio_wmapro.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2018, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -177,7 +177,7 @@
 		pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
 		rc = audio->codec_ioctl(file, cmd, arg);
 		if (rc)
-			pr_err("Failed in utils_ioctl: %d\n", rc);
+			pr_err_ratelimited("Failed in utils_ioctl: %d\n", rc);
 		break;
 	}
 	}
@@ -287,7 +287,7 @@
 		pr_debug("%s[%pK]: Calling utils ioctl\n", __func__, audio);
 		rc = audio->codec_compat_ioctl(file, cmd, arg);
 		if (rc)
-			pr_err("Failed in utils_ioctl: %d\n", rc);
+			pr_err_ratelimited("Failed in utils_ioctl: %d\n", rc);
 		break;
 	}
 	}
diff --git a/dsp/q6adm.c b/dsp/q6adm.c
index 74a9244..e42e329 100644
--- a/dsp/q6adm.c
+++ b/dsp/q6adm.c
@@ -635,18 +635,21 @@
  * session_type - Passed value, session_type for RX or TX
  * ch_mixer - Passed value, ch_mixer for which channel mixer config is needed
  * channel_index - Passed value, channel_index for which channel is needed
+ * use_default_chmap - true if default channel map  to be used
+ * ch_map - input/output channel map for playback/capture session respectively
  */
 int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id,
 				  int session_type,
 				  struct msm_pcm_channel_mixer *ch_mixer,
-				  int channel_index)
+				  int channel_index, bool use_default_chmap,
+				  char *ch_map)
 {
 	struct adm_cmd_set_pspd_mtmx_strtr_params_v5 *adm_params = NULL;
 	struct adm_param_data_v5 data_v5;
 	int ret = 0, port_idx, sz = 0, param_size = 0;
 	u16 *adm_pspd_params;
 	u16 *ptr;
-	int index = 0;
+	int index = 0, i;
 
 	pr_debug("%s: port_id = %d\n", __func__, port_id);
 	port_id = afe_convert_virtual_to_portid(port_id);
@@ -671,7 +674,8 @@
 			ch_mixer->input_channels[channel_index] +
 			ch_mixer->input_channels[channel_index] *
 			ch_mixer->output_channel);
-	roundup(param_size, 4);
+	/* Params size should be multiple of 4 bytes i.e 32bit aligned */
+	param_size = round_up(param_size, 4);
 
 	sz = sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5) +
 			sizeof(struct default_chmixer_param_id_coeff) +
@@ -713,87 +717,96 @@
 	adm_pspd_params[3] = ch_mixer->input_channels[channel_index];
 	index = 4;
 
-	if (ch_mixer->output_channel == 1) {
-		adm_pspd_params[index] = PCM_CHANNEL_FC;
-	} else if (ch_mixer->output_channel == 2) {
-		adm_pspd_params[index] = PCM_CHANNEL_FL;
-		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-	} else if (ch_mixer->output_channel == 3) {
-		adm_pspd_params[index] = PCM_CHANNEL_FL;
-		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-		adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
-	} else if (ch_mixer->output_channel == 4) {
-		adm_pspd_params[index] = PCM_CHANNEL_FL;
-		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-		adm_pspd_params[index + 2] = PCM_CHANNEL_LS;
-		adm_pspd_params[index + 3] = PCM_CHANNEL_RS;
-	} else if (ch_mixer->output_channel == 5) {
-		adm_pspd_params[index] = PCM_CHANNEL_FL;
-		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-		adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
-		adm_pspd_params[index + 3] = PCM_CHANNEL_LS;
-		adm_pspd_params[index + 4] = PCM_CHANNEL_RS;
-	} else if (ch_mixer->output_channel == 6) {
-		adm_pspd_params[index] = PCM_CHANNEL_FL;
-		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-		adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
-		adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
-		adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
-		adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
-	} else if (ch_mixer->output_channel == 8) {
-		adm_pspd_params[index] = PCM_CHANNEL_FL;
-		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-		adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
-		adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
-		adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
-		adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
-		adm_pspd_params[index + 6] = PCM_CHANNEL_LB;
-		adm_pspd_params[index + 7] = PCM_CHANNEL_RB;
+	if ((session_type == SESSION_TYPE_TX) && !use_default_chmap && ch_map) {
+		for (i = 0; i < ch_mixer->output_channel; i++)
+			adm_pspd_params[index++] = ch_map[i];
+	} else {
+		if (ch_mixer->output_channel == 1) {
+			adm_pspd_params[index] = PCM_CHANNEL_FC;
+		} else if (ch_mixer->output_channel == 2) {
+			adm_pspd_params[index] = PCM_CHANNEL_FL;
+			adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+		} else if (ch_mixer->output_channel == 3) {
+			adm_pspd_params[index] = PCM_CHANNEL_FL;
+			adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+			adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
+		} else if (ch_mixer->output_channel == 4) {
+			adm_pspd_params[index] = PCM_CHANNEL_FL;
+			adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+			adm_pspd_params[index + 2] = PCM_CHANNEL_LS;
+			adm_pspd_params[index + 3] = PCM_CHANNEL_RS;
+		} else if (ch_mixer->output_channel == 5) {
+			adm_pspd_params[index] = PCM_CHANNEL_FL;
+			adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+			adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
+			adm_pspd_params[index + 3] = PCM_CHANNEL_LS;
+			adm_pspd_params[index + 4] = PCM_CHANNEL_RS;
+		} else if (ch_mixer->output_channel == 6) {
+			adm_pspd_params[index] = PCM_CHANNEL_FL;
+			adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+			adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
+			adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
+			adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
+			adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
+		} else if (ch_mixer->output_channel == 8) {
+			adm_pspd_params[index] = PCM_CHANNEL_FL;
+			adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+			adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
+			adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
+			adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
+			adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
+			adm_pspd_params[index + 6] = PCM_CHANNEL_LB;
+			adm_pspd_params[index + 7] = PCM_CHANNEL_RB;
+		}
+		index = index + ch_mixer->output_channel;
 	}
 
-	index = index + ch_mixer->output_channel;
-	if (ch_mixer->input_channels[channel_index] == 1) {
-		adm_pspd_params[index] = PCM_CHANNEL_FC;
-	} else if (ch_mixer->input_channels[channel_index] == 2) {
-		adm_pspd_params[index] = PCM_CHANNEL_FL;
-		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-	} else if (ch_mixer->input_channels[channel_index] == 3) {
-		adm_pspd_params[index] = PCM_CHANNEL_FL;
-		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-		adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
-	} else if (ch_mixer->input_channels[channel_index] == 4) {
-		adm_pspd_params[index] = PCM_CHANNEL_FL;
-		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-		adm_pspd_params[index + 2] = PCM_CHANNEL_LS;
-		adm_pspd_params[index + 3] = PCM_CHANNEL_RS;
-	} else if (ch_mixer->input_channels[channel_index] == 5) {
-		adm_pspd_params[index] = PCM_CHANNEL_FL;
-		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-		adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
-		adm_pspd_params[index + 3] = PCM_CHANNEL_LS;
-		adm_pspd_params[index + 4] = PCM_CHANNEL_RS;
-	} else if (ch_mixer->input_channels[channel_index] == 6) {
-		adm_pspd_params[index] = PCM_CHANNEL_FL;
-		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-		adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
-		adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
-		adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
-		adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
-	} else if (ch_mixer->input_channels[channel_index] == 8) {
-		adm_pspd_params[index] = PCM_CHANNEL_FL;
-		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-		adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
-		adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
-		adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
-		adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
-		adm_pspd_params[index + 6] = PCM_CHANNEL_LB;
-		adm_pspd_params[index + 7] = PCM_CHANNEL_RB;
+	if ((session_type == SESSION_TYPE_RX) && !use_default_chmap && ch_map) {
+		for (i = 0; i < ch_mixer->input_channels[channel_index]; i++)
+			adm_pspd_params[index++] = ch_map[i];
+	} else {
+		if (ch_mixer->input_channels[channel_index] == 1) {
+			adm_pspd_params[index] = PCM_CHANNEL_FC;
+		} else if (ch_mixer->input_channels[channel_index] == 2) {
+			adm_pspd_params[index] = PCM_CHANNEL_FL;
+			adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+		} else if (ch_mixer->input_channels[channel_index] == 3) {
+			adm_pspd_params[index] = PCM_CHANNEL_FL;
+			adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+			adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
+		} else if (ch_mixer->input_channels[channel_index] == 4) {
+			adm_pspd_params[index] = PCM_CHANNEL_FL;
+			adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+			adm_pspd_params[index + 2] = PCM_CHANNEL_LS;
+			adm_pspd_params[index + 3] = PCM_CHANNEL_RS;
+		} else if (ch_mixer->input_channels[channel_index] == 5) {
+			adm_pspd_params[index] = PCM_CHANNEL_FL;
+			adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+			adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
+			adm_pspd_params[index + 3] = PCM_CHANNEL_LS;
+			adm_pspd_params[index + 4] = PCM_CHANNEL_RS;
+		} else if (ch_mixer->input_channels[channel_index] == 6) {
+			adm_pspd_params[index] = PCM_CHANNEL_FL;
+			adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+			adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
+			adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
+			adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
+			adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
+		} else if (ch_mixer->input_channels[channel_index] == 8) {
+			adm_pspd_params[index] = PCM_CHANNEL_FL;
+			adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+			adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
+			adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
+			adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
+			adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
+			adm_pspd_params[index + 6] = PCM_CHANNEL_LB;
+			adm_pspd_params[index + 7] = PCM_CHANNEL_RB;
+		}
+		index = index + ch_mixer->input_channels[channel_index];
 	}
-
-	index = index + ch_mixer->input_channels[channel_index];
 	ret = adm_populate_channel_weight(&adm_pspd_params[index],
 					ch_mixer, channel_index);
-	if (!ret) {
+	if (ret) {
 		pr_err("%s: fail to get channel weight with error %d\n",
 			__func__, ret);
 		goto fail_cmd;
@@ -2158,7 +2171,8 @@
 			struct cal_block_data, list);
 
 		if (cal_index == ADM_AUDPROC_CAL ||
-		    cal_index == ADM_LSM_AUDPROC_CAL) {
+		    cal_index == ADM_LSM_AUDPROC_CAL ||
+		    cal_index == ADM_LSM_AUDPROC_PERSISTENT_CAL) {
 			audproc_cal_info = cal_block->cal_info;
 			if ((audproc_cal_info->path == path) &&
 			    (cal_block->cal_data.size > 0))
@@ -2192,7 +2206,8 @@
 			struct cal_block_data, list);
 
 		if (cal_index == ADM_AUDPROC_CAL ||
-		    cal_index == ADM_LSM_AUDPROC_CAL) {
+		    cal_index == ADM_LSM_AUDPROC_CAL ||
+		    cal_index == ADM_LSM_AUDPROC_PERSISTENT_CAL) {
 			audproc_cal_info = cal_block->cal_info;
 			if ((audproc_cal_info->path == path) &&
 			    (audproc_cal_info->app_type == app_type) &&
@@ -2230,7 +2245,8 @@
 			struct cal_block_data, list);
 
 		if (cal_index == ADM_AUDPROC_CAL ||
-		    cal_index == ADM_LSM_AUDPROC_CAL) {
+		    cal_index == ADM_LSM_AUDPROC_CAL ||
+		    cal_index == ADM_LSM_AUDPROC_PERSISTENT_CAL) {
 			audproc_cal_info = cal_block->cal_info;
 			if ((audproc_cal_info->path == path) &&
 			    (audproc_cal_info->app_type == app_type) &&
@@ -2317,12 +2333,18 @@
 {
 	pr_debug("%s: port id 0x%x copp_idx %d\n", __func__, port_id, copp_idx);
 
-	if (passthr_mode != LISTEN)
+	if (passthr_mode != LISTEN) {
 		send_adm_cal_type(ADM_AUDPROC_CAL, path, port_id, copp_idx,
 				perf_mode, app_type, acdb_id, sample_rate);
-	else
+	} else {
 		send_adm_cal_type(ADM_LSM_AUDPROC_CAL, path, port_id, copp_idx,
 				  perf_mode, app_type, acdb_id, sample_rate);
+
+		send_adm_cal_type(ADM_LSM_AUDPROC_PERSISTENT_CAL, path,
+				  port_id, copp_idx, perf_mode, app_type,
+				  acdb_id, sample_rate);
+	}
+
 	send_adm_cal_type(ADM_AUDVOL_CAL, path, port_id, copp_idx, perf_mode,
 			  app_type, acdb_id, sample_rate);
 }
@@ -2624,6 +2646,7 @@
 	}
 
 	if ((topology == VPM_TX_SM_ECNS_V2_COPP_TOPOLOGY) ||
+	    (topology == VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
 	    (topology == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
 	    (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY))
 		rate = 16000;
@@ -3492,6 +3515,9 @@
 	case ADM_RTAC_AUDVOL_CAL_TYPE:
 		ret = ADM_RTAC_AUDVOL_CAL;
 		break;
+	case ADM_LSM_AUDPROC_PERSISTENT_CAL_TYPE:
+		ret = ADM_LSM_AUDPROC_PERSISTENT_CAL;
+		break;
 	default:
 		pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
 	}
@@ -3713,6 +3739,12 @@
 		adm_set_cal, NULL, NULL} },
 		{adm_map_cal_data, adm_unmap_cal_data,
 		cal_utils_match_buf_num} },
+
+		{{ADM_LSM_AUDPROC_PERSISTENT_CAL_TYPE,
+		 {adm_alloc_cal, adm_dealloc_cal, NULL,
+		  adm_set_cal, NULL, NULL} },
+		 {adm_map_cal_data, adm_unmap_cal_data,
+		  cal_utils_match_buf_num} },
 	};
 	pr_debug("%s:\n", __func__);
 
@@ -4503,6 +4535,13 @@
 			rc = -ENOMEM;
 			goto unlock;
 		}
+	} else if (cal_index == ADM_LSM_AUDPROC_PERSISTENT_CAL) {
+		if (cal_block->cal_data.size > AUD_PROC_PERSIST_BLOCK_SIZE) {
+			pr_err("%s:persist invalid size exp/actual[%zd, %d]\n",
+				__func__, cal_block->cal_data.size, *size);
+			rc = -ENOMEM;
+			goto unlock;
+		}
 	} else if (cal_index == ADM_AUDVOL_CAL) {
 		if (cal_block->cal_data.size > AUD_VOL_BLOCK_SIZE) {
 			pr_err("%s:aud_vol:invalid size exp/actual[%zd, %d]\n",
diff --git a/dsp/q6asm.c b/dsp/q6asm.c
index 8701962..4091faf 100644
--- a/dsp/q6asm.c
+++ b/dsp/q6asm.c
@@ -9543,11 +9543,11 @@
 	int cnt = 0;
 
 	if (!ac) {
-		pr_err("%s: APR handle NULL\n", __func__);
+		pr_err_ratelimited("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	if (ac->apr == NULL) {
-		pr_err("%s: AC APR handle NULL\n", __func__);
+		pr_err_ratelimited("%s: AC APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	q6asm_stream_add_hdr(ac, &hdr, sizeof(hdr), TRUE, stream_id);
@@ -9707,11 +9707,11 @@
 	int rc;
 
 	if (!ac) {
-		pr_err("%s: APR handle NULL\n", __func__);
+		pr_err_ratelimited("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	if (ac->apr == NULL) {
-		pr_err("%s: AC APR handle NULL\n", __func__);
+		pr_err_ratelimited("%s: AC APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	q6asm_stream_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE, stream_id);
@@ -9796,11 +9796,11 @@
 	int rc = 0;
 
 	if (!ac) {
-		pr_err("%s: APR handle NULL\n", __func__);
+		pr_err_ratelimited("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	if (ac->apr == NULL) {
-		pr_err("%s: AC APR handle NULL\n", __func__);
+		pr_err_ratelimited("%s: AC APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	pr_debug("%s: session[%d]\n", __func__, ac->session);
diff --git a/dsp/q6voice.c b/dsp/q6voice.c
index 4d86def..e5b1139 100644
--- a/dsp/q6voice.c
+++ b/dsp/q6voice.c
@@ -141,6 +141,8 @@
 static int voice_send_get_source_tracking_cmd(struct voice_data *v,
 			struct source_tracking_param *sourceTrackingData);
 
+static void voice_vote_powerstate_to_bms(struct voice_data *v, bool state);
+
 static void voice_itr_init(struct voice_session_itr *itr,
 			   u32 session_id)
 {
@@ -1950,6 +1952,47 @@
 EXPORT_SYMBOL(voc_set_destroy_cvd_flag);
 
 /**
+ * voc_set_vote_bms_flag -
+ *      set flag for BMS voting
+ *
+ * @is_destroy_cvd: bool value used to indicate
+ *                  to vote for BMS or not in voice call.
+ *
+ */
+void voc_set_vote_bms_flag(bool is_vote_bms)
+{
+	pr_debug("%s: flag value: %d\n", __func__, is_vote_bms);
+	common.is_vote_bms = is_vote_bms;
+}
+EXPORT_SYMBOL(voc_set_vote_bms_flag);
+
+static void voice_vote_powerstate_to_bms(struct voice_data *v, bool state)
+{
+	union power_supply_propval psp_val;
+
+	if (!v->psy)
+		v->psy = power_supply_get_by_name("bms");
+
+	psp_val.intval = VMBMS_VOICE_CALL_BIT;
+	if (v->psy && !(is_voip_session(v->session_id) ||
+			is_vowlan_session(v->session_id))) {
+		if (state) {
+			pr_debug("%s : Vote High power to BMS\n",
+				__func__);
+			power_supply_set_property(v->psy,
+					POWER_SUPPLY_PROP_HI_POWER, &psp_val);
+		} else {
+			pr_debug("%s: Vote low power to BMS\n",
+				__func__);
+			power_supply_set_property(v->psy,
+					POWER_SUPPLY_PROP_LOW_POWER, &psp_val);
+		}
+	} else {
+		pr_debug("%s: No OP", __func__);
+	}
+}
+
+/**
  * voc_alloc_cal_shared_memory -
  *       Alloc mem map table for calibration
  *
@@ -2422,6 +2465,10 @@
 				v->async_err);
 		goto fail;
 	}
+	if (common.is_vote_bms) {
+		/* vote high power to BMS during call start */
+		voice_vote_powerstate_to_bms(v, true);
+	}
 	return 0;
 fail:
 	return ret;
@@ -6873,6 +6920,10 @@
 
 		voice_destroy_mvm_cvs_session(v);
 		v->voc_state = VOC_RELEASE;
+		if (common.is_vote_bms) {
+			/* vote low power to BMS during call stop */
+			voice_vote_powerstate_to_bms(v, false);
+		}
 	} else {
 		pr_err("%s: Error: End voice called in state %d\n",
 			__func__, v->voc_state);
diff --git a/dsp/rtac.c b/dsp/rtac.c
index 0455779..a4dec9a 100644
--- a/dsp/rtac.c
+++ b/dsp/rtac.c
@@ -35,7 +35,7 @@
 #define MAX_PAYLOAD_SIZE		4076
 #define RTAC_MAX_ACTIVE_VOICE_COMBOS	2
 #define RTAC_MAX_ACTIVE_POPP		8
-#define RTAC_BUF_SIZE			57344
+#define RTAC_BUF_SIZE			163840
 
 #define TIMEOUT_MS	1000
 
diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h
index a608a66..d313d64 100644
--- a/include/dsp/apr_audio-v2.h
+++ b/include/dsp/apr_audio-v2.h
@@ -4015,6 +4015,7 @@
 #define DEFAULT_POPP_TOPOLOGY				0x00010BE4
 #define COMPRESSED_PASSTHROUGH_DEFAULT_TOPOLOGY         0x0001076B
 #define COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY            0x00010774
+#define VPM_TX_SM_ECNS_COPP_TOPOLOGY			0x00010F71
 #define VPM_TX_SM_ECNS_V2_COPP_TOPOLOGY			0x00010F89
 #define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY			0x00010F72
 #define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY		0x00010F75
diff --git a/include/dsp/q6adm-v2.h b/include/dsp/q6adm-v2.h
index e8000ab..5308b6e 100644
--- a/include/dsp/q6adm-v2.h
+++ b/include/dsp/q6adm-v2.h
@@ -27,8 +27,12 @@
 		((MAX_MODULES_IN_TOPO + 1) * sizeof(uint32_t))
 #define AUD_PROC_BLOCK_SIZE	4096
 #define AUD_VOL_BLOCK_SIZE	4096
+#define AUD_PROC_PERSIST_BLOCK_SIZE	(2 * 1024 * 1020)
 #define AUDIO_RX_CALIBRATION_SIZE	(AUD_PROC_BLOCK_SIZE + \
 						AUD_VOL_BLOCK_SIZE)
+#define SESSION_TYPE_RX 0
+#define SESSION_TYPE_TX 1
+
 enum {
 	ADM_CUSTOM_TOP_CAL = 0,
 	ADM_AUDPROC_CAL,
@@ -38,6 +42,7 @@
 	ADM_RTAC_APR_CAL,
 	ADM_SRS_TRUMEDIA,
 	ADM_RTAC_AUDVOL_CAL,
+	ADM_LSM_AUDPROC_PERSISTENT_CAL,
 	ADM_MAX_CAL_TYPES
 };
 
@@ -184,7 +189,8 @@
 int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id,
 			int session_type,
 			struct msm_pcm_channel_mixer *ch_mixer,
-			int channel_index);
+			int channel_index, bool use_default_chmap,
+			char *ch_map);
 void msm_dts_srs_acquire_lock(void);
 void msm_dts_srs_release_lock(void);
 #endif /* __Q6_ADM_V2_H__ */
diff --git a/include/dsp/q6voice.h b/include/dsp/q6voice.h
index 86be4e1..4d1cf92 100644
--- a/include/dsp/q6voice.h
+++ b/include/dsp/q6voice.h
@@ -13,6 +13,8 @@
 #define __QDSP6VOICE_H__
 
 #include <linux/msm_ion.h>
+#include <linux/power_supply.h>
+#include <uapi/linux/vm_bms.h>
 #include <sound/voice_params.h>
 #include <dsp/rtac.h>
 #include <dsp/q6core.h>
@@ -1916,6 +1918,8 @@
 
 	bool mic_break_status;
 	struct work_struct voice_mic_break_work;
+
+	struct power_supply *psy;
 };
 
 struct cal_mem {
@@ -1980,6 +1984,7 @@
 	bool sidetone_enable;
 	bool mic_break_enable;
 	struct audio_uevent_data *uevent_data;
+	bool is_vote_bms;
 };
 
 struct voice_session_itr {
@@ -2107,6 +2112,7 @@
 int voc_disable_device(uint32_t session_id);
 int voc_enable_device(uint32_t session_id);
 void voc_set_destroy_cvd_flag(bool is_destroy_cvd);
+void voc_set_vote_bms_flag(bool is_vote_bms);
 int voc_disable_topology(uint32_t session_id, uint32_t disable);
 int voc_set_device_config(uint32_t session_id, uint8_t path_dir,
 			  struct media_format_info *finfo);
diff --git a/include/uapi/Android.mk b/include/uapi/Android.mk
index 36bcfde..b8c209a 100644
--- a/include/uapi/Android.mk
+++ b/include/uapi/Android.mk
@@ -17,6 +17,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_PREBUILT_INT_KERNEL)
 
 GEN := $(addprefix $(UAPI_OUT)/,$(AUDIO_KERNEL_HEADERS))
+$(GEN): $(KERNEL_USR)
 $(GEN): PRIVATE_PATH := $(MYLOCAL_PATH)
 $(GEN): PRIVATE_CUSTOM_TOOL = $(shell cd $(PRODUCT_OUT)/obj/KERNEL_OBJ; $(BUILD_ROOT_RELATIVE)$(HEADER_INSTALL_DIR)/headers_install.sh $(BUILD_ROOT_RELATIVE)$(dir $@) $(BUILD_ROOT_RELATIVE)$(subst $(UAPI_OUT),$(MYLOCAL_PATH),$(dir $@)) $(notdir $@))
 $(GEN): $(addprefix $(MYLOCAL_PATH)/,$(AUDIO_KERNEL_HEADERS))
diff --git a/include/uapi/linux/msm_audio_calibration.h b/include/uapi/linux/msm_audio_calibration.h
index 3b97ab2..c5811d0 100644
--- a/include/uapi/linux/msm_audio_calibration.h
+++ b/include/uapi/linux/msm_audio_calibration.h
@@ -103,6 +103,7 @@
 	AFE_LSM_TX_CAL_TYPE,
 	ADM_LSM_TOPOLOGY_CAL_TYPE,
 	ADM_LSM_AUDPROC_CAL_TYPE,
+	ADM_LSM_AUDPROC_PERSISTENT_CAL_TYPE,
 	MAX_CAL_TYPES,
 };
 
@@ -115,6 +116,7 @@
 #define AFE_LSM_TX_CAL_TYPE AFE_LSM_TX_CAL_TYPE
 #define ADM_LSM_TOPOLOGY_CAL_TYPE ADM_LSM_TOPOLOGY_CAL_TYPE
 #define ADM_LSM_AUDPROC_CAL_TYPE ADM_LSM_AUDPROC_CAL_TYPE
+#define ADM_LSM_AUDPROC_PERSISTENT_CAL_TYPE ADM_LSM_AUDPROC_PERSISTENT_CAL_TYPE
 #define LSM_CAL_TYPES
 
 #define TOPOLOGY_SPECIFIC_CHANNEL_INFO
diff --git a/soc/soundwire.c b/soc/soundwire.c
index cda4789..69a9ed4 100644
--- a/soc/soundwire.c
+++ b/soc/soundwire.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -245,7 +245,7 @@
 	if (!dev->group_id)
 		return 0;
 
-	if (master->gr_sid == dev_num)
+	if (master->gr_sid != dev_num)
 		return 0;
 
 	if (master->remove_from_group && master->remove_from_group(master))
diff --git a/soc/swr-wcd-ctrl.c b/soc/swr-wcd-ctrl.c
index c5ba37b..455e03b 100644
--- a/soc/swr-wcd-ctrl.c
+++ b/soc/swr-wcd-ctrl.c
@@ -1756,6 +1756,8 @@
 		    (swrm->state == SWR_MSTR_UP)) {
 			dev_dbg(swrm->dev, "%s: SWR master is already UP: %d\n",
 				__func__, swrm->state);
+			list_for_each_entry(swr_dev, &mstr->devices, dev_list)
+				swr_reset_device(swr_dev);
 		} else {
 			pm_runtime_mark_last_busy(&pdev->dev);
 			mutex_unlock(&swrm->reslock);