|
@@ -3203,51 +3203,30 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec,
|
|
|
EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache);
|
|
|
#endif /* CONFIG_PM */
|
|
|
|
|
|
-/*
|
|
|
- * set power state of the codec
|
|
|
- */
|
|
|
-static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
|
|
- unsigned int power_state)
|
|
|
+void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
|
|
|
+ unsigned int power_state,
|
|
|
+ bool eapd_workaround)
|
|
|
{
|
|
|
- hda_nid_t nid;
|
|
|
+ hda_nid_t nid = codec->start_nid;
|
|
|
int i;
|
|
|
|
|
|
- /* this delay seems necessary to avoid click noise at power-down */
|
|
|
- if (power_state == AC_PWRST_D3)
|
|
|
- msleep(100);
|
|
|
- snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
|
|
|
- power_state);
|
|
|
- /* partial workaround for "azx_get_response timeout" */
|
|
|
- if (power_state == AC_PWRST_D0 &&
|
|
|
- (codec->vendor_id & 0xffff0000) == 0x14f10000)
|
|
|
- msleep(10);
|
|
|
-
|
|
|
- nid = codec->start_nid;
|
|
|
for (i = 0; i < codec->num_nodes; i++, nid++) {
|
|
|
unsigned int wcaps = get_wcaps(codec, nid);
|
|
|
- if (wcaps & AC_WCAP_POWER) {
|
|
|
- unsigned int wid_type = get_wcaps_type(wcaps);
|
|
|
- if (power_state == AC_PWRST_D3 &&
|
|
|
- wid_type == AC_WID_PIN) {
|
|
|
- unsigned int pincap;
|
|
|
- /*
|
|
|
- * don't power down the widget if it controls
|
|
|
- * eapd and EAPD_BTLENABLE is set.
|
|
|
- */
|
|
|
- pincap = snd_hda_query_pin_caps(codec, nid);
|
|
|
- if (pincap & AC_PINCAP_EAPD) {
|
|
|
- int eapd = snd_hda_codec_read(codec,
|
|
|
- nid, 0,
|
|
|
+ if (!(wcaps & AC_WCAP_POWER))
|
|
|
+ continue;
|
|
|
+ /* don't power down the widget if it controls eapd and
|
|
|
+ * EAPD_BTLENABLE is set.
|
|
|
+ */
|
|
|
+ if (eapd_workaround && power_state == AC_PWRST_D3 &&
|
|
|
+ get_wcaps_type(wcaps) == AC_WID_PIN &&
|
|
|
+ (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) {
|
|
|
+ int eapd = snd_hda_codec_read(codec, nid, 0,
|
|
|
AC_VERB_GET_EAPD_BTLENABLE, 0);
|
|
|
- eapd &= 0x02;
|
|
|
- if (eapd)
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- snd_hda_codec_write(codec, nid, 0,
|
|
|
- AC_VERB_SET_POWER_STATE,
|
|
|
- power_state);
|
|
|
+ if (eapd & 0x02)
|
|
|
+ continue;
|
|
|
}
|
|
|
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
|
|
|
+ power_state);
|
|
|
}
|
|
|
|
|
|
if (power_state == AC_PWRST_D0) {
|
|
@@ -3264,6 +3243,26 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
|
|
} while (time_after_eq(end_time, jiffies));
|
|
|
}
|
|
|
}
|
|
|
+EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
|
|
|
+
|
|
|
+/*
|
|
|
+ * set power state of the codec
|
|
|
+ */
|
|
|
+static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
|
|
+ unsigned int power_state)
|
|
|
+{
|
|
|
+ if (codec->patch_ops.set_power_state) {
|
|
|
+ codec->patch_ops.set_power_state(codec, fg, power_state);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* this delay seems necessary to avoid click noise at power-down */
|
|
|
+ if (power_state == AC_PWRST_D3)
|
|
|
+ msleep(100);
|
|
|
+ snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
|
|
|
+ power_state);
|
|
|
+ snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
|
|
|
+}
|
|
|
|
|
|
#ifdef CONFIG_SND_HDA_HWDEP
|
|
|
/* execute additional init verbs */
|
|
@@ -4073,9 +4072,6 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
|
|
|
EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
|
|
|
|
|
|
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
|
|
-static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
|
|
- unsigned int power_state);
|
|
|
-
|
|
|
static void hda_power_work(struct work_struct *work)
|
|
|
{
|
|
|
struct hda_codec *codec =
|