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; |
