diff options
| -rw-r--r-- | sound/pci/hda/hda_codec.c | 78 | ||||
| -rw-r--r-- | sound/pci/hda/hda_codec.h | 5 | ||||
| -rw-r--r-- | sound/pci/hda/patch_conexant.c | 14 |
3 files changed, 56 insertions, 41 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 056cd9ade1fb..3e7850c238c3 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
| @@ -3203,51 +3203,30 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, | |||
| 3203 | EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache); | 3203 | EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache); |
| 3204 | #endif /* CONFIG_PM */ | 3204 | #endif /* CONFIG_PM */ |
| 3205 | 3205 | ||
| 3206 | /* | 3206 | void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, |
| 3207 | * set power state of the codec | 3207 | unsigned int power_state, |
| 3208 | */ | 3208 | bool eapd_workaround) |
| 3209 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | ||
| 3210 | unsigned int power_state) | ||
| 3211 | { | 3209 | { |
| 3212 | hda_nid_t nid; | 3210 | hda_nid_t nid = codec->start_nid; |
| 3213 | int i; | 3211 | int i; |
| 3214 | 3212 | ||
| 3215 | /* this delay seems necessary to avoid click noise at power-down */ | ||
| 3216 | if (power_state == AC_PWRST_D3) | ||
| 3217 | msleep(100); | ||
| 3218 | snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, | ||
| 3219 | power_state); | ||
| 3220 | /* partial workaround for "azx_get_response timeout" */ | ||
| 3221 | if (power_state == AC_PWRST_D0 && | ||
| 3222 | (codec->vendor_id & 0xffff0000) == 0x14f10000) | ||
| 3223 | msleep(10); | ||
| 3224 | |||
| 3225 | nid = codec->start_nid; | ||
| 3226 | for (i = 0; i < codec->num_nodes; i++, nid++) { | 3213 | for (i = 0; i < codec->num_nodes; i++, nid++) { |
| 3227 | unsigned int wcaps = get_wcaps(codec, nid); | 3214 | unsigned int wcaps = get_wcaps(codec, nid); |
| 3228 | if (wcaps & AC_WCAP_POWER) { | 3215 | if (!(wcaps & AC_WCAP_POWER)) |
| 3229 | unsigned int wid_type = get_wcaps_type(wcaps); | 3216 | continue; |
| 3230 | if (power_state == AC_PWRST_D3 && | 3217 | /* don't power down the widget if it controls eapd and |
| 3231 | wid_type == AC_WID_PIN) { | 3218 | * EAPD_BTLENABLE is set. |
| 3232 | unsigned int pincap; | 3219 | */ |
| 3233 | /* | 3220 | if (eapd_workaround && power_state == AC_PWRST_D3 && |
| 3234 | * don't power down the widget if it controls | 3221 | get_wcaps_type(wcaps) == AC_WID_PIN && |
| 3235 | * eapd and EAPD_BTLENABLE is set. | 3222 | (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) { |
| 3236 | */ | 3223 | int eapd = snd_hda_codec_read(codec, nid, 0, |
| 3237 | pincap = snd_hda_query_pin_caps(codec, nid); | ||
| 3238 | if (pincap & AC_PINCAP_EAPD) { | ||
| 3239 | int eapd = snd_hda_codec_read(codec, | ||
| 3240 | nid, 0, | ||
| 3241 | AC_VERB_GET_EAPD_BTLENABLE, 0); | 3224 | AC_VERB_GET_EAPD_BTLENABLE, 0); |
| 3242 | eapd &= 0x02; | 3225 | if (eapd & 0x02) |
| 3243 | if (eapd) | 3226 | continue; |
| 3244 | continue; | ||
| 3245 | } | ||
| 3246 | } | ||
| 3247 | snd_hda_codec_write(codec, nid, 0, | ||
| 3248 | AC_VERB_SET_POWER_STATE, | ||
| 3249 | power_state); | ||
| 3250 | } | 3227 | } |
| 3228 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, | ||
| 3229 | power_state); | ||
| 3251 | } | 3230 | } |
| 3252 | 3231 | ||
| 3253 | if (power_state == AC_PWRST_D0) { | 3232 | if (power_state == AC_PWRST_D0) { |
| @@ -3264,6 +3243,26 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | |||
| 3264 | } while (time_after_eq(end_time, jiffies)); | 3243 | } while (time_after_eq(end_time, jiffies)); |
| 3265 | } | 3244 | } |
| 3266 | } | 3245 | } |
| 3246 | EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all); | ||
| 3247 | |||
| 3248 | /* | ||
| 3249 | * set power state of the codec | ||
| 3250 | */ | ||
| 3251 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | ||
| 3252 | unsigned int power_state) | ||
| 3253 | { | ||
| 3254 | if (codec->patch_ops.set_power_state) { | ||
| 3255 | codec->patch_ops.set_power_state(codec, fg, power_state); | ||
| 3256 | return; | ||
| 3257 | } | ||
| 3258 | |||
| 3259 | /* this delay seems necessary to avoid click noise at power-down */ | ||
| 3260 | if (power_state == AC_PWRST_D3) | ||
| 3261 | msleep(100); | ||
| 3262 | snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, | ||
| 3263 | power_state); | ||
| 3264 | snd_hda_codec_set_power_to_all(codec, fg, power_state, true); | ||
| 3265 | } | ||
| 3267 | 3266 | ||
| 3268 | #ifdef CONFIG_SND_HDA_HWDEP | 3267 | #ifdef CONFIG_SND_HDA_HWDEP |
| 3269 | /* execute additional init verbs */ | 3268 | /* execute additional init verbs */ |
| @@ -4073,9 +4072,6 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, | |||
| 4073 | EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); | 4072 | EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); |
| 4074 | 4073 | ||
| 4075 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 4074 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 4076 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | ||
| 4077 | unsigned int power_state); | ||
| 4078 | |||
| 4079 | static void hda_power_work(struct work_struct *work) | 4075 | static void hda_power_work(struct work_struct *work) |
| 4080 | { | 4076 | { |
| 4081 | struct hda_codec *codec = | 4077 | struct hda_codec *codec = |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index c7ca753d94ee..755f2b0f9d8e 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
| @@ -700,6 +700,8 @@ struct hda_codec_ops { | |||
| 700 | int (*init)(struct hda_codec *codec); | 700 | int (*init)(struct hda_codec *codec); |
| 701 | void (*free)(struct hda_codec *codec); | 701 | void (*free)(struct hda_codec *codec); |
| 702 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); | 702 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); |
| 703 | void (*set_power_state)(struct hda_codec *codec, hda_nid_t fg, | ||
| 704 | unsigned int power_state); | ||
| 703 | #ifdef CONFIG_PM | 705 | #ifdef CONFIG_PM |
| 704 | int (*suspend)(struct hda_codec *codec, pm_message_t state); | 706 | int (*suspend)(struct hda_codec *codec, pm_message_t state); |
| 705 | int (*post_suspend)(struct hda_codec *codec); | 707 | int (*post_suspend)(struct hda_codec *codec); |
| @@ -1006,6 +1008,9 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | |||
| 1006 | */ | 1008 | */ |
| 1007 | void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); | 1009 | void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); |
| 1008 | void snd_hda_bus_reboot_notify(struct hda_bus *bus); | 1010 | void snd_hda_bus_reboot_notify(struct hda_bus *bus); |
| 1011 | void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, | ||
| 1012 | unsigned int power_state, | ||
| 1013 | bool eapd_workaround); | ||
| 1009 | 1014 | ||
| 1010 | /* | 1015 | /* |
| 1011 | * power management | 1016 | * power management |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 884f67b8f4e0..502fc9499453 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
| @@ -446,6 +446,19 @@ static int conexant_init_jacks(struct hda_codec *codec) | |||
| 446 | return 0; | 446 | return 0; |
| 447 | } | 447 | } |
| 448 | 448 | ||
| 449 | static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg, | ||
| 450 | unsigned int power_state) | ||
| 451 | { | ||
| 452 | if (power_state == AC_PWRST_D3) | ||
| 453 | msleep(100); | ||
| 454 | snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, | ||
| 455 | power_state); | ||
| 456 | /* partial workaround for "azx_get_response timeout" */ | ||
| 457 | if (power_state == AC_PWRST_D0) | ||
| 458 | msleep(10); | ||
| 459 | snd_hda_codec_set_power_to_all(codec, fg, power_state, true); | ||
| 460 | } | ||
| 461 | |||
| 449 | static int conexant_init(struct hda_codec *codec) | 462 | static int conexant_init(struct hda_codec *codec) |
| 450 | { | 463 | { |
| 451 | struct conexant_spec *spec = codec->spec; | 464 | struct conexant_spec *spec = codec->spec; |
| @@ -588,6 +601,7 @@ static const struct hda_codec_ops conexant_patch_ops = { | |||
| 588 | .build_pcms = conexant_build_pcms, | 601 | .build_pcms = conexant_build_pcms, |
| 589 | .init = conexant_init, | 602 | .init = conexant_init, |
| 590 | .free = conexant_free, | 603 | .free = conexant_free, |
| 604 | .set_power_state = conexant_set_power, | ||
| 591 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 605 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 592 | .suspend = conexant_suspend, | 606 | .suspend = conexant_suspend, |
| 593 | #endif | 607 | #endif |
