diff options
author | Takashi Iwai <tiwai@suse.de> | 2007-08-10 11:09:26 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2007-10-16 09:58:43 -0400 |
commit | 82beb8fd365afe3891b277c46425083f13e23c56 (patch) | |
tree | a564d7228b59170aa490d4fc9284b5fa4442adb0 /sound/pci/hda/patch_realtek.c | |
parent | b3ac56364126f78cae94eb2a75b72d9ea85aca9d (diff) |
[ALSA] hda-codec - optimize resume using caches
So far, the driver looked the table of snd_kcontrol_new used for creating
mixer elements and forces to call each of its put callbacks in PM resume
code. This is too ugly and hackish.
Now, the resume is simplified using the codec amp and command register
caches. The driver simply restores the values that have been written
in the cache table. With this simplification, most codec support codes
don't require any special resume callback.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci/hda/patch_realtek.c')
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 167 |
1 files changed, 87 insertions, 80 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 39c08bb670d1..63011133e3fb 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -442,8 +442,9 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, | |||
442 | change = pinctl != alc_pin_mode_values[val]; | 442 | change = pinctl != alc_pin_mode_values[val]; |
443 | if (change) { | 443 | if (change) { |
444 | /* Set pin mode to that requested */ | 444 | /* Set pin mode to that requested */ |
445 | snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL, | 445 | snd_hda_codec_write_cache(codec, nid, 0, |
446 | alc_pin_mode_values[val]); | 446 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
447 | alc_pin_mode_values[val]); | ||
447 | 448 | ||
448 | /* Also enable the retasking pin's input/output as required | 449 | /* Also enable the retasking pin's input/output as required |
449 | * for the requested pin mode. Enum values of 2 or less are | 450 | * for the requested pin mode. Enum values of 2 or less are |
@@ -456,19 +457,23 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, | |||
456 | * this turns out to be necessary in the future. | 457 | * this turns out to be necessary in the future. |
457 | */ | 458 | */ |
458 | if (val <= 2) { | 459 | if (val <= 2) { |
459 | snd_hda_codec_write(codec, nid, 0, | 460 | snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0, |
460 | AC_VERB_SET_AMP_GAIN_MUTE, | 461 | 0x80, 0x80); |
461 | AMP_OUT_MUTE); | 462 | snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0, |
462 | snd_hda_codec_write(codec, nid, 0, | 463 | 0x80, 0x80); |
463 | AC_VERB_SET_AMP_GAIN_MUTE, | 464 | snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, 0, |
464 | AMP_IN_UNMUTE(0)); | 465 | 0x80, 0x00); |
466 | snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, 0, | ||
467 | 0x80, 0x00); | ||
465 | } else { | 468 | } else { |
466 | snd_hda_codec_write(codec, nid, 0, | 469 | snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, 0, |
467 | AC_VERB_SET_AMP_GAIN_MUTE, | 470 | 0x80, 0x80); |
468 | AMP_IN_MUTE(0)); | 471 | snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, 0, |
469 | snd_hda_codec_write(codec, nid, 0, | 472 | 0x80, 0x80); |
470 | AC_VERB_SET_AMP_GAIN_MUTE, | 473 | snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0, |
471 | AMP_OUT_UNMUTE); | 474 | 0x80, 0x00); |
475 | snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0, | ||
476 | 0x80, 0x00); | ||
472 | } | 477 | } |
473 | } | 478 | } |
474 | return change; | 479 | return change; |
@@ -520,7 +525,8 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, | |||
520 | gpio_data &= ~mask; | 525 | gpio_data &= ~mask; |
521 | else | 526 | else |
522 | gpio_data |= mask; | 527 | gpio_data |= mask; |
523 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data); | 528 | snd_hda_codec_write_cache(codec, nid, 0, |
529 | AC_VERB_SET_GPIO_DATA, gpio_data); | ||
524 | 530 | ||
525 | return change; | 531 | return change; |
526 | } | 532 | } |
@@ -573,8 +579,8 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, | |||
573 | ctrl_data &= ~mask; | 579 | ctrl_data &= ~mask; |
574 | else | 580 | else |
575 | ctrl_data |= mask; | 581 | ctrl_data |= mask; |
576 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | 582 | snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, |
577 | ctrl_data); | 583 | ctrl_data); |
578 | 584 | ||
579 | return change; | 585 | return change; |
580 | } | 586 | } |
@@ -2026,27 +2032,6 @@ static void alc_unsol_event(struct hda_codec *codec, unsigned int res) | |||
2026 | spec->unsol_event(codec, res); | 2032 | spec->unsol_event(codec, res); |
2027 | } | 2033 | } |
2028 | 2034 | ||
2029 | #ifdef CONFIG_PM | ||
2030 | /* | ||
2031 | * resume | ||
2032 | */ | ||
2033 | static int alc_resume(struct hda_codec *codec) | ||
2034 | { | ||
2035 | struct alc_spec *spec = codec->spec; | ||
2036 | int i; | ||
2037 | |||
2038 | alc_init(codec); | ||
2039 | for (i = 0; i < spec->num_mixers; i++) | ||
2040 | snd_hda_resume_ctls(codec, spec->mixers[i]); | ||
2041 | if (spec->multiout.dig_out_nid) | ||
2042 | snd_hda_resume_spdif_out(codec); | ||
2043 | if (spec->dig_in_nid) | ||
2044 | snd_hda_resume_spdif_in(codec); | ||
2045 | |||
2046 | return 0; | ||
2047 | } | ||
2048 | #endif | ||
2049 | |||
2050 | /* | 2035 | /* |
2051 | * Analog playback callbacks | 2036 | * Analog playback callbacks |
2052 | */ | 2037 | */ |
@@ -2278,9 +2263,6 @@ static struct hda_codec_ops alc_patch_ops = { | |||
2278 | .init = alc_init, | 2263 | .init = alc_init, |
2279 | .free = alc_free, | 2264 | .free = alc_free, |
2280 | .unsol_event = alc_unsol_event, | 2265 | .unsol_event = alc_unsol_event, |
2281 | #ifdef CONFIG_PM | ||
2282 | .resume = alc_resume, | ||
2283 | #endif | ||
2284 | }; | 2266 | }; |
2285 | 2267 | ||
2286 | 2268 | ||
@@ -2377,11 +2359,15 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, | |||
2377 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | 2359 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); |
2378 | new_ctl = ctls[ucontrol->value.enumerated.item[0]]; | 2360 | new_ctl = ctls[ucontrol->value.enumerated.item[0]]; |
2379 | if (old_ctl != new_ctl) { | 2361 | if (old_ctl != new_ctl) { |
2380 | snd_hda_codec_write(codec, nid, 0, | 2362 | int val; |
2381 | AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); | 2363 | snd_hda_codec_write_cache(codec, nid, 0, |
2382 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 2364 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
2383 | (ucontrol->value.enumerated.item[0] >= 3 ? | 2365 | new_ctl); |
2384 | 0xb080 : 0xb000)); | 2366 | val = ucontrol->value.enumerated.item[0] >= 3 ? 0x80 : 0x00; |
2367 | snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0, | ||
2368 | 0x80, val); | ||
2369 | snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0, | ||
2370 | 0x80, val); | ||
2385 | return 1; | 2371 | return 1; |
2386 | } | 2372 | } |
2387 | return 0; | 2373 | return 0; |
@@ -2424,7 +2410,8 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, | |||
2424 | sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; | 2410 | sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; |
2425 | if (ucontrol->value.enumerated.item[0] != sel) { | 2411 | if (ucontrol->value.enumerated.item[0] != sel) { |
2426 | sel = ucontrol->value.enumerated.item[0] & 3; | 2412 | sel = ucontrol->value.enumerated.item[0] & 3; |
2427 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel); | 2413 | snd_hda_codec_write_cache(codec, nid, 0, |
2414 | AC_VERB_SET_CONNECT_SEL, sel); | ||
2428 | return 1; | 2415 | return 1; |
2429 | } | 2416 | } |
2430 | return 0; | 2417 | return 0; |
@@ -4054,13 +4041,17 @@ static void alc260_replacer_672v_automute(struct hda_codec *codec) | |||
4054 | present = snd_hda_codec_read(codec, 0x0f, 0, | 4041 | present = snd_hda_codec_read(codec, 0x0f, 0, |
4055 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 4042 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
4056 | if (present) { | 4043 | if (present) { |
4057 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 1); | 4044 | snd_hda_codec_write_cache(codec, 0x01, 0, |
4058 | snd_hda_codec_write(codec, 0x0f, 0, | 4045 | AC_VERB_SET_GPIO_DATA, 1); |
4059 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); | 4046 | snd_hda_codec_write_cache(codec, 0x0f, 0, |
4047 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
4048 | PIN_HP); | ||
4060 | } else { | 4049 | } else { |
4061 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); | 4050 | snd_hda_codec_write_cache(codec, 0x01, 0, |
4062 | snd_hda_codec_write(codec, 0x0f, 0, | 4051 | AC_VERB_SET_GPIO_DATA, 0); |
4063 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | 4052 | snd_hda_codec_write_cache(codec, 0x0f, 0, |
4053 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
4054 | PIN_OUT); | ||
4064 | } | 4055 | } |
4065 | } | 4056 | } |
4066 | 4057 | ||
@@ -4797,12 +4788,16 @@ static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
4797 | idx = ucontrol->value.enumerated.item[0]; | 4788 | idx = ucontrol->value.enumerated.item[0]; |
4798 | if (idx >= imux->num_items) | 4789 | if (idx >= imux->num_items) |
4799 | idx = imux->num_items - 1; | 4790 | idx = imux->num_items - 1; |
4800 | if (*cur_val == idx && !codec->in_resume) | 4791 | if (*cur_val == idx) |
4801 | return 0; | 4792 | return 0; |
4802 | for (i = 0; i < imux->num_items; i++) { | 4793 | for (i = 0; i < imux->num_items; i++) { |
4803 | unsigned int v = (i == idx) ? 0x7000 : 0x7080; | 4794 | unsigned int v = (i == idx) ? 0x00 : 0x80; |
4804 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 4795 | snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, |
4805 | v | (imux->items[i].index << 8)); | 4796 | imux->items[i].index, |
4797 | 0x80, v); | ||
4798 | snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, | ||
4799 | imux->items[i].index, | ||
4800 | 0x80, v); | ||
4806 | } | 4801 | } |
4807 | *cur_val = idx; | 4802 | *cur_val = idx; |
4808 | return 1; | 4803 | return 1; |
@@ -5187,7 +5182,8 @@ static void alc882_targa_automute(struct hda_codec *codec) | |||
5187 | 0x80, present ? 0x80 : 0); | 5182 | 0x80, present ? 0x80 : 0); |
5188 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | 5183 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, |
5189 | 0x80, present ? 0x80 : 0); | 5184 | 0x80, present ? 0x80 : 0); |
5190 | snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3); | 5185 | snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, |
5186 | present ? 1 : 3); | ||
5191 | } | 5187 | } |
5192 | 5188 | ||
5193 | static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) | 5189 | static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) |
@@ -5777,12 +5773,16 @@ static int alc883_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
5777 | idx = ucontrol->value.enumerated.item[0]; | 5773 | idx = ucontrol->value.enumerated.item[0]; |
5778 | if (idx >= imux->num_items) | 5774 | if (idx >= imux->num_items) |
5779 | idx = imux->num_items - 1; | 5775 | idx = imux->num_items - 1; |
5780 | if (*cur_val == idx && !codec->in_resume) | 5776 | if (*cur_val == idx) |
5781 | return 0; | 5777 | return 0; |
5782 | for (i = 0; i < imux->num_items; i++) { | 5778 | for (i = 0; i < imux->num_items; i++) { |
5783 | unsigned int v = (i == idx) ? 0x7000 : 0x7080; | 5779 | unsigned int v = (i == idx) ? 0x00 : 0x80; |
5784 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 5780 | snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, |
5785 | v | (imux->items[i].index << 8)); | 5781 | imux->items[i].index, |
5782 | 0x80, v); | ||
5783 | snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, | ||
5784 | imux->items[i].index, | ||
5785 | 0x80, v); | ||
5786 | } | 5786 | } |
5787 | *cur_val = idx; | 5787 | *cur_val = idx; |
5788 | return 1; | 5788 | return 1; |
@@ -6509,8 +6509,8 @@ static void alc883_tagra_automute(struct hda_codec *codec) | |||
6509 | 0x80, bits); | 6509 | 0x80, bits); |
6510 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | 6510 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, |
6511 | 0x80, bits); | 6511 | 0x80, bits); |
6512 | snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, | 6512 | snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, |
6513 | present ? 1 : 3); | 6513 | present ? 1 : 3); |
6514 | } | 6514 | } |
6515 | 6515 | ||
6516 | static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) | 6516 | static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) |
@@ -7510,8 +7510,8 @@ static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, | |||
7510 | 0x80, valp[0] ? 0 : 0x80); | 7510 | 0x80, valp[0] ? 0 : 0x80); |
7511 | change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | 7511 | change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, |
7512 | 0x80, valp[1] ? 0 : 0x80); | 7512 | 0x80, valp[1] ? 0 : 0x80); |
7513 | if (change || codec->in_resume) | 7513 | if (change) |
7514 | alc262_fujitsu_automute(codec, codec->in_resume); | 7514 | alc262_fujitsu_automute(codec, 0); |
7515 | return change; | 7515 | return change; |
7516 | } | 7516 | } |
7517 | 7517 | ||
@@ -8328,14 +8328,17 @@ static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
8328 | idx = ucontrol->value.enumerated.item[0]; | 8328 | idx = ucontrol->value.enumerated.item[0]; |
8329 | if (idx >= imux->num_items) | 8329 | if (idx >= imux->num_items) |
8330 | idx = imux->num_items - 1; | 8330 | idx = imux->num_items - 1; |
8331 | if (*cur_val == idx && !codec->in_resume) | 8331 | if (*cur_val == idx) |
8332 | return 0; | 8332 | return 0; |
8333 | for (i = 0; i < imux->num_items; i++) { | 8333 | for (i = 0; i < imux->num_items; i++) { |
8334 | unsigned int v = (i == idx) ? 0x7000 : 0x7080; | 8334 | unsigned int v = (i == idx) ? 0x00 : 0x80; |
8335 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 8335 | snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, |
8336 | v | (imux->items[i].index << 8)); | 8336 | imux->items[i].index, 0x80, v); |
8337 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, | 8337 | snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, |
8338 | idx ); | 8338 | imux->items[i].index, 0x80, v); |
8339 | snd_hda_codec_write_cache(codec, nid, 0, | ||
8340 | AC_VERB_SET_CONNECT_SEL, | ||
8341 | idx ); | ||
8339 | } | 8342 | } |
8340 | *cur_val = idx; | 8343 | *cur_val = idx; |
8341 | return 1; | 8344 | return 1; |
@@ -9916,12 +9919,14 @@ static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
9916 | idx = ucontrol->value.enumerated.item[0]; | 9919 | idx = ucontrol->value.enumerated.item[0]; |
9917 | if (idx >= imux->num_items) | 9920 | if (idx >= imux->num_items) |
9918 | idx = imux->num_items - 1; | 9921 | idx = imux->num_items - 1; |
9919 | if (*cur_val == idx && !codec->in_resume) | 9922 | if (*cur_val == idx) |
9920 | return 0; | 9923 | return 0; |
9921 | for (i = 0; i < imux->num_items; i++) { | 9924 | for (i = 0; i < imux->num_items; i++) { |
9922 | unsigned int v = (i == idx) ? 0x7000 : 0x7080; | 9925 | unsigned int v = (i == idx) ? 0x00 : 0x80; |
9923 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 9926 | snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, |
9924 | v | (imux->items[i].index << 8)); | 9927 | imux->items[i].index, 0x80, v); |
9928 | snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, | ||
9929 | imux->items[i].index, 0x80, v); | ||
9925 | } | 9930 | } |
9926 | *cur_val = idx; | 9931 | *cur_val = idx; |
9927 | return 1; | 9932 | return 1; |
@@ -10847,12 +10852,14 @@ static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
10847 | idx = ucontrol->value.enumerated.item[0]; | 10852 | idx = ucontrol->value.enumerated.item[0]; |
10848 | if (idx >= imux->num_items) | 10853 | if (idx >= imux->num_items) |
10849 | idx = imux->num_items - 1; | 10854 | idx = imux->num_items - 1; |
10850 | if (*cur_val == idx && !codec->in_resume) | 10855 | if (*cur_val == idx) |
10851 | return 0; | 10856 | return 0; |
10852 | for (i = 0; i < imux->num_items; i++) { | 10857 | for (i = 0; i < imux->num_items; i++) { |
10853 | unsigned int v = (i == idx) ? 0x7000 : 0x7080; | 10858 | unsigned int v = (i == idx) ? 0x00 : 0x80; |
10854 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 10859 | snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, |
10855 | v | (imux->items[i].index << 8)); | 10860 | imux->items[i].index, 0x80, v); |
10861 | snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, | ||
10862 | imux->items[i].index, 0x80, v); | ||
10856 | } | 10863 | } |
10857 | *cur_val = idx; | 10864 | *cur_val = idx; |
10858 | return 1; | 10865 | return 1; |