aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_generic.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-03-18 04:23:10 -0400
committerTakashi Iwai <tiwai@suse.de>2015-03-18 04:23:10 -0400
commit5ccf835cc76d89bc0d426659c63d81f609050842 (patch)
treea601871aa85d8115b63f999c00a8a2808b79678f /sound/pci/hda/hda_generic.c
parent688b12cc3ca8a5155b95ce8d01e0e43006813b27 (diff)
ALSA: hda - Adjust power of beep widget and outputs
As the widget PM may turn off the pins, this might lead to the silent output for beep when no explicit paths are given. This patch adds fake output paths for the beep widget so that the output pins are dynamically powered upon beep on/off. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_generic.c')
-rw-r--r--sound/pci/hda/hda_generic.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 8a5055d296f5..d7ca388651da 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -654,6 +654,9 @@ static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
654 int type = get_wcaps_type(get_wcaps(codec, nid)); 654 int type = get_wcaps_type(get_wcaps(codec, nid));
655 int i, n; 655 int i, n;
656 656
657 if (nid == codec->afg)
658 return true;
659
657 for (n = 0; n < spec->paths.used; n++) { 660 for (n = 0; n < spec->paths.used; n++) {
658 struct nid_path *path = snd_array_elem(&spec->paths, n); 661 struct nid_path *path = snd_array_elem(&spec->paths, n);
659 if (!path->active) 662 if (!path->active)
@@ -829,6 +832,8 @@ static hda_nid_t path_power_update(struct hda_codec *codec,
829 832
830 for (i = 0; i < path->depth; i++) { 833 for (i = 0; i < path->depth; i++) {
831 nid = path->path[i]; 834 nid = path->path[i];
835 if (nid == codec->afg)
836 continue;
832 if (!allow_powerdown || is_active_nid_for_any(codec, nid)) 837 if (!allow_powerdown || is_active_nid_for_any(codec, nid))
833 state = AC_PWRST_D0; 838 state = AC_PWRST_D0;
834 else 839 else
@@ -4073,6 +4078,64 @@ static void sync_all_pin_power_ctls(struct hda_codec *codec)
4073 sync_pin_power_ctls(codec, 1, &cfg->inputs[i].pin); 4078 sync_pin_power_ctls(codec, 1, &cfg->inputs[i].pin);
4074} 4079}
4075 4080
4081/* add fake paths if not present yet */
4082static int add_fake_paths(struct hda_codec *codec, hda_nid_t nid,
4083 int num_pins, const hda_nid_t *pins)
4084{
4085 struct hda_gen_spec *spec = codec->spec;
4086 struct nid_path *path;
4087 int i;
4088
4089 for (i = 0; i < num_pins; i++) {
4090 if (!pins[i])
4091 break;
4092 if (get_nid_path(codec, nid, pins[i], 0))
4093 continue;
4094 path = snd_array_new(&spec->paths);
4095 if (!path)
4096 return -ENOMEM;
4097 memset(path, 0, sizeof(*path));
4098 path->depth = 2;
4099 path->path[0] = nid;
4100 path->path[1] = pins[i];
4101 path->active = true;
4102 }
4103 return 0;
4104}
4105
4106/* create fake paths to all outputs from beep */
4107static int add_fake_beep_paths(struct hda_codec *codec)
4108{
4109 struct hda_gen_spec *spec = codec->spec;
4110 struct auto_pin_cfg *cfg = &spec->autocfg;
4111 hda_nid_t nid = spec->beep_nid;
4112 int err;
4113
4114 if (!codec->power_mgmt || !nid)
4115 return 0;
4116 err = add_fake_paths(codec, nid, cfg->line_outs, cfg->line_out_pins);
4117 if (err < 0)
4118 return err;
4119 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
4120 err = add_fake_paths(codec, nid, cfg->hp_outs, cfg->hp_pins);
4121 if (err < 0)
4122 return err;
4123 }
4124 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
4125 err = add_fake_paths(codec, nid, cfg->speaker_outs,
4126 cfg->speaker_pins);
4127 if (err < 0)
4128 return err;
4129 }
4130 return 0;
4131}
4132
4133/* power up/down beep widget and its output paths */
4134static void beep_power_hook(struct hda_beep *beep, bool on)
4135{
4136 set_path_power(beep->codec, beep->nid, -1, on);
4137}
4138
4076/* 4139/*
4077 * Jack detections for HP auto-mute and mic-switch 4140 * Jack detections for HP auto-mute and mic-switch
4078 */ 4141 */
@@ -4837,6 +4900,12 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
4837 err = snd_hda_attach_beep_device(codec, spec->beep_nid); 4900 err = snd_hda_attach_beep_device(codec, spec->beep_nid);
4838 if (err < 0) 4901 if (err < 0)
4839 return err; 4902 return err;
4903 if (codec->beep && codec->power_mgmt) {
4904 err = add_fake_beep_paths(codec);
4905 if (err < 0)
4906 return err;
4907 codec->beep->power_hook = beep_power_hook;
4908 }
4840 } 4909 }
4841 4910
4842 return 1; 4911 return 1;