Loading sound/pci/hda/patch_via.c +43 −82 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,7 @@ struct via_spec { struct hda_multi_out multiout; struct hda_multi_out multiout; hda_nid_t slave_dig_outs[2]; hda_nid_t slave_dig_outs[2]; hda_nid_t hp_dac_nid; hda_nid_t hp_dac_nid; int num_active_streams; struct nid_path out_path[4]; struct nid_path out_path[4]; struct nid_path hp_path; struct nid_path hp_path; Loading Loading @@ -157,11 +158,9 @@ struct via_spec { void (*set_widgets_power_state)(struct hda_codec *codec); void (*set_widgets_power_state)(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; struct hda_loopback_check loopback; int num_loopbacks; int num_loopbacks; struct hda_amp_list loopback_list[8]; struct hda_amp_list loopback_list[8]; #endif }; }; static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec); static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec); Loading Loading @@ -241,8 +240,8 @@ enum { VIA_CTL_WIDGET_ANALOG_MUTE, VIA_CTL_WIDGET_ANALOG_MUTE, }; }; static void analog_low_current_mode(struct hda_codec *codec, int stream_idle); static void analog_low_current_mode(struct hda_codec *codec); static int is_aa_path_mute(struct hda_codec *codec); static bool is_aa_path_mute(struct hda_codec *codec); static void vt1708_start_hp_work(struct via_spec *spec) static void vt1708_start_hp_work(struct via_spec *spec) { { Loading Loading @@ -281,7 +280,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct hda_codec *codec = snd_kcontrol_chip(kcontrol); set_widgets_power_state(codec); set_widgets_power_state(codec); analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1); analog_low_current_mode(snd_kcontrol_chip(kcontrol)); if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) { if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) { if (is_aa_path_mute(codec)) if (is_aa_path_mute(codec)) vt1708_start_hp_work(codec->spec); vt1708_start_hp_work(codec->spec); Loading Loading @@ -895,77 +894,33 @@ static int via_smart51_build(struct hda_codec *codec) return 0; return 0; } } /* check AA path's mute statue */ /* check AA path's mute status */ static int is_aa_path_mute(struct hda_codec *codec) static bool is_aa_path_mute(struct hda_codec *codec) { { int mute = 1; int start_idx; int end_idx; int i; struct via_spec *spec = codec->spec; struct via_spec *spec = codec->spec; /* get nid of MW0 and start & end index */ const struct hda_amp_list *p; switch (spec->codec_type) { int i, ch, v; case VT1708B_8CH: case VT1708B_4CH: for (i = 0; i < spec->num_loopbacks; i++) { case VT1708S: p = &spec->loopback_list[i]; case VT1716S: for (ch = 0; ch < 2; ch++) { start_idx = 2; v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir, end_idx = 4; p->idx); break; if (!(v & HDA_AMP_MUTE) && v > 0) case VT1702: return false; start_idx = 1; end_idx = 3; break; case VT1718S: start_idx = 1; end_idx = 3; break; case VT2002P: case VT1812: case VT1802: start_idx = 0; end_idx = 2; break; default: return 0; } /* check AA path's mute status */ for (i = start_idx; i <= end_idx; i++) { unsigned int con_list = snd_hda_codec_read( codec, spec->aa_mix_nid, 0, AC_VERB_GET_CONNECT_LIST, i/4*4); int shift = 8 * (i % 4); hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift; unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin); if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) { /* check mute status while the pin is connected */ int mute_l = snd_hda_codec_amp_read(codec, spec->aa_mix_nid, 0, HDA_INPUT, i) >> 7; int mute_r = snd_hda_codec_amp_read(codec, spec->aa_mix_nid, 1, HDA_INPUT, i) >> 7; if (!mute_l || !mute_r) { mute = 0; break; } } } } } return mute; return true; } } /* enter/exit analog low-current mode */ /* enter/exit analog low-current mode */ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) static void analog_low_current_mode(struct hda_codec *codec) { { struct via_spec *spec = codec->spec; struct via_spec *spec = codec->spec; static int saved_stream_idle = 1; /* saved stream idle status */ bool enable; int enable = is_aa_path_mute(codec); unsigned int verb, parm; unsigned int verb = 0; unsigned int parm = 0; if (stream_idle == -1) /* stream status did not change */ enable = is_aa_path_mute(codec) && (spec->num_active_streams > 0); enable = enable && saved_stream_idle; else { enable = enable && stream_idle; saved_stream_idle = stream_idle; } /* decide low current mode's verb & parameter */ /* decide low current mode's verb & parameter */ switch (spec->codec_type) { switch (spec->codec_type) { Loading Loading @@ -1006,12 +961,15 @@ static const struct hda_verb vt1708_init_verbs[] = { { } { } }; }; static void substream_set_idle(struct hda_codec *codec, static void set_stream_active(struct hda_codec *codec, bool active) struct snd_pcm_substream *substream) { { int idle = substream->pstr->substream_opened == 1 struct via_spec *spec = codec->spec; && substream->ref_count == 0; analog_low_current_mode(codec, idle); if (active) spec->num_active_streams++; else spec->num_active_streams--; analog_low_current_mode(codec); } } static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo, static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo, Loading @@ -1019,12 +977,19 @@ static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) struct snd_pcm_substream *substream) { { struct via_spec *spec = codec->spec; struct via_spec *spec = codec->spec; int err; if (!spec->hp_independent_mode) if (!spec->hp_independent_mode) spec->multiout.hp_nid = spec->hp_dac_nid; spec->multiout.hp_nid = spec->hp_dac_nid; substream_set_idle(codec, substream); set_stream_active(codec, true); return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, hinfo); hinfo); if (err < 0) { spec->multiout.hp_nid = 0; set_stream_active(codec, false); return err; } return 0; } } static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo, static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo, Loading @@ -1034,7 +999,7 @@ static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo, struct via_spec *spec = codec->spec; struct via_spec *spec = codec->spec; spec->multiout.hp_nid = 0; spec->multiout.hp_nid = 0; substream_set_idle(codec, substream); set_stream_active(codec, false); return 0; return 0; } } Loading @@ -1048,7 +1013,7 @@ static int via_playback_hp_pcm_open(struct hda_pcm_stream *hinfo, return -EINVAL; return -EINVAL; if (!spec->hp_independent_mode || spec->multiout.hp_nid) if (!spec->hp_independent_mode || spec->multiout.hp_nid) return -EBUSY; return -EBUSY; substream_set_idle(codec, substream); set_stream_active(codec, true); return 0; return 0; } } Loading @@ -1056,7 +1021,7 @@ static int via_playback_hp_pcm_close(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct hda_codec *codec, struct snd_pcm_substream *substream) struct snd_pcm_substream *substream) { { substream_set_idle(codec, substream); set_stream_active(codec, false); return 0; return 0; } } Loading Loading @@ -1334,7 +1299,7 @@ static int via_build_controls(struct hda_codec *codec) /* init power states */ /* init power states */ set_widgets_power_state(codec); set_widgets_power_state(codec); analog_low_current_mode(codec, 1); analog_low_current_mode(codec); via_free_kctls(codec); /* no longer needed */ via_free_kctls(codec); /* no longer needed */ return 0; return 0; Loading Loading @@ -1860,7 +1825,6 @@ static const struct snd_kcontrol_new via_input_src_ctl = { .put = via_mux_enum_put, .put = via_mux_enum_put, }; }; #ifdef CONFIG_SND_HDA_POWER_SAVE static void add_loopback_list(struct via_spec *spec, hda_nid_t mix, int idx) static void add_loopback_list(struct via_spec *spec, hda_nid_t mix, int idx) { { struct hda_amp_list *list; struct hda_amp_list *list; Loading @@ -1874,9 +1838,6 @@ static void add_loopback_list(struct via_spec *spec, hda_nid_t mix, int idx) spec->num_loopbacks++; spec->num_loopbacks++; spec->loopback.amplist = spec->loopback_list; spec->loopback.amplist = spec->loopback_list; } } #else #define add_loopback_list(spec, mix, idx) /* NOP */ #endif /* create playback/capture controls for input pins */ /* create playback/capture controls for input pins */ static int via_auto_create_analog_input_ctls(struct hda_codec *codec, static int via_auto_create_analog_input_ctls(struct hda_codec *codec, Loading Loading
sound/pci/hda/patch_via.c +43 −82 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,7 @@ struct via_spec { struct hda_multi_out multiout; struct hda_multi_out multiout; hda_nid_t slave_dig_outs[2]; hda_nid_t slave_dig_outs[2]; hda_nid_t hp_dac_nid; hda_nid_t hp_dac_nid; int num_active_streams; struct nid_path out_path[4]; struct nid_path out_path[4]; struct nid_path hp_path; struct nid_path hp_path; Loading Loading @@ -157,11 +158,9 @@ struct via_spec { void (*set_widgets_power_state)(struct hda_codec *codec); void (*set_widgets_power_state)(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; struct hda_loopback_check loopback; int num_loopbacks; int num_loopbacks; struct hda_amp_list loopback_list[8]; struct hda_amp_list loopback_list[8]; #endif }; }; static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec); static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec); Loading Loading @@ -241,8 +240,8 @@ enum { VIA_CTL_WIDGET_ANALOG_MUTE, VIA_CTL_WIDGET_ANALOG_MUTE, }; }; static void analog_low_current_mode(struct hda_codec *codec, int stream_idle); static void analog_low_current_mode(struct hda_codec *codec); static int is_aa_path_mute(struct hda_codec *codec); static bool is_aa_path_mute(struct hda_codec *codec); static void vt1708_start_hp_work(struct via_spec *spec) static void vt1708_start_hp_work(struct via_spec *spec) { { Loading Loading @@ -281,7 +280,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct hda_codec *codec = snd_kcontrol_chip(kcontrol); set_widgets_power_state(codec); set_widgets_power_state(codec); analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1); analog_low_current_mode(snd_kcontrol_chip(kcontrol)); if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) { if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) { if (is_aa_path_mute(codec)) if (is_aa_path_mute(codec)) vt1708_start_hp_work(codec->spec); vt1708_start_hp_work(codec->spec); Loading Loading @@ -895,77 +894,33 @@ static int via_smart51_build(struct hda_codec *codec) return 0; return 0; } } /* check AA path's mute statue */ /* check AA path's mute status */ static int is_aa_path_mute(struct hda_codec *codec) static bool is_aa_path_mute(struct hda_codec *codec) { { int mute = 1; int start_idx; int end_idx; int i; struct via_spec *spec = codec->spec; struct via_spec *spec = codec->spec; /* get nid of MW0 and start & end index */ const struct hda_amp_list *p; switch (spec->codec_type) { int i, ch, v; case VT1708B_8CH: case VT1708B_4CH: for (i = 0; i < spec->num_loopbacks; i++) { case VT1708S: p = &spec->loopback_list[i]; case VT1716S: for (ch = 0; ch < 2; ch++) { start_idx = 2; v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir, end_idx = 4; p->idx); break; if (!(v & HDA_AMP_MUTE) && v > 0) case VT1702: return false; start_idx = 1; end_idx = 3; break; case VT1718S: start_idx = 1; end_idx = 3; break; case VT2002P: case VT1812: case VT1802: start_idx = 0; end_idx = 2; break; default: return 0; } /* check AA path's mute status */ for (i = start_idx; i <= end_idx; i++) { unsigned int con_list = snd_hda_codec_read( codec, spec->aa_mix_nid, 0, AC_VERB_GET_CONNECT_LIST, i/4*4); int shift = 8 * (i % 4); hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift; unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin); if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) { /* check mute status while the pin is connected */ int mute_l = snd_hda_codec_amp_read(codec, spec->aa_mix_nid, 0, HDA_INPUT, i) >> 7; int mute_r = snd_hda_codec_amp_read(codec, spec->aa_mix_nid, 1, HDA_INPUT, i) >> 7; if (!mute_l || !mute_r) { mute = 0; break; } } } } } return mute; return true; } } /* enter/exit analog low-current mode */ /* enter/exit analog low-current mode */ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) static void analog_low_current_mode(struct hda_codec *codec) { { struct via_spec *spec = codec->spec; struct via_spec *spec = codec->spec; static int saved_stream_idle = 1; /* saved stream idle status */ bool enable; int enable = is_aa_path_mute(codec); unsigned int verb, parm; unsigned int verb = 0; unsigned int parm = 0; if (stream_idle == -1) /* stream status did not change */ enable = is_aa_path_mute(codec) && (spec->num_active_streams > 0); enable = enable && saved_stream_idle; else { enable = enable && stream_idle; saved_stream_idle = stream_idle; } /* decide low current mode's verb & parameter */ /* decide low current mode's verb & parameter */ switch (spec->codec_type) { switch (spec->codec_type) { Loading Loading @@ -1006,12 +961,15 @@ static const struct hda_verb vt1708_init_verbs[] = { { } { } }; }; static void substream_set_idle(struct hda_codec *codec, static void set_stream_active(struct hda_codec *codec, bool active) struct snd_pcm_substream *substream) { { int idle = substream->pstr->substream_opened == 1 struct via_spec *spec = codec->spec; && substream->ref_count == 0; analog_low_current_mode(codec, idle); if (active) spec->num_active_streams++; else spec->num_active_streams--; analog_low_current_mode(codec); } } static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo, static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo, Loading @@ -1019,12 +977,19 @@ static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) struct snd_pcm_substream *substream) { { struct via_spec *spec = codec->spec; struct via_spec *spec = codec->spec; int err; if (!spec->hp_independent_mode) if (!spec->hp_independent_mode) spec->multiout.hp_nid = spec->hp_dac_nid; spec->multiout.hp_nid = spec->hp_dac_nid; substream_set_idle(codec, substream); set_stream_active(codec, true); return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, hinfo); hinfo); if (err < 0) { spec->multiout.hp_nid = 0; set_stream_active(codec, false); return err; } return 0; } } static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo, static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo, Loading @@ -1034,7 +999,7 @@ static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo, struct via_spec *spec = codec->spec; struct via_spec *spec = codec->spec; spec->multiout.hp_nid = 0; spec->multiout.hp_nid = 0; substream_set_idle(codec, substream); set_stream_active(codec, false); return 0; return 0; } } Loading @@ -1048,7 +1013,7 @@ static int via_playback_hp_pcm_open(struct hda_pcm_stream *hinfo, return -EINVAL; return -EINVAL; if (!spec->hp_independent_mode || spec->multiout.hp_nid) if (!spec->hp_independent_mode || spec->multiout.hp_nid) return -EBUSY; return -EBUSY; substream_set_idle(codec, substream); set_stream_active(codec, true); return 0; return 0; } } Loading @@ -1056,7 +1021,7 @@ static int via_playback_hp_pcm_close(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct hda_codec *codec, struct snd_pcm_substream *substream) struct snd_pcm_substream *substream) { { substream_set_idle(codec, substream); set_stream_active(codec, false); return 0; return 0; } } Loading Loading @@ -1334,7 +1299,7 @@ static int via_build_controls(struct hda_codec *codec) /* init power states */ /* init power states */ set_widgets_power_state(codec); set_widgets_power_state(codec); analog_low_current_mode(codec, 1); analog_low_current_mode(codec); via_free_kctls(codec); /* no longer needed */ via_free_kctls(codec); /* no longer needed */ return 0; return 0; Loading Loading @@ -1860,7 +1825,6 @@ static const struct snd_kcontrol_new via_input_src_ctl = { .put = via_mux_enum_put, .put = via_mux_enum_put, }; }; #ifdef CONFIG_SND_HDA_POWER_SAVE static void add_loopback_list(struct via_spec *spec, hda_nid_t mix, int idx) static void add_loopback_list(struct via_spec *spec, hda_nid_t mix, int idx) { { struct hda_amp_list *list; struct hda_amp_list *list; Loading @@ -1874,9 +1838,6 @@ static void add_loopback_list(struct via_spec *spec, hda_nid_t mix, int idx) spec->num_loopbacks++; spec->num_loopbacks++; spec->loopback.amplist = spec->loopback_list; spec->loopback.amplist = spec->loopback_list; } } #else #define add_loopback_list(spec, mix, idx) /* NOP */ #endif /* create playback/capture controls for input pins */ /* create playback/capture controls for input pins */ static int via_auto_create_analog_input_ctls(struct hda_codec *codec, static int via_auto_create_analog_input_ctls(struct hda_codec *codec, Loading