aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_analog.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2007-08-10 11:21:45 -0400
committerJaroslav Kysela <perex@perex.cz>2007-10-16 09:58:46 -0400
commitcb53c626e1145edf1d619bc4953f6293d3a77ace (patch)
tree715c2ef3d56a5ac7c79498800e888f562c1aa961 /sound/pci/hda/patch_analog.c
parentcca3b3718ca96dca51daf1129ac03003bcede751 (diff)
[ALSA] hda-intel - Add POWER_SAVE option
Added CONFIG_SND_HDA_POWER_SAVE kconfig. It's an experimental option to achieve an aggressive power-saving. With this option, the driver will turn on/off the power of each codec and controller chip dynamically on demand. The patch introduces a new module option 'power_save'. It specifies the second of time-out for automatic power-down. As default, it's 10 seconds. Setting 0 means to suppress the power-saving feature. The codec may have analog-input loopbacks, which are usually represented by mixer elements such as 'Mic Playback Switch' or 'CD Playback Switch'. When these are on, we cannot turn off the mixer and the codec chip has to be kept on. For bookkeeping these states, a new codec-callback is introduced. For the bus-controller side, a new callback pm_notify is introduced, which can be used to turn on/off the contoller appropriately. Note that this power-saving might cause slight click-noise at power-on/off. Also, it might take some time to wake up the codec, and might even drop some tones at the very beginning. This seems to be the side-effect of turning off the controller chip. This turn-off of the controller can be disabled by undefining HDA_POWER_SAVE_RESET_CONTOLLER in hda_intel.c. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
-rw-r--r--sound/pci/hda/patch_analog.c91
1 files changed, 91 insertions, 0 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index f9390a544ea4..53cfa0da4964 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -73,6 +73,10 @@ struct ad198x_spec {
73 struct snd_kcontrol_new *kctl_alloc; 73 struct snd_kcontrol_new *kctl_alloc;
74 struct hda_input_mux private_imux; 74 struct hda_input_mux private_imux;
75 hda_nid_t private_dac_nids[4]; 75 hda_nid_t private_dac_nids[4];
76
77#ifdef CONFIG_SND_HDA_POWER_SAVE
78 struct hda_loopback_check loopback;
79#endif
76}; 80};
77 81
78/* 82/*
@@ -144,6 +148,14 @@ static int ad198x_build_controls(struct hda_codec *codec)
144 return 0; 148 return 0;
145} 149}
146 150
151#ifdef CONFIG_SND_HDA_POWER_SAVE
152static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
153{
154 struct ad198x_spec *spec = codec->spec;
155 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
156}
157#endif
158
147/* 159/*
148 * Analog playback callbacks 160 * Analog playback callbacks
149 */ 161 */
@@ -323,6 +335,9 @@ static struct hda_codec_ops ad198x_patch_ops = {
323 .build_pcms = ad198x_build_pcms, 335 .build_pcms = ad198x_build_pcms,
324 .init = ad198x_init, 336 .init = ad198x_init,
325 .free = ad198x_free, 337 .free = ad198x_free,
338#ifdef CONFIG_SND_HDA_POWER_SAVE
339 .check_power_status = ad198x_check_power_status,
340#endif
326}; 341};
327 342
328 343
@@ -736,6 +751,17 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
736 {} 751 {}
737}; 752};
738 753
754#ifdef CONFIG_SND_HDA_POWER_SAVE
755static struct hda_amp_list ad1986a_loopbacks[] = {
756 { 0x13, HDA_OUTPUT, 0 }, /* Mic */
757 { 0x14, HDA_OUTPUT, 0 }, /* Phone */
758 { 0x15, HDA_OUTPUT, 0 }, /* CD */
759 { 0x16, HDA_OUTPUT, 0 }, /* Aux */
760 { 0x17, HDA_OUTPUT, 0 }, /* Line */
761 { } /* end */
762};
763#endif
764
739static int patch_ad1986a(struct hda_codec *codec) 765static int patch_ad1986a(struct hda_codec *codec)
740{ 766{
741 struct ad198x_spec *spec; 767 struct ad198x_spec *spec;
@@ -759,6 +785,9 @@ static int patch_ad1986a(struct hda_codec *codec)
759 spec->mixers[0] = ad1986a_mixers; 785 spec->mixers[0] = ad1986a_mixers;
760 spec->num_init_verbs = 1; 786 spec->num_init_verbs = 1;
761 spec->init_verbs[0] = ad1986a_init_verbs; 787 spec->init_verbs[0] = ad1986a_init_verbs;
788#ifdef CONFIG_SND_HDA_POWER_SAVE
789 spec->loopback.amplist = ad1986a_loopbacks;
790#endif
762 791
763 codec->patch_ops = ad198x_patch_ops; 792 codec->patch_ops = ad198x_patch_ops;
764 793
@@ -944,6 +973,13 @@ static struct hda_verb ad1983_init_verbs[] = {
944 { } /* end */ 973 { } /* end */
945}; 974};
946 975
976#ifdef CONFIG_SND_HDA_POWER_SAVE
977static struct hda_amp_list ad1983_loopbacks[] = {
978 { 0x12, HDA_OUTPUT, 0 }, /* Mic */
979 { 0x13, HDA_OUTPUT, 0 }, /* Line */
980 { } /* end */
981};
982#endif
947 983
948static int patch_ad1983(struct hda_codec *codec) 984static int patch_ad1983(struct hda_codec *codec)
949{ 985{
@@ -968,6 +1004,9 @@ static int patch_ad1983(struct hda_codec *codec)
968 spec->num_init_verbs = 1; 1004 spec->num_init_verbs = 1;
969 spec->init_verbs[0] = ad1983_init_verbs; 1005 spec->init_verbs[0] = ad1983_init_verbs;
970 spec->spdif_route = 0; 1006 spec->spdif_route = 0;
1007#ifdef CONFIG_SND_HDA_POWER_SAVE
1008 spec->loopback.amplist = ad1983_loopbacks;
1009#endif
971 1010
972 codec->patch_ops = ad198x_patch_ops; 1011 codec->patch_ops = ad198x_patch_ops;
973 1012
@@ -1091,6 +1130,17 @@ static struct hda_verb ad1981_init_verbs[] = {
1091 { } /* end */ 1130 { } /* end */
1092}; 1131};
1093 1132
1133#ifdef CONFIG_SND_HDA_POWER_SAVE
1134static struct hda_amp_list ad1981_loopbacks[] = {
1135 { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
1136 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1137 { 0x1b, HDA_OUTPUT, 0 }, /* Aux */
1138 { 0x1c, HDA_OUTPUT, 0 }, /* Mic */
1139 { 0x1d, HDA_OUTPUT, 0 }, /* CD */
1140 { } /* end */
1141};
1142#endif
1143
1094/* 1144/*
1095 * Patch for HP nx6320 1145 * Patch for HP nx6320
1096 * 1146 *
@@ -1350,6 +1400,9 @@ static int patch_ad1981(struct hda_codec *codec)
1350 spec->num_init_verbs = 1; 1400 spec->num_init_verbs = 1;
1351 spec->init_verbs[0] = ad1981_init_verbs; 1401 spec->init_verbs[0] = ad1981_init_verbs;
1352 spec->spdif_route = 0; 1402 spec->spdif_route = 0;
1403#ifdef CONFIG_SND_HDA_POWER_SAVE
1404 spec->loopback.amplist = ad1981_loopbacks;
1405#endif
1353 1406
1354 codec->patch_ops = ad198x_patch_ops; 1407 codec->patch_ops = ad198x_patch_ops;
1355 1408
@@ -2103,6 +2156,15 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
2103 snd_hda_sequence_write(codec, ad1988_laptop_hp_off); 2156 snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
2104} 2157}
2105 2158
2159#ifdef CONFIG_SND_HDA_POWER_SAVE
2160static struct hda_amp_list ad1988_loopbacks[] = {
2161 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
2162 { 0x20, HDA_INPUT, 1 }, /* Line */
2163 { 0x20, HDA_INPUT, 4 }, /* Mic */
2164 { 0x20, HDA_INPUT, 6 }, /* CD */
2165 { } /* end */
2166};
2167#endif
2106 2168
2107/* 2169/*
2108 * Automatic parse of I/O pins from the BIOS configuration 2170 * Automatic parse of I/O pins from the BIOS configuration
@@ -2647,6 +2709,9 @@ static int patch_ad1988(struct hda_codec *codec)
2647 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; 2709 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
2648 break; 2710 break;
2649 } 2711 }
2712#ifdef CONFIG_SND_HDA_POWER_SAVE
2713 spec->loopback.amplist = ad1988_loopbacks;
2714#endif
2650 2715
2651 return 0; 2716 return 0;
2652} 2717}
@@ -2803,6 +2868,16 @@ static struct hda_verb ad1884_init_verbs[] = {
2803 { } /* end */ 2868 { } /* end */
2804}; 2869};
2805 2870
2871#ifdef CONFIG_SND_HDA_POWER_SAVE
2872static struct hda_amp_list ad1884_loopbacks[] = {
2873 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
2874 { 0x20, HDA_INPUT, 1 }, /* Mic */
2875 { 0x20, HDA_INPUT, 2 }, /* CD */
2876 { 0x20, HDA_INPUT, 4 }, /* Docking */
2877 { } /* end */
2878};
2879#endif
2880
2806static int patch_ad1884(struct hda_codec *codec) 2881static int patch_ad1884(struct hda_codec *codec)
2807{ 2882{
2808 struct ad198x_spec *spec; 2883 struct ad198x_spec *spec;
@@ -2827,6 +2902,9 @@ static int patch_ad1884(struct hda_codec *codec)
2827 spec->num_init_verbs = 1; 2902 spec->num_init_verbs = 1;
2828 spec->init_verbs[0] = ad1884_init_verbs; 2903 spec->init_verbs[0] = ad1884_init_verbs;
2829 spec->spdif_route = 0; 2904 spec->spdif_route = 0;
2905#ifdef CONFIG_SND_HDA_POWER_SAVE
2906 spec->loopback.amplist = ad1884_loopbacks;
2907#endif
2830 2908
2831 codec->patch_ops = ad198x_patch_ops; 2909 codec->patch_ops = ad198x_patch_ops;
2832 2910
@@ -3208,6 +3286,16 @@ static struct hda_verb ad1882_init_verbs[] = {
3208 { } /* end */ 3286 { } /* end */
3209}; 3287};
3210 3288
3289#ifdef CONFIG_SND_HDA_POWER_SAVE
3290static struct hda_amp_list ad1882_loopbacks[] = {
3291 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3292 { 0x20, HDA_INPUT, 1 }, /* Mic */
3293 { 0x20, HDA_INPUT, 4 }, /* Line */
3294 { 0x20, HDA_INPUT, 6 }, /* CD */
3295 { } /* end */
3296};
3297#endif
3298
3211/* models */ 3299/* models */
3212enum { 3300enum {
3213 AD1882_3STACK, 3301 AD1882_3STACK,
@@ -3246,6 +3334,9 @@ static int patch_ad1882(struct hda_codec *codec)
3246 spec->num_init_verbs = 1; 3334 spec->num_init_verbs = 1;
3247 spec->init_verbs[0] = ad1882_init_verbs; 3335 spec->init_verbs[0] = ad1882_init_verbs;
3248 spec->spdif_route = 0; 3336 spec->spdif_route = 0;
3337#ifdef CONFIG_SND_HDA_POWER_SAVE
3338 spec->loopback.amplist = ad1882_loopbacks;
3339#endif
3249 3340
3250 codec->patch_ops = ad198x_patch_ops; 3341 codec->patch_ops = ad198x_patch_ops;
3251 3342