aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-08-28 12:59:20 -0400
committerTakashi Iwai <tiwai@suse.de>2012-08-30 10:48:55 -0400
commit432c641e013d6e294e2ddf06d32a610eb1d4d856 (patch)
tree09cb193f39c9c4b6fa7126a49c291707449f6dbc /sound/pci/hda
parent68467f51c1b578ad98593bf5dee4337bd8d7798d (diff)
ALSA: hda - Fix D3 clock stop check for codecs with own set_power_state op
When a codec provides its own set_power_state op, the D3-clock-stop isn't checked correctly. And the recent changes for repeating the state-setting operation isn't applied to such a codec, too. This patch fixes these issues by moving the call of codec's own op to the place where the generic power-set operation is done, and move the power-state synchronization code out of snd_hda_set_power_state_to_all() so that it can be called always at the end of power-up/down sequence, and updates the D3 clock-stop flag properly. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_codec.c61
1 files changed, 37 insertions, 24 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 90b34e830415..409f5ecd0a71 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -3518,20 +3518,6 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
3518 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, 3518 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
3519 power_state); 3519 power_state);
3520 } 3520 }
3521
3522 if (power_state == AC_PWRST_D0) {
3523 unsigned long end_time;
3524 int state;
3525 /* wait until the codec reachs to D0 */
3526 end_time = jiffies + msecs_to_jiffies(500);
3527 do {
3528 state = snd_hda_codec_read(codec, fg, 0,
3529 AC_VERB_GET_POWER_STATE, 0);
3530 if (state == power_state)
3531 break;
3532 msleep(1);
3533 } while (time_after_eq(end_time, jiffies));
3534 }
3535} 3521}
3536EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all); 3522EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
3537 3523
@@ -3552,6 +3538,32 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, hda_nid_t fg
3552} 3538}
3553 3539
3554/* 3540/*
3541 * wait until the state is reached, returns the current state
3542 */
3543static unsigned int hda_sync_power_state(struct hda_codec *codec,
3544 hda_nid_t fg,
3545 unsigned int power_state)
3546{
3547 unsigned long end_time = jiffies + msecs_to_jiffies(500);
3548 unsigned int state, actual_state;
3549
3550 for (;;) {
3551 state = snd_hda_codec_read(codec, fg, 0,
3552 AC_VERB_GET_POWER_STATE, 0);
3553 if (state & AC_PWRST_ERROR)
3554 break;
3555 actual_state = (state >> 4) & 0x0f;
3556 if (actual_state == power_state)
3557 break;
3558 if (time_after_eq(jiffies, end_time))
3559 break;
3560 /* wait until the codec reachs to the target state */
3561 msleep(1);
3562 }
3563 return state;
3564}
3565
3566/*
3555 * set power state of the codec 3567 * set power state of the codec
3556 */ 3568 */
3557static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, 3569static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
@@ -3564,11 +3576,6 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
3564 codec->d3_stop_clk_ok = 0; 3576 codec->d3_stop_clk_ok = 0;
3565#endif 3577#endif
3566 3578
3567 if (codec->patch_ops.set_power_state) {
3568 codec->patch_ops.set_power_state(codec, fg, power_state);
3569 return;
3570 }
3571
3572 /* this delay seems necessary to avoid click noise at power-down */ 3579 /* this delay seems necessary to avoid click noise at power-down */
3573 if (power_state == AC_PWRST_D3) { 3580 if (power_state == AC_PWRST_D3) {
3574 /* transition time less than 10ms for power down */ 3581 /* transition time less than 10ms for power down */
@@ -3577,11 +3584,17 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
3577 3584
3578 /* repeat power states setting at most 10 times*/ 3585 /* repeat power states setting at most 10 times*/
3579 for (count = 0; count < 10; count++) { 3586 for (count = 0; count < 10; count++) {
3580 snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, 3587 if (codec->patch_ops.set_power_state)
3581 power_state); 3588 codec->patch_ops.set_power_state(codec, fg,
3582 snd_hda_codec_set_power_to_all(codec, fg, power_state, true); 3589 power_state);
3583 state = snd_hda_codec_read(codec, fg, 0, 3590 else {
3584 AC_VERB_GET_POWER_STATE, 0); 3591 snd_hda_codec_read(codec, fg, 0,
3592 AC_VERB_SET_POWER_STATE,
3593 power_state);
3594 snd_hda_codec_set_power_to_all(codec, fg, power_state,
3595 true);
3596 }
3597 state = hda_sync_power_state(codec, fg, power_state);
3585 if (!(state & AC_PWRST_ERROR)) 3598 if (!(state & AC_PWRST_ERROR))
3586 break; 3599 break;
3587 } 3600 }