|
@@ -654,6 +654,9 @@ static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
|
|
|
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)
|
|
@@ -829,6 +832,8 @@ static hda_nid_t path_power_update(struct hda_codec *codec,
|
|
|
|
|
|
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
|
|
@@ -4073,6 +4078,64 @@ static void sync_all_pin_power_ctls(struct hda_codec *codec)
|
|
|
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
|
|
|
*/
|
|
@@ -4837,6 +4900,12 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
|
|
|
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;
|