hal: Refactor HDMI backend configuration

-In current design HDMI backend configuration does not validate
incoming configuration against what is supported by the
connected sink ( using edid). This results in an incorrect
configuration of the HDMI backend, sometimes leading to no audio.
-Move HDMI backend configuration to
platform_check_and_set_codec_backend_cfg, this design ensures
that HDMI backend configuration happens with valid and only
supported parameters (sample rate, channels and bit width)
by the connected sink.
-Remove usleep from keep_alive and move to conditional timed wait,
this ensures to break from the keep_alive loop quickly, instead
of waiting for the complete usleep duration.

CRs-Fixed: 1039831
Change-Id: Id46ae76575f1b8169370cee817b505b97af8fe01
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index b316473..569b4b2 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -763,6 +763,7 @@
    audio_extn_pm_set_parameters(parms);
    audio_extn_source_track_set_parameters(adev, parms);
    audio_extn_fbsp_set_parameters(parms);
+   audio_extn_keep_alive_set_parameters(adev, parms);
    check_and_set_hdmi_connection_status(parms);
    if (adev->offload_effects_set_parameters != NULL)
        adev->offload_effects_set_parameters(parms);
diff --git a/hal/audio_extn/keep_alive.c b/hal/audio_extn/keep_alive.c
index 1a4f135..60e7eef 100644
--- a/hal/audio_extn/keep_alive.c
+++ b/hal/audio_extn/keep_alive.c
@@ -38,7 +38,7 @@
 
 #define SILENCE_MIXER_PATH "silence-playback hdmi"
 #define SILENCE_DEV_ID 32           /* index into machine driver */
-#define SILENCE_INTERVAL_US 2000000
+#define SILENCE_INTERVAL 2 /*In secs*/
 
 typedef enum {
     STATE_DEINIT = -1,
@@ -52,7 +52,9 @@
 
 typedef struct {
     pthread_mutex_t lock;
+    pthread_mutex_t sleep_lock;
     pthread_cond_t  cond;
+    pthread_cond_t  wake_up_cond;
     pthread_t thread;
     state_t state;
     struct listnode cmd_list;
@@ -88,6 +90,8 @@
     ka.pcm = NULL;
     pthread_mutex_init(&ka.lock, (const pthread_mutexattr_t *) NULL);
     pthread_cond_init(&ka.cond, (const pthread_condattr_t *) NULL);
+    pthread_cond_init(&ka.wake_up_cond, (const pthread_condattr_t *) NULL);
+    pthread_mutex_init(&ka.sleep_lock, (const pthread_mutexattr_t *) NULL);
     list_init(&ka.cmd_list);
     if (pthread_create(&ka.thread,  (const pthread_attr_t *) NULL,
                        keep_alive_loop, NULL) < 0) {
@@ -143,6 +147,27 @@
     return 0;
 }
 
+
+static int set_mixer_control(struct mixer *mixer,
+                             const char * mixer_ctl_name,
+                             const char *mixer_val)
+{
+    struct mixer_ctl *ctl;
+    if ((mixer == NULL) || (mixer_ctl_name == NULL) || (mixer_val == NULL)) {
+       ALOGE("%s: Invalid input", __func__);
+       return -EINVAL;
+    }
+    ALOGD("setting mixer ctl %s with value %s", mixer_ctl_name, mixer_val);
+    ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+
+    return mixer_ctl_set_enum_by_string(ctl, mixer_val);
+}
+
 /* must be called with adev lock held */
 void audio_extn_keep_alive_start()
 {
@@ -151,18 +176,20 @@
     int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT], len = 0, rc;
     struct mixer_ctl *ctl;
     int acdb_dev_id, snd_device;
+    struct listnode *node;
+    struct audio_usecase *usecase;
     int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
 
     pthread_mutex_lock(&ka.lock);
 
     if (ka.state == STATE_DEINIT) {
         ALOGE(" %s : Invalid state ",__func__);
-        return;
+        goto exit;
     }
 
     if (audio_extn_passthru_is_active()) {
         ALOGE(" %s : Pass through is already active", __func__);
-        return;
+        goto exit;
     }
 
     if (ka.state == STATE_ACTIVE) {
@@ -170,6 +197,14 @@
         goto exit;
     }
 
+    /* Dont start keep_alive if any other PCM session is routed to HDMI*/
+    list_for_each(node, &adev->usecase_list) {
+         usecase = node_to_item(node, struct audio_usecase, list);
+         if (usecase->type == PCM_PLAYBACK &&
+                 usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+             goto exit;
+    }
+
     ka.done = false;
 
     /*configure app type */
@@ -202,9 +237,15 @@
           platform_get_default_app_type(adev->platform),
           acdb_dev_id, sample_rate);
     mixer_ctl_set_array(ctl, app_type_cfg, len);
+    /*Configure HDMI Backend with default values, this as well
+     *helps reconfigure HDMI backend after passthrough
+     */
+    set_mixer_control(adev->mixer, "HDMI RX Format", "LPCM");
+    set_mixer_control(adev->mixer, "HDMI_RX SampleRate", "KHZ_48");
+    set_mixer_control(adev->mixer, "HDMI_RX Channels", "Two");
 
     /*send calibration*/
-    struct audio_usecase *usecase = calloc(1, sizeof(struct audio_usecase));
+    usecase = calloc(1, sizeof(struct audio_usecase));
     usecase->type = PCM_PLAYBACK;
     usecase->out_snd_device = SND_DEVICE_OUT_HDMI;
 
@@ -232,13 +273,13 @@
 
     pthread_mutex_lock(&ka.lock);
 
-    if (ka.state == STATE_DEINIT)
-        return;
-
-    if (ka.state == STATE_IDLE)
+    if ((ka.state == STATE_DEINIT) || (ka.state == STATE_IDLE))
         goto exit;
 
+    pthread_mutex_lock(&ka.sleep_lock);
     ka.done = true;
+    pthread_cond_signal(&ka.wake_up_cond);
+    pthread_mutex_unlock(&ka.sleep_lock);
     while (ka.state != STATE_IDLE) {
         pthread_cond_wait(&ka.cond, &ka.lock);
     }
@@ -290,6 +331,7 @@
     struct listnode *item;
     uint8_t * silence = NULL;
     int32_t bytes = 0;
+    struct timespec ts;
 
     while (true) {
         pthread_mutex_lock(&ka.lock);
@@ -328,9 +370,17 @@
              * Just something to keep the connection alive is sufficient.
              * Hence a short burst of silence periodically.
              */
-            usleep(SILENCE_INTERVAL_US);
-        }
+            pthread_mutex_lock(&ka.sleep_lock);
+            clock_gettime(CLOCK_REALTIME, &ts);
+            ts.tv_sec += SILENCE_INTERVAL;
+            ts.tv_nsec = 0;
 
+            if (!ka.done)
+              pthread_cond_timedwait(&ka.wake_up_cond,
+                            &ka.sleep_lock, &ts);
+
+            pthread_mutex_unlock(&ka.sleep_lock);
+        }
         pthread_mutex_lock(&ka.lock);
         ka.state = STATE_IDLE;
         pthread_cond_signal(&ka.cond);
diff --git a/hal/audio_extn/passthru.c b/hal/audio_extn/passthru.c
index e6ac4dd..eaa8c0a 100644
--- a/hal/audio_extn/passthru.c
+++ b/hal/audio_extn/passthru.c
@@ -82,8 +82,14 @@
  */
 bool audio_extn_passthru_should_drop_data(struct stream_out * out)
 {
-
-    if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+    /*Drop data only
+     *stream is routed to HDMI and
+     *stream has PCM format or
+     *if a compress offload (DSP decode) session
+     */
+    if ((out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+        (((out->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) ||
+        ((out->compr_config.codec != NULL) && (out->compr_config.codec->compr_passthr == LEGACY_PCM)))) {
         if (android_atomic_acquire_load(&compress_passthru_active) > 0) {
             ALOGI("drop data as pass thru is active");
             return true;
@@ -112,9 +118,6 @@
     ALOGV("inc pass thru count to notify other streams");
     android_atomic_inc(&compress_passthru_active);
 
-    ALOGV("keep_alive_stop");
-    audio_extn_keep_alive_stop();
-
     while (true) {
         /* find max period time among active playback use cases */
         list_for_each(node, &adev->usecase_list) {
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 65c285f..69d5cce 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -892,8 +892,9 @@
         if (usecase->type != PCM_CAPTURE &&
             usecase != uc_info &&
             (usecase->out_snd_device != snd_device || force_routing) &&
-            (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND ||
-            force_restart_session) &&
+            ((usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
+             (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
+             (force_restart_session)) &&
             platform_check_backends_match(snd_device, usecase->out_snd_device)) {
                 ALOGD("%s:becf: check_usecases (%s) is active on (%s) - disabling ..",
                     __func__, use_case_table[usecase->id],
@@ -1802,193 +1803,6 @@
     return 0;
 }
 
-static bool allow_hdmi_channel_config(struct audio_device *adev,
-                                      bool enable_passthru)
-{
-    struct listnode *node;
-    struct audio_usecase *usecase;
-    bool ret = true;
-
-    if (enable_passthru && !audio_extn_passthru_is_enabled()) {
-        ret = false;
-        goto exit;
-    }
-
-    if (audio_extn_passthru_is_active()) {
-        ALOGI("%s: Compress audio passthrough is active,"
-              "no HDMI config change allowed", __func__);
-        ret = false;
-        goto exit;
-    }
-
-    list_for_each(node, &adev->usecase_list) {
-        usecase = node_to_item(node, struct audio_usecase, list);
-        if (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
-            /*
-             * If voice call is already existing, do not proceed further to avoid
-             * disabling/enabling both RX and TX devices, CSD calls, etc.
-             * Once the voice call done, the HDMI channels can be configured to
-             * max channels of remaining use cases.
-             */
-            if (usecase->id == USECASE_VOICE_CALL) {
-                ALOGV("%s: voice call is active, no change in HDMI channels",
-                      __func__);
-                ret = false;
-                break;
-            } else if (usecase->id == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
-                if (!enable_passthru) {
-                    ALOGV("%s: multi channel playback is active, "
-                          "no change in HDMI channels", __func__);
-                    ret = false;
-                    break;
-                }
-            } else if (is_offload_usecase(usecase->id) &&
-                       audio_channel_count_from_out_mask(usecase->stream.out->channel_mask) > 2) {
-                if (!enable_passthru) {
-                    ALOGD("%s:multi-channel(%x) compress offload playback is active"
-                        ", no change in HDMI channels", __func__,
-                        usecase->stream.out->channel_mask);
-                    ret = false;
-                    break;
-                }
-            }
-        }
-    }
-    ALOGV("allow hdmi config %d", ret);
-exit:
-    return ret;
-}
-
-static int check_and_set_hdmi_config(struct audio_device *adev,
-                                     uint32_t channels,
-                                     uint32_t sample_rate,
-                                     audio_format_t format,
-                                     bool enable_passthru)
-{
-    struct listnode *node;
-    struct audio_usecase *usecase;
-    int32_t factor = 1;
-    bool config = false;
-
-    ALOGV("%s channels %d sample_rate %d format:%x enable_passthru:%d",
-         __func__, channels, sample_rate, format, enable_passthru);
-
-    if (channels != adev->cur_hdmi_channels) {
-        ALOGV("channel does not match current hdmi channels");
-        config = true;
-    }
-
-    if (sample_rate != adev->cur_hdmi_sample_rate) {
-        ALOGV("sample rate does not match current hdmi sample rate");
-        config = true;
-    }
-
-    if (format != adev->cur_hdmi_format) {
-        ALOGV("format does not match current hdmi format");
-        config = true;
-    }
-
-    /* TBD - add check for bit width */
-    if (!config) {
-        ALOGV("No need to config hdmi");
-        return 0;
-    }
-
-    if (enable_passthru &&
-        (format == AUDIO_FORMAT_E_AC3)) {
-        ALOGV("factor 4 for E_AC3 passthru");
-        factor = 4;
-    }
-
-    platform_set_hdmi_config(adev->platform, channels, factor * sample_rate,
-                             enable_passthru);
-    adev->cur_hdmi_channels = channels;
-    adev->cur_hdmi_format = format;
-    adev->cur_hdmi_sample_rate = sample_rate;
-
-    /*
-     * Deroute all the playback streams routed to HDMI so that
-     * the back end is deactivated. Note that backend will not
-     * be deactivated if any one stream is connected to it.
-     */
-    list_for_each(node, &adev->usecase_list) {
-        usecase = node_to_item(node, struct audio_usecase, list);
-        if (usecase->type == PCM_PLAYBACK &&
-                usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
-            disable_audio_route(adev, usecase);
-        }
-    }
-
-    bool was_active = audio_extn_keep_alive_is_active();
-    if (was_active)
-        audio_extn_keep_alive_stop();
-
-    /*
-     * Enable all the streams disabled above. Now the HDMI backend
-     * will be activated with new channel configuration
-     */
-    list_for_each(node, &adev->usecase_list) {
-        usecase = node_to_item(node, struct audio_usecase, list);
-        if (usecase->type == PCM_PLAYBACK &&
-                usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
-            enable_audio_route(adev, usecase);
-        }
-    }
-
-    if (was_active)
-        audio_extn_keep_alive_start();
-
-    return 0;
-}
-
-/* called with out lock taken */
-static int check_and_set_hdmi_backend(struct stream_out *out)
-{
-    struct audio_device *adev = out->dev;
-    int ret;
-    bool enable_passthru = false;
-
-    if (!(out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL))
-        return -1;
-
-    ALOGV("%s usecase %s out->format:%x out->bit_width:%d", __func__, use_case_table[out->usecase],out->format,out->bit_width);
-
-    if (is_offload_usecase(out->usecase) &&
-        audio_extn_passthru_is_passthrough_stream(out)) {
-        enable_passthru = true;
-        ALOGV("%s : enable_passthru is set to true", __func__);
-    }
-
-    /* Check if change in HDMI channel config is allowed */
-    if (!allow_hdmi_channel_config(adev, enable_passthru)) {
-        return -EPERM;
-    }
-
-    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
-        uint32_t channels;
-        ALOGV("Offload usecase, enable passthru %d", enable_passthru);
-
-        if (enable_passthru) {
-            audio_extn_passthru_on_start(out);
-            audio_extn_passthru_update_stream_configuration(adev, out);
-        }
-
-        /* For pass through case, the backend should be configured as stereo */
-        channels = enable_passthru ? DEFAULT_HDMI_OUT_CHANNELS :
-                                     out->compr_config.codec->ch_in;
-
-        ret = check_and_set_hdmi_config(adev, channels,
-                                        out->sample_rate, out->format,
-                                        enable_passthru);
-    } else
-        ret = check_and_set_hdmi_config(adev, out->config.channels,
-                                        out->config.rate,
-                                        out->format,
-                                        false);
-    return ret;
-}
-
-
 static int stop_output_stream(struct stream_out *out)
 {
     int ret = 0;
@@ -2029,17 +1843,14 @@
         ALOGV("Disable passthrough , reset mixer to pcm");
         /* NO_PASSTHROUGH */
         out->compr_config.codec->compr_passthr = 0;
-
         audio_extn_passthru_on_stop(out);
         audio_extn_dolby_set_dap_bypass(adev, DAP_STATE_ON);
     }
 
     /* Must be called after removing the usecase from list */
     if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
-        check_and_set_hdmi_config(adev, DEFAULT_HDMI_OUT_CHANNELS,
-                                  DEFAULT_HDMI_OUT_SAMPLE_RATE,
-                                  DEFAULT_HDMI_OUT_FORMAT,
-                                  false);
+        audio_extn_keep_alive_start();
+
     ALOGV("%s: exit: status(%d)", __func__, ret);
     return ret;
 }
@@ -2081,12 +1892,6 @@
         goto error_config;
     }
 
-    /* This must be called before adding this usecase to the list */
-    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
-        /* This call can fail if compress pass thru is already active */
-        check_and_set_hdmi_backend(out);
-    }
-
     uc_info->id = out->usecase;
     uc_info->type = PCM_PLAYBACK;
     uc_info->stream.out = out;
@@ -2098,6 +1903,16 @@
     audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
                                  adev->perf_lock_opts,
                                  adev->perf_lock_opts_size);
+
+    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+        audio_extn_keep_alive_stop();
+        if (audio_extn_passthru_is_enabled() &&
+            audio_extn_passthru_is_passthrough_stream(out)) {
+            audio_extn_passthru_on_start(out);
+            audio_extn_passthru_update_stream_configuration(adev, out);
+        }
+    }
+
     select_devices(adev, out->usecase);
 
     ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
@@ -2791,9 +2606,10 @@
     }
 
     if (audio_extn_passthru_should_drop_data(out)) {
-        ALOGD(" %s : Drop data as compress passthrough session is going on", __func__);
-        usleep((uint64_t)bytes * 1000000 / audio_stream_out_frame_size(stream) /
-                        out_get_sample_rate(&out->stream.common));
+        ALOGV(" %s : Drop data as compress passthrough session is going on", __func__);
+        if (audio_bytes_per_sample(out->format) != 0)
+            out->written += bytes / (out->config.channels * audio_bytes_per_sample(out->format));
+        ret = -EIO;
         goto exit;
     }
 
@@ -3168,7 +2984,6 @@
                 if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
                     pthread_mutex_lock(&out->dev->lock);
                     ALOGV("offload resume, check and set hdmi backend again");
-                    check_and_set_hdmi_backend(out);
                     pthread_mutex_unlock(&out->dev->lock);
                 }
                 status = compress_resume(out->compr);
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index c8e3a3b..bf5b62b 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -192,8 +192,10 @@
 typedef struct codec_backend_cfg {
     uint32_t sample_rate;
     uint32_t bit_width;
+    uint32_t channels;
     char     *bitwidth_mixer_ctl;
     char     *samplerate_mixer_ctl;
+    char     *channels_mixer_ctl;
 } codec_backend_cfg_t;
 
 static native_audio_prop na_props = {0, 0, 0};
@@ -1927,6 +1929,8 @@
         strdup("HDMI_RX Bit Format");
     my_data->current_backend_cfg[HDMI_RX_BACKEND].samplerate_mixer_ctl =
         strdup("HDMI_RX SampleRate");
+    my_data->current_backend_cfg[HDMI_RX_BACKEND].channels_mixer_ctl =
+        strdup("HDMI_RX Channels");
 
     ret = audio_extn_utils_get_codec_version(snd_card_name,
                                              my_data->adev->snd_card,
@@ -4046,16 +4050,21 @@
  * configures afe with bit width and Sample Rate
  */
 static int platform_set_codec_backend_cfg(struct audio_device* adev,
-                         snd_device_t snd_device, unsigned int bit_width,
-                         unsigned int sample_rate, audio_format_t format)
+                         snd_device_t snd_device, struct audio_backend_cfg backend_cfg)
 {
     int ret = 0;
     int backend_idx = DEFAULT_CODEC_BACKEND;
     struct platform_data *my_data = (struct platform_data *)adev->platform;
+    unsigned int bit_width = backend_cfg.bit_width;
+    unsigned int sample_rate = backend_cfg.sample_rate;
+    unsigned int channels = backend_cfg.channels;
+    audio_format_t format = backend_cfg.format;
+    bool passthrough_enabled = backend_cfg.passthrough_enabled;
 
     backend_idx = platform_get_backend_index(snd_device);
-    ALOGI("%s:becf: afe: bitwidth %d, samplerate %d, backend_idx %d device (%s)",
-          __func__, bit_width, sample_rate, backend_idx,
+
+    ALOGI("%s:becf: afe: bitwidth %d, samplerate %d channels %d, backend_idx %d device (%s)",
+          __func__, bit_width, sample_rate, channels,backend_idx,
           platform_get_snd_device_name(snd_device));
 
     if (bit_width !=
@@ -4147,19 +4156,146 @@
             mixer_ctl_set_enum_by_string(ctl, rate_str);
             my_data->current_backend_cfg[backend_idx].sample_rate = sample_rate;
     }
+    if ((backend_idx == HDMI_RX_BACKEND) &&
+        (channels != my_data->current_backend_cfg[backend_idx].channels)) {
+        struct  mixer_ctl *ctl;
+        char *channel_cnt_str = NULL;
+
+        switch (channels) {
+        case 8:
+            channel_cnt_str = "Eight"; break;
+        case 7:
+            channel_cnt_str = "Seven"; break;
+        case 6:
+            channel_cnt_str = "Six"; break;
+        case 5:
+            channel_cnt_str = "Five"; break;
+        case 4:
+            channel_cnt_str = "Four"; break;
+        case 3:
+            channel_cnt_str = "Three"; break;
+        default:
+            channel_cnt_str = "Two"; break;
+        }
+
+        ctl = mixer_get_ctl_by_name(adev->mixer,
+           my_data->current_backend_cfg[backend_idx].channels_mixer_ctl);
+        if (!ctl) {
+            ALOGE("%s:becf: afe: Could not get ctl for mixer command - %s",
+                   __func__,
+                   my_data->current_backend_cfg[backend_idx].channels_mixer_ctl);
+            return -EINVAL;
+        }
+        mixer_ctl_set_enum_by_string(ctl, channel_cnt_str);
+        my_data->current_backend_cfg[backend_idx].channels = channels;
+        platform_set_edid_channels_configuration(adev->platform, channels);
+        ALOGD("%s:becf: afe: %s set to %s", __func__,
+               my_data->current_backend_cfg[backend_idx].channels_mixer_ctl, channel_cnt_str);
+    }
+
+    if (backend_idx == HDMI_RX_BACKEND) {
+        const char *hdmi_format_ctrl = "HDMI RX Format";
+        struct mixer_ctl *ctl;
+        ctl = mixer_get_ctl_by_name(adev->mixer,hdmi_format_ctrl);
+
+        if (!ctl) {
+            ALOGE("%s:becf: afe: Could not get ctl for mixer command - %s",
+                   __func__, hdmi_format_ctrl);
+            return -EINVAL;
+        }
+
+        if (passthrough_enabled) {
+            ALOGD("%s:HDMI compress format", __func__);
+            mixer_ctl_set_enum_by_string(ctl, "Compr");
+        } else {
+            ALOGD("%s: HDMI PCM format", __func__);
+            mixer_ctl_set_enum_by_string(ctl, "LPCM");
+        }
+    }
 
     return ret;
 }
 
 /*
+ *Validate the selected bit_width, sample_rate and channels using the edid
+ *of the connected sink device.
+ */
+static void platform_check_hdmi_backend_cfg(struct audio_device* adev,
+                                   struct audio_usecase* usecase,
+                                   struct audio_backend_cfg *hdmi_backend_cfg)
+{
+    unsigned int bit_width;
+    unsigned int sample_rate;
+    unsigned int channels, max_supported_channels = 0;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+    edid_audio_info *edid_info = (edid_audio_info *)my_data->edid_info;
+    bool passthrough_enabled = false;
+
+    bit_width = hdmi_backend_cfg->bit_width;
+    sample_rate = hdmi_backend_cfg->sample_rate;
+    channels = hdmi_backend_cfg->channels;
+
+
+    ALOGI("%s:becf: HDMI: bitwidth %d, samplerate %d, channels %d"
+          ", usecase = %d", __func__, bit_width,
+          sample_rate, channels, usecase->id);
+
+    if (audio_extn_passthru_is_enabled() && audio_extn_passthru_is_active()
+        && (usecase->stream.out->compr_config.codec->compr_passthr != 0)) {
+        passthrough_enabled = true;
+        ALOGI("passthrough is enabled for this stream");
+    }
+
+    // For voice calls use default configuration i.e. 16b/48K, only applicable to
+    // default backend
+    if (!passthrough_enabled) {
+
+        max_supported_channels = platform_edid_get_max_channels(my_data);
+
+        //Check EDID info for supported samplerate
+        if (!edid_is_supported_sr(edid_info,sample_rate)) {
+            //reset to current sample rate
+            sample_rate = my_data->current_backend_cfg[HDMI_RX_BACKEND].sample_rate;
+        }
+
+        //Check EDID info for supported bit width
+        if (!edid_is_supported_bps(edid_info,bit_width)) {
+            //reset to current sample rate
+            bit_width = my_data->current_backend_cfg[HDMI_RX_BACKEND].bit_width;
+        }
+
+        if (channels > max_supported_channels)
+            channels = max_supported_channels;
+
+    } else {
+        /*During pass through set default bit width and channels*/
+        channels = DEFAULT_HDMI_OUT_CHANNELS;
+        if ((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+            (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))
+            sample_rate = sample_rate * 4 ;
+
+        bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        /* We force route so that the BE format can be set to Compr */
+    }
+
+    ALOGI("%s:becf: afe: HDMI backend: passthrough %d updated bit width: %d and sample rate: %d"
+           "channels %d", __func__, passthrough_enabled , bit_width,
+           sample_rate, channels);
+
+    hdmi_backend_cfg->bit_width = bit_width;
+    hdmi_backend_cfg->sample_rate = sample_rate;
+    hdmi_backend_cfg->channels = channels;
+    hdmi_backend_cfg->passthrough_enabled = passthrough_enabled;
+}
+
+/*
  * goes through all the current usecases and picks the highest
  * bitwidth & samplerate
  */
 static bool platform_check_codec_backend_cfg(struct audio_device* adev,
                                    struct audio_usecase* usecase,
                                    snd_device_t snd_device,
-                                   unsigned int* new_bit_width,
-                                   unsigned int* new_sample_rate)
+                                   struct audio_backend_cfg *backend_cfg)
 {
     bool backend_change = false;
     struct listnode *node;
@@ -4167,18 +4303,21 @@
     char value[PROPERTY_VALUE_MAX] = {0};
     unsigned int bit_width;
     unsigned int sample_rate;
+    unsigned int channels;
+    bool passthrough_enabled = false;
     int backend_idx = DEFAULT_CODEC_BACKEND;
     struct platform_data *my_data = (struct platform_data *)adev->platform;
     int na_mode = platform_get_native_support();
-    edid_audio_info *edid_info = (edid_audio_info *)my_data->edid_info;
+    bool channels_updated = false;
 
     backend_idx = platform_get_backend_index(snd_device);
 
-    bit_width = *new_bit_width;
-    sample_rate = *new_sample_rate;
+    bit_width = backend_cfg->bit_width;
+    sample_rate = backend_cfg->sample_rate;
+    channels = backend_cfg->channels;
 
-    ALOGI("%s:becf: afe: Codec selected backend: %d current bit width: %d and sample rate: %d",
-          __func__, backend_idx, bit_width, sample_rate);
+    ALOGI("%s:becf: afe: Codec selected backend: %d current bit width: %d sample rate: %d channels: %d",
+          __func__, backend_idx, bit_width, sample_rate, channels);
 
     // For voice calls use default configuration i.e. 16b/48K, only applicable to
     // default backend
@@ -4204,12 +4343,13 @@
             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) {
 
                 ALOGD("%s:napb: (%d) - (%s)id (%d) sr %d bw "
-                      "(%d) device %s", __func__, i++, use_case_table[uc->id],
+                      "(%d) ch (%d) device %s", __func__, i++, use_case_table[uc->id],
                       uc->id, out->sample_rate,
-                      out->bit_width,
+                      out->bit_width, out_channels,
                       platform_get_snd_device_name(uc->out_snd_device));
 
                 if (platform_check_backends_match(snd_device, uc->out_snd_device)) {
@@ -4219,6 +4359,8 @@
                             sample_rate = out->sample_rate;
                         if (out->sample_rate < OUTPUT_SAMPLING_RATE_44100)
                             sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+                        if (channels < out_channels)
+                            channels = out_channels;
                 }
             }
         }
@@ -4276,16 +4418,21 @@
     }
 
     if (backend_idx == HDMI_RX_BACKEND) {
-        //Check EDID info for supported samplerate
-        if (!edid_is_supported_sr(edid_info,sample_rate)) {
-            //reset to current sample rate
-            sample_rate = my_data->current_backend_cfg[backend_idx].sample_rate;
-        }
-        //Check EDID info for supported bit widhth
-        if (!edid_is_supported_bps(edid_info,bit_width)) {
-            //reset to current sample rate
-            bit_width = my_data->current_backend_cfg[backend_idx].bit_width;
-        }
+        struct audio_backend_cfg hdmi_backend_cfg;
+        hdmi_backend_cfg.bit_width = bit_width;
+        hdmi_backend_cfg.sample_rate = sample_rate;
+        hdmi_backend_cfg.channels = channels;
+        hdmi_backend_cfg.passthrough_enabled = false;
+
+        platform_check_hdmi_backend_cfg(adev, usecase, &hdmi_backend_cfg);
+
+        bit_width = hdmi_backend_cfg.bit_width;
+        sample_rate = hdmi_backend_cfg.sample_rate;
+        channels = hdmi_backend_cfg.channels;
+        passthrough_enabled = hdmi_backend_cfg.passthrough_enabled;
+
+        if (channels != my_data->current_backend_cfg[backend_idx].channels)
+            channels_updated = true;
     }
 
     //check if mulitchannel clip needs to be down sampled to 48k
@@ -4316,13 +4463,16 @@
     // Force routing if the expected bitwdith or samplerate
     // is not same as current backend comfiguration
     if ((bit_width != my_data->current_backend_cfg[backend_idx].bit_width) ||
-        (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate)) {
-        *new_bit_width = bit_width;
-        *new_sample_rate = sample_rate;
+        (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate) ||
+         passthrough_enabled || channels_updated) {
+        backend_cfg->bit_width = bit_width;
+        backend_cfg->sample_rate = sample_rate;
+        backend_cfg->channels = channels;
+        backend_cfg->passthrough_enabled = passthrough_enabled;
         backend_change = true;
-        ALOGI("%s:becf: afe: Codec backend needs to be updated. new bit width: %d new sample rate: %d",
-              __func__,
-             *new_bit_width, *new_sample_rate);
+        ALOGI("%s:becf: afe: Codec backend needs to be updated. new bit width: %d"
+              " new sample rate: %d new channels %d",__func__,
+               backend_cfg->bit_width, backend_cfg->sample_rate, backend_cfg->channels);
     }
 
     return backend_change;
@@ -4331,23 +4481,24 @@
 bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev,
     struct audio_usecase *usecase, snd_device_t snd_device)
 {
-    unsigned int new_bit_width;
-    unsigned int new_sample_rate;
     int backend_idx = DEFAULT_CODEC_BACKEND;
     int new_snd_devices[SND_DEVICE_OUT_END];
     int i, num_devices = 1;
+    struct audio_backend_cfg backend_cfg;
     bool ret = false;
-    audio_format_t format;
 
     backend_idx = platform_get_backend_index(snd_device);
 
-    new_bit_width = usecase->stream.out->bit_width;
-    new_sample_rate = usecase->stream.out->sample_rate;
-    format = usecase->stream.out->format;
+    backend_cfg.bit_width = usecase->stream.out->bit_width;
+    backend_cfg.sample_rate = usecase->stream.out->sample_rate;
+    backend_cfg.format = usecase->stream.out->format;
+    backend_cfg.channels = audio_channel_count_from_out_mask(usecase->stream.out->channel_mask);
+    /*this is populated by check_codec_backend_cfg hence set default value to false*/
+    backend_cfg.passthrough_enabled = false;
 
-    ALOGI("%s:becf: afe: bitwidth %d, samplerate %d"
-          ", backend_idx %d usecase = %d device (%s)", __func__, new_bit_width,
-          new_sample_rate, backend_idx, usecase->id,
+    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,
           platform_get_snd_device_name(snd_device));
 
     if (!platform_can_split_snd_device(adev->platform, snd_device,
@@ -4358,9 +4509,9 @@
         ALOGI("%s: becf: new_snd_devices[%d] is %s", __func__, i,
             platform_get_snd_device_name(new_snd_devices[i]));
         if (platform_check_codec_backend_cfg(adev, usecase, new_snd_devices[i],
-                                             &new_bit_width, &new_sample_rate)) {
+                                             &backend_cfg)) {
                 platform_set_codec_backend_cfg(adev, new_snd_devices[i],
-                                               new_bit_width, new_sample_rate, format);
+                                               backend_cfg);
                 ret = true;
         }
     }
@@ -5030,6 +5181,7 @@
     //reset HDMI_RX_BACKEND to default values
     my_data->current_backend_cfg[HDMI_RX_BACKEND].sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
     my_data->current_backend_cfg[HDMI_RX_BACKEND].bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    my_data->current_backend_cfg[HDMI_RX_BACKEND].channels = DEFAULT_HDMI_OUT_CHANNELS;
 }
 
 int platform_set_mixer_control(struct stream_out *out, const char * mixer_ctl_name,
@@ -5048,91 +5200,6 @@
     return mixer_ctl_set_enum_by_string(ctl, mixer_val);
 }
 
-static int set_mixer_control(struct mixer *mixer,
-                             const char * mixer_ctl_name,
-                             const char *mixer_val)
-{
-    struct mixer_ctl *ctl;
-    ALOGD("setting mixer ctl %s with value %s", mixer_ctl_name, mixer_val);
-    ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
-    if (!ctl) {
-        ALOGE("%s: could not get ctl for mixer cmd - %s",
-              __func__, mixer_ctl_name);
-        return -EINVAL;
-    }
-
-    return mixer_ctl_set_enum_by_string(ctl, mixer_val);
-}
-
-int platform_set_hdmi_config(void *platform, uint32_t channel_count,
-                             uint32_t sample_rate, bool enable_passthrough)
-{
-    struct platform_data *my_data = (struct platform_data *)platform;
-    struct audio_device *adev = my_data->adev;
-    const char *hdmi_format_ctrl = "HDMI RX Format";
-    const char *hdmi_rate_ctrl   = "HDMI_RX SampleRate";
-    const char *hdmi_chans_ctrl  = "HDMI_RX Channels";
-    const char *channel_cnt_str  = NULL;
-
-    ALOGI("%s ch[%d] sr[%d], pthru[%d]", __func__,
-        channel_count, sample_rate, enable_passthrough);
-
-    switch (channel_count) {
-    case 8:
-        channel_cnt_str = "Eight"; break;
-    case 7:
-        channel_cnt_str = "Seven"; break;
-    case 6:
-        channel_cnt_str = "Six"; break;
-    case 5:
-        channel_cnt_str = "Five"; break;
-    case 4:
-        channel_cnt_str = "Four"; break;
-    case 3:
-        channel_cnt_str = "Three"; break;
-    default:
-        channel_cnt_str = "Two"; break;
-    }
-    ALOGV("%s: HDMI channel count: %s", __func__, channel_cnt_str);
-    set_mixer_control(adev->mixer, hdmi_chans_ctrl, channel_cnt_str);
-
-    if (enable_passthrough) {
-        ALOGD("%s:HDMI compress format", __func__);
-        set_mixer_control(adev->mixer, hdmi_format_ctrl, "Compr");
-    } else {
-        ALOGD("%s: HDMI PCM format", __func__);
-        set_mixer_control(adev->mixer, hdmi_format_ctrl, "LPCM");
-    }
-
-    switch (sample_rate) {
-    case 32000:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_32");
-        break;
-    case 44100:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_44P1");
-        break;
-    case 96000:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_96");
-        break;
-    case 128000:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_128");
-        break;
-    case 176400:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_176_4");
-        break;
-    case 192000:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_192");
-        break;
-    default:
-    case 48000:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_48");
-        break;
-    }
-
-    return 0;
-}
-
-
 int platform_set_device_params(struct stream_out *out, int param, int value)
 {
     struct audio_device *adev = out->dev;
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index cd5aeb7..dcd351a 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -372,4 +372,13 @@
     char device_name[100];
     char interface_name[100];
 };
+
+struct audio_backend_cfg {
+    unsigned int   sample_rate;
+    unsigned int   channels;
+    unsigned int   bit_width;
+    bool           passthrough_enabled;
+    audio_format_t format;
+};
+
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index e2adc3e..f0f507d 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -188,8 +188,10 @@
 typedef struct codec_backend_cfg {
     uint32_t sample_rate;
     uint32_t bit_width;
+    uint32_t channels;
     char     *bitwidth_mixer_ctl;
     char     *samplerate_mixer_ctl;
+    char     *channels_mixer_ctl;
 } codec_backend_cfg_t;
 
 static native_audio_prop na_props = {0, 0, 0};
@@ -1751,6 +1753,8 @@
         strdup("HDMI_RX Bit Format");
     my_data->current_backend_cfg[HDMI_RX_BACKEND].samplerate_mixer_ctl =
         strdup("HDMI_RX SampleRate");
+    my_data->current_backend_cfg[HDMI_RX_BACKEND].channels_mixer_ctl =
+        strdup("HDMI_RX Channels");
 
     my_data->current_backend_cfg[USB_AUDIO_RX_BACKEND].bitwidth_mixer_ctl =
         strdup("USB_AUDIO_RX Format");
@@ -4022,17 +4026,20 @@
  * configures afe with bit width and Sample Rate
  */
 static int platform_set_codec_backend_cfg(struct audio_device* adev,
-                         snd_device_t snd_device, unsigned int bit_width,
-                         unsigned int sample_rate, audio_format_t format)
+                         snd_device_t snd_device, struct audio_backend_cfg backend_cfg)
 {
     int ret = 0;
     int backend_idx = DEFAULT_CODEC_BACKEND;
     struct platform_data *my_data = (struct platform_data *)adev->platform;
-
     backend_idx = platform_get_backend_index(snd_device);
+    unsigned int bit_width = backend_cfg.bit_width;
+    unsigned int sample_rate = backend_cfg.sample_rate;
+    unsigned int channels = backend_cfg.channels;
+    audio_format_t format = backend_cfg.format;
+    bool passthrough_enabled = backend_cfg.passthrough_enabled;
 
-    ALOGI("%s:becf: afe: bitwidth %d, samplerate %d"
-          ", backend_idx %d device (%s)", __func__,  bit_width, sample_rate, backend_idx,
+    ALOGI("%s:becf: afe: bitwidth %d, samplerate %d channels %d"
+          ", backend_idx %d device (%s)", __func__,  bit_width, sample_rate, channels, backend_idx,
           platform_get_snd_device_name(snd_device));
 
     if (bit_width !=
@@ -4116,37 +4123,167 @@
             mixer_ctl_set_enum_by_string(ctl, rate_str);
             my_data->current_backend_cfg[backend_idx].sample_rate = sample_rate;
     }
+    if ((backend_idx == HDMI_RX_BACKEND) &&
+        (channels != my_data->current_backend_cfg[backend_idx].channels)) {
+        struct  mixer_ctl *ctl;
+        char *channel_cnt_str = NULL;
+
+        switch (channels) {
+        case 8:
+            channel_cnt_str = "Eight"; break;
+        case 7:
+            channel_cnt_str = "Seven"; break;
+        case 6:
+            channel_cnt_str = "Six"; break;
+        case 5:
+            channel_cnt_str = "Five"; break;
+        case 4:
+            channel_cnt_str = "Four"; break;
+        case 3:
+            channel_cnt_str = "Three"; break;
+        default:
+            channel_cnt_str = "Two"; break;
+        }
+
+        ctl = mixer_get_ctl_by_name(adev->mixer,
+           my_data->current_backend_cfg[backend_idx].channels_mixer_ctl);
+        if (!ctl) {
+            ALOGE("%s:becf: afe: Could not get ctl for mixer command - %s",
+                   __func__,
+                   my_data->current_backend_cfg[backend_idx].channels_mixer_ctl);
+            return -EINVAL;
+        }
+        mixer_ctl_set_enum_by_string(ctl, channel_cnt_str);
+        my_data->current_backend_cfg[backend_idx].channels = channels;
+        platform_set_edid_channels_configuration(adev->platform, channels);
+        ALOGD("%s:becf: afe: %s set to %s", __func__,
+               my_data->current_backend_cfg[backend_idx].channels_mixer_ctl, channel_cnt_str);
+    }
+
+    if (backend_idx == HDMI_RX_BACKEND) {
+        const char *hdmi_format_ctrl = "HDMI RX Format";
+        struct mixer_ctl *ctl;
+        ctl = mixer_get_ctl_by_name(adev->mixer,hdmi_format_ctrl);
+
+        if (!ctl) {
+            ALOGE("%s:becf: afe: Could not get ctl for mixer command - %s",
+                   __func__, hdmi_format_ctrl);
+            return -EINVAL;
+        }
+
+        if (passthrough_enabled) {
+            ALOGD("%s:HDMI compress format", __func__);
+            mixer_ctl_set_enum_by_string(ctl, "Compr");
+        } else {
+            ALOGD("%s: HDMI PCM format", __func__);
+            mixer_ctl_set_enum_by_string(ctl, "LPCM");
+        }
+    }
 
     return ret;
 }
 
 /*
+ *Validate the selected bit_width, sample_rate and channels using the edid
+ *of the connected sink device.
+ */
+static void platform_check_hdmi_backend_cfg(struct audio_device* adev,
+                                   struct audio_usecase* usecase,
+                                   struct audio_backend_cfg *hdmi_backend_cfg)
+{
+    unsigned int bit_width;
+    unsigned int sample_rate;
+    unsigned int channels, max_supported_channels = 0;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+    edid_audio_info *edid_info = (edid_audio_info *)my_data->edid_info;
+    bool passthrough_enabled = false;
+
+    bit_width = hdmi_backend_cfg->bit_width;
+    sample_rate = hdmi_backend_cfg->sample_rate;
+    channels = hdmi_backend_cfg->channels;
+
+
+    ALOGI("%s:becf: HDMI: bitwidth %d, samplerate %d, channels %d"
+          ", usecase = %d", __func__, bit_width,
+          sample_rate, channels, usecase->id);
+
+    if (audio_extn_passthru_is_enabled() && audio_extn_passthru_is_active()
+        && (usecase->stream.out->compr_config.codec->compr_passthr != 0)) {
+        passthrough_enabled = true;
+        ALOGI("passthrough is enabled for this stream");
+    }
+
+    // For voice calls use default configuration i.e. 16b/48K, only applicable to
+    // default backend
+    if (!passthrough_enabled) {
+
+        max_supported_channels = platform_edid_get_max_channels(my_data);
+
+        //Check EDID info for supported samplerate
+        if (!edid_is_supported_sr(edid_info,sample_rate)) {
+            //reset to current sample rate
+            sample_rate = my_data->current_backend_cfg[HDMI_RX_BACKEND].sample_rate;
+        }
+
+        //Check EDID info for supported bit width
+        if (!edid_is_supported_bps(edid_info,bit_width)) {
+            //reset to current sample rate
+            bit_width = my_data->current_backend_cfg[HDMI_RX_BACKEND].bit_width;
+        }
+
+        if (channels > max_supported_channels)
+            channels = max_supported_channels;
+
+    } else {
+        /*During pass through set default bit width and channels*/
+        channels = DEFAULT_HDMI_OUT_CHANNELS;
+        if ((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+            (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))
+            sample_rate = sample_rate * 4 ;
+
+        bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        /* We force route so that the BE format can be set to Compr */
+    }
+
+    ALOGI("%s:becf: afe: HDMI backend: passthrough %d updated bit width: %d and sample rate: %d"
+           "channels %d", __func__, passthrough_enabled , bit_width,
+           sample_rate, channels);
+
+    hdmi_backend_cfg->bit_width = bit_width;
+    hdmi_backend_cfg->sample_rate = sample_rate;
+    hdmi_backend_cfg->channels = channels;
+    hdmi_backend_cfg->passthrough_enabled = passthrough_enabled;
+}
+
+/*
  * goes through all the current usecases and picks the highest
  * bitwidth & samplerate
  */
 static bool platform_check_codec_backend_cfg(struct audio_device* adev,
                                    struct audio_usecase* usecase,
                                    snd_device_t snd_device,
-                                   unsigned int* new_bit_width,
-                                   unsigned int* new_sample_rate)
+                                   struct audio_backend_cfg *backend_cfg)
 {
     bool backend_change = false;
     struct listnode *node;
     unsigned int bit_width;
     unsigned int sample_rate;
+    unsigned int channels;
+    bool passthrough_enabled = false;
     int backend_idx = DEFAULT_CODEC_BACKEND;
     struct platform_data *my_data = (struct platform_data *)adev->platform;
     int na_mode = platform_get_native_support();
-    edid_audio_info *edid_info = (edid_audio_info *)my_data->edid_info;
+    bool channels_updated = false;
 
     backend_idx = platform_get_backend_index(snd_device);
 
-    bit_width = *new_bit_width;
-    sample_rate = *new_sample_rate;
+    bit_width = backend_cfg->bit_width;
+    sample_rate = backend_cfg->sample_rate;
+    channels = backend_cfg->channels;
 
-    ALOGI("%s:becf: afe: bitwidth %d, samplerate %d"
+    ALOGI("%s:becf: afe: bitwidth %d, samplerate %d channels %d"
           ", backend_idx %d usecase = %d device (%s)", __func__, bit_width,
-          sample_rate, backend_idx, usecase->id,
+          sample_rate, channels, backend_idx, usecase->id,
           platform_get_snd_device_name(snd_device));
 
     // For voice calls use default configuration i.e. 16b/48K, only applicable to
@@ -4173,12 +4310,13 @@
             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) {
 
                 ALOGD("%s:napb: (%d) - (%s)id (%d) sr %d bw "
-                      "(%d) device %s", __func__, i++, use_case_table[uc->id],
+                      "(%d) ch (%d) device %s", __func__, i++, use_case_table[uc->id],
                       uc->id, out->sample_rate,
-                      out->bit_width,
+                      out->bit_width, out_channels,
                       platform_get_snd_device_name(uc->out_snd_device));
 
                 if (platform_check_backends_match(snd_device, uc->out_snd_device)) {
@@ -4188,6 +4326,8 @@
                             sample_rate = out->sample_rate;
                         if (out->sample_rate < OUTPUT_SAMPLING_RATE_44100)
                             sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+                        if (channels < out_channels)
+                            channels = out_channels;
                 }
             }
         }
@@ -4243,29 +4383,39 @@
     }
 
     if (backend_idx == HDMI_RX_BACKEND) {
-        //Check EDID info for supported samplerate
-        if (!edid_is_supported_sr(edid_info,sample_rate)) {
-            //reset to current sample rate
-            sample_rate = my_data->current_backend_cfg[backend_idx].sample_rate;
-        }
-        //Check EDID info for supported bit widhth
-        if (!edid_is_supported_bps(edid_info,bit_width)) {
-            //reset to current sample rate
-            bit_width = my_data->current_backend_cfg[backend_idx].bit_width;
-        }
+        struct audio_backend_cfg hdmi_backend_cfg;
+        hdmi_backend_cfg.bit_width = bit_width;
+        hdmi_backend_cfg.sample_rate = sample_rate;
+        hdmi_backend_cfg.channels = channels;
+        hdmi_backend_cfg.passthrough_enabled = false;
+
+        platform_check_hdmi_backend_cfg(adev, usecase, &hdmi_backend_cfg);
+
+        bit_width = hdmi_backend_cfg.bit_width;
+        sample_rate = hdmi_backend_cfg.sample_rate;
+        channels = hdmi_backend_cfg.channels;
+        passthrough_enabled = hdmi_backend_cfg.passthrough_enabled;
+
+        if (channels != my_data->current_backend_cfg[backend_idx].channels)
+            channels_updated = true;
     }
+
     ALOGI("%s:becf: afe: Codec selected backend: %d updated bit width: %d and sample rate: %d",
           __func__, backend_idx , bit_width, sample_rate);
 
     // Force routing if the expected bitwdith or samplerate
     // is not same as current backend comfiguration
     if ((bit_width != my_data->current_backend_cfg[backend_idx].bit_width) ||
-        (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate)) {
-        *new_bit_width = bit_width;
-        *new_sample_rate = sample_rate;
+        (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate) ||
+         passthrough_enabled || channels_updated) {
+        backend_cfg->bit_width = bit_width;
+        backend_cfg->sample_rate = sample_rate;
+        backend_cfg->channels = channels;
+        backend_cfg->passthrough_enabled = passthrough_enabled;
         backend_change = true;
-        ALOGI("%s:becf: afe: Codec backend needs to be updated. new bit width: %d new sample rate: %d",
-              __func__, *new_bit_width, *new_sample_rate);
+        ALOGI("%s:becf: afe: Codec backend needs to be updated. new bit width: %d"
+               "new sample rate: %d new channels: %d",
+              __func__, backend_cfg->bit_width, backend_cfg->sample_rate, backend_cfg->channels);
     }
 
     return backend_change;
@@ -4274,40 +4424,39 @@
 bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev,
     struct audio_usecase *usecase, snd_device_t snd_device)
 {
-    unsigned int new_bit_width;
-    unsigned int new_sample_rate;
     int backend_idx = DEFAULT_CODEC_BACKEND;
     int new_snd_devices[SND_DEVICE_OUT_END];
     int i, num_devices = 1;
     bool ret = false;
     struct platform_data *my_data = (struct platform_data *)adev->platform;
-    audio_format_t format;
+    struct audio_backend_cfg backend_cfg;
 
     backend_idx = platform_get_backend_index(snd_device);
 
-    new_bit_width = usecase->stream.out->bit_width;
-    new_sample_rate = usecase->stream.out->sample_rate;
-    format = usecase->stream.out->format;
+    backend_cfg.bit_width = usecase->stream.out->bit_width;
+    backend_cfg.sample_rate = usecase->stream.out->sample_rate;
+    backend_cfg.format = usecase->stream.out->format;
+    backend_cfg.channels = audio_channel_count_from_out_mask(usecase->stream.out->channel_mask);
+    /*this is populated by check_codec_backend_cfg hence set default value to false*/
+    backend_cfg.passthrough_enabled = false;
 
-    ALOGI("%s:becf: afe: bitwidth %d, samplerate %d"
-          ", backend_idx %d usecase = %d device (%s)", __func__, new_bit_width,
-          new_sample_rate, backend_idx, usecase->id,
+    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,
           platform_get_snd_device_name(snd_device));
 
-
     if (!platform_can_split_snd_device(my_data, snd_device, &num_devices, new_snd_devices))
         new_snd_devices[0] = snd_device;
 
     for (i = 0; i < num_devices; i++) {
         ALOGI("%s: new_snd_devices[%d] is %d", __func__, i, new_snd_devices[i]);
-        if (platform_check_codec_backend_cfg(adev, usecase, new_snd_devices[i],
-                                             &new_bit_width, &new_sample_rate)) {
-                platform_set_codec_backend_cfg(adev, new_snd_devices[i],
-                                               new_bit_width, new_sample_rate, format);
-                ret = true;
+        if ((platform_check_codec_backend_cfg(adev, usecase, new_snd_devices[i],
+                                             &backend_cfg))) {
+            platform_set_codec_backend_cfg(adev, new_snd_devices[i],
+                                           backend_cfg);
+            ret = true;
         }
     }
-
     return ret;
 }
 
@@ -4972,6 +5121,7 @@
 
     //reset HDMI_RX_BACKEND to default values
     my_data->current_backend_cfg[HDMI_RX_BACKEND].sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    my_data->current_backend_cfg[HDMI_RX_BACKEND].channels = DEFAULT_HDMI_OUT_CHANNELS;
     my_data->current_backend_cfg[HDMI_RX_BACKEND].bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
 }
 
@@ -4991,90 +5141,6 @@
     return mixer_ctl_set_enum_by_string(ctl, mixer_val);
 }
 
-static int set_mixer_control(struct mixer *mixer,
-                             const char * mixer_ctl_name,
-                             const char *mixer_val)
-{
-    struct mixer_ctl *ctl;
-    ALOGD("setting mixer ctl %s with value %s", mixer_ctl_name, mixer_val);
-    ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
-    if (!ctl) {
-        ALOGE("%s: could not get ctl for mixer cmd - %s",
-              __func__, mixer_ctl_name);
-        return -EINVAL;
-    }
-
-    return mixer_ctl_set_enum_by_string(ctl, mixer_val);
-}
-
-int platform_set_hdmi_config(void *platform, uint32_t channel_count,
-                             uint32_t sample_rate, bool enable_passthrough)
-{
-    struct platform_data *my_data = (struct platform_data *)platform;
-    struct audio_device *adev = my_data->adev;
-    const char *hdmi_format_ctrl = "HDMI RX Format";
-    const char *hdmi_rate_ctrl   = "HDMI_RX SampleRate";
-    const char *hdmi_chans_ctrl  = "HDMI_RX Channels";
-    const char *channel_cnt_str  = NULL;
-
-    ALOGI("%s ch[%d] sr[%d], pthru[%d]", __func__,
-        channel_count, sample_rate, enable_passthrough);
-
-    switch (channel_count) {
-    case 8:
-        channel_cnt_str = "Eight"; break;
-    case 7:
-        channel_cnt_str = "Seven"; break;
-    case 6:
-        channel_cnt_str = "Six"; break;
-    case 5:
-        channel_cnt_str = "Five"; break;
-    case 4:
-        channel_cnt_str = "Four"; break;
-    case 3:
-        channel_cnt_str = "Three"; break;
-    default:
-        channel_cnt_str = "Two"; break;
-    }
-    ALOGV("%s: HDMI channel count: %s", __func__, channel_cnt_str);
-    set_mixer_control(adev->mixer, hdmi_chans_ctrl, channel_cnt_str);
-
-    if (enable_passthrough) {
-        ALOGD("%s:HDMI compress format", __func__);
-        set_mixer_control(adev->mixer, hdmi_format_ctrl, "Compr");
-    } else {
-        ALOGD("%s: HDMI PCM format", __func__);
-        set_mixer_control(adev->mixer, hdmi_format_ctrl, "LPCM");
-    }
-
-    switch (sample_rate) {
-    case 32000:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_32");
-        break;
-    case 44100:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_44P1");
-        break;
-    case 96000:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_96");
-        break;
-    case 128000:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_128");
-        break;
-    case 176400:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_176_4");
-        break;
-    case 192000:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_192");
-        break;
-    default:
-    case 48000:
-        set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_48");
-        break;
-    }
-
-    return 0;
-}
-
 int platform_set_device_params(struct stream_out *out, int param, int value)
 {
     struct audio_device *adev = out->dev;
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index ec307b8..48bfb2b 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -463,4 +463,13 @@
     char device_name[100];
     char interface_name[100];
 };
+
+struct audio_backend_cfg {
+    unsigned int   sample_rate;
+    unsigned int   channels;
+    unsigned int   bit_width;
+    bool           passthrough_enabled;
+    audio_format_t format;
+};
+
 #endif // QCOM_AUDIO_PLATFORM_H