#endif
 };
 
-struct cea_channel_speaker_allocation;
-
 /* operations used by generic code that can be overridden by patches */
 struct hdmi_ops {
        int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid,
                               struct snd_ctl_elem_info *uinfo)
 {
        struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
-       struct hda_codec *codec = info->private_data;
-       struct hdmi_spec *spec = codec->spec;
-       struct hdac_chmap *chmap = &spec->chmap;
+       struct hdac_chmap *chmap = info->private_data;
 
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = chmap->channels_max;
        WARN_ON(count != channels);
 }
 
+static void hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx,
+                                       unsigned char *chmap)
+{
+       struct hda_codec *codec = container_of(hdac, struct hda_codec, core);
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
+
+       /* chmap is already set to 0 in caller */
+       if (!per_pin)
+               return;
+
+       memcpy(chmap, per_pin->chmap, ARRAY_SIZE(per_pin->chmap));
+}
+
+static void hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
+                               unsigned char *chmap, int prepared)
+{
+       struct hda_codec *codec = container_of(hdac, struct hda_codec, core);
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
+
+       mutex_lock(&per_pin->lock);
+       per_pin->chmap_set = true;
+       memcpy(per_pin->chmap, chmap, ARRAY_SIZE(per_pin->chmap));
+       if (prepared)
+               hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+       mutex_unlock(&per_pin->lock);
+}
+
+static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
+{
+       struct hda_codec *codec = container_of(hdac, struct hda_codec, core);
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
+
+       return per_pin ? true:false;
+}
+
 static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
                              unsigned int size, unsigned int __user *tlv)
 {
        struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
-       struct hda_codec *codec = info->private_data;
-       struct hdmi_spec *spec = codec->spec;
-       struct hdac_chmap *chmap = &spec->chmap;
+       struct hdac_chmap *chmap = info->private_data;
        unsigned int __user *dst;
        int chs, count = 0;
 
                              struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
-       struct hda_codec *codec = info->private_data;
-       struct hdmi_spec *spec = codec->spec;
-       struct hdac_chmap *chmap = &spec->chmap;
+       struct hdac_chmap *chmap = info->private_data;
        int pcm_idx = kcontrol->private_value;
-       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
+       unsigned char pcm_chmap[8];
        int i;
 
-       if (!per_pin) {
-               for (i = 0; i < chmap->channels_max; i++)
-                       ucontrol->value.integer.value[i] = 0;
-               return 0;
-       }
+       memset(pcm_chmap, 0, sizeof(pcm_chmap));
+       chmap->ops.get_chmap(chmap->hdac, pcm_idx, pcm_chmap);
+
+       for (i = 0; i < sizeof(chmap); i++)
+               ucontrol->value.integer.value[i] = pcm_chmap[i];
 
-       for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++)
-               ucontrol->value.integer.value[i] = per_pin->chmap[i];
        return 0;
 }
 
                              struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
-       struct hda_codec *codec = info->private_data;
-       struct hdmi_spec *spec = codec->spec;
-       struct hdac_chmap *hchmap = &spec->chmap;
+       struct hdac_chmap *hchmap = info->private_data;
        int pcm_idx = kcontrol->private_value;
-       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
        unsigned int ctl_idx;
        struct snd_pcm_substream *substream;
-       unsigned char chmap[8];
+       unsigned char chmap[8], per_pin_chmap[8];
        int i, err, ca, prepared = 0;
 
        /* No monitor is connected in dyn_pcm_assign.
         * It's invalid to setup the chmap
         */
-       if (!per_pin)
+       if (!hchmap->ops.is_pcm_attached(hchmap->hdac, pcm_idx))
                return 0;
 
        ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        memset(chmap, 0, sizeof(chmap));
        for (i = 0; i < ARRAY_SIZE(chmap); i++)
                chmap[i] = ucontrol->value.integer.value[i];
-       if (!memcmp(chmap, per_pin->chmap, sizeof(chmap)))
+
+       hchmap->ops.get_chmap(hchmap->hdac, pcm_idx, per_pin_chmap);
+       if (!memcmp(chmap, per_pin_chmap, sizeof(chmap)))
                return 0;
        ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap);
        if (ca < 0)
                if (err)
                        return err;
        }
-       mutex_lock(&per_pin->lock);
-       per_pin->chmap_set = true;
-       memcpy(per_pin->chmap, chmap, sizeof(chmap));
-       if (prepared)
-               hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
-       mutex_unlock(&per_pin->lock);
+
+       hchmap->ops.set_chmap(hchmap->hdac, pcm_idx, chmap, prepared);
 
        return 0;
 }
                if (err < 0)
                        return err;
                /* override handlers */
-               chmap->private_data = codec;
+               chmap->private_data = &spec->chmap;
                kctl = chmap->kctl;
                for (i = 0; i < kctl->count; i++)
                        kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
 static const struct hdac_chmap_ops chmap_ops = {
        .chmap_cea_alloc_validate_get_type      = hdmi_chmap_cea_alloc_validate_get_type,
        .cea_alloc_to_tlv_chmap                 = hdmi_cea_alloc_to_tlv_chmap,
+       .get_chmap                              = hdmi_get_chmap,
+       .set_chmap                              = hdmi_set_chmap,
+       .is_pcm_attached                        = is_hdmi_pcm_attached,
 };
 
-
 static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
                                             hda_nid_t nid)
 {