DIGBEEP_HZ_MAX = 12000000,      /* 12 KHz */
 };
 
-static void snd_hda_generate_beep(struct work_struct *work)
+/* generate or stop tone */
+static void generate_tone(struct hda_beep *beep, int tone)
 {
-       struct hda_beep *beep =
-               container_of(work, struct hda_beep, beep_work);
        struct hda_codec *codec = beep->codec;
-       int tone;
 
-       if (!beep->enabled)
-               return;
-
-       tone = beep->tone;
        if (tone && !beep->playing) {
                snd_hda_power_up(codec);
+               if (beep->power_hook)
+                       beep->power_hook(beep, true);
                beep->playing = 1;
        }
-       /* generate tone */
        snd_hda_codec_write(codec, beep->nid, 0,
                            AC_VERB_SET_BEEP_CONTROL, tone);
        if (!tone && beep->playing) {
                beep->playing = 0;
+               if (beep->power_hook)
+                       beep->power_hook(beep, false);
                snd_hda_power_down(codec);
        }
 }
 
+static void snd_hda_generate_beep(struct work_struct *work)
+{
+       struct hda_beep *beep =
+               container_of(work, struct hda_beep, beep_work);
+
+       if (beep->enabled)
+               generate_tone(beep, beep->tone);
+}
+
 /* (non-standard) Linear beep tone calculation for IDT/STAC codecs 
  *
  * The tone frequency of beep generator on IDT/STAC codecs is
        cancel_work_sync(&beep->beep_work);
        if (beep->playing) {
                /* turn off beep */
-               snd_hda_codec_write(beep->codec, beep->nid, 0,
-                                   AC_VERB_SET_BEEP_CONTROL, 0);
-               beep->playing = 0;
-               snd_hda_power_down(beep->codec);
+               generate_tone(beep, 0);
        }
 }
 
 
        int type = get_wcaps_type(get_wcaps(codec, nid));
        int i, n;
 
+       if (nid == codec->afg)
+               return true;
+
        for (n = 0; n < spec->paths.used; n++) {
                struct nid_path *path = snd_array_elem(&spec->paths, n);
                if (!path->active)
 
        for (i = 0; i < path->depth; i++) {
                nid = path->path[i];
+               if (nid == codec->afg)
+                       continue;
                if (!allow_powerdown || is_active_nid_for_any(codec, nid))
                        state = AC_PWRST_D0;
                else
                sync_pin_power_ctls(codec, 1, &cfg->inputs[i].pin);
 }
 
+/* add fake paths if not present yet */
+static int add_fake_paths(struct hda_codec *codec, hda_nid_t nid,
+                          int num_pins, const hda_nid_t *pins)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *path;
+       int i;
+
+       for (i = 0; i < num_pins; i++) {
+               if (!pins[i])
+                       break;
+               if (get_nid_path(codec, nid, pins[i], 0))
+                       continue;
+               path = snd_array_new(&spec->paths);
+               if (!path)
+                       return -ENOMEM;
+               memset(path, 0, sizeof(*path));
+               path->depth = 2;
+               path->path[0] = nid;
+               path->path[1] = pins[i];
+               path->active = true;
+       }
+       return 0;
+}
+
+/* create fake paths to all outputs from beep */
+static int add_fake_beep_paths(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t nid = spec->beep_nid;
+       int err;
+
+       if (!codec->power_mgmt || !nid)
+               return 0;
+       err = add_fake_paths(codec, nid, cfg->line_outs, cfg->line_out_pins);
+       if (err < 0)
+               return err;
+       if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+               err = add_fake_paths(codec, nid, cfg->hp_outs, cfg->hp_pins);
+               if (err < 0)
+                       return err;
+       }
+       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+               err = add_fake_paths(codec, nid, cfg->speaker_outs,
+                                    cfg->speaker_pins);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+/* power up/down beep widget and its output paths */
+static void beep_power_hook(struct hda_beep *beep, bool on)
+{
+       set_path_power(beep->codec, beep->nid, -1, on);
+}
+
 /*
  * Jack detections for HP auto-mute and mic-switch
  */
                err = snd_hda_attach_beep_device(codec, spec->beep_nid);
                if (err < 0)
                        return err;
+               if (codec->beep && codec->power_mgmt) {
+                       err = add_fake_beep_paths(codec);
+                       if (err < 0)
+                               return err;
+                       codec->beep->power_hook = beep_power_hook;
+               }
        }
 
        return 1;