aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-07-26 04:33:10 -0400
committerTakashi Iwai <tiwai@suse.de>2011-07-26 11:21:24 -0400
commit4d7fbdbcb1d563b1822c74da3c9e4aa4523d8d6d (patch)
treee8b38eb8d7c67388595f11b140c97382a1384b1d /sound/pci
parente581f3dba509f6d48e4939aa70e9b768aa5fd4f3 (diff)
ALSA: hda - Allow codec-specific set_power_state ops
The procedure for codec D-state change may have exceptional cases depending on the codec chip, such as a longer delay or suppressing D3. This patch adds a new codec ops, set_power_state() to override the system default function. For ease of porting, snd_hda_codec_set_power_to_all() helper function is extracted from the default set_power_state() function. As an example, the Conexant codec-specific delay is removed from the default routine but moved to patch_conexant.c. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_codec.c78
-rw-r--r--sound/pci/hda/hda_codec.h5
-rw-r--r--sound/pci/hda/patch_conexant.c14
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,
3203EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache); 3203EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache);
3204#endif /* CONFIG_PM */ 3204#endif /* CONFIG_PM */
3205 3205
3206/* 3206void 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)
3209static 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}
3246EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
3247
3248/*
3249 * set power state of the codec
3250 */
3251static 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,
4073EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); 4072EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
4074 4073
4075#ifdef CONFIG_SND_HDA_POWER_SAVE 4074#ifdef CONFIG_SND_HDA_POWER_SAVE
4076static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
4077 unsigned int power_state);
4078
4079static void hda_power_work(struct work_struct *work) 4075static 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 */
1007void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); 1009void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
1008void snd_hda_bus_reboot_notify(struct hda_bus *bus); 1010void snd_hda_bus_reboot_notify(struct hda_bus *bus);
1011void 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
449static 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
449static int conexant_init(struct hda_codec *codec) 462static 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