#include <sound/hdaudio_ext.h>
 #include <sound/hda_i915.h>
 #include <sound/pcm_drm_eld.h>
+#include <sound/hda_chmap.h>
 #include "../../hda/local.h"
 #include "hdac_hdmi.h"
 
        struct hdac_ext_device *edev;
        int repoll_count;
        struct delayed_work work;
+       struct mutex lock;
+       bool chmap_set;
+       unsigned char chmap[8]; /* ALSA API channel-map */
+       int channels; /* current number of channels */
 };
 
 struct hdac_hdmi_pcm {
        int num_pin;
        int num_cvt;
        struct mutex pin_mutex;
+       struct hdac_chmap chmap;
 };
 
 static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
        int i;
        const u8 *eld_buf;
        u8 conn_type;
-       int channels = 2;
+       int channels, ca;
 
        list_for_each_entry(pin, &hdmi->pin_list, head) {
                if (pin->nid == pin_nid)
                        break;
        }
 
+       ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc,
+                       pin->channels, pin->chmap_set, true, pin->chmap);
+
+       channels = snd_hdac_get_active_channels(ca);
+       hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt_nid, channels);
+
+       snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca,
+                               pin->channels, pin->chmap, pin->chmap_set);
+
        eld_buf = pin->eld.eld_buffer;
        conn_type = drm_eld_get_conn_type(eld_buf);
 
-       /* setup channel count */
-       snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
-                           AC_VERB_SET_CVT_CHAN_COUNT, channels - 1);
-
        switch (conn_type) {
        case DRM_ELD_CONN_TYPE_HDMI:
                hdmi_audio_infoframe_init(&frame);
 
-               /* Default stereo for now */
                frame.channels = channels;
+               frame.channel_allocation = ca;
 
                ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
                if (ret < 0)
                dp_ai.len       = 0x1b;
                dp_ai.ver       = 0x11 << 2;
                dp_ai.CC02_CT47 = channels - 1;
-               dp_ai.CA        = 0;
+               dp_ai.CA        = ca;
 
                dip = (u8 *)&dp_ai;
                break;
        struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
        struct hdac_hdmi_priv *hdmi = hdac->private_data;
        struct hdac_hdmi_dai_pin_map *dai_map;
+       struct hdac_hdmi_pin *pin;
        struct hdac_ext_dma_params *dd;
        int ret;
 
        dai_map = &hdmi->dai_map[dai->id];
+       pin = dai_map->pin;
 
        dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
        dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
                        dd->stream_tag, dd->format);
 
+       mutex_lock(&pin->lock);
+       pin->channels = substream->runtime->channels;
+
        ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
                                                dai_map->pin->nid);
+       mutex_unlock(&pin->lock);
        if (ret < 0)
                return ret;
 
                snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
                        AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
 
+               mutex_lock(&dai_map->pin->lock);
+               dai_map->pin->channels = 0;
+               mutex_unlock(&dai_map->pin->lock);
+
                dai_map->pin = NULL;
        }
 }
 static int
 hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
 {
+       unsigned int chans;
+       struct hdac_ext_device *edev = to_ehdac_device(hdac);
+       struct hdac_hdmi_priv *hdmi = edev->private_data;
        int err;
 
-       /* Only stereo supported as of now */
-       cvt->params.channels_min = cvt->params.channels_max = 2;
+       chans = get_wcaps(hdac, cvt->nid);
+       chans = get_wcaps_channels(chans);
+
+       cvt->params.channels_min = 2;
+
+       cvt->params.channels_max = chans;
+       if (chans > hdmi->chmap.channels_max)
+               hdmi->chmap.channels_max = chans;
 
        err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
                        &cvt->params.rates,
        hdmi->num_pin++;
 
        pin->edev = edev;
+       mutex_init(&pin->lock);
        INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
 
        return 0;
                return -ENOMEM;
 
        edev->private_data = hdmi_priv;
+       snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap);
 
        dev_set_drvdata(&codec->dev, edev);