Commit ada509ec authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Simplify analog-low-current mode check for VIA codecs

Use the existing aa-loop list for simplifying the check for analog
low-current mode.  Also fix the stream count test for playback streams.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 47be05ce
...@@ -108,6 +108,7 @@ struct via_spec { ...@@ -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;
...@@ -157,11 +158,9 @@ struct via_spec { ...@@ -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);
...@@ -241,8 +240,8 @@ enum { ...@@ -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)
{ {
...@@ -281,7 +280,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol, ...@@ -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);
...@@ -895,77 +894,33 @@ static int via_smart51_build(struct hda_codec *codec) ...@@ -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) {
...@@ -1006,12 +961,15 @@ static const struct hda_verb vt1708_init_verbs[] = { ...@@ -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,
...@@ -1019,12 +977,19 @@ static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo, ...@@ -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,
...@@ -1034,7 +999,7 @@ static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo, ...@@ -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;
} }
...@@ -1048,7 +1013,7 @@ static int via_playback_hp_pcm_open(struct hda_pcm_stream *hinfo, ...@@ -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;
} }
...@@ -1056,7 +1021,7 @@ static int via_playback_hp_pcm_close(struct hda_pcm_stream *hinfo, ...@@ -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;
} }
...@@ -1334,7 +1299,7 @@ static int via_build_controls(struct hda_codec *codec) ...@@ -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;
...@@ -1860,7 +1825,6 @@ static const struct snd_kcontrol_new via_input_src_ctl = { ...@@ -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;
...@@ -1874,9 +1838,6 @@ static void add_loopback_list(struct via_spec *spec, hda_nid_t mix, int idx) ...@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment