aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_via.c
diff options
context:
space:
mode:
authorLydia Wang <lydiawang@viatech.com.cn>2009-10-10 07:07:35 -0400
committerTakashi Iwai <tiwai@suse.de>2009-10-11 11:54:47 -0400
commitf5271101faf1655d862849f42518c2a88ef394fb (patch)
tree9a83d326430df953640c25262305d0fefa15dbed /sound/pci/hda/patch_via.c
parentc2c02ea326d3683f551120e74a297b354a223357 (diff)
ALSA HDA VIA: Add VIA_CTL_WIDGET_ANALOG_MUTE control type
Enter low power state if AA-Path volume is muted. Signed-off-by: Lydia Wang <lydiawang@viatech.com.cn> Signed-off-by: Logan Li <loganli@viatech.com.cn> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_via.c')
-rw-r--r--sound/pci/hda/patch_via.c240
1 files changed, 239 insertions, 1 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index e62698984287..d6bee620ced6 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -128,6 +128,7 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
128enum { 128enum {
129 VIA_CTL_WIDGET_VOL, 129 VIA_CTL_WIDGET_VOL,
130 VIA_CTL_WIDGET_MUTE, 130 VIA_CTL_WIDGET_MUTE,
131 VIA_CTL_WIDGET_ANALOG_MUTE,
131}; 132};
132 133
133enum { 134enum {
@@ -177,9 +178,34 @@ static int mic_boost_volume_info(struct snd_kcontrol *kcontrol,
177 return 0; 178 return 0;
178} 179}
179 180
181static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
182static void set_jack_power_state(struct hda_codec *codec);
183
184static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
185 struct snd_ctl_elem_value *ucontrol)
186{
187 int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
188 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
189
190 set_jack_power_state(codec);
191 analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
192 return change;
193}
194
195/* modify .put = snd_hda_mixer_amp_switch_put */
196#define ANALOG_INPUT_MUTE \
197 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
198 .name = NULL, \
199 .index = 0, \
200 .info = snd_hda_mixer_amp_switch_info, \
201 .get = snd_hda_mixer_amp_switch_get, \
202 .put = analog_input_switch_put, \
203 .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
204
180static struct snd_kcontrol_new vt1708_control_templates[] = { 205static struct snd_kcontrol_new vt1708_control_templates[] = {
181 HDA_CODEC_VOLUME(NULL, 0, 0, 0), 206 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
182 HDA_CODEC_MUTE(NULL, 0, 0, 0), 207 HDA_CODEC_MUTE(NULL, 0, 0, 0),
208 ANALOG_INPUT_MUTE,
183}; 209};
184 210
185 211
@@ -303,7 +329,7 @@ static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
303 if (err < 0) 329 if (err < 0)
304 return err; 330 return err;
305 sprintf(name, "%s Playback Switch", ctlname); 331 sprintf(name, "%s Playback Switch", ctlname);
306 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, 332 err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name,
307 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); 333 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
308 if (err < 0) 334 if (err < 0)
309 return err; 335 return err;
@@ -362,6 +388,131 @@ static void via_auto_init_analog_input(struct hda_codec *codec)
362 388
363 } 389 }
364} 390}
391
392static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
393 unsigned int *affected_parm)
394{
395 unsigned parm;
396 unsigned def_conf = snd_hda_codec_get_pincfg(codec, nid);
397 unsigned no_presence = (def_conf & AC_DEFCFG_MISC)
398 >> AC_DEFCFG_MISC_SHIFT
399 & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
400 unsigned present = snd_hda_codec_read(codec, nid, 0,
401 AC_VERB_GET_PIN_SENSE, 0) >> 31;
402
403 if ((no_presence || present) && get_defcfg_connect(def_conf)
404 != AC_JACK_PORT_NONE) {
405 *affected_parm = AC_PWRST_D0; /* if it's connected */
406 parm = AC_PWRST_D0;
407 } else
408 parm = AC_PWRST_D3;
409
410 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
411}
412
413static void set_jack_power_state(struct hda_codec *codec)
414{
415 struct via_spec *spec = codec->spec;
416 int imux_is_smixer;
417 unsigned int parm;
418
419 if (spec->codec_type == VT1702) {
420 imux_is_smixer = snd_hda_codec_read(
421 codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
422 /* inputs */
423 /* PW 1/2/5 (14h/15h/18h) */
424 parm = AC_PWRST_D3;
425 set_pin_power_state(codec, 0x14, &parm);
426 set_pin_power_state(codec, 0x15, &parm);
427 set_pin_power_state(codec, 0x18, &parm);
428 if (imux_is_smixer)
429 parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */
430 /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
431 snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
432 parm);
433 snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE,
434 parm);
435 snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
436 parm);
437 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE,
438 parm);
439
440 /* outputs */
441 /* PW 3/4 (16h/17h) */
442 parm = AC_PWRST_D3;
443 set_pin_power_state(codec, 0x16, &parm);
444 set_pin_power_state(codec, 0x17, &parm);
445 /* MW0 (1ah), AOW 0/1 (10h/1dh) */
446 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
447 imux_is_smixer ? AC_PWRST_D0 : parm);
448 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
449 parm);
450 snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE,
451 parm);
452 } else if (spec->codec_type == VT1708B_8CH
453 || spec->codec_type == VT1708B_4CH
454 || spec->codec_type == VT1708S) {
455 /* SW0 (17h) = stereo mixer */
456 int is_8ch = spec->codec_type != VT1708B_4CH;
457 imux_is_smixer = snd_hda_codec_read(
458 codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
459 == ((spec->codec_type == VT1708S) ? 5 : 0);
460 /* inputs */
461 /* PW 1/2/5 (1ah/1bh/1eh) */
462 parm = AC_PWRST_D3;
463 set_pin_power_state(codec, 0x1a, &parm);
464 set_pin_power_state(codec, 0x1b, &parm);
465 set_pin_power_state(codec, 0x1e, &parm);
466 if (imux_is_smixer)
467 parm = AC_PWRST_D0;
468 /* SW0 (17h), AIW 0/1 (13h/14h) */
469 snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
470 parm);
471 snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
472 parm);
473 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
474 parm);
475
476 /* outputs */
477 /* PW0 (19h), SW1 (18h), AOW1 (11h) */
478 parm = AC_PWRST_D3;
479 set_pin_power_state(codec, 0x19, &parm);
480 snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
481 parm);
482 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
483 parm);
484
485 /* PW6 (22h), SW2 (26h), AOW2 (24h) */
486 if (is_8ch) {
487 parm = AC_PWRST_D3;
488 set_pin_power_state(codec, 0x22, &parm);
489 snd_hda_codec_write(codec, 0x26, 0,
490 AC_VERB_SET_POWER_STATE, parm);
491 snd_hda_codec_write(codec, 0x24, 0,
492 AC_VERB_SET_POWER_STATE, parm);
493 }
494
495 /* PW 3/4/7 (1ch/1dh/23h) */
496 parm = AC_PWRST_D3;
497 /* force to D0 for internal Speaker */
498 set_pin_power_state(codec, 0x1c, &parm);
499 set_pin_power_state(codec, 0x1d, &parm);
500 if (is_8ch)
501 set_pin_power_state(codec, 0x23, &parm);
502 /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
503 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
504 imux_is_smixer ? AC_PWRST_D0 : parm);
505 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
506 parm);
507 if (is_8ch) {
508 snd_hda_codec_write(codec, 0x25, 0,
509 AC_VERB_SET_POWER_STATE, parm);
510 snd_hda_codec_write(codec, 0x27, 0,
511 AC_VERB_SET_POWER_STATE, parm);
512 }
513 }
514}
515
365/* 516/*
366 * input MUX handling 517 * input MUX handling
367 */ 518 */
@@ -504,6 +655,93 @@ static struct snd_kcontrol_new vt1708_capture_mixer[] = {
504 }, 655 },
505 { } /* end */ 656 { } /* end */
506}; 657};
658
659/* check AA path's mute statue */
660static int is_aa_path_mute(struct hda_codec *codec)
661{
662 int mute = 1;
663 hda_nid_t nid_mixer;
664 int start_idx;
665 int end_idx;
666 int i;
667 struct via_spec *spec = codec->spec;
668 /* get nid of MW0 and start & end index */
669 switch (spec->codec_type) {
670 case VT1708B_8CH:
671 case VT1708B_4CH:
672 case VT1708S:
673 nid_mixer = 0x16;
674 start_idx = 2;
675 end_idx = 4;
676 break;
677 case VT1702:
678 nid_mixer = 0x1a;
679 start_idx = 1;
680 end_idx = 3;
681 break;
682 default:
683 return 0;
684 }
685 /* check AA path's mute status */
686 for (i = start_idx; i <= end_idx; i++) {
687 unsigned int con_list = snd_hda_codec_read(
688 codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4);
689 int shift = 8 * (i % 4);
690 hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift;
691 unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin);
692 if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) {
693 /* check mute status while the pin is connected */
694 int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0,
695 HDA_INPUT, i) >> 7;
696 int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1,
697 HDA_INPUT, i) >> 7;
698 if (!mute_l || !mute_r) {
699 mute = 0;
700 break;
701 }
702 }
703 }
704 return mute;
705}
706
707/* enter/exit analog low-current mode */
708static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
709{
710 struct via_spec *spec = codec->spec;
711 static int saved_stream_idle = 1; /* saved stream idle status */
712 int enable = is_aa_path_mute(codec);
713 unsigned int verb = 0;
714 unsigned int parm = 0;
715
716 if (stream_idle == -1) /* stream status did not change */
717 enable = enable && saved_stream_idle;
718 else {
719 enable = enable && stream_idle;
720 saved_stream_idle = stream_idle;
721 }
722
723 /* decide low current mode's verb & parameter */
724 switch (spec->codec_type) {
725 case VT1708B_8CH:
726 case VT1708B_4CH:
727 verb = 0xf70;
728 parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */
729 break;
730 case VT1708S:
731 verb = 0xf73;
732 parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */
733 break;
734 case VT1702:
735 verb = 0xf73;
736 parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */
737 break;
738 default:
739 return; /* other codecs are not supported */
740 }
741 /* send verb */
742 snd_hda_codec_write(codec, codec->afg, 0, verb, parm);
743}
744
507/* 745/*
508 * generic initialization of ADC, input mixers and output mixers 746 * generic initialization of ADC, input mixers and output mixers
509 */ 747 */