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

Commit 8128c9f2 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'topic/hda' into for-linus

parents bb14eb0d 6b452142
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -600,7 +600,8 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
#define get_amp_nid_(pv)	((pv) & 0xffff)
#define get_amp_nid(kc)		get_amp_nid_((kc)->private_value)
#define get_amp_channels(kc)	(((kc)->private_value >> 16) & 0x3)
#define get_amp_direction(kc)	(((kc)->private_value >> 18) & 0x1)
#define get_amp_direction_(pv)	(((pv) >> 18) & 0x1)
#define get_amp_direction(kc)	get_amp_direction_((kc)->private_value)
#define get_amp_index(kc)	(((kc)->private_value >> 19) & 0xf)
#define get_amp_offset(kc)	(((kc)->private_value >> 23) & 0x3f)
#define get_amp_min_mute(kc)	(((kc)->private_value >> 29) & 0x1)
+49 −23
Original line number Diff line number Diff line
@@ -136,6 +136,8 @@ struct conexant_spec {
	unsigned int thinkpad:1;
	unsigned int hp_laptop:1;
	unsigned int asus:1;
	unsigned int pin_eapd_ctrls:1;
	unsigned int single_adc_amp:1;

	unsigned int adc_switching:1;

@@ -3430,11 +3432,13 @@ static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
static void do_automute(struct hda_codec *codec, int num_pins,
			hda_nid_t *pins, bool on)
{
	struct conexant_spec *spec = codec->spec;
	int i;
	for (i = 0; i < num_pins; i++)
		snd_hda_codec_write(codec, pins[i], 0,
				    AC_VERB_SET_PIN_WIDGET_CONTROL,
				    on ? PIN_OUT : 0);
	if (spec->pin_eapd_ctrls)
		cx_auto_turn_eapd(codec, num_pins, pins, on);
}

@@ -3460,9 +3464,12 @@ static void cx_auto_update_speakers(struct hda_codec *codec)
	int on = 1;

	/* turn on HP EAPD when HP jacks are present */
	if (spec->pin_eapd_ctrls) {
		if (spec->auto_mute)
			on = spec->hp_present;
		cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
	}

	/* mute speakers in auto-mode if HP or LO jacks are plugged */
	if (spec->auto_mute)
		on = !(spec->hp_present ||
@@ -3889,20 +3896,10 @@ static void cx_auto_parse_beep(struct hda_codec *codec)
#define cx_auto_parse_beep(codec)
#endif

static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
{
	int i;
	for (i = 0; i < nums; i++)
		if (list[i] == nid)
			return true;
	return false;
}

/* parse extra-EAPD that aren't assigned to any pins */
/* parse EAPDs */
static void cx_auto_parse_eapd(struct hda_codec *codec)
{
	struct conexant_spec *spec = codec->spec;
	struct auto_pin_cfg *cfg = &spec->autocfg;
	hda_nid_t nid, end_nid;

	end_nid = codec->start_nid + codec->num_nodes;
@@ -3911,14 +3908,18 @@ static void cx_auto_parse_eapd(struct hda_codec *codec)
			continue;
		if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
			continue;
		if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) ||
		    found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) ||
		    found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs))
			continue;
		spec->eapds[spec->num_eapds++] = nid;
		if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
			break;
	}

	/* NOTE: below is a wild guess; if we have more than two EAPDs,
	 * it's a new chip, where EAPDs are supposed to be associated to
	 * pins, and we can control EAPD per pin.
	 * OTOH, if only one or two EAPDs are found, it's an old chip,
	 * thus it might control over all pins.
	 */
	spec->pin_eapd_ctrls = spec->num_eapds > 2;
}

static int cx_auto_parse_auto_config(struct hda_codec *codec)
@@ -4024,7 +4025,8 @@ static void cx_auto_init_output(struct hda_codec *codec)
		}
	}
	cx_auto_update_speakers(codec);
	/* turn on/off extra EAPDs, too */
	/* turn on all EAPDs if no individual EAPD control is available */
	if (!spec->pin_eapd_ctrls)
		cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
}

@@ -4212,6 +4214,8 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
		int idx = get_input_connection(codec, adc_nid, nid);
		if (idx < 0)
			continue;
		if (spec->single_adc_amp)
			idx = 0;
		return cx_auto_add_volume_idx(codec, label, pfx,
					      cidx, adc_nid, HDA_INPUT, idx);
	}
@@ -4252,14 +4256,21 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
	struct hda_input_mux *imux = &spec->private_imux;
	const char *prev_label;
	int input_conn[HDA_MAX_NUM_INPUTS];
	int i, err, cidx;
	int i, j, err, cidx;
	int multi_connection;

	if (!imux->num_items)
		return 0;

	multi_connection = 0;
	for (i = 0; i < imux->num_items; i++) {
		cidx = get_input_connection(codec, spec->imux_info[i].adc,
					    spec->imux_info[i].pin);
		input_conn[i] = (spec->imux_info[i].adc << 8) | cidx;
		if (cidx < 0)
			continue;
		input_conn[i] = spec->imux_info[i].adc;
		if (!spec->single_adc_amp)
			input_conn[i] |= cidx << 8;
		if (i > 0 && input_conn[i] != input_conn[0])
			multi_connection = 1;
	}
@@ -4288,6 +4299,15 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
			err = cx_auto_add_capture_volume(codec, nid,
							 "Capture", "", cidx);
		} else {
			bool dup_found = false;
			for (j = 0; j < i; j++) {
				if (input_conn[j] == input_conn[i]) {
					dup_found = true;
					break;
				}
			}
			if (dup_found)
				continue;
			err = cx_auto_add_capture_volume(codec, nid,
							 label, " Capture", cidx);
		}
@@ -4412,6 +4432,12 @@ static int patch_conexant_auto(struct hda_codec *codec)
	codec->spec = spec;
	codec->pin_amp_workaround = 1;

	switch (codec->vendor_id) {
	case 0x14f15045:
		spec->single_adc_amp = 1;
		break;
	}

	apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl);

	err = cx_auto_search_adcs(codec);
+37 −5
Original line number Diff line number Diff line
@@ -116,6 +116,8 @@ struct alc_spec {
	const hda_nid_t *capsrc_nids;
	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
	hda_nid_t mixer_nid;		/* analog-mixer NID */
	DECLARE_BITMAP(vol_ctls, 0x20 << 1);
	DECLARE_BITMAP(sw_ctls, 0x20 << 1);

	/* capture setup for dynamic dual-adc switch */
	hda_nid_t cur_adc;
@@ -3006,14 +3008,32 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
	return 0;
}

static inline unsigned int get_ctl_pos(unsigned int data)
{
	hda_nid_t nid = get_amp_nid_(data);
	unsigned int dir = get_amp_direction_(data);
	return (nid << 1) | dir;
}

#define is_ctl_used(bits, data) \
	test_bit(get_ctl_pos(data), bits)
#define mark_ctl_usage(bits, data) \
	set_bit(get_ctl_pos(data), bits)

static int alc_auto_add_vol_ctl(struct hda_codec *codec,
			      const char *pfx, int cidx,
			      hda_nid_t nid, unsigned int chs)
{
	struct alc_spec *spec = codec->spec;
	unsigned int val;
	if (!nid)
		return 0;
	val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
	if (is_ctl_used(spec->vol_ctls, val) && chs != 2) /* exclude LFE */
		return 0;
	mark_ctl_usage(spec->vol_ctls, val);
	return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
				 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
				 val);
}

#define alc_auto_add_stereo_vol(codec, pfx, cidx, nid)	\
@@ -3026,6 +3046,7 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec,
			     const char *pfx, int cidx,
			     hda_nid_t nid, unsigned int chs)
{
	struct alc_spec *spec = codec->spec;
	int wid_type;
	int type;
	unsigned long val;
@@ -3042,6 +3063,9 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec,
		type = ALC_CTL_BIND_MUTE;
		val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT);
	}
	if (is_ctl_used(spec->sw_ctls, val) && chs != 2) /* exclude LFE */
		return 0;
	mark_ctl_usage(spec->sw_ctls, val);
	return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
}

@@ -3136,12 +3160,16 @@ static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
	int err;

	if (!dac) {
		unsigned int val;
		/* the corresponding DAC is already occupied */
		if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
			return 0; /* no way */
		/* create a switch only */
		return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
				   HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
		val = HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT);
		if (is_ctl_used(spec->sw_ctls, val))
			return 0; /* already created */
		mark_ctl_usage(spec->sw_ctls, val);
		return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
	}

	sw = alc_look_for_out_mute_nid(codec, pin, dac);
@@ -3186,8 +3214,12 @@ static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins,
	if (!num_pins || !pins[0])
		return 0;

	if (num_pins == 1)
		return alc_auto_create_extra_out(codec, *pins, *dacs, pfx);
	if (num_pins == 1) {
		hda_nid_t dac = *dacs;
		if (!dac)
			dac = spec->multiout.dac_nids[0];
		return alc_auto_create_extra_out(codec, *pins, dac, pfx);
	}

	if (dacs[num_pins - 1]) {
		/* OK, we have a multi-output system with individual volumes */