Merge "configs: msmcobalt: Add mixer controls for native playback" into audio-userspace.lnx.2.1-dev
diff --git a/configs/msmcobalt/sound_trigger_mixer_paths_wcd9340.xml b/configs/msmcobalt/sound_trigger_mixer_paths_wcd9340.xml
new file mode 100755
index 0000000..3c75b8e
--- /dev/null
+++ b/configs/msmcobalt/sound_trigger_mixer_paths_wcd9340.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--- Copyright (c) 2014-2016, 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    -->
+<!--- met:                                                                      -->
+<!---     * Redistributions of source code must retain the above copyright      -->
+<!---       notice, this list of conditions and the following disclaimer.       -->
+<!---     * Redistributions in binary form must reproduce the above             -->
+<!---       copyright notice, this list of conditions and the following         -->
+<!---       disclaimer in the documentation and/or other materials provided     -->
+<!---       with the distribution.                                              -->
+<!---     * Neither the name of The Linux Foundation nor the names of its       -->
+<!---       contributors may be used to endorse or promote products derived     -->
+<!---       from this software without specific prior written permission.       -->
+<!---                                                                           -->
+<!--- THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED              -->
+<!--- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF      -->
+<!--- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT    -->
+<!--- ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS    -->
+<!--- BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR    -->
+<!--- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF      -->
+<!--- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR           -->
+<!--- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,     -->
+<!--- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE      -->
+<!--- OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN    -->
+<!--- IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                             -->
+
+<mixer>
+    <!-- These are the initial mixer settings -->
+    <ctl name="LSM1 MUX" value="None" />
+    <ctl name="LSM2 MUX" value="None" />
+    <ctl name="LSM3 MUX" value="None" />
+    <ctl name="LSM4 MUX" value="None" />
+    <ctl name="LSM5 MUX" value="None" />
+    <ctl name="LSM6 MUX" value="None" />
+    <ctl name="LSM7 MUX" value="None" />
+    <ctl name="LSM8 MUX" value="None" />
+    <ctl name="SLIMBUS_5_TX LSM Function" value="None" />
+    <ctl name="MADONOFF Switch" value="0" />
+    <ctl name="MAD Input" value="DMIC1" />
+    <ctl name="MAD_BROADCAST Switch" value="0" />
+    <ctl name="TX13 INP MUX" value="CDC_DEC_5" />
+    <ctl name="AIF4_MAD Mixer SLIM TX12" value="0" />
+    <ctl name="AIF4_MAD Mixer SLIM TX13" value="0" />
+    <ctl name="CPE AFE MAD Enable" value="0"/>
+    <ctl name="CLK MODE" value="EXTERNAL" />
+    <ctl name="EC BUF MUX INP" value="ZERO" />
+    <ctl name="ADC MUX1" value="DMIC" />
+    <ctl name="DMIC MUX1" value="ZERO" />
+
+    <path name="listen-voice-wakeup-1">
+        <ctl name="SLIMBUS_5_TX LSM Function" value="AUDIO" />
+        <ctl name="LSM1 MUX" value="SLIMBUS_5_TX" />
+    </path>
+
+    <path name="listen-voice-wakeup-2">
+        <ctl name="SLIMBUS_5_TX LSM Function" value="AUDIO" />
+        <ctl name="LSM2 MUX" value="SLIMBUS_5_TX" />
+    </path>
+    <path name="listen-voice-wakeup-3">
+        <ctl name="SLIMBUS_5_TX LSM Function" value="AUDIO" />
+        <ctl name="LSM3 MUX" value="SLIMBUS_5_TX" />
+    </path>
+    <path name="listen-voice-wakeup-4">
+        <ctl name="SLIMBUS_5_TX LSM Function" value="AUDIO" />
+        <ctl name="LSM4 MUX" value="SLIMBUS_5_TX" />
+    </path>
+    <path name="listen-voice-wakeup-5">
+        <ctl name="SLIMBUS_5_TX LSM Function" value="AUDIO" />
+        <ctl name="LSM5 MUX" value="SLIMBUS_5_TX" />
+    </path>
+    <path name="listen-voice-wakeup-6">
+        <ctl name="SLIMBUS_5_TX LSM Function" value="AUDIO" />
+        <ctl name="LSM6 MUX" value="SLIMBUS_5_TX" />
+    </path>
+    <path name="listen-voice-wakeup-7">
+        <ctl name="SLIMBUS_5_TX LSM Function" value="AUDIO" />
+        <ctl name="LSM7 MUX" value="SLIMBUS_5_TX" />
+    </path>
+    <path name="listen-voice-wakeup-8">
+        <ctl name="SLIMBUS_5_TX LSM Function" value="AUDIO" />
+        <ctl name="LSM8 MUX" value="SLIMBUS_5_TX" />
+    </path>
+
+    <path name="listen-cpe-handset-mic">
+        <ctl name="MAD Input" "DMIC0" />
+        <ctl name="MAD_SEL MUX" "SPE" />
+        <ctl name="MAD_INP MUX" "MAD" />
+        <ctl name="MAD_CPE1 Switch" 1 />
+    </path>
+
+    <path name="listen-cpe-handset-mic-ecpp">
+        <ctl name="CLK MODE" value="INTERNAL" />
+        <ctl name="EC BUF MUX INP" value="DEC1" />
+        <ctl name="ADC MUX1" value="DMIC" />
+        <ctl name="DMIC MUX1" value="DMIC0" />
+    </path>
+
+    <!-- path name used for low bandwidth FTRT codec interface -->
+    <path name="listen-cpe-handset-mic low-speed-intf">
+        <ctl name="MADONOFF Switch" value="1" />
+        <ctl name="AIF4_MAD Mixer SLIM TX12" value="1" />
+        <ctl name="MAD Input" value="DMIC0" />
+        <ctl name="CPE AFE MAD Enable" value="1"/>
+    </path>
+
+    <path name="listen-ape-handset-mic">
+        <ctl name="MAD_BROADCAST Switch" value="1" />
+        <ctl name="TX13 INP MUX" value="MAD_BRDCST" />
+        <ctl name="AIF4_MAD Mixer SLIM TX13" value="1" />
+        <ctl name="MAD Input" value="DMIC0" />
+    </path>
+
+</mixer>
diff --git a/configs/msmcobalt/sound_trigger_platform_info.xml b/configs/msmcobalt/sound_trigger_platform_info.xml
index b92ea48..1f90bd5 100644
--- a/configs/msmcobalt/sound_trigger_platform_info.xml
+++ b/configs/msmcobalt/sound_trigger_platform_info.xml
@@ -29,8 +29,7 @@
     <param version="0x0101" /> <!-- this must be the first param -->
 
     <common_config>
-        <param execution_type="CPE" /> <!-- value: "CPE" "APE" -->
-        <param max_cpe_sessions="1" />
+        <param max_cpe_sessions="2" />
         <param max_ape_sessions="8" />
         <param enable_failure_detection="false" />
     </common_config>
@@ -41,11 +40,12 @@
         <param DEVICE_HANDSET_CPE_ECPP_ACDB_ID="128" />
     </acdb_ids>
 
-    <!-- Multiple sound_model_config tags can be listed, each with unique    -->
-    <!-- vendor_uuid. The below tag represents QTI SVA engine sound model    -->
-    <!-- configuration. ISV must use their own unique vendor_uuid.           -->
+    <!-- Multiple sound_model_config tags can be listed, each with unique   -->
+    <!-- vendor_uuid. The below tag represents QTI SVA engine sound model   -->
+    <!-- configuration. ISV must use their own unique vendor_uuid.          -->
     <sound_model_config>
         <param vendor_uuid="68ab2d40-e860-11e3-95ef-0002a5d5c51b" />
+        <param execution_type="WDSP" /> <!-- value: "WDSP" "ADSP" "DYNAMIC" -->
         <param app_type="2" /> <!-- app type used in ACDB -->
         <param library="libsmwrapper.so" />
         <param max_cpe_phrases="6" />
@@ -54,7 +54,18 @@
         <param max_ape_users="10" />
         <param sample_rate="16000" />
 
-        <!-- Module and param ids with which the algorithm is integrated in firmware -->
+        <gcs_uid>
+            <param uid="0x1" />
+            <param did="0x4" />
+            <param load_sound_model_ids="0x00012C0D, 0x0, 0x00012C14" />
+            <param confidence_levels_ids="0x00012C0D, 0x0, 0x00012C28" />
+            <param operation_mode_ids="0x00012C0D, 0x0, 0x00012C28" />
+            <param detection_event_ids="0x00012C0D, 0x0, 0x00012C29" />
+            <param capture_event_ids="0x00020013, 0x0,0x00020015" />
+        </gcs_uid>
+
+        <!-- Module and param ids with which the algorithm is integrated
+            in non-graphite firmware (note these must come after gcs params) -->
         <param load_sound_model_ids="0x00012C0D, 0x00012C14" />
         <param unload_sound_model_ids="0x00012C0D, 0x00012C15" />
         <param confidence_levels_ids="0x00012C0D, 0x00012C07" />
@@ -62,7 +73,8 @@
 
         <!-- format: "ADPCM_packet" or "PCM_packet" !-->
         <!-- transfer_mode: "FTRT" or "RT" -->
-        <!--  kw_duration is in milli seconds. It is valid only for FTRT transfer mode -->
+        <!--  kw_duration is in milli seconds. It is valid only for FTRT
+            transfer mode -->
         <param capture_keyword="PCM_packet, RT, 2000" />
         <param client_capture_read_delay="2000" />
     </sound_model_config>
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index d186a5f..12a8082 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -401,6 +401,10 @@
 
 #endif
 
+#ifndef AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH
+#define AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH  0x10000
+#endif
+
 #ifndef HDMI_PASSTHROUGH_ENABLED
 #define audio_extn_passthru_update_stream_configuration(adev, out)            (0)
 #define audio_extn_passthru_is_convert_supported(adev, out)                   (0)
@@ -419,8 +423,6 @@
 #define audio_extn_passthru_set_parameters(a, p) (-ENOSYS)
 #define audio_extn_passthru_init(a) do {} while(0)
 #define audio_extn_passthru_should_standby(o) (1)
-
-#define AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH  0x1000
 #else
 bool audio_extn_passthru_is_convert_supported(struct audio_device *adev,
                                                  struct stream_out *out);
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index e3f1b6c..26c43b4 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -90,9 +90,7 @@
 #ifdef INCALL_MUSIC_ENABLED
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_INCALL_MUSIC),
 #endif
-#ifdef HDMI_PASSTHROUGH_ENABLED
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH),
-#endif
 };
 
 const struct string_to_enum s_format_name_to_enum_table[] = {
@@ -133,6 +131,7 @@
     STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_LC),
     STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_HE_V1),
     STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_HE_V2),
+    STRING_TO_ENUM(AUDIO_FORMAT_DSD),
 #endif
 };
 
@@ -515,6 +514,21 @@
                                __func__, sample_rate);
         }
     }
+
+    /* Set sampling rate to 176.4 for DSD64
+     * and 352.8Khz for DSD128.
+     * Set Bit Width to 16. output will be 16 bit
+     * post DoP in ASM.
+     */
+    if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH) &&
+        (format == AUDIO_FORMAT_DSD)) {
+        bit_width = 16;
+        if (sample_rate == INPUT_SAMPLING_RATE_DSD64)
+            sample_rate = OUTPUT_SAMPLING_RATE_DSD64;
+        else if (sample_rate == INPUT_SAMPLING_RATE_DSD128)
+            sample_rate = OUTPUT_SAMPLING_RATE_DSD128;
+    }
+
     ALOGV("%s: flags: %x, format: %x sample_rate %d",
            __func__, flags, format, sample_rate);
     list_for_each(node_i, streams_output_cfg_list) {
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index af399a1..70909f5 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -82,6 +82,7 @@
 /* ToDo: Check and update a proper value in msec */
 #define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50
 #define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
+#define DSD_VOLUME_MIN_DB (-110)
 
 #define PROXY_OPEN_RETRY_COUNT           100
 #define PROXY_OPEN_WAIT_TIME             20
@@ -501,6 +502,7 @@
         format == AUDIO_FORMAT_FLAC ||
         format == AUDIO_FORMAT_ALAC ||
         format == AUDIO_FORMAT_APE ||
+        format == AUDIO_FORMAT_DSD ||
         format == AUDIO_FORMAT_VORBIS ||
         format == AUDIO_FORMAT_WMA ||
         format == AUDIO_FORMAT_WMA_PRO)
@@ -541,6 +543,9 @@
     case AUDIO_FORMAT_APE:
         id = SND_AUDIOCODEC_APE;
         break;
+    case AUDIO_FORMAT_DSD:
+        id = SND_AUDIOCODEC_DSD;
+        break;
     case AUDIO_FORMAT_VORBIS:
         id = SND_AUDIOCODEC_VORBIS;
         break;
@@ -1166,6 +1171,28 @@
     return active;
 }
 
+/*
+ * if native DSD playback active
+ */
+bool audio_is_dsd_native_stream_active(struct audio_device *adev)
+{
+    bool active = false;
+    struct listnode *node = NULL;
+    struct audio_usecase *uc = NULL;
+    struct stream_out *curr_out = NULL;
+
+    list_for_each(node, &adev->usecase_list) {
+        uc = node_to_item(node, struct audio_usecase, list);
+        curr_out = (struct stream_out*) uc->stream.out;
+
+        if (curr_out && PCM_PLAYBACK == uc->type &&
+               (DSD_NATIVE_BACKEND == platform_get_backend_index(uc->out_snd_device))) {
+            active = true;
+            ALOGV("%s:DSD playback is active", __func__);
+        }
+    }
+    return active;
+}
 
 static bool force_device_switch(struct audio_usecase *usecase)
 {
@@ -2537,6 +2564,14 @@
     return latency;
 }
 
+static float AmpToDb(float amplification)
+{
+    if (amplification == 0) {
+        return DSD_VOLUME_MIN_DB;
+    }
+    return 20 * log10(amplification);
+}
+
 static int out_set_volume(struct audio_stream_out *stream, float left,
                           float right)
 {
@@ -2555,6 +2590,20 @@
              * Mute is 0 and unmute 1
              */
             audio_extn_passthru_set_volume(out, (left == 0.0f));
+        } else if (out->format == AUDIO_FORMAT_DSD){
+            char mixer_ctl_name[128] =  "DSD Volume";
+            struct audio_device *adev = out->dev;
+            struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+
+            if (!ctl) {
+                ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                      __func__, mixer_ctl_name);
+                return -EINVAL;
+            }
+            volume[0] = (int)(AmpToDb(left));
+            volume[1] = (int)(AmpToDb(right));
+            mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
+            return 0;
         } else {
             char mixer_ctl_name[128];
             struct audio_device *adev = out->dev;
@@ -3666,12 +3715,24 @@
                 __func__, config->offload_info.version,
                 config->offload_info.bit_rate);
 
+        /*Check if DSD audio format is supported in codec
+         *and there is no active native DSD use case
+         */
+
+        if ((config->format == AUDIO_FORMAT_DSD) &&
+               (!platform_check_codec_dsd_support(adev->platform) ||
+               audio_is_dsd_native_stream_active(adev))) {
+            ret = -EINVAL;
+            goto error_open;
+        }
+
         /* Disable gapless if any of the following is true
          * passthrough playback
          * AV playback
          * Direct PCM playback
          */
         if (audio_extn_passthru_is_passthrough_stream(out) ||
+            (config->format == AUDIO_FORMAT_DSD) ||
             config->offload_info.has_video ||
             out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) {
             check_and_set_gapless_mode(adev, false);
@@ -3681,6 +3742,10 @@
         if (audio_extn_passthru_is_passthrough_stream(out)) {
             out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
         }
+        if (config->format == AUDIO_FORMAT_DSD) {
+            out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
+            out->compr_config.codec->compr_passthr = PASSTHROUGH_DSD;
+        }
     } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
         ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
         if (ret != 0) {
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index ee28157..1b5c6c9 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -410,6 +410,7 @@
 
 bool audio_is_true_native_stream_active(struct audio_device *adev);
 
+bool audio_is_dsd_native_stream_active(struct audio_device *adev);
 int pcm_ioctl(struct pcm *pcm, int request, ...);
 
 int get_snd_card_state(struct audio_device *adev);
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index e0400c6..8894b2f 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -2448,7 +2448,7 @@
     return ret;
 }
 
-static int platform_get_backend_index(snd_device_t snd_device)
+int platform_get_backend_index(snd_device_t snd_device)
 {
     int32_t port = DEFAULT_CODEC_BACKEND;
 
@@ -4343,8 +4343,8 @@
             struct audio_usecase *uc;
             uc = node_to_item(node, struct audio_usecase, list);
             struct stream_out *out = (struct stream_out*) uc->stream.out;
-            unsigned int out_channels = audio_channel_count_from_out_mask(out->channel_mask);
             if (uc->type == PCM_PLAYBACK && out && usecase != uc) {
+                unsigned int out_channels = audio_channel_count_from_out_mask(out->channel_mask);
 
                 ALOGD("%s:napb: (%d) - (%s)id (%d) sr %d bw "
                       "(%d) ch (%d) device %s", __func__, i++, use_case_table[uc->id],
@@ -5408,3 +5408,8 @@
     }
     return 0;
 }
+
+bool platform_check_codec_dsd_support(void *platform __unused)
+{
+    return false;
+}
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index dcd351a..6c89d0a 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -198,9 +198,12 @@
     SND_DEVICE_MAX = SND_DEVICE_IN_END,
 
 };
-
+#define INPUT_SAMPLING_RATE_DSD64       2822400
+#define INPUT_SAMPLING_RATE_DSD128      5644800
 #define DEFAULT_OUTPUT_SAMPLING_RATE 48000
 #define OUTPUT_SAMPLING_RATE_44100      44100
+#define OUTPUT_SAMPLING_RATE_DSD64       176400
+#define OUTPUT_SAMPLING_RATE_DSD128      352800
 #define MAX_PORT                        6
 #define ALL_CODEC_BACKEND_PORT          0
 #define HEADPHONE_44_1_BACKEND_PORT     5
@@ -208,6 +211,8 @@
 enum {
     DEFAULT_CODEC_BACKEND,
     SLIMBUS_0_RX = DEFAULT_CODEC_BACKEND,
+    DSD_NATIVE_BACKEND,
+    SLIMBUS_2_RX = DSD_NATIVE_BACKEND,
     HEADPHONE_44_1_BACKEND,
     SLIMBUS_5_RX = HEADPHONE_44_1_BACKEND,
     HEADPHONE_BACKEND,
@@ -356,7 +361,8 @@
 enum {
     LEGACY_PCM = 0,
     PASSTHROUGH,
-    PASSTHROUGH_CONVERT
+    PASSTHROUGH_CONVERT,
+    PASSTHROUGH_DSD
 };
 /*
  * ID for setting mute and lateny on the device side
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 2b6a1d7..1b47e7d 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1257,3 +1257,13 @@
     }
     return 0;
 }
+
+bool platform_check_codec_dsd_support(void *platform __unused)
+{
+    return false;
+}
+
+int platform_get_backend_index(snd_device_t snd_device __unused);
+{
+    return 0;
+}
\ No newline at end of file
diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h
index e42af8c..07060b6 100644
--- a/hal/msm8960/platform.h
+++ b/hal/msm8960/platform.h
@@ -112,6 +112,12 @@
 #define SOUND_CARD 0
 
 #define DEFAULT_OUTPUT_SAMPLING_RATE 48000
+#define INPUT_SAMPLING_RATE_DSD64       2822400
+#define INPUT_SAMPLING_RATE_DSD128      5644800
+#define OUTPUT_SAMPLING_RATE_DSD64       176400
+#define OUTPUT_SAMPLING_RATE_DSD128      352800
+#define DSD_NATIVE_BACKEND 1
+#define PASSTHROUGH_DSD 3
 
 #define ALL_SESSION_VSID                0xFFFFFFFF
 #define DEFAULT_MUTE_RAMP_DURATION_MS   20
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 8daa715..9c85d10 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -247,6 +247,7 @@
     int metainfo_key;
     int source_mic_type;
     int max_mic_count;
+    bool is_dsd_supported;
 };
 
 static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
@@ -334,6 +335,7 @@
     [SND_DEVICE_OUT_SPEAKER_VBAT] = "speaker-vbat",
     [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse",
     [SND_DEVICE_OUT_HEADPHONES] = "headphones",
+    [SND_DEVICE_OUT_HEADPHONES_DSD] = "headphones-dsd",
     [SND_DEVICE_OUT_HEADPHONES_44_1] = "headphones-44.1",
     [SND_DEVICE_OUT_LINE] = "line",
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones",
@@ -451,6 +453,7 @@
     [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
     [SND_DEVICE_OUT_LINE] = 10,
     [SND_DEVICE_OUT_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_HEADPHONES_DSD] = 10,
     [SND_DEVICE_OUT_HEADPHONES_44_1] = 10,
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10,
     [SND_DEVICE_OUT_SPEAKER_AND_LINE] = 10,
@@ -568,6 +571,7 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_VBAT)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_REVERSE)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES_DSD)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES_44_1)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_LINE)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES)},
@@ -1102,11 +1106,13 @@
     backend_tag_table[SND_DEVICE_IN_USB_HEADSET_MIC] = strdup("usb-headset-mic");
     backend_tag_table[SND_DEVICE_IN_CAPTURE_FM] = strdup("capture-fm");
     backend_tag_table[SND_DEVICE_OUT_TRANSMISSION_FM] = strdup("transmission-fm");
+    backend_tag_table[SND_DEVICE_OUT_HEADPHONES_DSD] = strdup("headphones-dsd");
     backend_tag_table[SND_DEVICE_OUT_HEADPHONES_44_1] = strdup("headphones-44.1");
     backend_tag_table[SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = strdup("voice-speaker-vbat");
     backend_tag_table[SND_DEVICE_OUT_BT_A2DP] = strdup("bt-a2dp");
     backend_tag_table[SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = strdup("speaker-and-bt-a2dp");
 
+    hw_interface_table[SND_DEVICE_OUT_HEADPHONES_DSD] = strdup("SLIMBUS_2_RX");
     hw_interface_table[SND_DEVICE_OUT_HEADPHONES_44_1] = strdup("SLIMBUS_5_RX");
     hw_interface_table[SND_DEVICE_OUT_HDMI] = strdup("HDMI_RX");
     hw_interface_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("SLIMBUS_0_RX-and-HDMI_RX");
@@ -1715,6 +1721,11 @@
     my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
         strdup("SLIM_0_RX SampleRate");
 
+    my_data->current_backend_cfg[DSD_NATIVE_BACKEND].bitwidth_mixer_ctl =
+        strdup("SLIM_2_RX Format");
+    my_data->current_backend_cfg[DSD_NATIVE_BACKEND].samplerate_mixer_ctl =
+        strdup("SLIM_2_RX SampleRate");
+
     my_data->current_backend_cfg[HEADPHONE_44_1_BACKEND].bitwidth_mixer_ctl =
         strdup("SLIM_5_RX Format");
     my_data->current_backend_cfg[HEADPHONE_44_1_BACKEND].samplerate_mixer_ctl =
@@ -1745,6 +1756,12 @@
         }
     }
 
+    if(strstr(snd_card_name, "tavil")) {
+        ALOGD("%s:DSD playback is supported", __func__);
+        my_data->is_dsd_supported = true;
+        platform_set_native_support(NATIVE_AUDIO_MODE_MULTIPLE_44_1);
+    }
+
     my_data->current_backend_cfg[HEADPHONE_BACKEND].bitwidth_mixer_ctl =
         strdup("SLIM_6_RX Format");
     my_data->current_backend_cfg[HEADPHONE_BACKEND].samplerate_mixer_ctl =
@@ -2092,7 +2109,8 @@
 
 int platform_set_native_support(int na_mode)
 {
-    if (NATIVE_AUDIO_MODE_SRC == na_mode || NATIVE_AUDIO_MODE_TRUE_44_1 == na_mode) {
+    if (NATIVE_AUDIO_MODE_SRC == na_mode || NATIVE_AUDIO_MODE_TRUE_44_1 == na_mode
+        || NATIVE_AUDIO_MODE_MULTIPLE_44_1 == na_mode) {
         na_props.platform_na_prop_enabled = na_props.ui_na_prop_enabled = true;
         na_props.na_mode = na_mode;
         ALOGD("%s:napb: native audio playback enabled in (%s) mode v2.0", __func__,
@@ -2107,6 +2125,12 @@
     return 0;
 }
 
+bool platform_check_codec_dsd_support(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    return my_data->is_dsd_supported;
+}
+
 int platform_get_native_support()
 {
     int ret = NATIVE_AUDIO_MODE_INVALID;
@@ -2159,6 +2183,8 @@
             mode = NATIVE_AUDIO_MODE_SRC;
         else if (value && !strncmp(value, "true", sizeof("true")))
             mode = NATIVE_AUDIO_MODE_TRUE_44_1;
+        else if (value && !strncmp(value, "multiple", sizeof("multiple")))
+            mode = NATIVE_AUDIO_MODE_MULTIPLE_44_1;
         else {
             mode = NATIVE_AUDIO_MODE_INVALID;
             ALOGE("%s:napb:native_audio_mode in platform info xml,invalid mode string",
@@ -2238,7 +2264,7 @@
     return ret;
 }
 
-static int platform_get_backend_index(snd_device_t snd_device)
+int platform_get_backend_index(snd_device_t snd_device)
 {
     int32_t port = DEFAULT_CODEC_BACKEND;
 
@@ -2247,6 +2273,9 @@
                 if (strncmp(backend_tag_table[snd_device], "headphones-44.1",
                             sizeof("headphones-44.1")) == 0)
                         port = HEADPHONE_44_1_BACKEND;
+                else if (strncmp(backend_tag_table[snd_device], "headphones-dsd",
+                            sizeof("headphones-dsd")) == 0)
+                        port = DSD_NATIVE_BACKEND;
                 else if (strncmp(backend_tag_table[snd_device], "headphones",
                             sizeof("headphones")) == 0)
                         port = HEADPHONE_BACKEND;
@@ -2764,6 +2793,12 @@
         } else if (NATIVE_AUDIO_MODE_SRC == na_mode &&
                    OUTPUT_SAMPLING_RATE_44100 == sample_rate) {
                 snd_device = SND_DEVICE_OUT_HEADPHONES_44_1;
+        } else if (NATIVE_AUDIO_MODE_MULTIPLE_44_1 == na_mode &&
+                   (sample_rate % OUTPUT_SAMPLING_RATE_44100 == 0) &&
+                   (out->format != AUDIO_FORMAT_DSD)) {
+                snd_device = SND_DEVICE_OUT_HEADPHONES_44_1;
+        } else if (out->format == AUDIO_FORMAT_DSD) {
+                snd_device = SND_DEVICE_OUT_HEADPHONES_DSD;
         } else
             snd_device = SND_DEVICE_OUT_HEADPHONES;
     } else if (devices & AUDIO_DEVICE_OUT_LINE) {
@@ -4070,14 +4105,6 @@
               my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl, bit_width, format);
     }
 
-    /*
-     * Backend sample rate configuration follows:
-     * 16 bit playback - 48khz for streams at any valid sample rate
-     * 24 bit playback - 48khz for stream sample rate less than 48khz
-     * 24 bit playback - 96khz for sample rate range of 48khz to 96khz
-     * 24 bit playback - 192khz for sample rate range of 96khz to 192 khz
-     * Upper limit is inclusive in the sample rate range.
-     */
     if (sample_rate !=
        my_data->current_backend_cfg[backend_idx].sample_rate) {
             char *rate_str = NULL;
@@ -4096,14 +4123,24 @@
                 rate_str = "KHZ_44P1";
                 break;
             case 64000:
-            case 88200:
             case 96000:
                 rate_str = "KHZ_96";
                 break;
+            case 88200:
+                rate_str = "KHZ_88P2";
+                break;
             case 176400:
+                rate_str = "KHZ_176P4";
+                break;
             case 192000:
                 rate_str = "KHZ_192";
                 break;
+            case 352800:
+                rate_str = "KHZ_352P8";
+                break;
+            case 384000:
+                rate_str = "KHZ_384";
+                break;
             default:
                 rate_str = "KHZ_48";
                 break;
@@ -4310,8 +4347,8 @@
             struct audio_usecase *uc;
             uc = node_to_item(node, struct audio_usecase, list);
             struct stream_out *out = (struct stream_out*) uc->stream.out;
-            unsigned int out_channels = audio_channel_count_from_out_mask(out->channel_mask);
             if (uc->type == PCM_PLAYBACK && out && usecase != uc) {
+                unsigned int out_channels = audio_channel_count_from_out_mask(out->channel_mask);
 
                 ALOGD("%s:napb: (%d) - (%s)id (%d) sr %d bw "
                       "(%d) ch (%d) device %s", __func__, i++, use_case_table[uc->id],
@@ -4400,6 +4437,24 @@
             channels_updated = true;
     }
 
+    /*
+     * Map native sampling rates to upper limit range
+     * if multiple of native sampling rates are not supported.
+     */
+    if (NATIVE_AUDIO_MODE_MULTIPLE_44_1 != na_mode) {
+        switch (sample_rate) {
+            case 88200:
+                sample_rate = 96000;
+                break;
+            case 176400:
+                sample_rate = 192000;
+                break;
+            case 352800:
+                sample_rate = 192000;
+                break;
+        }
+    }
+
     ALOGI("%s:becf: afe: Codec selected backend: %d updated bit width: %d and sample rate: %d",
           __func__, backend_idx , bit_width, sample_rate);
 
@@ -4440,6 +4495,17 @@
     /*this is populated by check_codec_backend_cfg hence set default value to false*/
     backend_cfg.passthrough_enabled = false;
 
+    /* Set Backend sampling rate to 176.4 for DSD64 and
+     * 352.8Khz for DSD128.
+     * Set Bit Width to 16
+     */
+    if ((backend_idx == DSD_NATIVE_BACKEND) && (backend_cfg.format == AUDIO_FORMAT_DSD)) {
+        backend_cfg.bit_width = 16;
+        if (backend_cfg.sample_rate == INPUT_SAMPLING_RATE_DSD64)
+            backend_cfg.sample_rate = OUTPUT_SAMPLING_RATE_DSD64;
+        else if (backend_cfg.sample_rate == INPUT_SAMPLING_RATE_DSD128)
+            backend_cfg.sample_rate = OUTPUT_SAMPLING_RATE_DSD128;
+    }
     ALOGI("%s:becf: afe: bitwidth %d, samplerate %d channels %d"
           ", backend_idx %d usecase = %d device (%s)", __func__, backend_cfg.bit_width,
           backend_cfg.sample_rate, backend_cfg.channels, backend_idx, usecase->id,
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 48bfb2b..9394ef8 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -80,6 +80,7 @@
     SND_DEVICE_OUT_SPEAKER_VBAT,
     SND_DEVICE_OUT_LINE,
     SND_DEVICE_OUT_HEADPHONES,
+    SND_DEVICE_OUT_HEADPHONES_DSD,
     SND_DEVICE_OUT_HEADPHONES_44_1,
     SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
     SND_DEVICE_OUT_SPEAKER_AND_LINE,
@@ -192,13 +193,18 @@
     SND_DEVICE_MAX = SND_DEVICE_IN_END,
 
 };
-
+#define INPUT_SAMPLING_RATE_DSD64       2822400
+#define INPUT_SAMPLING_RATE_DSD128      5644800
 #define DEFAULT_OUTPUT_SAMPLING_RATE    48000
 #define OUTPUT_SAMPLING_RATE_44100      44100
+#define OUTPUT_SAMPLING_RATE_DSD64       176400
+#define OUTPUT_SAMPLING_RATE_DSD128      352800
 #define MAX_CODEC_TX_BACKENDS           1
 enum {
     DEFAULT_CODEC_BACKEND,
     SLIMBUS_0_RX = DEFAULT_CODEC_BACKEND,
+    DSD_NATIVE_BACKEND,
+    SLIMBUS_2_RX = DSD_NATIVE_BACKEND,
     HEADPHONE_44_1_BACKEND,
     SLIMBUS_5_RX = HEADPHONE_44_1_BACKEND,
     HEADPHONE_BACKEND,
@@ -447,7 +453,8 @@
 enum {
     LEGACY_PCM = 0,
     PASSTHROUGH,
-    PASSTHROUGH_CONVERT
+    PASSTHROUGH_CONVERT,
+    PASSTHROUGH_DSD
 };
 /*
  * ID for setting mute and lateny on the device side
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 0bb73f3..60e46f1 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -27,6 +27,7 @@
 enum {
     NATIVE_AUDIO_MODE_SRC = 1,
     NATIVE_AUDIO_MODE_TRUE_44_1,
+    NATIVE_AUDIO_MODE_MULTIPLE_44_1,
     NATIVE_AUDIO_MODE_INVALID
 };
 
@@ -151,4 +152,6 @@
                           bool enable,
                           char * str);
 bool platform_supports_true_32bit();
+bool platform_check_codec_dsd_support(void *platform);
+int platform_get_backend_index(snd_device_t snd_device);
 #endif // AUDIO_PLATFORM_API_H