Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ada509ec authored by Takashi Iwai's avatar Takashi Iwai
Browse files

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
Loading
Loading
Loading
Loading
+43 −82
Original line number Original line Diff line number Diff line
@@ -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 {


	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 {
	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,
	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)
	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[] = {
	{ }
	{ }
};
};


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,
				 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,
	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,
		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,
				     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)


	/* 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 = {
	.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)
	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,