Merge "audio: 24 bit audio output profiles" into oc-dr1-dev
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 77a693c..cb54e80 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -86,6 +86,7 @@
 #define XSTR(x) STR(x)
 #define STR(x) #x
 #endif
+#define MAX_HIFI_CHANNEL_COUNT 8
 
 #define ULL_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
 
@@ -299,8 +300,17 @@
     STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
     STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
     STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+    STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
     STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
-    //TBD - string values for channel_in > 2?
+    STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_1),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_2),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_3),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_4),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_5),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_6),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_7),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_8),
 };
 
 static int set_voice_volume_l(struct audio_device *adev, float volume);
@@ -680,9 +690,15 @@
     if (adev->snd_dev_ref_cnt[snd_device] == 0) {
         audio_extn_dsm_feedback_enable(adev, snd_device, false);
         if ((snd_device == SND_DEVICE_OUT_SPEAKER ||
+            snd_device == SND_DEVICE_OUT_SPEAKER_REVERSE ||
             snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
             audio_extn_spkr_prot_is_enabled()) {
             audio_extn_spkr_prot_stop_processing(snd_device);
+
+            // when speaker device is disabled, reset swap.
+            // will be renabled on usecase start
+            platform_set_swap_channels(adev, false);
+
         } else if (platform_can_split_snd_device(snd_device,
                                                  &num_devices,
                                                  new_snd_devices) == 0) {
@@ -1005,19 +1021,39 @@
 
 static int read_usb_sup_channel_masks(bool is_playback,
                                       audio_channel_mask_t *supported_channel_masks,
-                                      uint32_t max_masks __unused)
+                                      uint32_t max_masks)
 {
     int channels = audio_extn_usb_get_max_channels(is_playback);
-    if (is_playback) {
-        supported_channel_masks[0] =
-                channels < 3 ? audio_channel_out_mask_from_count(channels) :
-                               audio_channel_mask_for_index_assignment_from_count(channels);
-    } else {
-        supported_channel_masks[0] = audio_channel_in_mask_from_count(channels);
+    int channel_count;
+    uint32_t num_masks = 0;
+    if (channels > MAX_HIFI_CHANNEL_COUNT) {
+        channels = MAX_HIFI_CHANNEL_COUNT;
     }
-    ALOGV("%s: %s supported ch %d", __func__,
-          is_playback ? "P" : "C", channels);
-    return 1;
+    if (is_playback) {
+        // For playback we never report mono because the framework always outputs stereo
+        channel_count = DEFAULT_CHANNEL_COUNT;
+        // audio_channel_out_mask_from_count() does return positional masks for channel counts
+        // above 2 but we want indexed masks here. So we
+        for ( ; channel_count <= channels && num_masks < max_masks; channel_count++) {
+            supported_channel_masks[num_masks++] = audio_channel_out_mask_from_count(channel_count);
+        }
+        for ( ; channel_count <= channels && num_masks < max_masks; channel_count++) {
+            supported_channel_masks[num_masks++] =
+                    audio_channel_mask_for_index_assignment_from_count(channel_count);
+        }
+    } else {
+        // For capture we report all supported channel masks from 1 channel up.
+        channel_count = MIN_CHANNEL_COUNT;
+        // audio_channel_in_mask_from_count() does the right conversion to either positional or
+        // indexed mask
+        for ( ; channel_count <= channels && num_masks < max_masks; channel_count++) {
+            supported_channel_masks[num_masks++] =
+                    audio_channel_in_mask_from_count(channel_count);
+        }
+    }
+    ALOGV("%s: %s supported ch %d supported_channel_masks[0] %08x num_masks %d", __func__,
+          is_playback ? "P" : "C", channels, supported_channel_masks[0], num_masks);
+    return num_masks;
 }
 
 static int read_usb_sup_formats(bool is_playback __unused,
@@ -1063,6 +1099,7 @@
                                        max_formats);
     num_masks = read_usb_sup_channel_masks(is_playback, supported_channel_masks,
                                            max_masks);
+
     num_rates = read_usb_sup_sample_rates(is_playback,
                                           supported_sample_rates, max_rates);
 
@@ -1871,6 +1908,14 @@
     audio_extn_utils_send_app_type_gain(out->dev,
                                         out->app_type_cfg.app_type,
                                         &out->app_type_cfg.gain[0]);
+
+    // consider a scenario where on pause lower layers are tear down.
+    // so on resume, swap mixer control need to be sent only when
+    // backend is active, hence rather than sending from enable device
+    // sending it from start of streamtream
+
+    platform_set_swap_channels(adev, true);
+
     ALOGV("%s: exit", __func__);
     return 0;
 error_open:
@@ -1882,18 +1927,20 @@
 
 static int check_input_parameters(uint32_t sample_rate,
                                   audio_format_t format,
-                                  int channel_count)
+                                  int channel_count, bool is_usb_hifi)
 {
     if ((format != AUDIO_FORMAT_PCM_16_BIT) &&
         (format != AUDIO_FORMAT_PCM_8_24_BIT) &&
-        (format != AUDIO_FORMAT_PCM_24_BIT_PACKED)) {
+        (format != AUDIO_FORMAT_PCM_24_BIT_PACKED) &&
+        !(is_usb_hifi && (format == AUDIO_FORMAT_PCM_32_BIT))) {
         ALOGE("%s: unsupported AUDIO FORMAT (%d) ", __func__, format);
         return -EINVAL;
     }
 
-    if ((channel_count < MIN_CHANNEL_COUNT) || (channel_count > MAX_CHANNEL_COUNT)) {
+    int max_channel_count = is_usb_hifi ? MAX_HIFI_CHANNEL_COUNT : MAX_CHANNEL_COUNT;
+    if ((channel_count < MIN_CHANNEL_COUNT) || (channel_count > max_channel_count)) {
         ALOGE("%s: unsupported channel count (%d) passed  Min / Max (%d / %d)", __func__,
-               channel_count, MIN_CHANNEL_COUNT, MAX_CHANNEL_COUNT);
+               channel_count, MIN_CHANNEL_COUNT, max_channel_count);
         return -EINVAL;
     }
 
@@ -1925,9 +1972,6 @@
 {
     size_t size = 0;
 
-    if (check_input_parameters(sample_rate, format, channel_count) != 0)
-        return 0;
-
     size = (sample_rate * duration_ms) / 1000;
     if (is_low_latency)
         size = configured_low_latency_capture_period_size;
@@ -2192,6 +2236,12 @@
                 }
                 select_devices(adev, out->usecase);
                 audio_extn_tfa_98xx_update();
+
+                // on device switch force swap, lower functions will make sure
+                // to check if swap is allowed or not.
+
+                if (!same_dev)
+                    platform_set_swap_channels(adev, true);
             }
 
         }
@@ -3892,7 +3942,10 @@
             status = -EINVAL;
         }
         if (status == 0) {
-            platform_swap_lr_channels(adev, reverse_speakers);
+            // check and set swap
+            //   - check if orientation changed and speaker active
+            //   - set rotation and cache the rotation value
+            platform_check_and_set_swap_lr_channels(adev, reverse_speakers);
         }
     }
 
@@ -4056,6 +4109,11 @@
 {
     int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
 
+    /* Don't know if USB HIFI in this context so use true to be conservative */
+    if (check_input_parameters(config->sample_rate, config->format, channel_count,
+                               true /*is_usb_hifi */) != 0)
+        return 0;
+
     return get_stream_buffer_size(AUDIO_CAPTURE_PERIOD_DURATION_MSEC,
                                  config->sample_rate, config->format,
                                  channel_count,
@@ -4110,25 +4168,29 @@
     struct audio_device *adev = (struct audio_device *)dev;
     struct stream_in *in;
     int ret = 0, buffer_size, frame_size;
-    int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
+    int channel_count;
     bool is_low_latency = false;
     bool is_usb_dev = audio_is_usb_in_device(devices);
     bool may_use_hifi_record = adev_input_allow_hifi_record(adev,
                                                             devices,
                                                             flags,
                                                             source);
-    ALOGE("%s: enter", __func__);
+    ALOGV("%s: enter", __func__);
     *stream_in = NULL;
 
-    if (config->sample_rate == 0)
-        config->sample_rate = DEFAULT_INPUT_SAMPLING_RATE;
-    if (config->channel_mask == AUDIO_CHANNEL_NONE)
-        config->channel_mask = AUDIO_CHANNEL_IN_MONO;
-    if (config->format == AUDIO_FORMAT_DEFAULT)
-        config->format = AUDIO_FORMAT_PCM_16_BIT;
+    if (!(is_usb_dev && may_use_hifi_record)) {
+        if (config->sample_rate == 0)
+            config->sample_rate = DEFAULT_INPUT_SAMPLING_RATE;
+        if (config->channel_mask == AUDIO_CHANNEL_NONE)
+            config->channel_mask = AUDIO_CHANNEL_IN_MONO;
+        if (config->format == AUDIO_FORMAT_DEFAULT)
+            config->format = AUDIO_FORMAT_PCM_16_BIT;
 
-    if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
-        return -EINVAL;
+        channel_count = audio_channel_count_from_in_mask(config->channel_mask);
+
+        if (check_input_parameters(config->sample_rate, config->format, channel_count, false) != 0)
+            return -EINVAL;
+    }
 
     if (audio_extn_tfa_98xx_is_supported() &&
         (audio_extn_hfp_is_active(adev) || voice_is_in_call(adev)))
@@ -4160,7 +4222,6 @@
     in->source = source;
     in->dev = adev;
     in->standby = 1;
-    in->channel_mask = config->channel_mask;
     in->capture_handle = handle;
     in->flags = flags;
 
@@ -4181,6 +4242,7 @@
             ret = -EINVAL;
             goto err_open;
         }
+        channel_count = audio_channel_count_from_in_mask(config->channel_mask);
     } else if (config->format == AUDIO_FORMAT_DEFAULT) {
         config->format = AUDIO_FORMAT_PCM_16_BIT;
     } else if (config->format == AUDIO_FORMAT_PCM_FLOAT ||
@@ -4211,6 +4273,7 @@
     }
 
     in->format = config->format;
+    in->channel_mask = config->channel_mask;
 
     /* Update config params with the requested sample rate and channels */
     if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index e5bc111..bc3e844 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -2258,46 +2258,93 @@
     return start_gain;
 }
 
-int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
+int platform_set_swap_mixer(struct audio_device *adev, bool swap_channels)
+{
+    const char *mixer_ctl_name = "Swap channel";
+    struct mixer_ctl *ctl;
+    const char *mixer_path;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    // forced to set to swap, but device not rotated ... ignore set
+    if (swap_channels && !my_data->speaker_lr_swap)
+        return 0;
+
+    ALOGV("%s:", __func__);
+
+    if (swap_channels) {
+        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
+        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+    } else {
+        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
+        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+    }
+
+    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;
+    }
+
+    if (mixer_ctl_set_value(ctl, 0, swap_channels) < 0) {
+        ALOGE("%s: Could not set reverse cotrol %d",__func__, swap_channels);
+        return -EINVAL;
+    }
+
+    ALOGV("platfor_force_swap_channel :: Channel orientation ( %s ) ",
+           swap_channels?"R --> L":"L --> R");
+
+    return 0;
+}
+
+int platform_check_and_set_swap_lr_channels(struct audio_device *adev, bool swap_channels)
 {
     // only update if there is active pcm playback on speaker
     struct audio_usecase *usecase;
     struct listnode *node;
     struct platform_data *my_data = (struct platform_data *)adev->platform;
 
-    if (my_data->speaker_lr_swap != swap_channels) {
-        my_data->speaker_lr_swap = swap_channels;
+    my_data->speaker_lr_swap = swap_channels;
 
-        list_for_each(node, &adev->usecase_list) {
-            usecase = node_to_item(node, struct audio_usecase, list);
-            if (usecase->type == PCM_PLAYBACK &&
-                    usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
-                /*
-                 * If acdb tuning is different for SPEAKER_REVERSE, it is must
-                 * to perform device switch to disable the current backend to
-                 * enable it with new acdb data.
-                 */
-                if (acdb_device_table[SND_DEVICE_OUT_SPEAKER] !=
-                    acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE]) {
-                    const int initial_skpr_gain = ramp_speaker_gain(adev, false /*ramp_up*/, -1);
-                    select_devices(adev, usecase->id);
-                    if (initial_skpr_gain != -EINVAL) {
-                        ramp_speaker_gain(adev, true /*ramp_up*/, initial_skpr_gain);
-                    }
-                } else {
-                    const char *mixer_path;
-                    if (swap_channels) {
-                        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
-                        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
-                    } else {
-                        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
-                        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
-                    }
-                }
-                break;
+    return platform_set_swap_channels(adev, swap_channels);
+}
+
+int platform_set_swap_channels(struct audio_device *adev, bool swap_channels)
+{
+    // only update if there is active pcm playback on speaker
+    struct audio_usecase *usecase;
+    struct listnode *node;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    // do not swap channels in audio modes with concurrent capture and playback
+    // as this may break the echo reference
+    if ((adev->mode == AUDIO_MODE_IN_COMMUNICATION) || (adev->mode == AUDIO_MODE_IN_CALL)) {
+        ALOGV("%s: will not swap due to audio mode %d", __func__, adev->mode);
+        return 0;
+    }
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type == PCM_PLAYBACK &&
+                usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+            /*
+             * If acdb tuning is different for SPEAKER_REVERSE, it is must
+             * to perform device switch to disable the current backend to
+             * enable it with new acdb data.
+             */
+            if (acdb_device_table[SND_DEVICE_OUT_SPEAKER] !=
+                acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE]) {
+                const int initial_skpr_gain = ramp_speaker_gain(adev, false /*ramp_up*/, -1);
+                select_devices(adev, usecase->id);
+                if (initial_skpr_gain != -EINVAL)
+                    ramp_speaker_gain(adev, true /*ramp_up*/, initial_skpr_gain);
+
+            } else {
+                platform_set_swap_mixer(adev, swap_channels);
             }
+            break;
         }
     }
+
     return 0;
 }
 
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 50c6490..d3c0aea 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -25,6 +25,7 @@
 #include <audio_hw.h>
 #include <platform_api.h>
 #include "platform.h"
+#include "audio_extn.h"
 
 #define LIB_ACDB_LOADER "libacdbloader.so"
 #define LIB_CSD_CLIENT "libcsd-client.so"
@@ -104,7 +105,7 @@
 static const int pcm_device_table[AUDIO_USECASE_MAX][2] = {
     [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
     [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {14, 14},
-    [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1},
+    [USECASE_AUDIO_PLAYBACK_HIFI] = {1, 1},
     [USECASE_AUDIO_RECORD] = {0, 0},
     [USECASE_AUDIO_RECORD_LOW_LATENCY] = {14, 14},
     [USECASE_VOICE_CALL] = {12, 12},
@@ -430,7 +431,7 @@
     return -ENODEV;
 }
 
-int platform_get_default_app_type_v2(void *platform, usecase_type_t type __unused,
+int platform_get_default_app_type_v2(void *platform __unused, usecase_type_t type __unused,
                                      int *app_type __unused)
 {
     ALOGE("%s: Not implemented", __func__);
@@ -1055,34 +1056,155 @@
     return;
 }
 
-int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
+#define DEFAULT_NOMINAL_SPEAKER_GAIN 20
+int ramp_speaker_gain(struct audio_device *adev, bool ramp_up, int target_ramp_up_gain) {
+    // backup_gain: gain to try to set in case of an error during ramp
+    int start_gain, end_gain, step, backup_gain, i;
+    bool error = false;
+    const struct mixer_ctl *ctl;
+    const char *mixer_ctl_name_gain_left = "Left Speaker Gain";
+    const char *mixer_ctl_name_gain_right = "Right Speaker Gain";
+    struct mixer_ctl *ctl_left = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name_gain_left);
+    struct mixer_ctl *ctl_right = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name_gain_right);
+    if (!ctl_left || !ctl_right) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s or %s, not applying speaker gain ramp",
+                      __func__, mixer_ctl_name_gain_left, mixer_ctl_name_gain_right);
+        return -EINVAL;
+    } else if ((mixer_ctl_get_num_values(ctl_left) != 1)
+            || (mixer_ctl_get_num_values(ctl_right) != 1)) {
+        ALOGE("%s: Unexpected num values for mixer cmd - %s or %s, not applying speaker gain ramp",
+                              __func__, mixer_ctl_name_gain_left, mixer_ctl_name_gain_right);
+        return -EINVAL;
+    }
+    if (ramp_up) {
+        start_gain = 0;
+        end_gain = target_ramp_up_gain > 0 ? target_ramp_up_gain : DEFAULT_NOMINAL_SPEAKER_GAIN;
+        step = +1;
+        backup_gain = end_gain;
+    } else {
+        // using same gain on left and right
+        const int left_gain = mixer_ctl_get_value(ctl_left, 0);
+        start_gain = left_gain > 0 ? left_gain : DEFAULT_NOMINAL_SPEAKER_GAIN;
+        end_gain = 0;
+        step = -1;
+        backup_gain = start_gain;
+    }
+    for (i = start_gain ; i != (end_gain + step) ; i += step) {
+        //ALOGV("setting speaker gain to %d", i);
+        if (mixer_ctl_set_value(ctl_left, 0, i)) {
+            ALOGE("%s: error setting %s to %d during gain ramp",
+                    __func__, mixer_ctl_name_gain_left, i);
+            error = true;
+            break;
+        }
+        if (mixer_ctl_set_value(ctl_right, 0, i)) {
+            ALOGE("%s: error setting %s to %d during gain ramp",
+                    __func__, mixer_ctl_name_gain_right, i);
+            error = true;
+            break;
+        }
+        usleep(1000);
+    }
+    if (error) {
+        // an error occured during the ramp, let's still try to go back to a safe volume
+        if (mixer_ctl_set_value(ctl_left, 0, backup_gain)) {
+            ALOGE("%s: error restoring left gain to %d", __func__, backup_gain);
+        }
+        if (mixer_ctl_set_value(ctl_right, 0, backup_gain)) {
+            ALOGE("%s: error restoring right gain to %d", __func__, backup_gain);
+        }
+    }
+    return start_gain;
+}
+
+int platform_set_swap_mixer(struct audio_device *adev, bool swap_channels)
 {
-    // only update the selected device if there is active pcm playback
+    const char *mixer_ctl_name = "Swap channel";
+    struct mixer_ctl *ctl;
+    const char *mixer_path;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    // forced to set to swap, but device not rotated ... ignore set
+    if (swap_channels && !my_data->speaker_lr_swap)
+        return 0;
+
+    ALOGV("%s:", __func__);
+
+    if (swap_channels) {
+        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
+        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+    } else {
+        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
+        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+    }
+
+    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;
+    }
+
+    if (mixer_ctl_set_value(ctl, 0, swap_channels) < 0) {
+        ALOGE("%s: Could not set reverse cotrol %d",__func__, swap_channels);
+        return -EINVAL;
+    }
+
+    ALOGV("platfor_force_swap_channel :: Channel orientation ( %s ) ",
+           swap_channels?"R --> L":"L --> R");
+
+    return 0;
+}
+
+int platform_check_and_set_swap_lr_channels(struct audio_device *adev, bool swap_channels)
+{
+    // only update if there is active pcm playback on speaker
     struct audio_usecase *usecase;
     struct listnode *node;
     struct platform_data *my_data = (struct platform_data *)adev->platform;
-    int status = 0;
 
-    if (my_data->speaker_lr_swap != swap_channels) {
-        my_data->speaker_lr_swap = swap_channels;
+    my_data->speaker_lr_swap = swap_channels;
 
-        list_for_each(node, &adev->usecase_list) {
-            usecase = node_to_item(node, struct audio_usecase, list);
-            if (usecase->type == PCM_PLAYBACK &&
+    return platform_set_swap_channels(adev, swap_channels);
+}
+
+int platform_set_swap_channels(struct audio_device *adev, bool swap_channels)
+{
+    // only update if there is active pcm playback on speaker
+    struct audio_usecase *usecase;
+    struct listnode *node;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    // do not swap channels in audio modes with concurrent capture and playback
+    // as this may break the echo reference
+    if ((adev->mode == AUDIO_MODE_IN_COMMUNICATION) || (adev->mode == AUDIO_MODE_IN_CALL)) {
+        ALOGV("%s: will not swap due to audio mode %d", __func__, adev->mode);
+        return 0;
+    }
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type == PCM_PLAYBACK &&
                 usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
-                const char *mixer_path;
-                if (swap_channels) {
-                    mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
-                    audio_route_apply_and_update_path(adev->audio_route, mixer_path);
-                } else {
-                    mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
-                    audio_route_apply_and_update_path(adev->audio_route, mixer_path);
-                }
-                break;
+            /*
+             * If acdb tuning is different for SPEAKER_REVERSE, it is must
+             * to perform device switch to disable the current backend to
+             * enable it with new acdb data.
+             */
+            if (acdb_device_table[SND_DEVICE_OUT_SPEAKER] !=
+                acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE]) {
+                const int initial_skpr_gain = ramp_speaker_gain(adev, false /*ramp_up*/, -1);
+                select_devices(adev, usecase->id);
+                if (initial_skpr_gain != -EINVAL)
+                    ramp_speaker_gain(adev, true /*ramp_up*/, initial_skpr_gain);
+
+            } else {
+                platform_set_swap_mixer(adev, swap_channels);
             }
+            break;
         }
     }
-    return status;
+
+    return 0;
 }
 
 bool platform_send_gain_dep_cal(void *platform __unused,
@@ -1121,7 +1243,7 @@
 }
 
 bool platform_check_and_set_capture_backend_cfg(struct audio_device* adev __unused,
-                                              struct audio_usecase *usecase __unused)
+    struct audio_usecase *usecase __unused, snd_device_t snd_device __unused)
 {
     return false;
 }
@@ -1143,19 +1265,19 @@
     return -1;
 }
 
-int platform_get_snd_device_backend_index(snd_device_t snd_device)
+int platform_get_snd_device_backend_index(snd_device_t snd_device __unused)
 {
     return -ENOSYS;
 }
 
-void platform_check_and_update_copp_sample_rate(void* platform, snd_device_t snd_device,
-                                                unsigned int stream_sr, int* sample_rate)
+void platform_check_and_update_copp_sample_rate(void* platform __unused, snd_device_t snd_device __unused,
+                                                unsigned int stream_sr __unused, int* sample_rate __unused)
 {
 
 }
 
-int platform_send_audio_calibration_v2(void *platform, struct audio_usecase *usecase,
-                                       int app_type, int sample_rate)
+int platform_send_audio_calibration_v2(void *platform __unused, struct audio_usecase *usecase __unused,
+                                       int app_type __unused, int sample_rate __unused)
 {
     return -ENOSYS;
 }
@@ -1175,10 +1297,6 @@
     return -ENOSYS;
 }
 
-int platform_get_snd_device_backend_index(snd_device_t snd_device) {
-    return -ENOSYS;
-}
-
 int platform_set_sidetone(struct audio_device *adev,
                           snd_device_t out_snd_device,
                           bool enable, char *str)
diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h
index 6fe8cb5..afbc7b3 100644
--- a/hal/msm8960/platform.h
+++ b/hal/msm8960/platform.h
@@ -77,6 +77,7 @@
     SND_DEVICE_IN_BT_SCO_MIC,
     SND_DEVICE_IN_BT_SCO_MIC_WB,
     SND_DEVICE_IN_CAMCORDER_MIC,
+    SND_DEVICE_IN_CAPTURE_VI_FEEDBACK,
     SND_DEVICE_IN_VOICE_DMIC_EF,
     SND_DEVICE_IN_VOICE_DMIC_BS,
     SND_DEVICE_IN_VOICE_DMIC_EF_TMUS,
@@ -136,5 +137,12 @@
 #define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
 #define AFE_PROXY_RECORD_PCM_DEVICE 8
 
+#define HFP_ASM_RX_TX 18
+
+#define PLATFORM_INFO_XML_PATH          "audio_platform_info.xml"
+#define PLATFORM_INFO_XML_BASE_STRING   "audio_platform_info"
+
+#define DEVICE_NAME_MAX_SIZE 128
+
 
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 3281d53..b14e831 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -167,7 +167,6 @@
 
     [USECASE_AUDIO_RECORD_MMAP] = {MMAP_RECORD_PCM_DEVICE,
             MMAP_RECORD_PCM_DEVICE},
-
     [USECASE_AUDIO_RECORD_HIFI] = {MULTIMEDIA2_PCM_DEVICE,
                                    MULTIMEDIA2_PCM_DEVICE},
 
@@ -3172,54 +3171,93 @@
     return start_gain;
 }
 
-int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
+int platform_set_swap_mixer(struct audio_device *adev, bool swap_channels)
+{
+    const char *mixer_ctl_name = "Swap channel";
+    struct mixer_ctl *ctl;
+    const char *mixer_path;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    // forced to set to swap, but device not rotated ... ignore set
+    if (swap_channels && !my_data->speaker_lr_swap)
+        return 0;
+
+    ALOGV("%s:", __func__);
+
+    if (swap_channels) {
+        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
+        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+    } else {
+        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
+        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+    }
+
+    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;
+    }
+
+    if (mixer_ctl_set_value(ctl, 0, swap_channels) < 0) {
+        ALOGE("%s: Could not set reverse cotrol %d",__func__, swap_channels);
+        return -EINVAL;
+    }
+
+    ALOGV("platfor_force_swap_channel :: Channel orientation ( %s ) ",
+           swap_channels?"R --> L":"L --> R");
+
+    return 0;
+}
+
+int platform_check_and_set_swap_lr_channels(struct audio_device *adev, bool swap_channels)
 {
     // only update if there is active pcm playback on speaker
     struct audio_usecase *usecase;
     struct listnode *node;
     struct platform_data *my_data = (struct platform_data *)adev->platform;
 
-    if (my_data->speaker_lr_swap != swap_channels) {
+    my_data->speaker_lr_swap = swap_channels;
 
-        // do not swap channels in audio modes with concurrent capture and playback
-        // as this may break the echo reference
-        if ((adev->mode == AUDIO_MODE_IN_COMMUNICATION) || (adev->mode == AUDIO_MODE_IN_CALL)) {
-            ALOGV("%s: will not swap due to audio mode %d", __func__, adev->mode);
-            return 0;
-        }
+    return platform_set_swap_channels(adev, swap_channels);
+}
 
-        my_data->speaker_lr_swap = swap_channels;
+int platform_set_swap_channels(struct audio_device *adev, bool swap_channels)
+{
+    // only update if there is active pcm playback on speaker
+    struct audio_usecase *usecase;
+    struct listnode *node;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
 
-        list_for_each(node, &adev->usecase_list) {
-            usecase = node_to_item(node, struct audio_usecase, list);
-            if (usecase->type == PCM_PLAYBACK &&
-                    usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
-                /*
-                 * If acdb tuning is different for SPEAKER_REVERSE, it is must
-                 * to perform device switch to disable the current backend to
-                 * enable it with new acdb data.
-                 */
-                if (acdb_device_table[SND_DEVICE_OUT_SPEAKER] !=
-                    acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE]) {
-                    const int initial_skpr_gain = ramp_speaker_gain(adev, false /*ramp_up*/, -1);
-                    select_devices(adev, usecase->id);
-                    if (initial_skpr_gain != -EINVAL) {
-                        ramp_speaker_gain(adev, true /*ramp_up*/, initial_skpr_gain);
-                    }
-                } else {
-                    const char *mixer_path;
-                    if (swap_channels) {
-                        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
-                        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
-                    } else {
-                        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
-                        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
-                    }
-                }
-                break;
+    // do not swap channels in audio modes with concurrent capture and playback
+    // as this may break the echo reference
+    if ((adev->mode == AUDIO_MODE_IN_COMMUNICATION) || (adev->mode == AUDIO_MODE_IN_CALL)) {
+        ALOGV("%s: will not swap due to audio mode %d", __func__, adev->mode);
+        return 0;
+    }
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type == PCM_PLAYBACK &&
+                usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+            /*
+             * If acdb tuning is different for SPEAKER_REVERSE, it is must
+             * to perform device switch to disable the current backend to
+             * enable it with new acdb data.
+             */
+            if (acdb_device_table[SND_DEVICE_OUT_SPEAKER] !=
+                acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE]) {
+                const int initial_skpr_gain = ramp_speaker_gain(adev, false /*ramp_up*/, -1);
+                select_devices(adev, usecase->id);
+                if (initial_skpr_gain != -EINVAL)
+                    ramp_speaker_gain(adev, true /*ramp_up*/, initial_skpr_gain);
+
+            } else {
+                platform_set_swap_mixer(adev, swap_channels);
             }
+            break;
         }
     }
+
     return 0;
 }
 
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 341afb2..e7c26e7 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -113,7 +113,8 @@
 int platform_get_usecase_index(const char * usecase);
 int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
 void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device);
-int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels);
+int platform_check_and_set_swap_lr_channels(struct audio_device *adev, bool swap_channels);
+int platform_set_swap_channels(struct audio_device *adev, bool swap_channels);
 
 int platform_can_split_snd_device(snd_device_t in_snd_device,
                                   int *num_devices,