per_pin->channels = 0;
 }
 
+static struct snd_jack *pin_idx_to_pcm_jack(struct hda_codec *codec,
+                                           struct hdmi_spec_per_pin *per_pin)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       if (per_pin->pcm_idx >= 0)
+               return spec->pcm_rec[per_pin->pcm_idx].jack;
+       else
+               return NULL;
+}
+
 /* update per_pin ELD from the given new ELD;
  * setup info frame and notification accordingly
+ * also notify ELD kctl and report jack status changes
  */
-static bool update_eld(struct hda_codec *codec,
+static void update_eld(struct hda_codec *codec,
                       struct hdmi_spec_per_pin *per_pin,
-                      struct hdmi_eld *eld)
+                      struct hdmi_eld *eld,
+                      int repoll)
 {
        struct hdmi_eld *pin_eld = &per_pin->sink_eld;
        struct hdmi_spec *spec = codec->spec;
+       struct snd_jack *pcm_jack;
        bool old_eld_valid = pin_eld->eld_valid;
        bool eld_changed;
        int pcm_idx;
 
+       if (eld->eld_valid) {
+               if (eld->eld_size <= 0 ||
+                   snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer,
+                                      eld->eld_size) < 0) {
+                       eld->eld_valid = false;
+                       if (repoll) {
+                               schedule_delayed_work(&per_pin->work,
+                                                     msecs_to_jiffies(300));
+                               return;
+                       }
+               }
+       }
+
+       if (!eld->eld_valid || eld->eld_size <= 0) {
+               eld->eld_valid = false;
+               eld->eld_size = 0;
+       }
+
        /* for monitor disconnection, save pcm_idx firstly */
        pcm_idx = per_pin->pcm_idx;
+
+       /*
+        * pcm_idx >=0 before update_eld() means it is in monitor
+        * disconnected event. Jack must be fetched before update_eld().
+        */
+       pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
+
        if (spec->dyn_pcm_assign) {
                if (eld->eld_valid) {
                        hdmi_attach_hda_pcm(spec, per_pin);
         */
        if (pcm_idx == -1)
                pcm_idx = per_pin->pcm_idx;
+       if (!pcm_jack)
+               pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
 
        if (eld->eld_valid)
                snd_hdmi_show_eld(codec, &eld->info);
                               SNDRV_CTL_EVENT_MASK_VALUE |
                               SNDRV_CTL_EVENT_MASK_INFO,
                               &get_hdmi_pcm(spec, pcm_idx)->eld_ctl->id);
-       return eld_changed;
-}
-
-static struct snd_jack *pin_idx_to_pcm_jack(struct hda_codec *codec,
-                                           struct hdmi_spec_per_pin *per_pin)
-{
-       struct hdmi_spec *spec = codec->spec;
 
-       if (per_pin->pcm_idx >= 0)
-               return spec->pcm_rec[per_pin->pcm_idx].jack;
-       else
-               return NULL;
-}
-
-static void do_update_eld(struct hda_codec *codec,
-                         struct hdmi_spec_per_pin *per_pin,
-                         struct hdmi_eld *eld)
-{
-       struct snd_jack *pcm_jack;
-       bool changed;
-
-       /*
-        * pcm_idx >=0 before update_eld() means it is in monitor
-        * disconnected event. Jack must be fetched before update_eld().
-        */
-       pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
-       changed = update_eld(codec, per_pin, eld);
-       if (!pcm_jack)
-               pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
-       if (changed && pcm_jack)
+       if (eld_changed && pcm_jack)
                snd_jack_report(pcm_jack,
                                (eld->monitor_present && eld->eld_valid) ?
                                SND_JACK_AVOUT : 0);
         * the unsolicited response to avoid custom WARs.
         */
        int present;
-       bool do_repoll = false;
        int ret;
 
        ret = snd_hda_power_up_pm(codec);
                if (spec->ops.pin_get_eld(codec, pin_nid, dev_id,
                                          eld->eld_buffer, &eld->eld_size) < 0)
                        eld->eld_valid = false;
-               else {
-                       if (snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer,
-                                                   eld->eld_size) < 0)
-                               eld->eld_valid = false;
-               }
-               if (!eld->eld_valid && repoll)
-                       do_repoll = true;
        }
 
-       if (do_repoll)
-               schedule_delayed_work(&per_pin->work, msecs_to_jiffies(300));
-       else
-               do_update_eld(codec, per_pin, eld);
-
+       update_eld(codec, per_pin, eld, repoll);
        mutex_unlock(&per_pin->lock);
  out:
        snd_hda_power_down_pm(codec);
 {
        struct hdmi_spec *spec = codec->spec;
        struct hdmi_eld *eld = &spec->temp_eld;
-       int size;
 
        mutex_lock(&per_pin->lock);
        eld->monitor_present = false;
-       size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
+       eld->eld_size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
                                      per_pin->dev_id, &eld->monitor_present,
                                      eld->eld_buffer, ELD_MAX_SIZE);
-       if (size > 0) {
-               size = min(size, ELD_MAX_SIZE);
-               if (snd_hdmi_parse_eld(codec, &eld->info,
-                                      eld->eld_buffer, size) < 0)
-                       size = -EINVAL;
-       }
-
-       if (size > 0) {
-               eld->eld_valid = true;
-               eld->eld_size = size;
-       } else {
-               eld->eld_valid = false;
-               eld->eld_size = 0;
-       }
-
-       do_update_eld(codec, per_pin, eld);
+       eld->eld_valid = (eld->eld_size > 0);
+       update_eld(codec, per_pin, eld, 0);
        mutex_unlock(&per_pin->lock);
 }