Merge "dsp: add support to send uevents"
diff --git a/Makefile.am b/Makefile.am
index bce2711..09e2504 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,7 +25,7 @@
 ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), sdm670 qcs605))
 obj-m += asoc/codecs/wcd934x/
 endif
-ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), apq8053 sdm670 qcs605))
+ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), apq8053 sdm670 qcs605 apq8009))
 obj-m += asoc/codecs/sdm660_cdc/
 endif
 ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), sdm670 qcs605))
diff --git a/asoc/Kbuild b/asoc/Kbuild
index fce6328..229299d 100644
--- a/asoc/Kbuild
+++ b/asoc/Kbuild
@@ -115,6 +115,10 @@
 	MACHINE_OBJS += msm8952.o
 endif
 
+ifdef CONFIG_SND_SOC_MSM8909
+	MACHINE_INT_OBJS += msm8952.o
+endif
+
 # for SDM450 external codec sound card driver
 ifdef CONFIG_SND_SOC_EXT_CODEC_SDM450
 	MACHINE_EXT_OBJS += msm8952-slimbus.o
@@ -214,6 +218,9 @@
 obj-$(CONFIG_SND_SOC_SDM450) += machine_dlkm.o
 machine_dlkm-y := $(MACHINE_OBJS)
 
+obj-$(CONFIG_SND_SOC_MSM8909) += machine_int_dlkm.o
+machine_int_dlkm-y := $(MACHINE_INT_OBJS)
+
 obj-$(CONFIG_SND_SOC_EXT_CODEC_8909) += machine_ext_dlkm.o
 machine_ext_dlkm-y := $(MACHINE_EXT_OBJS)
 
diff --git a/asoc/codecs/sdm660_cdc/Kbuild b/asoc/codecs/sdm660_cdc/Kbuild
index e5b3ae9..0744af0 100644
--- a/asoc/codecs/sdm660_cdc/Kbuild
+++ b/asoc/codecs/sdm660_cdc/Kbuild
@@ -40,6 +40,11 @@
 		export
 		INCS    +=  -include $(AUDIO_ROOT)/config/sdm450autoconf.h
 	endif
+	ifeq ($(CONFIG_ARCH_MSM8909), y)
+		include $(AUDIO_ROOT)/config/msm8909auto.conf
+		export
+		INCS    +=  -include $(AUDIO_ROOT)/config/msm8909autoconf.h
+	endif
 endif
 
 # As per target team, build is done as follows:
diff --git a/asoc/codecs/sdm660_cdc/msm-analog-cdc.c b/asoc/codecs/sdm660_cdc/msm-analog-cdc.c
index 77981dd..de112bc 100644
--- a/asoc/codecs/sdm660_cdc/msm-analog-cdc.c
+++ b/asoc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -4577,7 +4577,7 @@
 	int adsp_state;
 
 	adsp_state = apr_get_subsys_state();
-	if (adsp_state != APR_SUBSYS_LOADED ||
+	if (adsp_state == APR_SUBSYS_DOWN ||
 		!q6core_is_adsp_ready()) {
 		dev_err(&pdev->dev, "Adsp is not loaded yet %d\n",
 			adsp_state);
diff --git a/asoc/codecs/sdm660_cdc/msm-digital-cdc-legacy.c b/asoc/codecs/sdm660_cdc/msm-digital-cdc-legacy.c
index 9805b2d..bc56412 100644
--- a/asoc/codecs/sdm660_cdc/msm-digital-cdc-legacy.c
+++ b/asoc/codecs/sdm660_cdc/msm-digital-cdc-legacy.c
@@ -1977,6 +1977,14 @@
 	u32 dig_cdc_addr;
 	struct msm_dig_priv *msm_dig_cdc;
 	struct dig_ctrl_platform_data *pdata;
+	int adsp_state = 0;
+
+	adsp_state = apr_get_subsys_state();
+	if (adsp_state == APR_SUBSYS_DOWN) {
+		dev_err(&pdev->dev, "Adsp is not loaded yet %d\n",
+			adsp_state);
+		return -EPROBE_DEFER;
+	}
 
 	msm_dig_cdc = devm_kzalloc(&pdev->dev, sizeof(struct msm_dig_priv),
 			      GFP_KERNEL);
diff --git a/asoc/codecs/wcd-dsp-mgr.c b/asoc/codecs/wcd-dsp-mgr.c
index cde9851..b0e5315 100644
--- a/asoc/codecs/wcd-dsp-mgr.c
+++ b/asoc/codecs/wcd-dsp-mgr.c
@@ -802,6 +802,7 @@
 		__wdsp_clr_ready_locked(wdsp, WDSP_SSR_STATUS_WDSP_READY);
 		wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_PRE_SHUTDOWN,
 					     NULL);
+		reinit_completion(&wdsp->ready_compl);
 		schedule_work(&wdsp->ssr_work);
 		break;
 
@@ -818,7 +819,7 @@
 						     WDSP_EVENT_PRE_SHUTDOWN,
 						     NULL);
 		}
-
+		reinit_completion(&wdsp->ready_compl);
 		schedule_work(&wdsp->ssr_work);
 		break;
 
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index 8989fea..80f5e3d 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -46,6 +46,7 @@
 
 enum {
 	ENC_FMT_NONE,
+	DEC_FMT_NONE = ENC_FMT_NONE,
 	ENC_FMT_SBC = ASM_MEDIA_FMT_SBC,
 	ENC_FMT_AAC_V2 = ASM_MEDIA_FMT_AAC_V2,
 	ENC_FMT_APTX = ASM_MEDIA_FMT_APTX,
@@ -200,6 +201,7 @@
 	u32 afe_in_channels;
 	u16 afe_in_bitformat;
 	struct afe_enc_config enc_config;
+	struct afe_dec_config dec_config;
 	union afe_port_config port_config;
 	u16 vi_feed_mono;
 };
@@ -1546,22 +1548,46 @@
 		if (dai_data->enc_config.format != ENC_FMT_NONE) {
 			int bitwidth = 0;
 
-			if (dai_data->afe_in_bitformat ==
-			    SNDRV_PCM_FORMAT_S24_LE)
+			switch (dai_data->afe_in_bitformat) {
+			case SNDRV_PCM_FORMAT_S32_LE:
+				bitwidth = 32;
+				break;
+			case SNDRV_PCM_FORMAT_S24_LE:
 				bitwidth = 24;
-			else if (dai_data->afe_in_bitformat ==
-				 SNDRV_PCM_FORMAT_S16_LE)
+				break;
+			case SNDRV_PCM_FORMAT_S16_LE:
+			default:
 				bitwidth = 16;
+				break;
+			}
 			pr_debug("%s: calling AFE_PORT_START_V2 with enc_format: %d\n",
 				 __func__, dai_data->enc_config.format);
 			rc = afe_port_start_v2(dai->id, &dai_data->port_config,
 					       dai_data->rate,
 					       dai_data->afe_in_channels,
 					       bitwidth,
-					       &dai_data->enc_config);
+					       &dai_data->enc_config, NULL);
 			if (rc < 0)
 				pr_err("%s: afe_port_start_v2 failed error: %d\n",
 					__func__, rc);
+		} else if (dai_data->dec_config.format != DEC_FMT_NONE) {
+			/*
+			 * A dummy Tx session is established in LPASS to
+			 * get the link statistics from BTSoC.
+			 * Depacketizer extracts the bit rate levels and
+			 * transmits them to the encoder on the Rx path.
+			 * Since this is a dummy decoder - channels, bit
+			 * width are sent as 0 and encoder config is NULL.
+			 * This could be updated in the future if there is
+			 * a complete Tx path set up that uses this decoder.
+			 */
+			rc = afe_port_start_v2(dai->id, &dai_data->port_config,
+					       dai_data->rate, 0, 0, NULL,
+					       &dai_data->dec_config);
+			if (rc < 0) {
+				pr_err("%s: fail to open AFE port 0x%x\n",
+					__func__, dai->id);
+			}
 		} else {
 			rc = afe_port_start(dai->id, &dai_data->port_config,
 						dai_data->rate);
@@ -2273,7 +2299,7 @@
 	if (dai_data) {
 		int format_size = sizeof(dai_data->enc_config.format);
 
-		pr_debug("%s:encoder config for %d format\n",
+		pr_debug("%s: encoder config for %d format\n",
 			 __func__, dai_data->enc_config.format);
 		memcpy(ucontrol->value.bytes.data,
 			&dai_data->enc_config.format,
@@ -2385,10 +2411,11 @@
 	SOC_ENUM_SINGLE_EXT(3, afe_input_chs_text),
 };
 
-static const char *const afe_input_bit_format_text[] = {"S16_LE", "S24_LE"};
+static const char *const afe_input_bit_format_text[] = {"S16_LE", "S24_LE",
+							"S32_LE"};
 
 static const struct soc_enum afe_input_bit_format_enum[] = {
-	SOC_ENUM_SINGLE_EXT(2, afe_input_bit_format_text),
+	SOC_ENUM_SINGLE_EXT(3, afe_input_bit_format_text),
 };
 
 static int msm_dai_q6_afe_input_channel_get(struct snd_kcontrol *kcontrol,
@@ -2431,6 +2458,9 @@
 	}
 
 	switch (dai_data->afe_in_bitformat) {
+	case SNDRV_PCM_FORMAT_S32_LE:
+		ucontrol->value.integer.value[0] = 2;
+		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
 		ucontrol->value.integer.value[0] = 1;
 		break;
@@ -2456,6 +2486,9 @@
 		return -EINVAL;
 	}
 	switch (ucontrol->value.integer.value[0]) {
+	case 2:
+		dai_data->afe_in_bitformat = SNDRV_PCM_FORMAT_S32_LE;
+		break;
 	case 1:
 		dai_data->afe_in_bitformat = SNDRV_PCM_FORMAT_S24_LE;
 		break;
@@ -2523,6 +2556,73 @@
 		       msm_dai_q6_afe_scrambler_mode_put),
 };
 
+static int  msm_dai_q6_afe_dec_cfg_info(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = sizeof(struct afe_dec_config);
+
+	return 0;
+}
+
+static int msm_dai_q6_afe_dec_cfg_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+	int format_size = 0;
+
+	if (!dai_data) {
+		pr_err("%s: Invalid dai data\n", __func__);
+		return -EINVAL;
+	}
+
+	format_size = sizeof(dai_data->dec_config.format);
+	memcpy(ucontrol->value.bytes.data,
+		&dai_data->dec_config.format,
+		format_size);
+	memcpy(ucontrol->value.bytes.data + format_size,
+		&dai_data->dec_config.abr_dec_cfg,
+		sizeof(struct afe_abr_dec_cfg_t));
+
+	return 0;
+}
+
+static int msm_dai_q6_afe_dec_cfg_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+	int format_size = 0;
+
+	if (!dai_data) {
+		pr_err("%s: Invalid dai data\n", __func__);
+		return -EINVAL;
+	}
+
+	memset(&dai_data->dec_config, 0x0,
+		sizeof(struct afe_dec_config));
+	format_size = sizeof(dai_data->dec_config.format);
+	memcpy(&dai_data->dec_config.format,
+		ucontrol->value.bytes.data,
+		format_size);
+	memcpy(&dai_data->dec_config.abr_dec_cfg,
+		ucontrol->value.bytes.data + format_size,
+		sizeof(struct afe_abr_dec_cfg_t));
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new afe_dec_config_controls[] = {
+	{
+		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			   SNDRV_CTL_ELEM_ACCESS_INACTIVE),
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "SLIM_7_TX Decoder Config",
+		.info = msm_dai_q6_afe_dec_cfg_info,
+		.get = msm_dai_q6_afe_dec_cfg_get,
+		.put = msm_dai_q6_afe_dec_cfg_put,
+	},
+};
+
 static int msm_dai_q6_slim_rx_drift_info(struct snd_kcontrol *kcontrol,
 				    struct snd_ctl_elem_info *uinfo)
 {
@@ -2694,6 +2794,11 @@
 				snd_ctl_new1(&avd_drift_config_controls[2],
 					dai));
 		break;
+	case SLIMBUS_7_TX:
+		rc = snd_ctl_add(dai->component->card->snd_card,
+				 snd_ctl_new1(&afe_dec_config_controls[0],
+				 dai_data));
+		break;
 	case RT_PROXY_DAI_001_RX:
 		rc = snd_ctl_add(dai->component->card->snd_card,
 				 snd_ctl_new1(&rt_proxy_config_controls[0],
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index 7e61358..6d9ba11 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -61,6 +61,7 @@
 
 static int fm_switch_enable;
 static int hfp_switch_enable;
+static int a2dp_switch_enable;
 static int int0_mi2s_switch_enable;
 static int int4_mi2s_switch_enable;
 static int pri_mi2s_switch_enable;
@@ -2162,6 +2163,34 @@
 	return 1;
 }
 
+static int msm_routing_a2dp_switch_mixer_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = a2dp_switch_enable;
+	pr_debug("%s: A2DP Switch enable %ld\n", __func__,
+		  ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_routing_a2dp_switch_mixer_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget =
+		snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_dapm_update *update = NULL;
+
+	pr_debug("%s: A2DP Switch enable %ld\n", __func__,
+		  ucontrol->value.integer.value[0]);
+	a2dp_switch_enable = ucontrol->value.integer.value[0];
+	if (a2dp_switch_enable)
+		snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol,
+						1, update);
+	else
+		snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol,
+						0, update);
+	return 1;
+}
+
 static int msm_routing_get_int0_mi2s_switch_mixer(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -11680,6 +11709,11 @@
 	0, 1, 0, msm_routing_get_usb_switch_mixer,
 	msm_routing_put_usb_switch_mixer);
 
+static const struct snd_kcontrol_new a2dp_slim7_switch_mixer_controls =
+	SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+	0, 1, 0, msm_routing_a2dp_switch_mixer_get,
+	msm_routing_a2dp_switch_mixer_put);
+
 static const struct soc_enum lsm_port_enum =
 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lsm_port_text), lsm_port_text);
 
@@ -13498,6 +13532,8 @@
 				&hfp_slim7_switch_mixer_controls),
 	SND_SOC_DAPM_SWITCH("USB_DL_HL", SND_SOC_NOPM, 0, 0,
 				&usb_switch_mixer_controls),
+	SND_SOC_DAPM_SWITCH("A2DP_SLIM7_UL_HL", SND_SOC_NOPM, 0, 0,
+				&a2dp_slim7_switch_mixer_controls),
 
 	/* Mixer definitions */
 	SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -15943,6 +15979,8 @@
 	{"HFP_SLIM7_UL_HL", "Switch", "SLIMBUS_7_TX"},
 	{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
 	{"AUX_PCM_RX", NULL, "INTHFP_DL_HL"},
+	{"SLIM7_UL_HL", NULL, "A2DP_SLIM7_UL_HL"},
+	{"A2DP_SLIM7_UL_HL", "Switch", "SLIMBUS_7_TX"},
 	{"SEC_AUX_PCM_RX", NULL, "SEC_AUXPCM_DL_HL"},
 	{"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
 	{"SEC_AUXPCM_UL_HL", NULL, "SEC_AUX_PCM_TX"},
diff --git a/asoc/sdm660-common.c b/asoc/sdm660-common.c
index 3695ae5..093eef4 100644
--- a/asoc/sdm660-common.c
+++ b/asoc/sdm660-common.c
@@ -3364,6 +3364,8 @@
 	  .data = "tavil_codec"},
 	{ .compatible = "qcom,qcs605-dig-asoc-snd",
 	  .data = "digital_codec"},
+	{ .compatible = "qcom,qcs605-asoc-snd-tavil",
+	  .data = "tavil_codec"},
 	{},
 };
 
diff --git a/config/msm8909auto.conf b/config/msm8909auto.conf
index ac6f399..2adfae5 100644
--- a/config/msm8909auto.conf
+++ b/config/msm8909auto.conf
@@ -35,3 +35,4 @@
 CONFIG_SND_SOC_WSA881X=m
 CONFIG_COMMON_CLK_MSM=m
 CONFIG_SND_SOC_EXT_CODEC_8909=m
+CONFIG_SND_SOC_WSA881X_ANALOG=m
diff --git a/config/msm8909autoconf.h b/config/msm8909autoconf.h
index bb80f88..9faddb1 100644
--- a/config/msm8909autoconf.h
+++ b/config/msm8909autoconf.h
@@ -48,3 +48,4 @@
 #define CONFIG_SND_SOC_WSA881X 1
 #define CONFIG_COMMON_CLK_MSM 1
 #define CONFIG_SND_SOC_EXT_CODEC_8909 1
+#define CONFIG_SND_SOC_WSA881X_ANALOG 1
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index 5a92fa5..ce67a19 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -2997,6 +2997,93 @@
 	return ret;
 }
 
+static int q6afe_send_dec_config(u16 port_id,
+			union afe_port_config afe_config,
+			struct afe_dec_config *cfg)
+{
+	struct afe_audioif_config_command config;
+	int index = 0;
+	int ret = 0;
+	size_t payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+				sizeof(config.param) - sizeof(config.port);
+
+	index = q6audio_get_port_index(port_id);
+	if (index < 0) {
+		pr_err("%s: Invalid index number: %d\n", __func__, index);
+		return -EINVAL;
+	}
+	memset(&config, 0, sizeof(config));
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = index;
+
+	config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	config.param.port_id = q6audio_get_port_id(port_id);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+	config.pdata.module_id = AFE_MODULE_ID_DECODER;
+	config.param.payload_size =
+			payload_size + sizeof(config.port.dec_depkt_id_param);
+	pr_debug("%s:sending AFE_DECODER_PARAM_ID_DEPACKETIZER to DSP payload = %d\n",
+		  __func__, config.param.payload_size);
+	config.pdata.param_id = AFE_DECODER_PARAM_ID_DEPACKETIZER_ID;
+	config.pdata.param_size = sizeof(config.port.dec_depkt_id_param);
+	config.port.dec_depkt_id_param.dec_depacketizer_id =
+					AFE_MODULE_ID_DEPACKETIZER_COP;
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
+		pr_err("%s: AFE_DECODER_PARAM_ID_DEPACKETIZER for port 0x%x failed %d\n",
+			__func__, port_id, ret);
+		goto exit;
+	}
+
+	config.param.payload_size =
+		payload_size + sizeof(config.port.imc_info_param);
+	pr_debug("%s:sending AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION to DSP payload = %d\n",
+		  __func__, config.param.payload_size);
+	config.pdata.param_id = AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION;
+	config.pdata.param_size = sizeof(config.port.imc_info_param);
+	config.port.imc_info_param.imc_info = cfg->abr_dec_cfg.imc_info;
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
+		pr_err("%s: AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION for port 0x%x failed %d\n",
+			__func__, port_id, ret);
+		goto exit;
+	}
+
+	config.param.payload_size =
+			payload_size + sizeof(config.port.media_type);
+	config.pdata.param_size = sizeof(config.port.media_type);
+
+	pr_debug("%s:Sending AFE_API_VERSION_PORT_MEDIA_TYPE to DSP\n",
+		 __func__);
+	config.pdata.module_id = AFE_MODULE_PORT;
+	config.pdata.param_id = AFE_PARAM_ID_PORT_MEDIA_TYPE;
+	config.port.media_type.minor_version = AFE_API_VERSION_PORT_MEDIA_TYPE;
+	config.port.media_type.sample_rate = afe_config.slim_sch.sample_rate;
+	config.port.media_type.bit_width =
+				afe_config.slim_sch.bit_width;
+	config.port.media_type.num_channels =
+				afe_config.slim_sch.num_channels;
+	config.port.media_type.data_format = AFE_PORT_DATA_FORMAT_PCM;
+	config.port.media_type.reserved = 0;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
+		pr_err("%s: AFE_API_VERSION_PORT_MEDIA_TYPE for port 0x%x failed %d\n",
+			__func__, port_id, ret);
+		goto exit;
+	}
+
+exit:
+	return ret;
+}
+
 static int q6afe_send_enc_config(u16 port_id,
 				 union afe_enc_config_data *cfg, u32 format,
 				 union afe_port_config afe_config,
@@ -3048,15 +3135,25 @@
 				__func__);
 		goto exit;
 	}
-
-	config.param.payload_size = payload_size
+	if (format == ASM_MEDIA_FMT_LDAC) {
+		config.param.payload_size = payload_size
+				+ sizeof(config.port.enc_blk_param)
+				- sizeof(struct afe_abr_enc_cfg_t);
+		config.pdata.param_size = sizeof(config.port.enc_blk_param)
+					    - sizeof(struct afe_abr_enc_cfg_t);
+		config.port.enc_blk_param.enc_cfg_blk_size =
+				sizeof(config.port.enc_blk_param.enc_blk_config)
+					- sizeof(struct afe_abr_enc_cfg_t);
+	} else {
+		config.param.payload_size = payload_size
 					+ sizeof(config.port.enc_blk_param);
+		config.pdata.param_size = sizeof(config.port.enc_blk_param);
+		config.port.enc_blk_param.enc_cfg_blk_size =
+			sizeof(config.port.enc_blk_param.enc_blk_config);
+	}
 	pr_debug("%s:send AFE_ENCODER_PARAM_ID_ENC_CFG_BLK to DSP payload:%d\n",
 				__func__, config.param.payload_size);
 	config.pdata.param_id = AFE_ENCODER_PARAM_ID_ENC_CFG_BLK;
-	config.pdata.param_size = sizeof(config.port.enc_blk_param);
-	config.port.enc_blk_param.enc_cfg_blk_size =
-			sizeof(config.port.enc_blk_param.enc_blk_config);
 	config.port.enc_blk_param.enc_blk_config = *cfg;
 	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
 	if (ret) {
@@ -3112,22 +3209,54 @@
 		goto exit;
 	}
 
+	if (format == ASM_MEDIA_FMT_LDAC) {
+		config.param.payload_size =
+			payload_size + sizeof(config.port.map_param);
+		pr_debug("%s:sending AFE_ENCODER_PARAM_ID_BIT_RATE_LEVEL_MAP to DSP payload = %d\n",
+			__func__, config.param.payload_size);
+		config.pdata.param_id = AFE_ENCODER_PARAM_ID_BIT_RATE_LEVEL_MAP;
+		config.pdata.param_size = sizeof(config.port.map_param);
+		config.port.map_param.mapping_table =
+			cfg->ldac_config.abr_config.mapping_info;
+		ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+		if (ret) {
+			pr_err("%s: AFE_ENCODER_PARAM_ID_BIT_RATE_LEVEL_MAP for port 0x%x failed %d\n",
+				__func__, port_id, ret);
+			goto exit;
+		}
+
+		config.param.payload_size =
+			payload_size + sizeof(config.port.imc_info_param);
+		pr_debug("%s:sending AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION to DSP payload = %d\n",
+				__func__, config.param.payload_size);
+		config.pdata.param_id =
+			AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION;
+		config.pdata.param_size = sizeof(config.port.imc_info_param);
+		config.port.imc_info_param.imc_info =
+			cfg->ldac_config.abr_config.imc_info;
+		ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+		if (ret) {
+			pr_err("%s: AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION for port 0x%x failed %d\n",
+					__func__, port_id, ret);
+			goto exit;
+		}
+	}
+
 	config.param.payload_size =
 			payload_size + sizeof(config.port.media_type);
 	config.pdata.param_size = sizeof(config.port.media_type);
 
-	pr_debug("%s:Sending AFE_API_VERSION_PORT_MEDIA_TYPE to DSP", __func__);
+	pr_debug("%s:Sending AFE_API_VERSION_PORT_MEDIA_TYPE to DSP\n",
+		 __func__);
 	config.pdata.module_id = AFE_MODULE_PORT;
 	config.pdata.param_id = AFE_PARAM_ID_PORT_MEDIA_TYPE;
 	config.port.media_type.minor_version = AFE_API_VERSION_PORT_MEDIA_TYPE;
-	if (format == ASM_MEDIA_FMT_LDAC) {
+	if (format == ASM_MEDIA_FMT_LDAC)
 		config.port.media_type.sample_rate =
-			config.port.enc_blk_param.enc_blk_config.ldac_config.
-				custom_config.sample_rate;
-	} else {
+			cfg->ldac_config.custom_config.sample_rate;
+	else
 		config.port.media_type.sample_rate =
 			afe_config.slim_sch.sample_rate;
-	}
 
 	if (afe_in_bit_width)
 		config.port.media_type.bit_width = afe_in_bit_width;
@@ -3156,8 +3285,9 @@
 
 static int __afe_port_start(u16 port_id, union afe_port_config *afe_config,
 			    u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
-			    union afe_enc_config_data *cfg, u32 enc_format,
-			    u32 scrambler_mode)
+			    union afe_enc_config_data *enc_cfg,
+			    u32 codec_format, u32 scrambler_mode,
+			    struct afe_dec_config *dec_cfg)
 {
 	struct afe_audioif_config_command config;
 	int ret = 0;
@@ -3402,7 +3532,8 @@
 	config.pdata.param_size = sizeof(config.port);
 
 	config.port = *afe_config;
-	if ((enc_format != ASM_MEDIA_FMT_NONE) &&
+	if (((enc_cfg != NULL) || (dec_cfg != NULL)) &&
+	    (codec_format != ASM_MEDIA_FMT_NONE) &&
 	    (cfg_type == AFE_PARAM_ID_SLIMBUS_CONFIG)) {
 		config.port.slim_sch.data_format =
 				AFE_SB_DATA_FORMAT_GENERIC_COMPRESSED;
@@ -3414,18 +3545,32 @@
 		goto fail_cmd;
 	}
 
-	if ((enc_format != ASM_MEDIA_FMT_NONE) &&
+	if ((codec_format != ASM_MEDIA_FMT_NONE) &&
 	    (cfg_type == AFE_PARAM_ID_SLIMBUS_CONFIG)) {
-		pr_debug("%s: Found AFE encoder support for SLIMBUS enc_format = %d\n",
-					__func__, enc_format);
-		ret = q6afe_send_enc_config(port_id, cfg, enc_format,
-					    *afe_config, afe_in_channels,
-					    afe_in_bit_width,
-					    scrambler_mode);
-		if (ret) {
-			pr_err("%s: AFE encoder config for port 0x%x failed %d\n",
-				__func__, port_id, ret);
-			goto fail_cmd;
+		if (enc_cfg != NULL) {
+			pr_debug("%s: Found AFE encoder support for SLIMBUS enc_format = %d\n",
+						__func__, codec_format);
+			ret = q6afe_send_enc_config(port_id, enc_cfg,
+						    codec_format, *afe_config,
+						    afe_in_channels,
+						    afe_in_bit_width,
+						    scrambler_mode);
+			if (ret) {
+				pr_err("%s: AFE encoder config for port 0x%x failed %d\n",
+					__func__, port_id, ret);
+				goto fail_cmd;
+			}
+		}
+		if (dec_cfg != NULL) {
+			pr_debug("%s: Found AFE decoder support for SLIMBUS dec_format = %d\n",
+				  __func__, codec_format);
+			ret = q6afe_send_dec_config(port_id, *afe_config,
+						    dec_cfg);
+			if (ret) {
+				pr_err("%s: AFE decoder config for port 0x%x failed %d\n",
+					 __func__, port_id, ret);
+				goto fail_cmd;
+			}
 		}
 	}
 
@@ -3474,31 +3619,42 @@
 		   u32 rate)
 {
 	return __afe_port_start(port_id, afe_config, rate,
-				0, 0, NULL, ASM_MEDIA_FMT_NONE, 0);
+				0, 0, NULL, ASM_MEDIA_FMT_NONE, 0, NULL);
 }
 EXPORT_SYMBOL(afe_port_start);
 
 /**
  * afe_port_start_v2 - to configure AFE session with
- * specified port configuration and encoder params
+ * specified port configuration and encoder/decoder params
  *
  * @port_id: AFE port id number
  * @afe_config: port configutation
  * @rate: sampling rate of port
- * @cfg: AFE encoder configuration information to setup encoder
+ * @enc_cfg: AFE enc configuration information to setup encoder
  * @afe_in_channels: AFE input channel configuration, this needs
  *  update only if input channel is differ from AFE output
+ * @dec_cfg: AFE dec configuration information to set up decoder
  *
  * Returns 0 on success or error value on port start failure.
  */
 int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config,
 		      u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
-		      struct afe_enc_config *enc_cfg)
+		      struct afe_enc_config *enc_cfg,
+		      struct afe_dec_config *dec_cfg)
 {
-	return __afe_port_start(port_id, afe_config, rate,
-				afe_in_channels, afe_in_bit_width,
-				&enc_cfg->data, enc_cfg->format,
-				enc_cfg->scrambler_mode);
+	int ret = 0;
+
+	if (enc_cfg != NULL)
+		ret = __afe_port_start(port_id, afe_config, rate,
+					afe_in_channels, afe_in_bit_width,
+					&enc_cfg->data, enc_cfg->format,
+					enc_cfg->scrambler_mode, NULL);
+	else if (dec_cfg != NULL)
+		ret = __afe_port_start(port_id, afe_config, rate,
+					afe_in_channels, afe_in_bit_width,
+					NULL, dec_cfg->format, 0, dec_cfg);
+
+	return ret;
 }
 EXPORT_SYMBOL(afe_port_start_v2);
 
diff --git a/dsp/q6asm.c b/dsp/q6asm.c
index 2553ec9..ce12374 100644
--- a/dsp/q6asm.c
+++ b/dsp/q6asm.c
@@ -576,7 +576,7 @@
 static void q6asm_session_free(struct audio_client *ac)
 {
 	int session_id;
-	unsigned long flags;
+	unsigned long flags = 0;
 
 	pr_debug("%s: sessionid[%d]\n", __func__, ac->session);
 	session_id = ac->session;
@@ -1639,7 +1639,7 @@
 	uint32_t dir = 0;
 	uint32_t i = IN;
 	uint32_t *payload;
-	unsigned long dsp_flags;
+	unsigned long dsp_flags = 0;
 	unsigned long flags = 0;
 	struct asm_buffer_node *buf_node = NULL;
 	struct list_head *ptr, *next;
@@ -1856,7 +1856,7 @@
 {
 	int i = 0;
 	struct audio_client *ac = (struct audio_client *)priv;
-	unsigned long dsp_flags;
+	unsigned long dsp_flags = 0;
 	uint32_t *payload;
 	uint32_t wakeup_flag = 1;
 	int32_t  ret = 0;
@@ -1864,7 +1864,7 @@
 	uint8_t buf_index;
 	struct msm_adsp_event_data *pp_event_package = NULL;
 	uint32_t payload_size = 0;
-	unsigned long flags;
+	unsigned long flags = 0;
 	int session_id;
 
 	if (ac == NULL) {
@@ -2549,7 +2549,7 @@
 static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
 			uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id)
 {
-	unsigned long flags;
+	unsigned long flags = 0;
 
 	dev_vdbg(ac->dev, "%s: pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n",
 			__func__, pkt_size, cmd_flg, ac->session, stream_id);
diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h
index 2510852..a608a66 100644
--- a/include/dsp/apr_audio-v2.h
+++ b/include/dsp/apr_audio-v2.h
@@ -3101,6 +3101,72 @@
 	u32		topology_id;
 } __packed;
 
+#define MAX_ABR_LEVELS 5
+
+struct afe_bit_rate_level_map_t {
+	/*
+	 * Key value pair for link quality level to bitrate
+	 * mapping in AFE
+	 */
+	uint32_t link_quality_level;
+	uint32_t bitrate;
+} __packed;
+
+struct afe_quality_level_to_bitrate_info {
+	/*
+	 * Number of quality levels being mapped.
+	 * This will be equal to the size of mapping table.
+	 */
+	uint32_t num_levels;
+	/*
+	 * Quality level to bitrate mapping table
+	 */
+	struct afe_bit_rate_level_map_t bit_rate_level_map[MAX_ABR_LEVELS];
+} __packed;
+
+struct afe_imc_dec_enc_info {
+	/*
+	 * Decoder to encoder communication direction.
+	 * Transmit = 0 / Receive = 1
+	 */
+	uint32_t direction;
+	/*
+	 * Enable / disable IMC between decoder and encoder
+	 */
+	uint32_t enable;
+	/*
+	 * Purpose of IMC being set up between decoder and encoder.
+	 * Param ID defined for link quality feedback in LPASS will
+	 * be the default value sent as purpose.
+	 * Supported values:
+	 * AFE_ENCDEC_PURPOSE_ID_BT_INFO
+	 */
+	uint32_t purpose;
+	/*
+	 * Unique communication instance ID.
+	 * Data type a2dp_abr_instance used to set instance ID.
+	 * purpose and comm_instance together form the actual key
+	 * used in IMC registration, which must be the same for
+	 * encoder and decoder for which IMC is being set up.
+	 */
+	uint32_t comm_instance;
+} __packed;
+
+struct afe_abr_dec_cfg_t {
+	struct afe_imc_dec_enc_info imc_info;
+} __packed;
+
+struct afe_abr_enc_cfg_t {
+	/*
+	 * Link quality level to bitrate mapping info sent to DSP.
+	 */
+	struct afe_quality_level_to_bitrate_info mapping_info;
+	/*
+	 * Information to set up IMC between decoder and encoder.
+	 */
+	struct afe_imc_dec_enc_info imc_info;
+} __packed;
+
 #define AFE_PARAM_ID_APTX_SYNC_MODE  0x00013205
 
 struct afe_param_id_aptx_sync_mode {
@@ -3152,6 +3218,39 @@
 #define AFE_ENCODER_PARAM_ID_ENABLE_SCRAMBLING         0x0001323C
 
 /*
+ * Link quality level to bitrate mapping info sent to AFE Encoder.
+ * This parameter may be set runtime.
+ */
+#define AFE_ENCODER_PARAM_ID_BIT_RATE_LEVEL_MAP        0x000132E1
+
+/*
+ * Parameter to set up Inter Module Communication (IMC) between
+ * AFE Decoder and Encoder.
+ * This parameter may be set runtime.
+ */
+#define AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION        0x0001323D
+
+/*
+ * Purpose of IMC set up between encoder and decoder.
+ * Communication instance and purpose together form the
+ * actual key used for IMC registration.
+ */
+#define AFE_ENCDEC_PURPOSE_ID_BT_INFO        0x000132E2
+
+#define AFE_MODULE_ID_DECODER        0x00013231
+
+/*
+ * Macro for defining the depacketizer ID: COP.
+ */
+#define AFE_MODULE_ID_DEPACKETIZER_COP        0x00013233
+
+/*
+ * Depacketizer type parameter for the #AVS_MODULE_ID_DECODER module.
+ * This parameter cannot be set runtime.
+ */
+#define AFE_DECODER_PARAM_ID_DEPACKETIZER_ID        0x00013235
+
+/*
  * Data format to send compressed data
  * is transmitted/received over Slimbus lines.
  */
@@ -3452,6 +3551,7 @@
 struct asm_ldac_enc_cfg_t {
 	struct asm_custom_enc_cfg_t  custom_config;
 	struct asm_ldac_specific_enc_cfg_t  ldac_specific_config;
+	struct afe_abr_enc_cfg_t abr_config;
 } __packed;
 
 struct afe_enc_fmt_id_param_t {
@@ -3533,6 +3633,11 @@
 	union afe_enc_config_data data;
 };
 
+struct afe_dec_config {
+	u32 format;
+	struct afe_abr_dec_cfg_t abr_dec_cfg;
+};
+
 struct afe_enc_cfg_blk_param_t {
 	uint32_t enc_cfg_blk_size;
 	/*
@@ -3565,6 +3670,39 @@
 	uint32_t enable_scrambler;
 };
 
+/*
+ * Payload of the AVS_ENCODER_PARAM_ID_BIT_RATE_LEVEL_MAP parameter.
+ */
+struct afe_enc_level_to_bitrate_map_param_t {
+	/*
+	 * Parameter for mapping link quality level to bitrate.
+	 */
+	struct afe_quality_level_to_bitrate_info mapping_table;
+};
+
+/*
+ * Payload of the AVS_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION parameter.
+ */
+struct afe_enc_dec_imc_info_param_t {
+	/*
+	 * Parameter to set up Inter Module Communication (IMC) between
+	 * AFE Decoder and Encoder.
+	 */
+	struct afe_imc_dec_enc_info imc_info;
+};
+
+/*
+ * Payload of the AVS_DECODER_PARAM_ID_DEPACKETIZER_ID parameter.
+ */
+struct avs_dec_depacketizer_id_param_t {
+	/*
+	 * Supported values:
+	 * #AVS_MODULE_ID_DEPACKETIZER_COP
+	 * Any OpenDSP supported values
+	 */
+	uint32_t dec_depacketizer_id;
+};
+
 union afe_port_config {
 	struct afe_param_id_pcm_cfg               pcm;
 	struct afe_param_id_i2s_cfg               i2s;
@@ -3584,6 +3722,9 @@
 	struct afe_enc_cfg_blk_param_t            enc_blk_param;
 	struct avs_enc_packetizer_id_param_t      enc_pkt_id_param;
 	struct avs_enc_set_scrambler_param_t      enc_set_scrambler_param;
+	struct avs_dec_depacketizer_id_param_t    dec_depkt_id_param;
+	struct afe_enc_level_to_bitrate_map_param_t    map_param;
+	struct afe_enc_dec_imc_info_param_t       imc_info_param;
 } __packed;
 
 struct afe_audioif_config_command_no_payload {
diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h
index 8b79c9b..7edbedd 100644
--- a/include/dsp/q6afe-v2.h
+++ b/include/dsp/q6afe-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -326,7 +326,8 @@
 	u32 rate);
 int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config,
 		      u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
-		      struct afe_enc_config *enc_config);
+		      struct afe_enc_config *enc_config,
+		      struct afe_dec_config *dec_config);
 int afe_spk_prot_feed_back_cfg(int src_port, int dst_port,
 	int l_ch, int r_ch, u32 enable);
 int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib);