diff options
Diffstat (limited to 'sound/pci/hda/patch_via.c')
-rw-r--r-- | sound/pci/hda/patch_via.c | 1526 |
1 files changed, 864 insertions, 662 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 0997031c48d..605c99e1e52 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -98,24 +98,30 @@ enum VIA_HDA_CODEC { VT1716S, VT2002P, VT1812, + VT1802, CODEC_TYPES, }; +#define VT2002P_COMPATIBLE(spec) \ + ((spec)->codec_type == VT2002P ||\ + (spec)->codec_type == VT1812 ||\ + (spec)->codec_type == VT1802) + struct via_spec { /* codec parameterization */ - struct snd_kcontrol_new *mixers[6]; + const struct snd_kcontrol_new *mixers[6]; unsigned int num_mixers; - struct hda_verb *init_verbs[5]; + const struct hda_verb *init_verbs[5]; unsigned int num_iverbs; char *stream_name_analog; - struct hda_pcm_stream *stream_analog_playback; - struct hda_pcm_stream *stream_analog_capture; + const struct hda_pcm_stream *stream_analog_playback; + const struct hda_pcm_stream *stream_analog_capture; char *stream_name_digital; - struct hda_pcm_stream *stream_digital_playback; - struct hda_pcm_stream *stream_digital_capture; + const struct hda_pcm_stream *stream_digital_playback; + const struct hda_pcm_stream *stream_digital_capture; /* playback */ struct hda_multi_out multiout; @@ -123,7 +129,7 @@ struct via_spec { /* capture */ unsigned int num_adc_nids; - hda_nid_t *adc_nids; + const hda_nid_t *adc_nids; hda_nid_t mux_nids[3]; hda_nid_t dig_in_nid; hda_nid_t dig_in_pin; @@ -154,6 +160,9 @@ struct via_spec { struct delayed_work vt1708_hp_work; int vt1708_jack_detectect; int vt1708_hp_present; + + void (*set_widgets_power_state)(struct hda_codec *codec); + #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; #endif @@ -218,17 +227,19 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) codec_type = VT1812; else if (dev_id == 0x0440) codec_type = VT1708S; + else if ((dev_id & 0xfff) == 0x446) + codec_type = VT1802; else codec_type = UNKNOWN; return codec_type; }; +#define VIA_JACK_EVENT 0x20 #define VIA_HP_EVENT 0x01 #define VIA_GPIO_EVENT 0x02 -#define VIA_JACK_EVENT 0x04 -#define VIA_MONO_EVENT 0x08 -#define VIA_SPEAKER_EVENT 0x10 -#define VIA_BIND_HP_EVENT 0x20 +#define VIA_MONO_EVENT 0x03 +#define VIA_SPEAKER_EVENT 0x04 +#define VIA_BIND_HP_EVENT 0x05 enum { VIA_CTL_WIDGET_VOL, @@ -245,7 +256,6 @@ enum { }; static void analog_low_current_mode(struct hda_codec *codec, int stream_idle); -static void set_jack_power_state(struct hda_codec *codec); static int is_aa_path_mute(struct hda_codec *codec); static void vt1708_start_hp_work(struct via_spec *spec) @@ -271,6 +281,12 @@ static void vt1708_stop_hp_work(struct via_spec *spec) cancel_delayed_work_sync(&spec->vt1708_hp_work); } +static void set_widgets_power_state(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + if (spec->set_widgets_power_state) + spec->set_widgets_power_state(codec); +} static int analog_input_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -278,7 +294,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol, int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - set_jack_power_state(codec); + set_widgets_power_state(codec); analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1); if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) { if (is_aa_path_mute(codec)) @@ -394,54 +410,54 @@ static int bind_pin_switch_put(struct snd_kcontrol *kcontrol, .put = bind_pin_switch_put, \ .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } -static struct snd_kcontrol_new via_control_templates[] = { +static const struct snd_kcontrol_new via_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), ANALOG_INPUT_MUTE, BIND_PIN_MUTE, }; -static hda_nid_t vt1708_adc_nids[2] = { +static const hda_nid_t vt1708_adc_nids[2] = { /* ADC1-2 */ 0x15, 0x27 }; -static hda_nid_t vt1709_adc_nids[3] = { +static const hda_nid_t vt1709_adc_nids[3] = { /* ADC1-2 */ 0x14, 0x15, 0x16 }; -static hda_nid_t vt1708B_adc_nids[2] = { +static const hda_nid_t vt1708B_adc_nids[2] = { /* ADC1-2 */ 0x13, 0x14 }; -static hda_nid_t vt1708S_adc_nids[2] = { +static const hda_nid_t vt1708S_adc_nids[2] = { /* ADC1-2 */ 0x13, 0x14 }; -static hda_nid_t vt1702_adc_nids[3] = { +static const hda_nid_t vt1702_adc_nids[3] = { /* ADC1-2 */ 0x12, 0x20, 0x1F }; -static hda_nid_t vt1718S_adc_nids[2] = { +static const hda_nid_t vt1718S_adc_nids[2] = { /* ADC1-2 */ 0x10, 0x11 }; -static hda_nid_t vt1716S_adc_nids[2] = { +static const hda_nid_t vt1716S_adc_nids[2] = { /* ADC1-2 */ 0x13, 0x14 }; -static hda_nid_t vt2002P_adc_nids[2] = { +static const hda_nid_t vt2002P_adc_nids[2] = { /* ADC1-2 */ 0x10, 0x11 }; -static hda_nid_t vt1812_adc_nids[2] = { +static const hda_nid_t vt1812_adc_nids[2] = { /* ADC1-2 */ 0x10, 0x11 }; @@ -471,7 +487,7 @@ static int __via_add_control(struct via_spec *spec, int type, const char *name, __via_add_control(spec, type, name, 0, val) static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec, - struct snd_kcontrol_new *tmpl) + const struct snd_kcontrol_new *tmpl) { struct snd_kcontrol_new *knew; @@ -602,482 +618,6 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); } -static void set_jack_power_state(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int imux_is_smixer; - unsigned int parm; - - if (spec->codec_type == VT1702) { - imux_is_smixer = snd_hda_codec_read( - codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; - /* inputs */ - /* PW 1/2/5 (14h/15h/18h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x14, &parm); - set_pin_power_state(codec, 0x15, &parm); - set_pin_power_state(codec, 0x18, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */ - /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */ - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW 3/4 (16h/17h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x16, &parm); - set_pin_power_state(codec, 0x17, &parm); - /* MW0 (1ah), AOW 0/1 (10h/1dh) */ - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, - parm); - } else if (spec->codec_type == VT1708B_8CH - || spec->codec_type == VT1708B_4CH - || spec->codec_type == VT1708S) { - /* SW0 (17h) = stereo mixer */ - int is_8ch = spec->codec_type != VT1708B_4CH; - imux_is_smixer = snd_hda_codec_read( - codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) - == ((spec->codec_type == VT1708S) ? 5 : 0); - /* inputs */ - /* PW 1/2/5 (1ah/1bh/1eh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1a, &parm); - set_pin_power_state(codec, 0x1b, &parm); - set_pin_power_state(codec, 0x1e, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* SW0 (17h), AIW 0/1 (13h/14h) */ - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW0 (19h), SW1 (18h), AOW1 (11h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x19, &parm); - if (spec->smart51_enabled) - parm = AC_PWRST_D0; - snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW6 (22h), SW2 (26h), AOW2 (24h) */ - if (is_8ch) { - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x22, &parm); - if (spec->smart51_enabled) - parm = AC_PWRST_D0; - snd_hda_codec_write(codec, 0x26, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x24, 0, - AC_VERB_SET_POWER_STATE, parm); - } - - /* PW 3/4/7 (1ch/1dh/23h) */ - parm = AC_PWRST_D3; - /* force to D0 for internal Speaker */ - set_pin_power_state(codec, 0x1c, &parm); - set_pin_power_state(codec, 0x1d, &parm); - if (is_8ch) - set_pin_power_state(codec, 0x23, &parm); - /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */ - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - parm); - if (is_8ch) { - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x27, 0, - AC_VERB_SET_POWER_STATE, parm); - } - } else if (spec->codec_type == VT1718S) { - /* MUX6 (1eh) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; - /* inputs */ - /* PW 5/6/7 (29h/2ah/2bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x29, &parm); - set_pin_power_state(codec, 0x2a, &parm); - set_pin_power_state(codec, 0x2b, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW3 (27h), MW2 (1ah), AOW3 (bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x27, &parm); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW2 (26h), AOW2 (ah) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x26, &parm); - snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW0/1 (24h/25h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x24, &parm); - set_pin_power_state(codec, 0x25, &parm); - if (!spec->hp_independent_mode) /* check for redirected HP */ - set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, - parm); - /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ - snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - if (spec->hp_independent_mode) { - /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x1b, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0xc, 0, - AC_VERB_SET_POWER_STATE, parm); - } - } else if (spec->codec_type == VT1716S) { - unsigned int mono_out, present; - /* SW0 (17h) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; - /* inputs */ - /* PW 1/2/5 (1ah/1bh/1eh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1a, &parm); - set_pin_power_state(codec, 0x1b, &parm); - set_pin_power_state(codec, 0x1e, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* SW0 (17h), AIW0(13h) */ - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, - parm); - - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1e, &parm); - /* PW11 (22h) */ - if (spec->dmic_enabled) - set_pin_power_state(codec, 0x22, &parm); - else - snd_hda_codec_write( - codec, 0x22, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - - /* SW2(26h), AIW1(14h) */ - snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW0 (19h), SW1 (18h), AOW1 (11h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x19, &parm); - /* Smart 5.1 PW2(1bh) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1b, &parm); - snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW7 (23h), SW3 (27h), AOW3 (25h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x23, &parm); - /* Smart 5.1 PW1(1ah) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1a, &parm); - snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* Smart 5.1 PW5(1eh) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1e, &parm); - snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* Mono out */ - /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ - present = snd_hda_jack_detect(codec, 0x1c); - if (present) - mono_out = 0; - else { - present = snd_hda_jack_detect(codec, 0x1d); - if (!spec->hp_independent_mode && present) - mono_out = 0; - else - mono_out = 1; - } - parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; - snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW 3/4 (1ch/1dh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1c, &parm); - set_pin_power_state(codec, 0x1d, &parm); - /* HP Independent Mode, power on AOW3 */ - if (spec->hp_independent_mode) - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* force to D0 for internal Speaker */ - /* MW0 (16h), AOW0 (10h) */ - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - mono_out ? AC_PWRST_D0 : parm); - } else if (spec->codec_type == VT2002P) { - unsigned int present; - /* MUX9 (1eh) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; - /* inputs */ - /* PW 5/6/7 (29h/2ah/2bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x29, &parm); - set_pin_power_state(codec, 0x2a, &parm); - set_pin_power_state(codec, 0x2b, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1f, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x10, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x11, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* outputs */ - /* AOW0 (8h)*/ - snd_hda_codec_write(codec, 0x8, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - - /* PW4 (26h), MW4 (1ch), MUX4(37h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x26, &parm); - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x37, - 0, AC_VERB_SET_POWER_STATE, parm); - - /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x25, &parm); - snd_hda_codec_write(codec, 0x19, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x35, 0, - AC_VERB_SET_POWER_STATE, parm); - if (spec->hp_independent_mode) { - snd_hda_codec_write(codec, 0x9, 0, - AC_VERB_SET_POWER_STATE, parm); - } - - /* Class-D */ - /* PW0 (24h), MW0(18h), MUX0(34h) */ - present = snd_hda_jack_detect(codec, 0x25); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x24, &parm); - if (present) { - snd_hda_codec_write( - codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - snd_hda_codec_write( - codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } else { - snd_hda_codec_write( - codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - snd_hda_codec_write( - codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - } - - /* Mono Out */ - /* PW15 (31h), MW8(17h), MUX8(3bh) */ - present = snd_hda_jack_detect(codec, 0x26); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x31, &parm); - if (present) { - snd_hda_codec_write( - codec, 0x17, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - snd_hda_codec_write( - codec, 0x3b, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } else { - snd_hda_codec_write( - codec, 0x17, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - snd_hda_codec_write( - codec, 0x3b, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - } - - /* MW9 (21h) */ - if (imux_is_smixer || !is_aa_path_mute(codec)) - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - else - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } else if (spec->codec_type == VT1812) { - unsigned int present; - /* MUX10 (1eh) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; - /* inputs */ - /* PW 5/6/7 (29h/2ah/2bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x29, &parm); - set_pin_power_state(codec, 0x2a, &parm); - set_pin_power_state(codec, 0x2b, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1f, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x10, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x11, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* outputs */ - /* AOW0 (8h)*/ - snd_hda_codec_write(codec, 0x8, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - - /* PW4 (28h), MW4 (18h), MUX4(38h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x38, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x25, &parm); - snd_hda_codec_write(codec, 0x15, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x35, 0, - AC_VERB_SET_POWER_STATE, parm); - if (spec->hp_independent_mode) { - snd_hda_codec_write(codec, 0x9, 0, - AC_VERB_SET_POWER_STATE, parm); - } - - /* Internal Speaker */ - /* PW0 (24h), MW0(14h), MUX0(34h) */ - present = snd_hda_jack_detect(codec, 0x25); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x24, &parm); - if (present) { - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - } else { - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - } - /* Mono Out */ - /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */ - present = snd_hda_jack_detect(codec, 0x28); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x31, &parm); - if (present) { - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - snd_hda_codec_write(codec, 0x3c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - snd_hda_codec_write(codec, 0x3e, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - } else { - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - snd_hda_codec_write(codec, 0x3c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - snd_hda_codec_write(codec, 0x3e, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - } - - /* PW15 (33h), MW15 (1dh), MUX15(3dh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x33, &parm); - snd_hda_codec_write(codec, 0x1d, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x3d, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* MW9 (21h) */ - if (imux_is_smixer || !is_aa_path_mute(codec)) - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - else - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } -} - /* * input MUX handling */ @@ -1120,7 +660,7 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol, spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); /* update jack power state */ - set_jack_power_state(codec); + set_widgets_power_state(codec); return ret; } @@ -1168,6 +708,9 @@ static hda_nid_t side_mute_channel(struct via_spec *spec) case VT1709_10CH: return 0x29; case VT1708B_8CH: /* fall thru */ case VT1708S: return 0x27; + case VT2002P: return 0x19; + case VT1802: return 0x15; + case VT1812: return 0x15; default: return 0; } } @@ -1176,13 +719,22 @@ static int update_side_mute_status(struct hda_codec *codec) { /* mute side channel */ struct via_spec *spec = codec->spec; - unsigned int parm = spec->hp_independent_mode - ? AMP_OUT_MUTE : AMP_OUT_UNMUTE; + unsigned int parm; hda_nid_t sw3 = side_mute_channel(spec); - if (sw3) - snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE, - parm); + if (sw3) { + if (VT2002P_COMPATIBLE(spec)) + parm = spec->hp_independent_mode ? + AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1); + else + parm = spec->hp_independent_mode ? + AMP_OUT_MUTE : AMP_OUT_UNMUTE; + snd_hda_codec_write(codec, sw3, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm); + if (spec->codec_type == VT1812) + snd_hda_codec_write(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm); + } return 0; } @@ -1217,19 +769,18 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, || spec->codec_type == VT1702 || spec->codec_type == VT1718S || spec->codec_type == VT1716S - || spec->codec_type == VT2002P - || spec->codec_type == VT1812) { + || VT2002P_COMPATIBLE(spec)) { activate_ctl(codec, "Headphone Playback Volume", spec->hp_independent_mode); activate_ctl(codec, "Headphone Playback Switch", spec->hp_independent_mode); } /* update jack power state */ - set_jack_power_state(codec); + set_widgets_power_state(codec); return 0; } -static struct snd_kcontrol_new via_hp_mixer[2] = { +static const struct snd_kcontrol_new via_hp_mixer[2] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Independent HP", @@ -1256,6 +807,7 @@ static int via_hp_build(struct hda_codec *codec) nid = 0x34; break; case VT2002P: + case VT1802: nid = 0x35; break; case VT1812: @@ -1447,11 +999,11 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, } } spec->smart51_enabled = *ucontrol->value.integer.value; - set_jack_power_state(codec); + set_widgets_power_state(codec); return 1; } -static struct snd_kcontrol_new via_smart51_mixer[2] = { +static const struct snd_kcontrol_new via_smart51_mixer[2] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Smart 5.1", @@ -1473,6 +1025,11 @@ static int via_smart51_build(struct via_spec *spec) hda_nid_t nid; int i; + if (!cfg) + return 0; + if (cfg->line_outs > 2) + return 0; + knew = via_clone_control(spec, &via_smart51_mixer[0]); if (knew == NULL) return -ENOMEM; @@ -1492,7 +1049,7 @@ static int via_smart51_build(struct via_spec *spec) } /* capture mixer elements */ -static struct snd_kcontrol_new vt1708_capture_mixer[] = { +static const struct snd_kcontrol_new vt1708_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT), @@ -1543,6 +1100,7 @@ static int is_aa_path_mute(struct hda_codec *codec) break; case VT2002P: case VT1812: + case VT1802: nid_mixer = 0x21; start_idx = 0; end_idx = 2; @@ -1607,6 +1165,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) break; case VT2002P: case VT1812: + case VT1802: verb = 0xf93; parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ break; @@ -1620,7 +1179,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb vt1708_volume_init_verbs[] = { +static const struct hda_verb vt1708_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -1650,6 +1209,8 @@ static struct hda_verb vt1708_volume_init_verbs[] = { {0x20, AC_VERB_SET_CONNECT_SEL, 0}, /* PW9 Output enable */ {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* power down jack detect function */ + {0x1, 0xf81, 0x1}, { } }; @@ -1672,7 +1233,7 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec, { struct via_spec *spec = codec->spec; struct hda_multi_out *mout = &spec->multiout; - hda_nid_t *nids = mout->dac_nids; + const hda_nid_t *nids = mout->dac_nids; int chs = substream->runtime->channels; int i; @@ -1741,7 +1302,7 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, { struct via_spec *spec = codec->spec; struct hda_multi_out *mout = &spec->multiout; - hda_nid_t *nids = mout->dac_nids; + const hda_nid_t *nids = mout->dac_nids; if (substream->number == 0) playback_multi_pcm_prep_0(codec, stream_tag, format, @@ -1762,7 +1323,7 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, { struct via_spec *spec = codec->spec; struct hda_multi_out *mout = &spec->multiout; - hda_nid_t *nids = mout->dac_nids; + const hda_nid_t *nids = mout->dac_nids; int i; if (substream->number == 0) { @@ -1860,7 +1421,7 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream vt1708_pcm_analog_playback = { +static const struct hda_pcm_stream vt1708_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 8, @@ -1872,7 +1433,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { +static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { .substreams = 2, .channels_min = 2, .channels_max = 8, @@ -1889,7 +1450,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { }, }; -static struct hda_pcm_stream vt1708_pcm_analog_capture = { +static const struct hda_pcm_stream vt1708_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -1900,7 +1461,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1708_pcm_digital_playback = { +static const struct hda_pcm_stream vt1708_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -1913,7 +1474,7 @@ static struct hda_pcm_stream vt1708_pcm_digital_playback = { }, }; -static struct hda_pcm_stream vt1708_pcm_digital_capture = { +static const struct hda_pcm_stream vt1708_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -1923,7 +1484,7 @@ static int via_build_controls(struct hda_codec *codec) { struct via_spec *spec = codec->spec; struct snd_kcontrol *kctl; - struct snd_kcontrol_new *knew; + const struct snd_kcontrol_new *knew; int err, i; for (i = 0; i < spec->num_mixers; i++) { @@ -1971,7 +1532,7 @@ static int via_build_controls(struct hda_codec *codec) } /* init power states */ - set_jack_power_state(codec); + set_widgets_power_state(codec); analog_low_current_mode(codec, 1); via_free_kctls(codec); /* no longer needed */ @@ -2135,7 +1696,7 @@ static void via_speaker_automute(struct hda_codec *codec) unsigned int hp_present; struct via_spec *spec = codec->spec; - if (spec->codec_type != VT2002P && spec->codec_type != VT1812) + if (!VT2002P_COMPATIBLE(spec)) return; hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); @@ -2194,17 +1755,21 @@ static void via_unsol_event(struct hda_codec *codec, unsigned int res) { res >>= 26; - if (res & VIA_HP_EVENT) + + if (res & VIA_JACK_EVENT) + set_widgets_power_state(codec); + + res &= ~VIA_JACK_EVENT; + + if (res == VIA_HP_EVENT) via_hp_automute(codec); - if (res & VIA_GPIO_EVENT) + else if (res == VIA_GPIO_EVENT) via_gpio_control(codec); - if (res & VIA_JACK_EVENT) - set_jack_power_state(codec); - if (res & VIA_MONO_EVENT) + else if (res == VIA_MONO_EVENT) via_mono_automute(codec); - if (res & VIA_SPEAKER_EVENT) + else if (res == VIA_SPEAKER_EVENT) via_speaker_automute(codec); - if (res & VIA_BIND_HP_EVENT) + else if (res == VIA_BIND_HP_EVENT) via_hp_bind_automute(codec); } @@ -2254,7 +1819,7 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) /* */ -static struct hda_codec_ops via_patch_ops = { +static const struct hda_codec_ops via_patch_ops = { .build_controls = via_build_controls, .build_pcms = via_build_pcms, .init = via_init, @@ -2284,16 +1849,16 @@ static int vt1708_auto_fill_dac_nids(struct via_spec *spec, /* config dac list */ switch (i) { case AUTO_SEQ_FRONT: - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: - spec->multiout.dac_nids[i] = 0x12; + spec->private_dac_nids[i] = 0x12; break; case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x11; + spec->private_dac_nids[i] = 0x11; break; case AUTO_SEQ_SIDE: - spec->multiout.dac_nids[i] = 0x13; + spec->private_dac_nids[i] = 0x13; break; } } @@ -2437,7 +2002,8 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg, hda_nid_t cap_nid, - hda_nid_t pin_idxs[], int num_idxs) + const hda_nid_t pin_idxs[], + int num_idxs) { struct via_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; @@ -2483,13 +2049,13 @@ static int vt_auto_create_analog_input_ctls(struct hda_codec *codec, static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 }; + static const hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs, ARRAY_SIZE(pin_idxs)); } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1708_loopbacks[] = { +static const struct hda_amp_list vt1708_loopbacks[] = { { 0x17, HDA_INPUT, 1 }, { 0x17, HDA_INPUT, 2 }, { 0x17, HDA_INPUT, 3 }, @@ -2548,7 +2114,7 @@ static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new vt1708_jack_detectect[] = { +static const struct snd_kcontrol_new vt1708_jack_detectect[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Jack Detect", @@ -2623,7 +2189,8 @@ static int via_auto_init(struct hda_codec *codec) via_auto_init_multi_out(codec); via_auto_init_hp_out(codec); via_auto_init_analog_input(codec); - if (spec->codec_type == VT2002P || spec->codec_type == VT1812) { + + if (VT2002P_COMPATIBLE(spec)) { via_hp_bind_automute(codec); } else { via_hp_automute(codec); @@ -2727,7 +2294,7 @@ static int patch_vt1708(struct hda_codec *codec) } /* capture mixer elements */ -static struct snd_kcontrol_new vt1709_capture_mixer[] = { +static const struct snd_kcontrol_new vt1709_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT), @@ -2749,7 +2316,7 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = { { } /* end */ }; -static struct hda_verb vt1709_uniwill_init_verbs[] = { +static const struct hda_verb vt1709_uniwill_init_verbs[] = { {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, { } @@ -2758,7 +2325,7 @@ static struct hda_verb vt1709_uniwill_init_verbs[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb vt1709_10ch_volume_init_verbs[] = { +static const struct hda_verb vt1709_10ch_volume_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -2798,7 +2365,7 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = { { } }; -static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { +static const struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 10, @@ -2810,7 +2377,7 @@ static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { +static const struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 6, @@ -2822,7 +2389,7 @@ static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1709_pcm_analog_capture = { +static const struct hda_pcm_stream vt1709_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -2833,7 +2400,7 @@ static struct hda_pcm_stream vt1709_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1709_pcm_digital_playback = { +static const struct hda_pcm_stream vt1709_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -2844,7 +2411,7 @@ static struct hda_pcm_stream vt1709_pcm_digital_playback = { }, }; -static struct hda_pcm_stream vt1709_pcm_digital_capture = { +static const struct hda_pcm_stream vt1709_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -2871,26 +2438,26 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec, switch (i) { case AUTO_SEQ_FRONT: /* AOW0 */ - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: /* AOW2 */ - spec->multiout.dac_nids[i] = 0x12; + spec-& |