aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorKailang Yang <kailang@realtek.com>2013-06-28 06:03:01 -0400
committerTakashi Iwai <tiwai@suse.de>2013-06-28 06:12:54 -0400
commitad60d502fb8aaa3c1e011f4d72b8228f553d87a8 (patch)
tree5fdd0ec7256d52e60f73ff831bf2796f830b408d /sound/pci/hda
parentdb10e7fbbc836fb66d4500c64c1960940cfad2b0 (diff)
ALSA: hda - Add support for ALC5505 DSP power-save mode
This patch adds the power-saving control for ALC5505 DSP on some Realtek codecs. Signed-off-by: Kailang Yang <kailang@realtek.com> Tested-by: Mengdong Lin <mengdong.lin@intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/patch_realtek.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index ae121113f223..eeb6ecc31366 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -115,6 +115,7 @@ struct alc_spec {
115 115
116 int init_amp; 116 int init_amp;
117 int codec_variant; /* flag for other variants */ 117 int codec_variant; /* flag for other variants */
118 bool has_alc5505_dsp;
118 119
119 /* for PLL fix */ 120 /* for PLL fix */
120 hda_nid_t pll_nid; 121 hda_nid_t pll_nid;
@@ -2580,7 +2581,96 @@ static void alc269_shutup(struct hda_codec *codec)
2580 } 2581 }
2581} 2582}
2582 2583
2584static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg,
2585 unsigned int val)
2586{
2587 snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1);
2588 snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val & 0xffff); /* LSB */
2589 snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val >> 16); /* MSB */
2590}
2591
2592static int alc5505_coef_get(struct hda_codec *codec, unsigned int index_reg)
2593{
2594 unsigned int val;
2595
2596 snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1);
2597 val = snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0)
2598 & 0xffff;
2599 val |= snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0)
2600 << 16;
2601 return val;
2602}
2603
2604static void alc5505_dsp_halt(struct hda_codec *codec)
2605{
2606 unsigned int val;
2607
2608 alc5505_coef_set(codec, 0x3000, 0x000c); /* DSP CPU stop */
2609 alc5505_coef_set(codec, 0x880c, 0x0008); /* DDR enter self refresh */
2610 alc5505_coef_set(codec, 0x61c0, 0x11110080); /* Clock control for PLL and CPU */
2611 alc5505_coef_set(codec, 0x6230, 0xfc0d4011); /* Disable Input OP */
2612 alc5505_coef_set(codec, 0x61b4, 0x040a2b03); /* Stop PLL2 */
2613 alc5505_coef_set(codec, 0x61b0, 0x00005b17); /* Stop PLL1 */
2614 alc5505_coef_set(codec, 0x61b8, 0x04133303); /* Stop PLL3 */
2615 val = alc5505_coef_get(codec, 0x6220);
2616 alc5505_coef_set(codec, 0x6220, (val | 0x3000)); /* switch Ringbuffer clock to DBUS clock */
2617}
2618
2619static void alc5505_dsp_back_from_halt(struct hda_codec *codec)
2620{
2621 alc5505_coef_set(codec, 0x61b8, 0x04133302);
2622 alc5505_coef_set(codec, 0x61b0, 0x00005b16);
2623 alc5505_coef_set(codec, 0x61b4, 0x040a2b02);
2624 alc5505_coef_set(codec, 0x6230, 0xf80d4011);
2625 alc5505_coef_set(codec, 0x6220, 0x2002010f);
2626 alc5505_coef_set(codec, 0x880c, 0x00000004);
2627}
2628
2629static void alc5505_dsp_init(struct hda_codec *codec)
2630{
2631 unsigned int val;
2632
2633 alc5505_dsp_halt(codec);
2634 alc5505_dsp_back_from_halt(codec);
2635 alc5505_coef_set(codec, 0x61b0, 0x5b14); /* PLL1 control */
2636 alc5505_coef_set(codec, 0x61b0, 0x5b16);
2637 alc5505_coef_set(codec, 0x61b4, 0x04132b00); /* PLL2 control */
2638 alc5505_coef_set(codec, 0x61b4, 0x04132b02);
2639 alc5505_coef_set(codec, 0x61b8, 0x041f3300); /* PLL3 control*/
2640 alc5505_coef_set(codec, 0x61b8, 0x041f3302);
2641 snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_CODEC_RESET, 0); /* Function reset */
2642 alc5505_coef_set(codec, 0x61b8, 0x041b3302);
2643 alc5505_coef_set(codec, 0x61b8, 0x04173302);
2644 alc5505_coef_set(codec, 0x61b8, 0x04163302);
2645 alc5505_coef_set(codec, 0x8800, 0x348b328b); /* DRAM control */
2646 alc5505_coef_set(codec, 0x8808, 0x00020022); /* DRAM control */
2647 alc5505_coef_set(codec, 0x8818, 0x00000400); /* DRAM control */
2648
2649 val = alc5505_coef_get(codec, 0x6200) >> 16; /* Read revision ID */
2650 if (val <= 3)
2651 alc5505_coef_set(codec, 0x6220, 0x2002010f); /* I/O PAD Configuration */
2652 else
2653 alc5505_coef_set(codec, 0x6220, 0x6002018f);
2654
2655 alc5505_coef_set(codec, 0x61ac, 0x055525f0); /**/
2656 alc5505_coef_set(codec, 0x61c0, 0x12230080); /* Clock control */
2657 alc5505_coef_set(codec, 0x61b4, 0x040e2b02); /* PLL2 control */
2658 alc5505_coef_set(codec, 0x61bc, 0x010234f8); /* OSC Control */
2659 alc5505_coef_set(codec, 0x880c, 0x00000004); /* DRAM Function control */
2660 alc5505_coef_set(codec, 0x880c, 0x00000003);
2661 alc5505_coef_set(codec, 0x880c, 0x00000010);
2662}
2663
2583#ifdef CONFIG_PM 2664#ifdef CONFIG_PM
2665static int alc269_suspend(struct hda_codec *codec)
2666{
2667 struct alc_spec *spec = codec->spec;
2668
2669 if (spec->has_alc5505_dsp)
2670 alc5505_dsp_halt(codec);
2671 return alc_suspend(codec);
2672}
2673
2584static int alc269_resume(struct hda_codec *codec) 2674static int alc269_resume(struct hda_codec *codec)
2585{ 2675{
2586 struct alc_spec *spec = codec->spec; 2676 struct alc_spec *spec = codec->spec;
@@ -2605,6 +2695,8 @@ static int alc269_resume(struct hda_codec *codec)
2605 snd_hda_codec_resume_cache(codec); 2695 snd_hda_codec_resume_cache(codec);
2606 alc_inv_dmic_sync(codec, true); 2696 alc_inv_dmic_sync(codec, true);
2607 hda_call_check_power_status(codec, 0x01); 2697 hda_call_check_power_status(codec, 0x01);
2698 if (spec->has_alc5505_dsp)
2699 alc5505_dsp_back_from_halt(codec);
2608 return 0; 2700 return 0;
2609} 2701}
2610#endif /* CONFIG_PM */ 2702#endif /* CONFIG_PM */
@@ -3730,6 +3822,11 @@ static int patch_alc269(struct hda_codec *codec)
3730 break; 3822 break;
3731 } 3823 }
3732 3824
3825 if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) {
3826 spec->has_alc5505_dsp = true;
3827 spec->init_hook = alc5505_dsp_init;
3828 }
3829
3733 /* automatic parse from the BIOS config */ 3830 /* automatic parse from the BIOS config */
3734 err = alc269_parse_auto_config(codec); 3831 err = alc269_parse_auto_config(codec);
3735 if (err < 0) 3832 if (err < 0)
@@ -3740,6 +3837,7 @@ static int patch_alc269(struct hda_codec *codec)
3740 3837
3741 codec->patch_ops = alc_patch_ops; 3838 codec->patch_ops = alc_patch_ops;
3742#ifdef CONFIG_PM 3839#ifdef CONFIG_PM
3840 codec->patch_ops.suspend = alc269_suspend;
3743 codec->patch_ops.resume = alc269_resume; 3841 codec->patch_ops.resume = alc269_resume;
3744#endif 3842#endif
3745 spec->shutup = alc269_shutup; 3843 spec->shutup = alc269_shutup;