Merge "hal:qap: Fix to avoid hang at the end of playback"
diff --git a/configs/apq8098_latv/apq8098_latv.mk b/configs/apq8098_latv/apq8098_latv.mk
index 83ffba0..7a5f6f4 100644
--- a/configs/apq8098_latv/apq8098_latv.mk
+++ b/configs/apq8098_latv/apq8098_latv.mk
@@ -169,7 +169,7 @@
 PRODUCT_PROPERTY_OVERRIDES += \
 audio.deep_buffer.media=true
 
-#QC property used when calculating client heap size in audio flinger
+#QTI property used when calculating client heap size in audio flinger
 PRODUCT_PROPERTY_OVERRIDES += \
 audio.heap.size.multiplier=7
 
diff --git a/configs/msm8953/sound_trigger_mixer_paths.xml b/configs/msm8953/sound_trigger_mixer_paths.xml
index f6abb6b..e7f3740 100644
--- a/configs/msm8953/sound_trigger_mixer_paths.xml
+++ b/configs/msm8953/sound_trigger_mixer_paths.xml
@@ -94,6 +94,54 @@
         <ctl name="LSM8 Mixer TERT_MI2S_TX" value="1" />
     </path>
 
+    <path name="listen-voice-wakeup-1 preproc">
+        <ctl name="TERT_MI2S_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM1 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM1 Mixer TERT_MI2S_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-2 preproc">
+        <ctl name="TERT_MI2S_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM2 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM2 Mixer TERT_MI2S_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-3 preproc">
+        <ctl name="TERT_MI2S_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM3 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM3 Mixer TERT_MI2S_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-4 preproc">
+        <ctl name="TERT_MI2S_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM4 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM4 Mixer TERT_MI2S_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-5 preproc">
+        <ctl name="TERT_MI2S_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM5 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM5 Mixer TERT_MI2S_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-6 preproc">
+        <ctl name="TERT_MI2S_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM6 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM6 Mixer TERT_MI2S_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-7 preproc">
+        <ctl name="TERT_MI2S_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM7 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM7 Mixer TERT_MI2S_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-8 preproc">
+        <ctl name="TERT_MI2S_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM8 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM8 Mixer TERT_MI2S_TX" value="1" />
+    </path>
+
     <path name="listen-ape-handset-mic">
         <!-- this is to avoid codec mute when device is not enabled first -->
         <ctl name="LOOPBACK Mode" value="ENABLE" />
@@ -102,4 +150,18 @@
         <ctl name="ADC2 MUX" value="INP3" />
     </path>
 
+    <path name="listen-ape-handset-mic-preproc">
+        <ctl name="DEC1 MUX" value="ADC2" />
+        <ctl name="ADC2 MUX" value="INP3" />
+    </path>
+
+    <path name="listen-ape-handset-dmic">
+        <ctl name="ADC1 Volume" value="6" />
+        <ctl name="DEC1 MUX" value="ADC1" />
+        <ctl name="ADC3 Volume" value="6" />
+        <ctl name="DEC2 MUX" value="ADC2" />
+        <ctl name="MI2S_TX Channels" value="Two" />
+        <ctl name="ADC2 MUX" value="INP3" />
+    </path>
+
 </mixer>
diff --git a/configs/msm8953/sound_trigger_mixer_paths_wcd9335.xml b/configs/msm8953/sound_trigger_mixer_paths_wcd9335.xml
index af630d0..c1b6097 100644
--- a/configs/msm8953/sound_trigger_mixer_paths_wcd9335.xml
+++ b/configs/msm8953/sound_trigger_mixer_paths_wcd9335.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="ISO-8859-1"?>
-<!--- Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+<!--- Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
 
       Redistribution and use in source and binary forms, with or without
       modification, are permitted provided that the following conditions are
@@ -57,6 +57,19 @@
     <ctl name="EC BUF MUX INP" value="ZERO" />
     <ctl name="ADC MUX1" value="DMIC" />
     <ctl name="DMIC MUX1" value="ZERO" />
+    <ctl name="ADC MUX5" value="AMIC" />
+    <ctl name="ADC MUX6" value="AMIC" />
+    <ctl name="ADC MUX7" value="AMIC" />
+    <ctl name="ADC MUX8" value="AMIC" />
+    <ctl name="DMIC MUX5" value="ZERO" />
+    <ctl name="DMIC MUX6" value="ZERO" />
+    <ctl name="DMIC MUX7" value="ZERO" />
+    <ctl name="DMIC MUX8" value="ZERO" />
+    <ctl name="IIR0 INP0 MUX" value="ZERO" />
+    <ctl name="AIF1_CAP Mixer SLIM TX5" value="0" />
+    <ctl name="AIF1_CAP Mixer SLIM TX6" value="0" />
+    <ctl name="AIF1_CAP Mixer SLIM TX7" value="0" />
+    <ctl name="AIF1_CAP Mixer SLIM TX8" value="0" />
 
     <path name="listen-voice-wakeup-1">
         <ctl name="SLIMBUS_5_TX LSM Function" value="AUDIO" />
@@ -100,6 +113,54 @@
         <ctl name="LSM8 Mixer SLIMBUS_5_TX" value="1" />
     </path>
 
+    <path name="listen-voice-wakeup-1 preproc">
+        <ctl name="SLIMBUS_0_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM1 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM1 Mixer SLIMBUS_0_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-2 preproc">
+        <ctl name="SLIMBUS_0_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM2 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM2 Mixer SLIMBUS_0_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-3 preproc">
+        <ctl name="SLIMBUS_0_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM3 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM3 Mixer SLIMBUS_0_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-4 preproc">
+        <ctl name="SLIMBUS_0_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM4 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM4 Mixer SLIMBUS_0_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-5 preproc">
+        <ctl name="SLIMBUS_0_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM5 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM5 Mixer SLIMBUS_0_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-6 preproc">
+        <ctl name="SLIMBUS_0_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM6 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM6 Mixer SLIMBUS_0_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-7 preproc">
+        <ctl name="SLIMBUS_0_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM7 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM7 Mixer SLIMBUS_0_TX" value="1" />
+    </path>
+
+    <path name="listen-voice-wakeup-8 preproc">
+        <ctl name="SLIMBUS_0_TX LSM Function" value="SWAUDIO" />
+        <ctl name="LSM8 Port" value="ADM_LSM_TX" />
+        <ctl name="LSM8 Mixer SLIMBUS_0_TX" value="1" />
+    </path>
+
     <path name="listen-cpe-handset-mic">
         <ctl name="MADONOFF Switch" value="1" />
         <ctl name="TX13 INP MUX" value="CPE_TX_PP" />
@@ -130,4 +191,67 @@
         <ctl name="MAD Input" value="DMIC0" />
     </path>
 
+    <path name="listen-ape-handset-mic-preproc">
+        <ctl name="AIF1_CAP Mixer SLIM TX7" value="1"/>
+        <ctl name="SLIM_0_TX Channels" value="One" />
+        <ctl name="SLIM TX7 MUX" value="DEC7" />
+        <ctl name="ADC MUX7" value="DMIC" />
+        <ctl name="DMIC MUX7" value="DMIC0" />
+        <ctl name="IIR0 INP0 MUX" value="DEC7" />
+    </path>
+
+    <path name="listen-ape-handset-dmic">
+        <ctl name="AIF1_CAP Mixer SLIM TX7" value="1" />
+        <ctl name="AIF1_CAP Mixer SLIM TX8" value="1" />
+        <ctl name="SLIM TX7 MUX" value="DEC7" />
+        <ctl name="ADC MUX7" value="DMIC" />
+        <ctl name="DMIC MUX7" value="DMIC0" />
+        <ctl name="SLIM TX8 MUX" value="DEC8" />
+        <ctl name="ADC MUX8" value="DMIC" />
+        <ctl name="DMIC MUX8" value="DMIC3" />
+        <ctl name="SLIM_0_TX Channels" value="Two" />
+   </path>
+
+    <path name="listen-ape-handset-qmic">
+        <ctl name="AIF1_CAP Mixer SLIM TX5" value="1" />
+        <ctl name="AIF1_CAP Mixer SLIM TX6" value="1" />
+        <ctl name="AIF1_CAP Mixer SLIM TX7" value="1" />
+        <ctl name="AIF1_CAP Mixer SLIM TX8" value="1" />
+        <ctl name="SLIM_0_TX Channels" value="Four" />
+        <ctl name="SLIM TX5 MUX" value="DEC5" />
+        <ctl name="ADC MUX5" value="DMIC" />
+        <ctl name="DMIC MUX5" value="DMIC0" />
+        <ctl name="SLIM TX6 MUX" value="DEC6" />
+        <ctl name="ADC MUX6" value="DMIC" />
+        <ctl name="DMIC MUX6" value="DMIC2" />
+        <ctl name="SLIM TX7 MUX" value="DEC7" />
+        <ctl name="ADC MUX7" value="DMIC" />
+        <ctl name="DMIC MUX7" value="DMIC1" />
+        <ctl name="SLIM TX8 MUX" value="DEC8" />
+        <ctl name="ADC MUX8" value="DMIC" />
+        <ctl name="DMIC MUX8" value="DMIC3" />
+    </path>
+
+    <path name="listen-ape-handset-tmic">
+        <ctl name="AIF1_CAP Mixer SLIM TX5" value="1"/>
+        <ctl name="AIF1_CAP Mixer SLIM TX6" value="1" />
+        <ctl name="AIF1_CAP Mixer SLIM TX7" value="1"/>
+        <ctl name="SLIM_0_TX Channels" value="Three" />
+        <ctl name="SLIM TX5 MUX" value="DEC5" />
+        <ctl name="ADC MUX5" value="DMIC" />
+        <ctl name="DMIC MUX5" value="DMIC0" />
+        <ctl name="SLIM TX6 MUX" value="DEC6" />
+        <ctl name="ADC MUX6" value="DMIC" />
+        <ctl name="DMIC MUX6" value="DMIC2" />
+        <ctl name="SLIM TX7 MUX" value="DEC7" />
+        <ctl name="ADC MUX7" value="DMIC" />
+        <ctl name="DMIC MUX7" value="DMIC4" />
+    </path>
+
+    <path name="echo-reference">
+        <ctl name="AUDIO_REF_EC_UL1 MUX" value="SLIM_RX" />
+        <ctl name="EC Reference Channels" value="Two"/>
+        <ctl name="EC Reference Bit Format" value="S16_LE"/>
+        <ctl name="EC Reference SampleRate" value="48000"/>
+    </path>
 </mixer>
diff --git a/configs/msm8953/sound_trigger_platform_info.xml b/configs/msm8953/sound_trigger_platform_info.xml
index 28026f7..a1f70a0 100644
--- a/configs/msm8953/sound_trigger_platform_info.xml
+++ b/configs/msm8953/sound_trigger_platform_info.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="ISO-8859-1"?>
-<!--- Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.       -->
+<!--- Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.       -->
 <!---                                                                           -->
 <!--- Redistribution and use in source and binary forms, with or without        -->
 <!--- modification, are permitted provided that the following conditions are    -->
@@ -35,12 +35,25 @@
         <param enable_failure_detection="false" />
         <param rx_concurrency_disabled="true" />
         <param rx_conc_max_st_ses="1" />
+        <!-- Below backend params must match with port used in mixer path file -->
+        <!-- param used to configure backend sample rate, format and channels -->
+        <!--Enable below backend params for internal codec-->
+        <!--param backend_port_name="MI2S_TX" />
+        <param backend_dai_name="TERT_MI2S_TX" /-->
+        <param backend_port_name="SLIM_0_TX" />
+        <param backend_dai_name="SLIMBUS_0_TX" />
     </common_config>
 
     <acdb_ids>
-        <param DEVICE_HANDSET_APE_ACDB_ID="130" />
-        <param DEVICE_HANDSET_CPE_ACDB_ID="128" />
-        <param DEVICE_HANDSET_CPE_ECPP_ACDB_ID="128" />
+        <!--For internal codec please enable below device-->
+        <!--param DEVICE_HANDSET_MIC_APE="130" /-->
+        <param DEVICE_HANDSET_MIC_APE="100" />
+        <param DEVICE_HANDSET_MIC_CPE="128" />
+        <param DEVICE_HANDSET_MIC_ECPP_CPE="128" />
+        <param DEVICE_HANDSET_MIC_PP_APE="151" />
+        <param DEVICE_HANDSET_QMIC_APE="150" />
+        <param DEVICE_HANDSET_DMIC_APE="149" />
+        <param DEVICE_HANDSET_TMIC_APE="152" />
     </acdb_ids>
 
     <!-- Multiple sound_model_config tags can be listed, each with unique    -->
@@ -55,6 +68,14 @@
         <param max_ape_phrases="10" />
         <param max_ape_users="10" />
         <param sample_rate="16000" />
+        <param bit_width="16" />
+        <param channel_count="1"/>
+        <!-- adm_cfg_profile should match with the one defined under adm_config -->
+        <!-- Set it to NONE if LSM directly connects to AFE -->
+        <param adm_cfg_profile="NONE" />
+        <!-- fluence_type: "FLUENCE", "FLUENCE_DMIC", "FLUENCE_TMIC", -->
+        <!-- "FLUENCE_QMIC". param value is valid when adm_cfg_profile="FLUENCE"-->
+        <param fluence_type="NONE" />
 
         <!-- Module and param ids with which the algorithm is integrated in firmware -->
         <param load_sound_model_ids="0x00012C0D, 0x00012C14" />
@@ -69,5 +90,21 @@
         <param client_capture_read_delay="2000" />
     </sound_model_config>
 
+    <!-- Multiple adm_config tags can be listed, each with unique profile name. -->
+    <!-- app_type to match corresponding value from ACDB -->
+    <adm_config>
+        <param adm_cfg_profile="DEFAULT" />
+        <param app_type="69938" />
+        <param sample_rate="16000" />
+        <param bit_width="16" />
+    </adm_config>
+
+    <adm_config>
+        <param adm_cfg_profile="FLUENCE" />
+        <param app_type="69944" />
+        <param sample_rate="16000" />
+        <param bit_width="16" />
+    </adm_config>
+
 </sound_trigger_platform_info>
 
diff --git a/configs/sdm670/audio_platform_info_skuw.xml b/configs/sdm670/audio_platform_info_skuw.xml
index c365450..475a441 100644
--- a/configs/sdm670/audio_platform_info_skuw.xml
+++ b/configs/sdm670/audio_platform_info_skuw.xml
@@ -61,6 +61,8 @@
         <usecase name="USECASE_AUDIO_PLAYBACK_EXT_DISP_SILENCE" type="out" id="27" />
         <usecase name="USECASE_AUDIO_HFP_SCO" type="in" id="12" />
         <usecase name="USECASE_AUDIO_HFP_SCO_WB" type="in" id="12" />
+        <usecase name="USECASE_AUDIO_PLAYBACK_VOIP" type="out" id="16" />
+        <usecase name="USECASE_AUDIO_RECORD_VOIP" type="in" id="16" />
     </pcm_ids>
     <config_params>
         <!-- In the below value string, the value indicates default mono -->
diff --git a/configs/sdm670/audio_policy_configuration.xml b/configs/sdm670/audio_policy_configuration.xml
index 8e51ba5..418cf42 100644
--- a/configs/sdm670/audio_policy_configuration.xml
+++ b/configs/sdm670/audio_policy_configuration.xml
@@ -328,7 +328,7 @@
                 <route type="mix" sink="voice_rx"
                        sources="Telephony Rx"/>
                 <route type="mix" sink="primary input"
-                       sources="Built-In Mic,Wired Headset Mic,BT SCO Headset Mic,FM Tuner,USB Device In,Telephony Rx"/>
+                       sources="Wired Headset Mic,BT SCO Headset Mic,FM Tuner,USB Device In,Telephony Rx"/>
                 <route type="mix" sink="surround_sound"
                        sources="Built-In Mic,Built-In Back Mic"/>
                 <route type="mix" sink="record_24"
diff --git a/configs/sdm670/mixer_paths_skuw.xml b/configs/sdm670/mixer_paths_skuw.xml
index d76faaa..7ed5142 100644
--- a/configs/sdm670/mixer_paths_skuw.xml
+++ b/configs/sdm670/mixer_paths_skuw.xml
@@ -68,6 +68,9 @@
     <ctl name="MultiMedia1 Mixer SLIM_7_TX" value="0" />
     <ctl name="MultiMedia8 Mixer INT3_MI2S_TX" value="0" />
     <ctl name="MultiMedia8 Mixer SLIM_7_TX" value="0" />
+    <ctl name="MultiMedia10 Mixer INT3_MI2S_TX" value="0" />
+    <ctl name="MultiMedia10 Mixer SLIM_7_TX" value="0" />
+    <ctl name="MultiMedia10 Mixer AFE_PCM_TX" value="0" />
     <ctl name="HDMI Mixer MultiMedia1" value="0" />
     <ctl name="HDMI Mixer MultiMedia2" value="0" />
     <ctl name="HDMI Mixer MultiMedia3" value="0" />
@@ -149,6 +152,7 @@
     <ctl name="MultiMedia1 Mixer USB_AUDIO_TX" value="0" />
     <ctl name="MultiMedia5 Mixer USB_AUDIO_TX" value="0" />
     <ctl name="MultiMedia8 Mixer USB_AUDIO_TX" value="0" />
+    <ctl name="MultiMedia10 Mixer USB_AUDIO_TX" value="0" />
     <ctl name="USB_AUDIO_TX Format" value="S16_LE" />
     <ctl name="USB_AUDIO_TX SampleRate" value="KHZ_48" />
     <ctl name="USB_AUDIO_TX Channels" value="One" />
@@ -1631,7 +1635,68 @@
         <path name="voicemmode2-call"/>
     </path>
 
-   <path name="spkr-rx-calib">
+    <!-- VoIP Rx settings -->
+    <path name="audio-playback-voip">
+        <ctl name="INT4_MI2S_RX Audio Mixer MultiMedia10" value="1" />
+    </path>
+
+    <path name="audio-playback-voip handset">
+        <ctl name="INT0_MI2S_RX Audio Mixer MultiMedia10" value="1" />
+    </path>
+
+    <path name="audio-playback-voip headphones">
+        <ctl name="INT0_MI2S_RX Audio Mixer MultiMedia10" value="1" />
+    </path>
+
+    <path name="audio-playback-voip bt-sco">
+        <ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia10" value="1" />
+    </path>
+
+    <path name="audio-playback-voip bt-sco-wb">
+        <ctl name="BT SampleRate" value="KHZ_16" />
+        <path name="audio-playback-voip bt-sco" />
+    </path>
+
+    <path name="audio-playback-voip afe-proxy">
+        <ctl name="AFE_PCM_RX Audio Mixer MultiMedia10" value="1" />
+    </path>
+
+    <path name="audio-playback-voip usb-headphones">
+        <ctl name="USB_AUDIO_RX Audio Mixer MultiMedia10" value="1" />
+    </path>
+
+    <path name="audio-playback-voip usb-headset">
+        <ctl name="USB_AUDIO_RX Audio Mixer MultiMedia10" value="1" />
+    </path>
+
+    <path name="audio-playback-voip display-port">
+        <ctl name="DISPLAY_PORT Mixer MultiMedia10" value="1" />
+    </path>
+
+    <path name="audio-playback-voip speaker-and-display-port">
+        <path name="audio-playback-voip display-port" />
+        <path name="audio-playback-voip" />
+    </path>
+
+    <!-- VoIP Tx settings -->
+    <path name="audio-record-voip">
+        <ctl name="MultiMedia10 Mixer INT3_MI2S_TX" value="1" />
+    </path>
+
+    <path name="audio-record-voip usb-headset-mic">
+        <ctl name="MultiMedia10 Mixer USB_AUDIO_TX" value="1" />
+    </path>
+
+    <path name="audio-record-voip bt-sco">
+        <ctl name="MultiMedia10 Mixer SLIM_7_TX" value="1" />
+    </path>
+
+    <path name="audio-record-voip bt-sco-wb">
+        <ctl name="BT SampleRate" value="KHZ_16" />
+        <path name="audio-record-voip bt-sco" />
+    </path>
+
+    <path name="spkr-rx-calib">
         <ctl name="INT4_MI2S_RX_DL_HL Switch"  value="1" />
     </path>
 
diff --git a/configs/sdm670/sdm670.mk b/configs/sdm670/sdm670.mk
index 67d4b4f..518ced2 100644
--- a/configs/sdm670/sdm670.mk
+++ b/configs/sdm670/sdm670.mk
@@ -139,6 +139,11 @@
 persist.vendor.audio.fluence.voicerec=false\
 persist.vendor.audio.fluence.speaker=true
 
+##speaker protection v3 switch and ADSP AFE API version
+PRODUCT_PROPERTY_OVERRIDES += \
+persist.vendor.audio.spv3.enable=true\
+persist.vendor.audio.avs.afe_api_version=2
+
 #disable tunnel encoding
 PRODUCT_PROPERTY_OVERRIDES += \
 vendor.audio.tunnel.encode=false
@@ -238,6 +243,10 @@
 PRODUCT_PROPERTY_OVERRIDES += \
 vendor.audio.offload.pstimeout.secs=3
 
+#Set AudioFlinger client heap size
+PRODUCT_PROPERTY_OVERRIDES += \
+ro.af.client_heap_size_kbyte=7168
+
 # for HIDL related packages
 PRODUCT_PACKAGES += \
     android.hardware.audio@2.0-service \
diff --git a/hal/Android.mk b/hal/Android.mk
index 42f6ec7..c8bfb10 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -65,6 +65,11 @@
 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/techpack/audio/include
 LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+ifneq ($(filter sdm670,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/vendor/qcom/opensource/audio-kernel/include
+  LOCAL_ADDITIONAL_DEPENDENCIES += $(BOARD_VENDOR_KERNEL_MODULES)
+endif
+
 LOCAL_CFLAGS += -DUSE_VENDOR_EXTN
 
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_EDID)),true)
diff --git a/hal/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c
index 2c0c53b..8ce3784 100644
--- a/hal/audio_extn/a2dp.c
+++ b/hal/audio_extn/a2dp.c
@@ -969,9 +969,9 @@
 
      ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value,
                             sizeof(value));
-     if( ret >= 0) {
+     if (ret >= 0) {
          val = atoi(value);
-         if (val & AUDIO_DEVICE_OUT_ALL_A2DP) {
+         if (audio_is_a2dp_out_device(val)) {
              ALOGV("Received device connect request for A2DP");
              open_a2dp_output();
          }
@@ -981,9 +981,9 @@
      ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value,
                          sizeof(value));
 
-     if( ret >= 0) {
+     if (ret >= 0) {
          val = atoi(value);
-         if (val & AUDIO_DEVICE_OUT_ALL_A2DP) {
+         if (audio_is_a2dp_out_device(val)) {
              ALOGV("Received device dis- connect request");
              reset_a2dp_enc_config_params();
              close_a2dp_output();
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 072d202..81f51e4 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -629,6 +629,9 @@
 int audio_extn_utils_get_snd_card_num();
 bool audio_extn_is_dsp_bit_width_enforce_mode_supported(audio_output_flags_t flags);
 bool audio_extn_utils_is_dolby_format(audio_format_t format);
+int audio_extn_utils_get_bit_width_from_string(const char *);
+int audio_extn_utils_get_sample_rate_from_string(const char *);
+int audio_extn_utils_get_channels_from_string(const char *);
 
 #ifdef DS2_DOLBY_DAP_ENABLED
 #define LIB_DS2_DAP_HAL "vendor/lib/libhwdaphal.so"
diff --git a/hal/audio_extn/gef.c b/hal/audio_extn/gef.c
index 2468cbb..4525f08 100644
--- a/hal/audio_extn/gef.c
+++ b/hal/audio_extn/gef.c
@@ -56,7 +56,7 @@
 #ifdef AUDIO_GENERIC_EFFECT_FRAMEWORK_ENABLED
 
 #if LINUX_ENABLED
-#define GEF_LIBRARY "/usr/lib/libqtigef.so"
+#define GEF_LIBRARY "libqtigef.so"
 #else
 #define GEF_LIBRARY "/vendor/lib/libqtigef.so"
 #endif
diff --git a/hal/audio_extn/ip_hdlr_intf.c b/hal/audio_extn/ip_hdlr_intf.c
index 1f5103c..a667a22 100644
--- a/hal/audio_extn/ip_hdlr_intf.c
+++ b/hal/audio_extn/ip_hdlr_intf.c
@@ -37,7 +37,7 @@
 #endif
 
 #ifdef LINUX_ENABLED
-#define LIB_PATH "/usr/lib/libaudio_ip_handler.so"
+#define LIB_PATH "libaudio_ip_handler.so"
 #else
 #define LIB_PATH "/system/vendor/lib/libaudio_ip_handler.so"
 #endif
diff --git a/hal/audio_extn/keep_alive.c b/hal/audio_extn/keep_alive.c
index af2db5c..d6a9055 100644
--- a/hal/audio_extn/keep_alive.c
+++ b/hal/audio_extn/keep_alive.c
@@ -380,7 +380,8 @@
     ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
     if (ret >= 0) {
         int val = atoi(value);
-        if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+        if (audio_is_output_devices(val) &&
+            (val & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
             if (!audio_extn_passthru_is_active()) {
                 ALOGV("start keep alive");
                 audio_extn_keep_alive_start();
@@ -392,7 +393,8 @@
                             sizeof(value));
     if (ret >= 0) {
         int val = atoi(value);
-        if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+        if (audio_is_output_devices(val) &&
+            (val & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
             ALOGV("stop keep_alive");
             audio_extn_keep_alive_stop();
         }
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index f9b38cc..5d41f59 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -2799,7 +2799,6 @@
     int status = 0, val = 0, k;
     char *format_params, *kv_parirs;
     struct str_parms *qaf_params;
-    char value[32];
 
     DEBUG_MSG("Entry");
 
@@ -2807,10 +2806,9 @@
         return -EINVAL;
     }
 
-    status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
+    status = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_CONNECT, &val);
 
-    if (status >= 0) {
-        val = atoi(value);
+    if ((status >= 0) && audio_is_output_device(val)) {
         if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) { //HDMI is connected.
 
             p_qaf->hdmi_connect = 1;
@@ -2847,9 +2845,8 @@
         //TODO else if: Need to consider other devices.
     }
 
-    status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
-    if (status >= 0) {
-        val = atoi(value);
+    status = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, &val);
+    if ((status >= 0) && audio_is_output_device(val)) {
         if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) { //HDMI is disconnected.
 
             qaf_params = str_parms_create();
diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c
index a38ca17..c2dee84 100644
--- a/hal/audio_extn/soundtrigger.c
+++ b/hal/audio_extn/soundtrigger.c
@@ -71,7 +71,7 @@
 static void get_library_path(char *lib_path)
 {
     snprintf(lib_path, MAX_LIBRARY_PATH,
-             "/usr/lib/sound_trigger.primary.default.so");
+             "sound_trigger.primary.default.so");
 }
 #else
 static void get_library_path(char *lib_path)
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index a33d432..ea4d856 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -46,6 +46,7 @@
 #include <cutils/properties.h>
 #include "audio_extn.h"
 #include <linux/msm_audio_calibration.h>
+#include <linux/msm_audio.h>
 
 #ifdef DYNAMIC_LOG_ENABLED
 #include <log_xml_parser.h>
@@ -59,7 +60,29 @@
 #define MIN_SPKR_TEMP_Q6 (-30 * (1 << 6))
 #define MAX_SPKR_TEMP_Q6 (80 * (1 << 6))
 #define VI_FEED_CHANNEL "VI_FEED_TX Channels"
+#define WSA8815_NAME_LEFT "wsatz.13"
+#define WSA8815_NAME_RIGHT "wsatz.14"
+#define WCD_LEFT_BOOST_MAX_STATE "SPKR Left Boost Max State"
+#define WCD_RIGHT_BOOST_MAX_STATE "SPKR Right Boost Max State"
+#define WSA_LEFT_BOOST_LEVEL "SpkrLeft Boost Level"
+#define WSA_RIGHT_BOOST_LEVEL "SpkrRight Boost Level"
+/* Min and max resistance value in lookup table. */
+#define MIN_RESISTANCE_LOOKUP (3.2)
+#define MAX_RESISTANCE_LOOKUP (8)
+#define SPV3_LOOKUP_TABLE_ROWS (49)
+/* default limiter threshold is 0dB */
+#define DEFAULT_LIMITER_TH (0x0)
+#define AFE_API_VERSION_SUPPORT_SPV3 (0x2)
+enum spv3_boost_max_state {
+    BOOST_NO_MAX_STATE,
+    BOOST_MAX_STATE_1,
+    BOOST_MAX_STATE_2,
+};
 
+enum sp_version {
+    SP_V2 = 0x1,
+    SP_V3 = AFE_API_VERSION_SUPPORT_SPV3,
+};
 /*Set safe temp value to 40C*/
 #define SAFE_SPKR_TEMP 40
 #define SAFE_SPKR_TEMP_Q6 (SAFE_SPKR_TEMP * (1 << 6))
@@ -162,6 +185,8 @@
     pthread_cond_t cal_wait_condition;
     bool init_check;
     volatile bool thread_exit;
+    unsigned int sp_version;
+    int limiter_th[SP_V2_NUM_MAX_SPKRS];
 };
 
 static struct pcm_config pcm_config_skr_prot = {
@@ -180,6 +205,86 @@
     char *spkr_2_name;
 };
 
+struct spv3_boost {
+    /* bit7-4: first stage; bit 3-0: second stage */
+    int boost_value;
+    int max_state;
+};
+
+#define SPV3_BOOST_VALUE_STATE(value, state) \
+{    .boost_value = (value), .max_state = (state) }
+
+static struct spv3_boost spv3_boost_lookup_table[SPV3_LOOKUP_TABLE_ROWS] = {
+    SPV3_BOOST_VALUE_STATE(0xc7, BOOST_MAX_STATE_1),
+    SPV3_BOOST_VALUE_STATE(0xd7, BOOST_MAX_STATE_1),
+    SPV3_BOOST_VALUE_STATE(0xd7, BOOST_MAX_STATE_1),
+    SPV3_BOOST_VALUE_STATE(0xe7, BOOST_MAX_STATE_1),
+    SPV3_BOOST_VALUE_STATE(0xe7, BOOST_MAX_STATE_1),
+    SPV3_BOOST_VALUE_STATE(0xf7, BOOST_MAX_STATE_1),
+    SPV3_BOOST_VALUE_STATE(0x70, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x70, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x71, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x71, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x72, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x72, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x73, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x73, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x74, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x75, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x75, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x76, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x76, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x77, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x77, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x78, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x78, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x79, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x79, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7a, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7a, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7a, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7b, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7b, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7c, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7c, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7d, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7d, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7e, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7e, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7f, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7f, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7f, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7f, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7f, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7f, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7f, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7f, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7f, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7f, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7f, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7f, BOOST_MAX_STATE_2),
+    SPV3_BOOST_VALUE_STATE(0x7f, BOOST_MAX_STATE_2),
+};
+
+/* 3.2 ohm in q24 format: (3.2 * (1 << 24)) */
+#define MIN_LOOKUP_RESISTANCE_SPKR_Q24    (53687091)
+/* 8 ohm in q24 format: (8 * (1 << 24)) */
+#define MAX_LOOKUP_RESISTANCE_SPKR_Q24    (134217728)
+/* 0.1 ohm in q24 format: (0.1 * (1 <<24)) */
+#define LOOKUP_RESISTANCE_GAP_SPKR_Q24    (1677722)
+
+/* 3.2ohm : 0.1ohm : 8ohm lookup table */
+static int spv3_limiter_th_q27_table[SPV3_LOOKUP_TABLE_ROWS] = {
+    -526133494, -508685189, -491236884, -473788580, -457682452, -441576325,
+    -426812375, -410706248, -395942298, -382520525, -367756575, -354334802,
+    -340913029, -327491256, -315411661, -301989888, -289910292, -277830697,
+    -265751101, -255013683, -242934088, -232196669, -221459251, -210721833,
+    -199984415, -190589174, -179851756, -170456515, -159719096, -150323855,
+    -140928614, -131533373, -122138132, -114085069, -104689828, -95294587,
+    -87241523,  -79188460,  -69793219,  -61740155,  -53687091,  -45634028,
+    -37580964,  -29527900,  -22817014,  -14763950,  -6710886,   0,
+    0
+};
 static struct speaker_prot_session handle;
 static int vi_feed_no_channels;
 static struct spkr_tz_names tz_names;
@@ -380,6 +485,11 @@
     cal_data.cal_type.cal_info.t0[SP_V2_SPKR_1] = protCfg->t0[SP_V2_SPKR_1];
     cal_data.cal_type.cal_info.t0[SP_V2_SPKR_2] = protCfg->t0[SP_V2_SPKR_2];
     cal_data.cal_type.cal_info.mode = protCfg->mode;
+#ifdef MSM_SPKR_PROT_SPV3
+    cal_data.cal_type.cal_info.sp_version = protCfg->sp_version;
+    cal_data.cal_type.cal_info.limiter_th[SP_V2_SPKR_1] = protCfg->limiter_th[SP_V2_SPKR_1];
+    cal_data.cal_type.cal_info.limiter_th[SP_V2_SPKR_2] = protCfg->limiter_th[SP_V2_SPKR_2];
+#endif
     property_get("persist.vendor.audio.spkr.cal.duration", value, "0");
     if (atoi(value) > 0) {
         ALOGD("%s: quick calibration enabled", __func__);
@@ -444,6 +554,179 @@
     }
 }
 
+static bool is_wsa_present(void)
+{
+   ALOGD("%s: tz1: %s, tz2: %s", __func__,
+          tz_names.spkr_1_name, tz_names.spkr_2_name);
+   handle.spkr_1_tzn = get_tzn(tz_names.spkr_1_name);
+   handle.spkr_2_tzn = get_tzn(tz_names.spkr_2_name);
+   if ((handle.spkr_1_tzn >= 0) || (handle.spkr_2_tzn >= 0))
+        handle.wsa_found = true;
+
+   return handle.wsa_found;
+}
+
+static void audio_extn_check_wsa_support_sp_v3(struct audio_device *adev,
+                unsigned int num_of_spkrs, bool *wsa_support_spv3)
+{
+    unsigned int i = 0;
+    if (!is_wsa_present() ||
+        platform_spkr_prot_is_wsa_analog_mode(adev)){
+        for (i = 0; i < num_of_spkrs; i++)
+            wsa_support_spv3[i] = false;
+
+        return;
+    }
+
+    if (!strncmp(WSA8815_NAME_LEFT, tz_names.spkr_1_name,
+            sizeof(WSA8815_NAME_LEFT)) ||
+            !strncmp(WSA8815_NAME_RIGHT, tz_names.spkr_1_name,
+                sizeof(WSA8815_NAME_RIGHT))) {
+        wsa_support_spv3[SP_V2_SPKR_1] = true;
+    } else {
+        wsa_support_spv3[SP_V2_SPKR_1] = false;
+        ALOGI("%s: Speaker1(%s) is not wsa8815.", __func__, tz_names.spkr_1_name);
+    }
+
+    if (num_of_spkrs == SP_V2_NUM_MAX_SPKRS &&
+        (!strncmp(WSA8815_NAME_RIGHT, tz_names.spkr_2_name,
+                    sizeof(WSA8815_NAME_RIGHT)) ||
+            !strncmp(WSA8815_NAME_LEFT, tz_names.spkr_2_name,
+                    sizeof(WSA8815_NAME_LEFT)))) {
+        wsa_support_spv3[SP_V2_SPKR_2] = true;
+    } else {
+        wsa_support_spv3[SP_V2_SPKR_2] = false;
+        ALOGI("%s: Speaker2(%s) is not wsa8815.", __func__, tz_names.spkr_2_name);
+    }
+
+}
+
+int audio_extn_set_wcd_boost_max_state(struct audio_device *adev,
+                int boost_max_state, int wsa_num)
+{
+    struct mixer_ctl *ctl = NULL;
+    const char *mixer_ctl_name[] = {
+        WCD_LEFT_BOOST_MAX_STATE,
+        WCD_RIGHT_BOOST_MAX_STATE
+    };
+    int status = 0;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name[wsa_num]);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                __func__, mixer_ctl_name[wsa_num]);
+        return -EINVAL;
+    }
+
+    status = mixer_ctl_set_value(ctl, 0, boost_max_state);
+    if (status < 0) {
+        ALOGE("%s: failed to set WCD boost state.\n", __func__);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+int audio_extn_set_wsa_boost_level(struct audio_device *adev,
+                int wsa_num, int boost_table_index)
+{
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name_boost_level[] = {
+        WSA_LEFT_BOOST_LEVEL,
+        WSA_RIGHT_BOOST_LEVEL
+    };
+    int status = 0;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer,
+        mixer_ctl_name_boost_level[wsa_num]);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                __func__, mixer_ctl_name_boost_level[wsa_num]);
+        return -EINVAL;
+    }
+
+    status = mixer_ctl_set_value(ctl, 0,
+                    spv3_boost_lookup_table[boost_table_index].boost_value);
+
+    if (status < 0) {
+        ALOGE("%s: Could not set ctl for mixer %s\n", __func__,
+                mixer_ctl_name_boost_level[wsa_num]);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int audio_extn_config_spv3(struct audio_device *adev, unsigned int wsa_num)
+{
+    float dcr = 0;
+    unsigned int r0_index = 0;
+    int boost_max_state = 0;
+    int ret = 0;
+
+    /* get R0 value */
+    dcr = ((float)handle.sp_r0t0_cal.r0[wsa_num] / MIN_RESISTANCE_SPKR_Q24 * 2);
+    if (dcr < MIN_RESISTANCE_LOOKUP) {
+        ALOGV("%s: resistance %f changes to min value of 3.2.",
+                __func__, dcr);
+        dcr = MIN_RESISTANCE_LOOKUP;
+    }
+
+    if (dcr > MAX_RESISTANCE_LOOKUP) {
+        ALOGV("%s: resistance %f changes to max value of 8.",
+                __func__, dcr);
+        dcr = MAX_RESISTANCE_LOOKUP;
+    }
+
+    r0_index = (int)((dcr - MIN_RESISTANCE_LOOKUP) * 10);
+    if (r0_index >= SPV3_LOOKUP_TABLE_ROWS) {
+        ALOGE("%s: r0_index=%d overflows.", __func__, r0_index);
+        return -EINVAL;
+    }
+
+    boost_max_state = spv3_boost_lookup_table[r0_index].max_state;
+    ret = audio_extn_set_wcd_boost_max_state(adev, boost_max_state, wsa_num);
+    if (ret < 0) {
+        ALOGE("%s: failed to set wcd max boost state.",
+            __func__);
+        return -EINVAL;
+    }
+
+    ret = audio_extn_set_wsa_boost_level(adev, wsa_num, r0_index);
+    if (ret < 0) {
+        ALOGE("%s: failed to set wsa boost level.",
+            __func__);
+        return -EINVAL;
+    }
+
+    handle.limiter_th[wsa_num] = spv3_limiter_th_q27_table[r0_index];
+
+    return 0;
+}
+
+static void audio_extn_check_config_sp_v3(struct audio_device *adev,
+                bool spv3_enable, unsigned int afe_api_version)
+{
+    int chn = 0;
+    bool wsa_support_spv3[SP_V2_NUM_MAX_SPKRS] = {false, false};
+
+    if (spv3_enable && afe_api_version >= AFE_API_VERSION_SUPPORT_SPV3) {
+        handle.sp_version = SP_V2;
+        audio_extn_check_wsa_support_sp_v3(adev, vi_feed_no_channels, wsa_support_spv3);
+        /*
+         * In case of WSA8815+8810, invalid limiter threshold is sent to DSP
+         * for WSA8810 speaker. DSP ignores the invalid value and use default one.
+         * The approach let spv3 apply on 8815 and spv2 on 8810 respectively.
+         */
+        for (chn = 0; chn < vi_feed_no_channels; chn++) {
+            if (wsa_support_spv3[chn] && !audio_extn_config_spv3(adev, chn))
+                handle.sp_version = SP_V3;
+            else
+                handle.limiter_th[chn] = DEFAULT_LIMITER_TH;
+        }
+    }
+}
+
 static int spkr_calibrate(int t0_spk_1, int t0_spk_2)
 {
     struct audio_device *adev = handle.adev_handle;
@@ -706,6 +989,8 @@
     int spk_1_tzn, spk_2_tzn;
     char buf[32] = {0};
     int ret;
+    bool spv3_enable = false;
+    unsigned int afe_api_version = 0;
 
     memset(&protCfg, 0, sizeof(protCfg));
     /* If the value of this persist.vendor.audio.spkr.cal.duration is 0
@@ -738,6 +1023,9 @@
         return NULL;
     }
 
+    spv3_enable = property_get_bool("persist.vendor.audio.spv3.enable", false);
+    afe_api_version = property_get_int32("persist.vendor.audio.avs.afe_api_version", 0);
+
     fp = fopen(CALIB_FILE,"rb");
     if (fp) {
         int i;
@@ -770,6 +1058,9 @@
             } else
                 handle.spkr_prot_mode = MSM_SPKR_PROT_CALIBRATED;
             close(acdb_fd);
+
+            audio_extn_check_config_sp_v3(adev, spv3_enable, vi_feed_no_channels);
+
             pthread_exit(0);
             return NULL;
         }
@@ -921,6 +1212,9 @@
     if (handle.thermal_handle)
         dlclose(handle.thermal_handle);
     handle.thermal_handle = NULL;
+
+    audio_extn_check_config_sp_v3(adev, spv3_enable, vi_feed_no_channels);
+
     pthread_exit(0);
     return NULL;
 }
@@ -936,17 +1230,6 @@
     return 0;
 }
 
-static bool is_wsa_present(void)
-{
-   ALOGD("%s: tz1: %s, tz2: %s", __func__,
-          tz_names.spkr_1_name, tz_names.spkr_2_name);
-   handle.spkr_1_tzn = get_tzn(tz_names.spkr_1_name);
-   handle.spkr_2_tzn = get_tzn(tz_names.spkr_2_name);
-   if ((handle.spkr_1_tzn >= 0) || (handle.spkr_2_tzn >= 0))
-        handle.wsa_found = true;
-   return handle.wsa_found;
-}
-
 void audio_extn_spkr_prot_set_parameters(struct str_parms *parms,
                                          char *value, int len)
 {
@@ -1449,6 +1732,11 @@
             break;
     }
     protCfg.mode = MSM_SPKR_PROT_CALIBRATED;
+#ifdef MSM_SPKR_PROT_SPV3
+    protCfg.sp_version = handle.sp_version;
+    protCfg.limiter_th[SP_V2_SPKR_1] = handle.limiter_th[SP_V2_SPKR_1];
+    protCfg.limiter_th[SP_V2_SPKR_2] = handle.limiter_th[SP_V2_SPKR_2];
+#endif
     ret = set_spkr_prot_cal(acdb_fd, &protCfg);
     if (ret)
         ALOGE("%s: speaker protection cal data swap failed", __func__);
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 35c33ca..cac1369 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -106,6 +106,11 @@
 #define MAX_CHANNELS_SUPPORTED 8
 #endif
 
+typedef struct {
+    const char *id_string;
+    const int value;
+} mixer_config_lookup;
+
 struct string_to_enum {
     const char *name;
     uint32_t value;
@@ -2372,4 +2377,63 @@
         return false;
 }
 
+int audio_extn_utils_get_bit_width_from_string(const char *id_string)
+{
+    int i;
+    const mixer_config_lookup mixer_bitwidth_config[] = {{"S24_3LE", 24},
+                                                         {"S32_LE", 32},
+                                                         {"S24_LE", 24},
+                                                         {"S16_LE", 16}};
+    int num_configs = sizeof(mixer_bitwidth_config) / sizeof(mixer_bitwidth_config[0]);
 
+    for (i = 0; i < num_configs; i++) {
+        if (!strcmp(id_string, mixer_bitwidth_config[i].id_string))
+            return mixer_bitwidth_config[i].value;
+    }
+
+    return -EINVAL;
+}
+
+int audio_extn_utils_get_sample_rate_from_string(const char *id_string)
+{
+    int i;
+    const mixer_config_lookup mixer_samplerate_config[] = {{"KHZ_32", 32000},
+                                                           {"KHZ_48", 48000},
+                                                           {"KHZ_96", 96000},
+                                                           {"KHZ_144", 144000},
+                                                           {"KHZ_192", 192000},
+                                                           {"KHZ_384", 384000},
+                                                           {"KHZ_44P1", 44100},
+                                                           {"KHZ_88P2", 88200},
+                                                           {"KHZ_176P4", 176400},
+                                                           {"KHZ_352P8", 352800}};
+    int num_configs = sizeof(mixer_samplerate_config) / sizeof(mixer_samplerate_config[0]);
+
+    for (i = 0; i < num_configs; i++) {
+        if (!strcmp(id_string, mixer_samplerate_config[i].id_string))
+            return mixer_samplerate_config[i].value;
+    }
+
+    return -EINVAL;
+}
+
+int audio_extn_utils_get_channels_from_string(const char *id_string)
+{
+    int i;
+    const mixer_config_lookup mixer_channels_config[] = {{"One", 1},
+                                                         {"Two", 2},
+                                                         {"Three",3},
+                                                         {"Four", 4},
+                                                         {"Five", 5},
+                                                         {"Six", 6},
+                                                         {"Seven", 7},
+                                                         {"Eight", 8}};
+    int num_configs = sizeof(mixer_channels_config) / sizeof(mixer_channels_config[0]);
+
+    for (i = 0; i < num_configs; i++) {
+        if (!strcmp(id_string, mixer_channels_config[i].id_string))
+            return mixer_channels_config[i].value;
+    }
+
+    return -EINVAL;
+}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 1de5484..aa52ef8 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -6243,7 +6243,8 @@
     ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
     if (ret >= 0) {
         val = atoi(value);
-        if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+        if (audio_is_output_device(val) &&
+            (val & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
             ALOGV("cache new ext disp type and edid");
             ret = platform_get_ext_disp_type(adev->platform);
             if (ret < 0) {
@@ -6252,8 +6253,8 @@
                 goto done;
             }
             platform_cache_edid(adev->platform);
-        } else if ((val & AUDIO_DEVICE_OUT_USB_DEVICE) ||
-                   !(val ^ AUDIO_DEVICE_IN_USB_DEVICE)) {
+        } else if ((audio_is_output_device(val) && (val & AUDIO_DEVICE_OUT_USB_DEVICE)) ||
+                   (audio_is_input_device(val) && ((uint32_t)val & AUDIO_DEVICE_IN_USB_DEVICE))) {
             /*
              * Do not allow AFE proxy port usage by WFD source when USB headset is connected.
              * Per AudioPolicyManager, USB device is higher priority than WFD.
@@ -6263,8 +6264,10 @@
              */
             ret = str_parms_get_str(parms, "card", value, sizeof(value));
             if (ret >= 0) {
-                audio_extn_usb_add_device(AUDIO_DEVICE_OUT_USB_DEVICE, atoi(value));
-                audio_extn_usb_add_device(AUDIO_DEVICE_IN_USB_DEVICE, atoi(value));
+                if (audio_is_output_device(val))
+                    audio_extn_usb_add_device(AUDIO_DEVICE_OUT_USB_DEVICE, atoi(value));
+                else
+                    audio_extn_usb_add_device(AUDIO_DEVICE_IN_USB_DEVICE, atoi(value));
             }
             ALOGV("detected USB connect .. disable proxy");
             adev->allow_afe_proxy_usage = false;
@@ -6280,12 +6283,14 @@
          * invalidated prior to updating sysfs of the disconnect event
          * Invalidate will be handled by audio_extn_ext_disp_set_parameters()
          */
-        if ((val & AUDIO_DEVICE_OUT_USB_DEVICE) ||
-                   !(val ^ AUDIO_DEVICE_IN_USB_DEVICE)) {
+        if ((audio_is_output_device(val) && (val & AUDIO_DEVICE_OUT_USB_DEVICE)) ||
+            (audio_is_input_device(val) && ((uint32_t)val == AUDIO_DEVICE_IN_USB_DEVICE))) {
             ret = str_parms_get_str(parms, "card", value, sizeof(value));
             if (ret >= 0) {
-                audio_extn_usb_remove_device(AUDIO_DEVICE_OUT_USB_DEVICE, atoi(value));
-                audio_extn_usb_remove_device(AUDIO_DEVICE_IN_USB_DEVICE, atoi(value));
+                if (audio_is_output_device(val))
+                    audio_extn_usb_remove_device(AUDIO_DEVICE_OUT_USB_DEVICE, atoi(value));
+                else
+                    audio_extn_usb_remove_device(AUDIO_DEVICE_IN_USB_DEVICE, atoi(value));
             }
             ALOGV("detected USB disconnect .. enable proxy");
             adev->allow_afe_proxy_usage = true;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 56ee9d0..3130f93 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -50,9 +50,9 @@
 #include "audio_hw_extn_api.h"
 
 #if LINUX_ENABLED
-#define VISUALIZER_LIBRARY_PATH "/usr/lib/libqcomvisualizer.so"
-#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/usr/lib/libqcompostprocbundle.so"
-#define ADM_LIBRARY_PATH "/usr/lib/libadm.so"
+#define VISUALIZER_LIBRARY_PATH "libqcomvisualizer.so"
+#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "libqcompostprocbundle.so"
+#define ADM_LIBRARY_PATH "libadm.so"
 #else
 #define VISUALIZER_LIBRARY_PATH "/vendor/lib/soundfx/libqcomvisualizer.so"
 #define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/vendor/lib/soundfx/libqcompostprocbundle.so"
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 2739ab5..e67d387 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -972,6 +972,8 @@
 #define ULL_PLATFORM_DELAY (6*1000LL)
 #define MMAP_PLATFORM_DELAY (3*1000LL)
 
+static const char *platform_get_mixer_control(struct mixer_ctl *);
+
 static void update_interface(const char *snd_card_name) {
      if (!strncmp(snd_card_name, "apq8009-tashalite-snd-card",
                   sizeof("apq8009-tashalite-snd-card"))) {
@@ -2149,6 +2151,8 @@
     int idx;
     int wsaCount =0;
     bool is_wsa_combo_supported = false;
+    const char *id_string = NULL;
+    int cfg_value = -1;
 
     snd_card_num = audio_extn_utils_get_snd_card_num();
     if(snd_card_num < 0) {
@@ -2599,6 +2603,41 @@
     my_data->current_backend_cfg[HDMI_TX_BACKEND].channels_mixer_ctl =
         strdup("QUAT_MI2S_TX Channels");
 
+    for (idx = 0; idx < MAX_CODEC_BACKENDS; idx++) {
+        if (my_data->current_backend_cfg[idx].bitwidth_mixer_ctl) {
+            ctl = mixer_get_ctl_by_name(adev->mixer,
+                         my_data->current_backend_cfg[idx].bitwidth_mixer_ctl);
+            id_string = platform_get_mixer_control(ctl);
+            if (id_string) {
+                cfg_value = audio_extn_utils_get_bit_width_from_string(id_string);
+                if (cfg_value > 0)
+                    my_data->current_backend_cfg[idx].bit_width = cfg_value;
+            }
+        }
+
+        if (my_data->current_backend_cfg[idx].samplerate_mixer_ctl) {
+            ctl = mixer_get_ctl_by_name(adev->mixer,
+                         my_data->current_backend_cfg[idx].samplerate_mixer_ctl);
+            id_string = platform_get_mixer_control(ctl);
+            if (id_string) {
+                cfg_value = audio_extn_utils_get_sample_rate_from_string(id_string);
+                if (cfg_value > 0)
+                    my_data->current_backend_cfg[idx].sample_rate = cfg_value;
+            }
+        }
+
+        if (my_data->current_backend_cfg[idx].channels_mixer_ctl) {
+            ctl = mixer_get_ctl_by_name(adev->mixer,
+                         my_data->current_backend_cfg[idx].channels_mixer_ctl);
+            id_string = platform_get_mixer_control(ctl);
+            if (id_string) {
+                cfg_value = audio_extn_utils_get_channels_from_string(id_string);
+                if (cfg_value > 0)
+                    my_data->current_backend_cfg[idx].channels = cfg_value;
+            }
+        }
+    }
+
     ret = audio_extn_utils_get_codec_version(snd_card_name,
                                              my_data->adev->snd_card,
                                              my_data->codec_version);
@@ -7894,3 +7933,20 @@
     return -1;
 }
 #endif
+
+static const char *platform_get_mixer_control(struct mixer_ctl *ctl)
+{
+    int id = -1;
+    const char *id_string = NULL;
+
+    if (!ctl) {
+        ALOGD("%s: mixer ctl not obtained", __func__);
+    } else {
+        id = mixer_ctl_get_value(ctl, 0);
+        if (id >= 0) {
+            id_string = mixer_ctl_get_enum_string(ctl, id);
+        }
+    }
+
+    return id_string;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 59472fc..85ed12a 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1024,6 +1024,8 @@
     return ret;
 }
 
+static const char *platform_get_mixer_control(struct mixer_ctl *);
+
 bool platform_send_gain_dep_cal(void *platform, int level) {
     bool ret_val = false;
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -1886,6 +1888,9 @@
     char *tmp = NULL;
     char mixer_xml_file[MIXER_PATH_MAX_LENGTH]= {0};
     int idx;
+    struct mixer_ctl *ctl = NULL;
+    const char *id_string = NULL;
+    int cfg_value = -1;
 
     adev->snd_card = audio_extn_utils_get_snd_card_num();
     if (adev->snd_card < 0) {
@@ -2350,6 +2355,41 @@
     my_data->current_backend_cfg[HDMI_TX_BACKEND].channels_mixer_ctl =
         strdup("QUAT_MI2S_TX Channels");
 
+    for (idx = 0; idx < MAX_CODEC_BACKENDS; idx++) {
+        if (my_data->current_backend_cfg[idx].bitwidth_mixer_ctl) {
+            ctl = mixer_get_ctl_by_name(adev->mixer,
+                         my_data->current_backend_cfg[idx].bitwidth_mixer_ctl);
+            id_string = platform_get_mixer_control(ctl);
+            if (id_string) {
+                cfg_value = audio_extn_utils_get_bit_width_from_string(id_string);
+                if (cfg_value > 0)
+                    my_data->current_backend_cfg[idx].bit_width = cfg_value;
+            }
+        }
+
+        if (my_data->current_backend_cfg[idx].samplerate_mixer_ctl) {
+            ctl = mixer_get_ctl_by_name(adev->mixer,
+                         my_data->current_backend_cfg[idx].samplerate_mixer_ctl);
+            id_string = platform_get_mixer_control(ctl);
+            if (id_string) {
+                cfg_value = audio_extn_utils_get_sample_rate_from_string(id_string);
+                if (cfg_value > 0)
+                    my_data->current_backend_cfg[idx].sample_rate = cfg_value;
+            }
+        }
+
+        if (my_data->current_backend_cfg[idx].channels_mixer_ctl) {
+            ctl = mixer_get_ctl_by_name(adev->mixer,
+                         my_data->current_backend_cfg[idx].channels_mixer_ctl);
+            id_string = platform_get_mixer_control(ctl);
+            if (id_string) {
+                cfg_value = audio_extn_utils_get_channels_from_string(id_string);
+                if (cfg_value > 0)
+                    my_data->current_backend_cfg[idx].channels = cfg_value;
+            }
+        }
+    }
+
     ret = audio_extn_utils_get_codec_version(snd_card_name,
                                              my_data->adev->snd_card,
                                              my_data->codec_version);
@@ -7636,3 +7676,20 @@
     return -1;
 }
 #endif
+
+static const char *platform_get_mixer_control(struct mixer_ctl *ctl)
+{
+    int id = -1;
+    const char *id_string = NULL;
+
+    if (!ctl) {
+        ALOGD("%s: mixer ctl not obtained", __func__);
+    } else {
+        id = mixer_ctl_get_value(ctl, 0);
+        if (id >= 0) {
+            id_string = mixer_ctl_get_enum_string(ctl, id);
+        }
+    }
+
+    return id_string;
+}
diff --git a/mm-audio/aenc-aac/qdsp6/Android.mk b/mm-audio/aenc-aac/qdsp6/Android.mk
index add61e5..2c169b6 100644
--- a/mm-audio/aenc-aac/qdsp6/Android.mk
+++ b/mm-audio/aenc-aac/qdsp6/Android.mk
@@ -39,6 +39,10 @@
 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/techpack/audio/include
 LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+ifneq ($(filter sdm670,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/vendor/qcom/opensource/audio-kernel/include
+  LOCAL_ADDITIONAL_DEPENDENCIES += $(BOARD_VENDOR_KERNEL_MODULES)
+endif
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/mm-audio/aenc-amrnb/qdsp6/Android.mk b/mm-audio/aenc-amrnb/qdsp6/Android.mk
index dbc6a5c..e8e985b 100644
--- a/mm-audio/aenc-amrnb/qdsp6/Android.mk
+++ b/mm-audio/aenc-amrnb/qdsp6/Android.mk
@@ -39,6 +39,10 @@
 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/techpack/audio/include
 LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+ifneq ($(filter sdm670,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/vendor/qcom/opensource/audio-kernel/include
+  LOCAL_ADDITIONAL_DEPENDENCIES += $(BOARD_VENDOR_KERNEL_MODULES)
+endif
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/mm-audio/aenc-evrc/qdsp6/Android.mk b/mm-audio/aenc-evrc/qdsp6/Android.mk
index 8655fb8..49384a4 100644
--- a/mm-audio/aenc-evrc/qdsp6/Android.mk
+++ b/mm-audio/aenc-evrc/qdsp6/Android.mk
@@ -39,6 +39,10 @@
 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/techpack/audio/include
 LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+ifneq ($(filter sdm670,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/vendor/qcom/opensource/audio-kernel/include
+  LOCAL_ADDITIONAL_DEPENDENCIES += $(BOARD_VENDOR_KERNEL_MODULES)
+endif
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/mm-audio/aenc-g711/qdsp6/Android.mk b/mm-audio/aenc-g711/qdsp6/Android.mk
index 62dc09a..97e105c 100644
--- a/mm-audio/aenc-g711/qdsp6/Android.mk
+++ b/mm-audio/aenc-g711/qdsp6/Android.mk
@@ -40,6 +40,10 @@
 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/techpack/audio/include
 LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+ifneq ($(filter sdm670,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/vendor/qcom/opensource/audio-kernel/include
+  LOCAL_ADDITIONAL_DEPENDENCIES += $(BOARD_VENDOR_KERNEL_MODULES)
+endif
 
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/mm-audio/aenc-qcelp13/qdsp6/Android.mk b/mm-audio/aenc-qcelp13/qdsp6/Android.mk
index fe245e0..9071eb3 100644
--- a/mm-audio/aenc-qcelp13/qdsp6/Android.mk
+++ b/mm-audio/aenc-qcelp13/qdsp6/Android.mk
@@ -39,6 +39,10 @@
 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/techpack/audio/include
 LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+ifneq ($(filter sdm670,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/vendor/qcom/opensource/audio-kernel/include
+  LOCAL_ADDITIONAL_DEPENDENCIES += $(BOARD_VENDOR_KERNEL_MODULES)
+endif
 
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
index cbc5f8e..314a73d 100644
--- a/post_proc/Android.mk
+++ b/post_proc/Android.mk
@@ -52,6 +52,11 @@
 	$(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/techpack/audio/include \
         $(call include-path-for, audio-effects)
 
+ifneq ($(filter sdm670,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/vendor/qcom/opensource/audio-kernel/include
+  LOCAL_ADDITIONAL_DEPENDENCIES += $(BOARD_VENDOR_KERNEL_MODULES)
+endif
+
 include $(BUILD_SHARED_LIBRARY)
 
 
@@ -116,6 +121,11 @@
         hardware/qcom/audio/hal/audio_extn \
         external/tinycompress/include
 
+ifneq ($(filter sdm670,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/vendor/qcom/opensource/audio-kernel/include
+  LOCAL_ADDITIONAL_DEPENDENCIES += $(BOARD_VENDOR_KERNEL_MODULES)
+endif
+
 include $(BUILD_SHARED_LIBRARY)
 
 endif
diff --git a/qahw_api/test/qahw_multi_record_test.c b/qahw_api/test/qahw_multi_record_test.c
index 23acdeb..5b07b0f 100644
--- a/qahw_api/test/qahw_multi_record_test.c
+++ b/qahw_api/test/qahw_multi_record_test.c
@@ -34,6 +34,7 @@
 #define nullptr NULL
 #define LATENCY_NODE "/sys/kernel/debug/audio_in_latency_measurement_node"
 #define LATENCY_NODE_INIT_STR "1"
+#define MAX_RECORD_SESSIONS 6
 
 static bool kpi_mode;
 FILE * log_file = NULL;
@@ -543,15 +544,7 @@
     thread_param->record_length = 8 /*sec*/;
     thread_param->record_delay = 0 /*sec*/;
 
-    if (rec_session == 1) {
-        thread_param->handle = 0x999;
-    } else if (rec_session == 2) {
-        thread_param->handle = 0x998;
-    } else if (rec_session == 3) {
-        thread_param->handle = 0x997;
-    } else if (rec_session == 4) {
-        thread_param->handle = 0x996;
-    }
+    thread_param->handle = 0x99A - rec_session;
 }
 
 void usage() {
@@ -592,14 +585,16 @@
 
 int main(int argc, char* argv[]) {
     int max_recordings_requested = 0, status = 0;
-    int thread_active[4] = {0};
+    int thread_active[MAX_RECORD_SESSIONS] = {0};
     qahw_module_handle_t *qahw_mod_handle;
     const  char *mod_name = "audio.primary";
-    struct audio_config_params params[4];
+    struct audio_config_params params[MAX_RECORD_SESSIONS];
     bool interactive_mode = false, source_tracking = false;
     struct listnode param_list;
     char log_filename[256] = "stdout";
     bool wakelock_acquired = false;
+    int i;
+    const char *recording_session[MAX_RECORD_SESSIONS] = {"first", "second", "third", "fourth", "fifth", "sixth"};
 
     log_file = stdout;
     list_init(&param_list);
@@ -692,8 +687,16 @@
         printf(" Enter logfile path (stdout or 1 for console out)::: \n");
         scanf(" %s", log_filename);
         printf(" Enter number of record sessions to be started \n");
-        printf("             (Maximum of 4 record sessions are allowed)::::  ");
+        printf("             (Maximum of %d record sessions are allowed)::::  ", MAX_RECORD_SESSIONS);
         scanf(" %d", &max_recordings_requested);
+        if (max_recordings_requested > MAX_RECORD_SESSIONS) {
+            fprintf(log_file, " INVALID input -- Max record sessions supported is %d -exit \n",
+                                                                                 MAX_RECORD_SESSIONS);
+            if (log_file != stdout)
+                fprintf(stdout, " INVALID input -- Max record sessions supported is %d -exit \n",
+                                                                                 MAX_RECORD_SESSIONS);
+            return -1;
+        }
     } else {
         max_recordings_requested = 1;
     }
@@ -705,51 +708,17 @@
         }
     }
 
-    switch (max_recordings_requested) {
-        case 4:
-            if (interactive_mode) {
-                printf(" Enter the config params for fourth record session \n");
-                fill_default_params(&params[3], 4);
-                read_config_params_from_user(&params[3]);
-            }
-            params[3].qahw_mod_handle = qahw_mod_handle;
-            thread_active[3] = 1;
-            printf(" \n");
-        case 3:
-            if (interactive_mode) {
-                printf(" Enter the config params for third record session \n");
-                fill_default_params(&params[2], 3);
-                read_config_params_from_user(&params[2]);
-            }
-            params[2].qahw_mod_handle = qahw_mod_handle;
-            thread_active[2] = 1;
-            printf(" \n");
-        case 2:
-            if (interactive_mode) {
-                printf(" Enter the config params for second record session \n");
-                fill_default_params(&params[1], 2);
-                read_config_params_from_user(&params[1]);
-            }
-            params[1].qahw_mod_handle = qahw_mod_handle;
-            thread_active[1] = 1;
-            printf(" \n");
-        case 1:
-            if (interactive_mode) {
-                printf(" Enter the config params for first record session \n");
-                fill_default_params(&params[0], 1);
-                read_config_params_from_user(&params[0]);
-            }
-            params[0].qahw_mod_handle = qahw_mod_handle;
-            thread_active[0] = 1;
-            printf(" \n");
-            break;
-        default:
-            fprintf(log_file, " INVALID input -- Max record sessions supported is 4 -exit \n");
-            if (log_file != stdout)
-                fprintf(stdout, " INVALID input -- Max record sessions supported is 4 -exit \n");
-            status = -1;
-            break;
+    for (i = max_recordings_requested; i > 0;  i--) {
+        if (interactive_mode) {
+            printf("Enter the config params for %s record session \n", recording_session[i - 1]);
+            fill_default_params(&params[i - 1], i);
+            read_config_params_from_user(&params[i - 1]);
+        }
+        params[i - 1].qahw_mod_handle = qahw_mod_handle;
+        thread_active[i - 1] = 1;
+        printf(" \n");
     }
+
     if (interactive_mode && status == 0) {
         int option = 0;
 
@@ -798,7 +767,7 @@
         qahw_set_parameters(qahw_mod_handle, params[0].kvpairs);
     }
 
-    pthread_t tid[4];
+    pthread_t tid[MAX_RECORD_SESSIONS];
     pthread_t sourcetrack_thread;
     int ret = -1;
 
@@ -829,50 +798,20 @@
     if (signal(SIGINT, stop_signal_handler) == SIG_ERR)
         fprintf(log_file, "Failed to register SIGINT:%d\n",errno);
 
-    if (thread_active[0] == 1) {
-        fprintf(log_file, "\n Create first record thread \n");
-        ret = pthread_create(&tid[0], NULL, start_input, (void *)&params[0]);
-        if (ret) {
-            status = -1;
-            fprintf(log_file, " Failed to create first record thread \n ");
-            if (log_file != stdout)
-                fprintf(stdout, " Failed to create first record thread \n ");
-            thread_active[0] = 0;
+    for (i = 0; i < MAX_RECORD_SESSIONS; i++) {
+        if (thread_active[i] == 1) {
+            fprintf(log_file, "\n Create %s record thread \n", recording_session[i]);
+            ret = pthread_create(&tid[i], NULL, start_input, (void *)&params[i]);
+            if (ret) {
+                status = -1;
+                fprintf(log_file, " Failed to create %s record thread \n", recording_session[i]);
+                if (log_file != stdout)
+                    fprintf(stdout, " Failed to create %s record thread \n", recording_session[i]);
+                thread_active[i] = 0;
+            }
         }
     }
-    if (thread_active[1] == 1) {
-        fprintf(log_file, "Create second record thread \n");
-        ret = pthread_create(&tid[1], NULL, start_input, (void *)&params[1]);
-        if (ret) {
-            status = -1;
-            fprintf(log_file, " Failed to create second record thread \n ");
-            if (log_file != stdout)
-                fprintf(stdout, " Failed to create second record thread \n ");
-            thread_active[1] = 0;
-        }
-    }
-    if (thread_active[2] == 1) {
-        fprintf(log_file, "Create third record thread \n");
-        ret = pthread_create(&tid[2], NULL, start_input, (void *)&params[2]);
-        if (ret) {
-            status = -1;
-            fprintf(log_file, " Failed to create third record thread \n ");
-            if (log_file != stdout)
-                fprintf(stdout, " Failed to create third record thread \n ");
-            thread_active[2] = 0;
-        }
-    }
-    if (thread_active[3] == 1) {
-        fprintf(log_file, "Create fourth record thread \n");
-        ret = pthread_create(&tid[3], NULL, start_input, (void *)&params[3]);
-        if (ret) {
-            status = -1;
-            fprintf(log_file, " Failed to create fourth record thread \n ");
-            if (log_file != stdout)
-                fprintf(stdout, " Failed to create fourth record thread \n ");
-            thread_active[3] = 0;
-        }
-    }
+
     fprintf(log_file, " All threads started \n");
     if (log_file != stdout)
         fprintf(stdout, " All threads started \n");
@@ -901,21 +840,12 @@
     fprintf(log_file, " Waiting for threads exit \n");
     if (log_file != stdout)
         fprintf(stdout, " Waiting for threads exit \n");
-    if (thread_active[0] == 1) {
-        pthread_join(tid[0], NULL);
-        fprintf(log_file, " after first record thread exit \n");
-    }
-    if (thread_active[1] == 1) {
-        pthread_join(tid[1], NULL);
-        fprintf(log_file, " after second record thread exit \n");
-    }
-    if (thread_active[2] == 1) {
-        pthread_join(tid[2], NULL);
-        fprintf(log_file, " after third record thread exit \n");
-    }
-    if (thread_active[3] == 1) {
-        pthread_join(tid[3], NULL);
-        fprintf(log_file, " after fourth record thread exit \n");
+
+    for (i = 0; i < MAX_RECORD_SESSIONS; i++) {
+        if (thread_active[i] == 1) {
+            pthread_join(tid[i], NULL);
+            fprintf(log_file, " after %s record thread exit \n", recording_session[i]);
+        }
     }
 
 sourcetrack_error:
diff --git a/visualizer/Android.mk b/visualizer/Android.mk
index e9da7a8..af4bea4 100644
--- a/visualizer/Android.mk
+++ b/visualizer/Android.mk
@@ -21,7 +21,7 @@
 
 LOCAL_CFLAGS+= -O2 -fvisibility=hidden
 
-ifneq ($(filter sdm660 sdm845 msm8998 apq8098_latv,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter sdm660 sdm845 msm8998 apq8098_latv sdm670,$(TARGET_BOARD_PLATFORM)),)
     LOCAL_CFLAGS += -DCAPTURE_DEVICE=7
 endif