diff options
-rw-r--r-- | sound/pci/hda/hda_codec.c | 4 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.c | 301 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.h | 5 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 5 |
5 files changed, 269 insertions, 48 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3e4fb7a8fdcb..7e38d6f7314b 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -1502,6 +1502,8 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, | |||
1502 | if (!p) | 1502 | if (!p) |
1503 | return; | 1503 | return; |
1504 | 1504 | ||
1505 | if (codec->patch_ops.stream_pm) | ||
1506 | codec->patch_ops.stream_pm(codec, nid, true); | ||
1505 | if (codec->pcm_format_first) | 1507 | if (codec->pcm_format_first) |
1506 | update_pcm_format(codec, p, nid, format); | 1508 | update_pcm_format(codec, p, nid, format); |
1507 | update_pcm_stream_id(codec, p, nid, stream_tag, channel_id); | 1509 | update_pcm_stream_id(codec, p, nid, stream_tag, channel_id); |
@@ -1570,6 +1572,8 @@ static void really_cleanup_stream(struct hda_codec *codec, | |||
1570 | ); | 1572 | ); |
1571 | memset(q, 0, sizeof(*q)); | 1573 | memset(q, 0, sizeof(*q)); |
1572 | q->nid = nid; | 1574 | q->nid = nid; |
1575 | if (codec->patch_ops.stream_pm) | ||
1576 | codec->patch_ops.stream_pm(codec, nid, false); | ||
1573 | } | 1577 | } |
1574 | 1578 | ||
1575 | /* clean up the all conflicting obsolete streams */ | 1579 | /* clean up the all conflicting obsolete streams */ |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 70851e6d5f10..148e84ce61cf 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -200,6 +200,7 @@ struct hda_codec_ops { | |||
200 | int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid); | 200 | int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid); |
201 | #endif | 201 | #endif |
202 | void (*reboot_notify)(struct hda_codec *codec); | 202 | void (*reboot_notify)(struct hda_codec *codec); |
203 | void (*stream_pm)(struct hda_codec *codec, hda_nid_t nid, bool on); | ||
203 | }; | 204 | }; |
204 | 205 | ||
205 | /* record for amp information cache */ | 206 | /* record for amp information cache */ |
@@ -370,6 +371,7 @@ struct hda_codec { | |||
370 | unsigned int cached_write:1; /* write only to caches */ | 371 | unsigned int cached_write:1; /* write only to caches */ |
371 | unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */ | 372 | unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */ |
372 | unsigned int dump_coef:1; /* dump processing coefs in codec proc file */ | 373 | unsigned int dump_coef:1; /* dump processing coefs in codec proc file */ |
374 | unsigned int power_mgmt:1; /* advanced PM for each widget */ | ||
373 | #ifdef CONFIG_PM | 375 | #ifdef CONFIG_PM |
374 | unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ | 376 | unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ |
375 | atomic_t in_pm; /* suspend/resume being performed */ | 377 | atomic_t in_pm; /* suspend/resume being performed */ |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 27ce54701f0f..8a5055d296f5 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -140,6 +140,9 @@ static void parse_user_hints(struct hda_codec *codec) | |||
140 | val = snd_hda_get_bool_hint(codec, "single_adc_amp"); | 140 | val = snd_hda_get_bool_hint(codec, "single_adc_amp"); |
141 | if (val >= 0) | 141 | if (val >= 0) |
142 | codec->single_adc_amp = !!val; | 142 | codec->single_adc_amp = !!val; |
143 | val = snd_hda_get_bool_hint(codec, "power_mgmt"); | ||
144 | if (val >= 0) | ||
145 | codec->power_mgmt = !!val; | ||
143 | 146 | ||
144 | val = snd_hda_get_bool_hint(codec, "auto_mute"); | 147 | val = snd_hda_get_bool_hint(codec, "auto_mute"); |
145 | if (val >= 0) | 148 | if (val >= 0) |
@@ -648,12 +651,21 @@ static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, | |||
648 | unsigned int dir, unsigned int idx) | 651 | unsigned int dir, unsigned int idx) |
649 | { | 652 | { |
650 | struct hda_gen_spec *spec = codec->spec; | 653 | struct hda_gen_spec *spec = codec->spec; |
654 | int type = get_wcaps_type(get_wcaps(codec, nid)); | ||
651 | int i, n; | 655 | int i, n; |
652 | 656 | ||
653 | for (n = 0; n < spec->paths.used; n++) { | 657 | for (n = 0; n < spec->paths.used; n++) { |
654 | struct nid_path *path = snd_array_elem(&spec->paths, n); | 658 | struct nid_path *path = snd_array_elem(&spec->paths, n); |
655 | if (!path->active) | 659 | if (!path->active) |
656 | continue; | 660 | continue; |
661 | if (codec->power_mgmt) { | ||
662 | if (!path->stream_enabled) | ||
663 | continue; | ||
664 | /* ignore unplugged paths except for DAC/ADC */ | ||
665 | if (!path->pin_enabled && | ||
666 | type != AC_WID_AUD_OUT && type != AC_WID_AUD_IN) | ||
667 | continue; | ||
668 | } | ||
657 | for (i = 0; i < path->depth; i++) { | 669 | for (i = 0; i < path->depth; i++) { |
658 | if (path->path[i] == nid) { | 670 | if (path->path[i] == nid) { |
659 | if (dir == HDA_OUTPUT || path->idx[i] == idx) | 671 | if (dir == HDA_OUTPUT || path->idx[i] == idx) |
@@ -807,6 +819,42 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, | |||
807 | } | 819 | } |
808 | } | 820 | } |
809 | 821 | ||
822 | /* sync power of each widget in the the given path */ | ||
823 | static hda_nid_t path_power_update(struct hda_codec *codec, | ||
824 | struct nid_path *path, | ||
825 | bool allow_powerdown) | ||
826 | { | ||
827 | hda_nid_t nid, changed = 0; | ||
828 | int i, state; | ||
829 | |||
830 | for (i = 0; i < path->depth; i++) { | ||
831 | nid = path->path[i]; | ||
832 | if (!allow_powerdown || is_active_nid_for_any(codec, nid)) | ||
833 | state = AC_PWRST_D0; | ||
834 | else | ||
835 | state = AC_PWRST_D3; | ||
836 | if (!snd_hda_check_power_state(codec, nid, state)) { | ||
837 | snd_hda_codec_write(codec, nid, 0, | ||
838 | AC_VERB_SET_POWER_STATE, state); | ||
839 | changed = nid; | ||
840 | /* here we assume that widget attributes (e.g. amp, | ||
841 | * pinctl connection) don't change with local power | ||
842 | * state change. If not, need to sync the cache. | ||
843 | */ | ||
844 | } | ||
845 | } | ||
846 | return changed; | ||
847 | } | ||
848 | |||
849 | /* do sync with the last power state change */ | ||
850 | static void sync_power_state_change(struct hda_codec *codec, hda_nid_t nid) | ||
851 | { | ||
852 | if (nid) { | ||
853 | msleep(10); | ||
854 | snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0); | ||
855 | } | ||
856 | } | ||
857 | |||
810 | /** | 858 | /** |
811 | * snd_hda_activate_path - activate or deactivate the given path | 859 | * snd_hda_activate_path - activate or deactivate the given path |
812 | * @codec: the HDA codec | 860 | * @codec: the HDA codec |
@@ -825,15 +873,13 @@ void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, | |||
825 | if (!enable) | 873 | if (!enable) |
826 | path->active = false; | 874 | path->active = false; |
827 | 875 | ||
876 | /* make sure the widget is powered up */ | ||
877 | if (enable && (spec->power_down_unused || codec->power_mgmt)) | ||
878 | path_power_update(codec, path, codec->power_mgmt); | ||
879 | |||
828 | for (i = path->depth - 1; i >= 0; i--) { | 880 | for (i = path->depth - 1; i >= 0; i--) { |
829 | hda_nid_t nid = path->path[i]; | 881 | hda_nid_t nid = path->path[i]; |
830 | if (enable && spec->power_down_unused) { | 882 | |
831 | /* make sure the widget is powered up */ | ||
832 | if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) | ||
833 | snd_hda_codec_write(codec, nid, 0, | ||
834 | AC_VERB_SET_POWER_STATE, | ||
835 | AC_PWRST_D0); | ||
836 | } | ||
837 | if (enable && path->multi[i]) | 883 | if (enable && path->multi[i]) |
838 | snd_hda_codec_update_cache(codec, nid, 0, | 884 | snd_hda_codec_update_cache(codec, nid, 0, |
839 | AC_VERB_SET_CONNECT_SEL, | 885 | AC_VERB_SET_CONNECT_SEL, |
@@ -853,28 +899,10 @@ EXPORT_SYMBOL_GPL(snd_hda_activate_path); | |||
853 | static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path) | 899 | static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path) |
854 | { | 900 | { |
855 | struct hda_gen_spec *spec = codec->spec; | 901 | struct hda_gen_spec *spec = codec->spec; |
856 | bool changed = false; | ||
857 | int i; | ||
858 | 902 | ||
859 | if (!spec->power_down_unused || path->active) | 903 | if (!(spec->power_down_unused || codec->power_mgmt) || path->active) |
860 | return; | 904 | return; |
861 | 905 | sync_power_state_change(codec, path_power_update(codec, path, true)); | |
862 | for (i = 0; i < path->depth; i++) { | ||
863 | hda_nid_t nid = path->path[i]; | ||
864 | if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D3) && | ||
865 | !is_active_nid_for_any(codec, nid)) { | ||
866 | snd_hda_codec_write(codec, nid, 0, | ||
867 | AC_VERB_SET_POWER_STATE, | ||
868 | AC_PWRST_D3); | ||
869 | changed = true; | ||
870 | } | ||
871 | } | ||
872 | |||
873 | if (changed) { | ||
874 | msleep(10); | ||
875 | snd_hda_codec_read(codec, path->path[0], 0, | ||
876 | AC_VERB_GET_POWER_STATE, 0); | ||
877 | } | ||
878 | } | 906 | } |
879 | 907 | ||
880 | /* turn on/off EAPD on the given pin */ | 908 | /* turn on/off EAPD on the given pin */ |
@@ -1574,6 +1602,7 @@ static int check_aamix_out_path(struct hda_codec *codec, int path_idx) | |||
1574 | return 0; | 1602 | return 0; |
1575 | /* print_nid_path(codec, "output-aamix", path); */ | 1603 | /* print_nid_path(codec, "output-aamix", path); */ |
1576 | path->active = false; /* unused as default */ | 1604 | path->active = false; /* unused as default */ |
1605 | path->pin_enabled = true; /* static route */ | ||
1577 | return snd_hda_get_path_idx(codec, path); | 1606 | return snd_hda_get_path_idx(codec, path); |
1578 | } | 1607 | } |
1579 | 1608 | ||
@@ -2998,6 +3027,7 @@ static int new_analog_input(struct hda_codec *codec, int input_idx, | |||
2998 | } | 3027 | } |
2999 | 3028 | ||
3000 | path->active = true; | 3029 | path->active = true; |
3030 | path->stream_enabled = true; /* no DAC/ADC involved */ | ||
3001 | err = add_loopback_list(spec, mix_nid, idx); | 3031 | err = add_loopback_list(spec, mix_nid, idx); |
3002 | if (err < 0) | 3032 | if (err < 0) |
3003 | return err; | 3033 | return err; |
@@ -3009,6 +3039,8 @@ static int new_analog_input(struct hda_codec *codec, int input_idx, | |||
3009 | if (path) { | 3039 | if (path) { |
3010 | print_nid_path(codec, "loopback-merge", path); | 3040 | print_nid_path(codec, "loopback-merge", path); |
3011 | path->active = true; | 3041 | path->active = true; |
3042 | path->pin_enabled = true; /* static route */ | ||
3043 | path->stream_enabled = true; /* no DAC/ADC involved */ | ||
3012 | spec->loopback_merge_path = | 3044 | spec->loopback_merge_path = |
3013 | snd_hda_get_path_idx(codec, path); | 3045 | snd_hda_get_path_idx(codec, path); |
3014 | } | 3046 | } |
@@ -3810,6 +3842,7 @@ static void parse_digital(struct hda_codec *codec) | |||
3810 | continue; | 3842 | continue; |
3811 | print_nid_path(codec, "digout", path); | 3843 | print_nid_path(codec, "digout", path); |
3812 | path->active = true; | 3844 | path->active = true; |
3845 | path->pin_enabled = true; /* no jack detection */ | ||
3813 | spec->digout_paths[i] = snd_hda_get_path_idx(codec, path); | 3846 | spec->digout_paths[i] = snd_hda_get_path_idx(codec, path); |
3814 | set_pin_target(codec, pin, PIN_OUT, false); | 3847 | set_pin_target(codec, pin, PIN_OUT, false); |
3815 | if (!nums) { | 3848 | if (!nums) { |
@@ -3837,6 +3870,7 @@ static void parse_digital(struct hda_codec *codec) | |||
3837 | if (path) { | 3870 | if (path) { |
3838 | print_nid_path(codec, "digin", path); | 3871 | print_nid_path(codec, "digin", path); |
3839 | path->active = true; | 3872 | path->active = true; |
3873 | path->pin_enabled = true; /* no jack */ | ||
3840 | spec->dig_in_nid = dig_nid; | 3874 | spec->dig_in_nid = dig_nid; |
3841 | spec->digin_path = snd_hda_get_path_idx(codec, path); | 3875 | spec->digin_path = snd_hda_get_path_idx(codec, path); |
3842 | set_pin_target(codec, pin, PIN_IN, false); | 3876 | set_pin_target(codec, pin, PIN_IN, false); |
@@ -3896,6 +3930,148 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx, | |||
3896 | return 1; | 3930 | return 1; |
3897 | } | 3931 | } |
3898 | 3932 | ||
3933 | /* power up/down widgets in the all paths that match with the given NID | ||
3934 | * as terminals (either start- or endpoint) | ||
3935 | * | ||
3936 | * returns the last changed NID, or zero if unchanged. | ||
3937 | */ | ||
3938 | static hda_nid_t set_path_power(struct hda_codec *codec, hda_nid_t nid, | ||
3939 | int pin_state, int stream_state) | ||
3940 | { | ||
3941 | struct hda_gen_spec *spec = codec->spec; | ||
3942 | hda_nid_t last, changed = 0; | ||
3943 | struct nid_path *path; | ||
3944 | int n; | ||
3945 | |||
3946 | for (n = 0; n < spec->paths.used; n++) { | ||
3947 | path = snd_array_elem(&spec->paths, n); | ||
3948 | if (path->path[0] == nid || | ||
3949 | path->path[path->depth - 1] == nid) { | ||
3950 | bool pin_old = path->pin_enabled; | ||
3951 | bool stream_old = path->stream_enabled; | ||
3952 | |||
3953 | if (pin_state >= 0) | ||
3954 | path->pin_enabled = pin_state; | ||
3955 | if (stream_state >= 0) | ||
3956 | path->stream_enabled = stream_state; | ||
3957 | if (path->pin_enabled != pin_old || | ||
3958 | path->stream_enabled != stream_old) { | ||
3959 | last = path_power_update(codec, path, true); | ||
3960 | if (last) | ||
3961 | changed = last; | ||
3962 | } | ||
3963 | } | ||
3964 | } | ||
3965 | return changed; | ||
3966 | } | ||
3967 | |||
3968 | /* power up/down the paths of the given pin according to the jack state; | ||
3969 | * power = 0/1 : only power up/down if it matches with the jack state, | ||
3970 | * < 0 : force power up/down to follow the jack sate | ||
3971 | * | ||
3972 | * returns the last changed NID, or zero if unchanged. | ||
3973 | */ | ||
3974 | static hda_nid_t set_pin_power_jack(struct hda_codec *codec, hda_nid_t pin, | ||
3975 | int power) | ||
3976 | { | ||
3977 | bool on; | ||
3978 | |||
3979 | if (!codec->power_mgmt) | ||
3980 | return 0; | ||
3981 | |||
3982 | on = snd_hda_jack_detect_state(codec, pin) != HDA_JACK_NOT_PRESENT; | ||
3983 | if (power >= 0 && on != power) | ||
3984 | return 0; | ||
3985 | return set_path_power(codec, pin, on, -1); | ||
3986 | } | ||
3987 | |||
3988 | static void pin_power_callback(struct hda_codec *codec, | ||
3989 | struct hda_jack_callback *jack, | ||
3990 | bool on) | ||
3991 | { | ||
3992 | if (jack && jack->tbl->nid) | ||
3993 | sync_power_state_change(codec, | ||
3994 | set_pin_power_jack(codec, jack->tbl->nid, on)); | ||
3995 | } | ||
3996 | |||
3997 | /* callback only doing power up -- called at first */ | ||
3998 | static void pin_power_up_callback(struct hda_codec *codec, | ||
3999 | struct hda_jack_callback *jack) | ||
4000 | { | ||
4001 | pin_power_callback(codec, jack, true); | ||
4002 | } | ||
4003 | |||
4004 | /* callback only doing power down -- called at last */ | ||
4005 | static void pin_power_down_callback(struct hda_codec *codec, | ||
4006 | struct hda_jack_callback *jack) | ||
4007 | { | ||
4008 | pin_power_callback(codec, jack, false); | ||
4009 | } | ||
4010 | |||
4011 | /* set up the power up/down callbacks */ | ||
4012 | static void add_pin_power_ctls(struct hda_codec *codec, int num_pins, | ||
4013 | const hda_nid_t *pins, bool on) | ||
4014 | { | ||
4015 | int i; | ||
4016 | hda_jack_callback_fn cb = | ||
4017 | on ? pin_power_up_callback : pin_power_down_callback; | ||
4018 | |||
4019 | for (i = 0; i < num_pins && pins[i]; i++) { | ||
4020 | if (is_jack_detectable(codec, pins[i])) | ||
4021 | snd_hda_jack_detect_enable_callback(codec, pins[i], cb); | ||
4022 | else | ||
4023 | set_path_power(codec, pins[i], true, -1); | ||
4024 | } | ||
4025 | } | ||
4026 | |||
4027 | /* enabled power callback to each available I/O pin with jack detections; | ||
4028 | * the digital I/O pins are excluded because of the unreliable detectsion | ||
4029 | */ | ||
4030 | static void add_all_pin_power_ctls(struct hda_codec *codec, bool on) | ||
4031 | { | ||
4032 | struct hda_gen_spec *spec = codec->spec; | ||
4033 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
4034 | int i; | ||
4035 | |||
4036 | if (!codec->power_mgmt) | ||
4037 | return; | ||
4038 | add_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins, on); | ||
4039 | if (cfg->line_out_type != AUTO_PIN_HP_OUT) | ||
4040 | add_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins, on); | ||
4041 | if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) | ||
4042 | add_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins, on); | ||
4043 | for (i = 0; i < cfg->num_inputs; i++) | ||
4044 | add_pin_power_ctls(codec, 1, &cfg->inputs[i].pin, on); | ||
4045 | } | ||
4046 | |||
4047 | /* sync path power up/down with the jack states of given pins */ | ||
4048 | static void sync_pin_power_ctls(struct hda_codec *codec, int num_pins, | ||
4049 | const hda_nid_t *pins) | ||
4050 | { | ||
4051 | int i; | ||
4052 | |||
4053 | for (i = 0; i < num_pins && pins[i]; i++) | ||
4054 | if (is_jack_detectable(codec, pins[i])) | ||
4055 | set_pin_power_jack(codec, pins[i], -1); | ||
4056 | } | ||
4057 | |||
4058 | /* sync path power up/down with pins; called at init and resume */ | ||
4059 | static void sync_all_pin_power_ctls(struct hda_codec *codec) | ||
4060 | { | ||
4061 | struct hda_gen_spec *spec = codec->spec; | ||
4062 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
4063 | int i; | ||
4064 | |||
4065 | if (!codec->power_mgmt) | ||
4066 | return; | ||
4067 | sync_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins); | ||
4068 | if (cfg->line_out_type != AUTO_PIN_HP_OUT) | ||
4069 | sync_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins); | ||
4070 | if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) | ||
4071 | sync_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins); | ||
4072 | for (i = 0; i < cfg->num_inputs; i++) | ||
4073 | sync_pin_power_ctls(codec, 1, &cfg->inputs[i].pin); | ||
4074 | } | ||
3899 | 4075 | ||
3900 | /* | 4076 | /* |
3901 | * Jack detections for HP auto-mute and mic-switch | 4077 | * Jack detections for HP auto-mute and mic-switch |
@@ -3933,6 +4109,10 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, | |||
3933 | if (!nid) | 4109 | if (!nid) |
3934 | break; | 4110 | break; |
3935 | 4111 | ||
4112 | oldval = snd_hda_codec_get_pin_target(codec, nid); | ||
4113 | if (oldval & PIN_IN) | ||
4114 | continue; /* no mute for inputs */ | ||
4115 | |||
3936 | if (spec->auto_mute_via_amp) { | 4116 | if (spec->auto_mute_via_amp) { |
3937 | struct nid_path *path; | 4117 | struct nid_path *path; |
3938 | hda_nid_t mute_nid; | 4118 | hda_nid_t mute_nid; |
@@ -3947,29 +4127,33 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, | |||
3947 | spec->mute_bits |= (1ULL << mute_nid); | 4127 | spec->mute_bits |= (1ULL << mute_nid); |
3948 | else | 4128 | else |
3949 | spec->mute_bits &= ~(1ULL << mute_nid); | 4129 | spec->mute_bits &= ~(1ULL << mute_nid); |
3950 | set_pin_eapd(codec, nid, !mute); | ||
3951 | continue; | 4130 | continue; |
4131 | } else { | ||
4132 | /* don't reset VREF value in case it's controlling | ||
4133 | * the amp (see alc861_fixup_asus_amp_vref_0f()) | ||
4134 | */ | ||
4135 | if (spec->keep_vref_in_automute) | ||
4136 | val = oldval & ~PIN_HP; | ||
4137 | else | ||
4138 | val = 0; | ||
4139 | if (!mute) | ||
4140 | val |= oldval; | ||
4141 | /* here we call update_pin_ctl() so that the pinctl is | ||
4142 | * changed without changing the pinctl target value; | ||
4143 | * the original target value will be still referred at | ||
4144 | * the init / resume again | ||
4145 | */ | ||
4146 | update_pin_ctl(codec, nid, val); | ||
3952 | } | 4147 | } |
3953 | 4148 | ||
3954 | oldval = snd_hda_codec_get_pin_target(codec, nid); | ||
3955 | if (oldval & PIN_IN) | ||
3956 | continue; /* no mute for inputs */ | ||
3957 | /* don't reset VREF value in case it's controlling | ||
3958 | * the amp (see alc861_fixup_asus_amp_vref_0f()) | ||
3959 | */ | ||
3960 | if (spec->keep_vref_in_automute) | ||
3961 | val = oldval & ~PIN_HP; | ||
3962 | else | ||
3963 | val = 0; | ||
3964 | if (!mute) | ||
3965 | val |= oldval; | ||
3966 | /* here we call update_pin_ctl() so that the pinctl is changed | ||
3967 | * without changing the pinctl target value; | ||
3968 | * the original target value will be still referred at the | ||
3969 | * init / resume again | ||
3970 | */ | ||
3971 | update_pin_ctl(codec, nid, val); | ||
3972 | set_pin_eapd(codec, nid, !mute); | 4149 | set_pin_eapd(codec, nid, !mute); |
4150 | if (codec->power_mgmt) { | ||
4151 | bool on = !mute; | ||
4152 | if (on) | ||
4153 | on = snd_hda_jack_detect_state(codec, nid) | ||
4154 | != HDA_JACK_NOT_PRESENT; | ||
4155 | set_path_power(codec, nid, on, -1); | ||
4156 | } | ||
3973 | } | 4157 | } |
3974 | } | 4158 | } |
3975 | 4159 | ||
@@ -4466,6 +4650,21 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix) | |||
4466 | } | 4650 | } |
4467 | 4651 | ||
4468 | /** | 4652 | /** |
4653 | * snd_hda_gen_stream_pm - Stream power management callback | ||
4654 | * @codec: the HDA codec | ||
4655 | * @nid: audio widget | ||
4656 | * @on: power on/off flag | ||
4657 | * | ||
4658 | * Set this in patch_ops.stream_pm. Only valid with power_mgmt flag. | ||
4659 | */ | ||
4660 | void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on) | ||
4661 | { | ||
4662 | if (codec->power_mgmt) | ||
4663 | set_path_power(codec, nid, -1, on); | ||
4664 | } | ||
4665 | EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm); | ||
4666 | |||
4667 | /** | ||
4469 | * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and | 4668 | * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and |
4470 | * set up the hda_gen_spec | 4669 | * set up the hda_gen_spec |
4471 | * @codec: the HDA codec | 4670 | * @codec: the HDA codec |
@@ -4549,6 +4748,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, | |||
4549 | if (err < 0) | 4748 | if (err < 0) |
4550 | return err; | 4749 | return err; |
4551 | 4750 | ||
4751 | /* add power-down pin callbacks at first */ | ||
4752 | add_all_pin_power_ctls(codec, false); | ||
4753 | |||
4552 | spec->const_channel_count = spec->ext_channel_count; | 4754 | spec->const_channel_count = spec->ext_channel_count; |
4553 | /* check the multiple speaker and headphone pins */ | 4755 | /* check the multiple speaker and headphone pins */ |
4554 | if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) | 4756 | if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) |
@@ -4618,6 +4820,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, | |||
4618 | } | 4820 | } |
4619 | } | 4821 | } |
4620 | 4822 | ||
4823 | /* add power-up pin callbacks at last */ | ||
4824 | add_all_pin_power_ctls(codec, true); | ||
4825 | |||
4621 | /* mute all aamix input initially */ | 4826 | /* mute all aamix input initially */ |
4622 | if (spec->mixer_nid) | 4827 | if (spec->mixer_nid) |
4623 | mute_all_mixer_nid(codec, spec->mixer_nid); | 4828 | mute_all_mixer_nid(codec, spec->mixer_nid); |
@@ -4625,7 +4830,7 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, | |||
4625 | dig_only: | 4830 | dig_only: |
4626 | parse_digital(codec); | 4831 | parse_digital(codec); |
4627 | 4832 | ||
4628 | if (spec->power_down_unused) | 4833 | if (spec->power_down_unused || codec->power_mgmt) |
4629 | codec->power_filter = snd_hda_gen_path_power_filter; | 4834 | codec->power_filter = snd_hda_gen_path_power_filter; |
4630 | 4835 | ||
4631 | if (!spec->no_analog && spec->beep_nid) { | 4836 | if (!spec->no_analog && spec->beep_nid) { |
@@ -5478,6 +5683,8 @@ int snd_hda_gen_init(struct hda_codec *codec) | |||
5478 | 5683 | ||
5479 | clear_unsol_on_unused_pins(codec); | 5684 | clear_unsol_on_unused_pins(codec); |
5480 | 5685 | ||
5686 | sync_all_pin_power_ctls(codec); | ||
5687 | |||
5481 | /* call init functions of standard auto-mute helpers */ | 5688 | /* call init functions of standard auto-mute helpers */ |
5482 | update_automute_all(codec); | 5689 | update_automute_all(codec); |
5483 | 5690 | ||
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index b211f889b335..54659b51fe16 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h | |||
@@ -46,7 +46,9 @@ struct nid_path { | |||
46 | unsigned char idx[MAX_NID_PATH_DEPTH]; | 46 | unsigned char idx[MAX_NID_PATH_DEPTH]; |
47 | unsigned char multi[MAX_NID_PATH_DEPTH]; | 47 | unsigned char multi[MAX_NID_PATH_DEPTH]; |
48 | unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */ | 48 | unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */ |
49 | bool active; | 49 | bool active:1; /* activated by driver */ |
50 | bool pin_enabled:1; /* pins are enabled */ | ||
51 | bool stream_enabled:1; /* stream is active */ | ||
50 | }; | 52 | }; |
51 | 53 | ||
52 | /* mic/line-in auto switching entry */ | 54 | /* mic/line-in auto switching entry */ |
@@ -340,5 +342,6 @@ int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid); | |||
340 | unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec, | 342 | unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec, |
341 | hda_nid_t nid, | 343 | hda_nid_t nid, |
342 | unsigned int power_state); | 344 | unsigned int power_state); |
345 | void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on); | ||
343 | 346 | ||
344 | #endif /* __SOUND_HDA_GENERIC_H */ | 347 | #endif /* __SOUND_HDA_GENERIC_H */ |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 2956a6ba6bf0..86b944a6b0ed 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -4394,6 +4394,7 @@ static const struct hda_codec_ops stac_patch_ops = { | |||
4394 | #ifdef CONFIG_PM | 4394 | #ifdef CONFIG_PM |
4395 | .suspend = stac_suspend, | 4395 | .suspend = stac_suspend, |
4396 | #endif | 4396 | #endif |
4397 | .stream_pm = snd_hda_gen_stream_pm, | ||
4397 | .reboot_notify = stac_shutup, | 4398 | .reboot_notify = stac_shutup, |
4398 | }; | 4399 | }; |
4399 | 4400 | ||
@@ -4487,6 +4488,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec) | |||
4487 | return err; | 4488 | return err; |
4488 | 4489 | ||
4489 | spec = codec->spec; | 4490 | spec = codec->spec; |
4491 | codec->power_mgmt = 1; | ||
4490 | spec->linear_tone_beep = 0; | 4492 | spec->linear_tone_beep = 0; |
4491 | spec->gen.mixer_nid = 0x1d; | 4493 | spec->gen.mixer_nid = 0x1d; |
4492 | spec->have_spdif_mux = 1; | 4494 | spec->have_spdif_mux = 1; |
@@ -4592,6 +4594,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) | |||
4592 | codec->epss = 0; /* longer delay needed for D3 */ | 4594 | codec->epss = 0; /* longer delay needed for D3 */ |
4593 | 4595 | ||
4594 | spec = codec->spec; | 4596 | spec = codec->spec; |
4597 | codec->power_mgmt = 1; | ||
4595 | spec->linear_tone_beep = 0; | 4598 | spec->linear_tone_beep = 0; |
4596 | spec->gen.own_eapd_ctl = 1; | 4599 | spec->gen.own_eapd_ctl = 1; |
4597 | spec->gen.power_down_unused = 1; | 4600 | spec->gen.power_down_unused = 1; |
@@ -4641,6 +4644,7 @@ static int patch_stac92hd95(struct hda_codec *codec) | |||
4641 | codec->epss = 0; /* longer delay needed for D3 */ | 4644 | codec->epss = 0; /* longer delay needed for D3 */ |
4642 | 4645 | ||
4643 | spec = codec->spec; | 4646 | spec = codec->spec; |
4647 | codec->power_mgmt = 1; | ||
4644 | spec->linear_tone_beep = 0; | 4648 | spec->linear_tone_beep = 0; |
4645 | spec->gen.own_eapd_ctl = 1; | 4649 | spec->gen.own_eapd_ctl = 1; |
4646 | spec->gen.power_down_unused = 1; | 4650 | spec->gen.power_down_unused = 1; |
@@ -4682,6 +4686,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) | |||
4682 | return err; | 4686 | return err; |
4683 | 4687 | ||
4684 | spec = codec->spec; | 4688 | spec = codec->spec; |
4689 | codec->power_mgmt = 1; | ||
4685 | spec->linear_tone_beep = 0; | 4690 | spec->linear_tone_beep = 0; |
4686 | spec->gen.own_eapd_ctl = 1; | 4691 | spec->gen.own_eapd_ctl = 1; |
4687 | spec->gen.power_down_unused = 1; | 4692 | spec->gen.power_down_unused = 1; |