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

Commit 9ad0e496 authored by Kailang Yang's avatar Kailang Yang Committed by Takashi Iwai
Browse files

ALSA: hda - Add input jack layer support to Realtek codec



Signed-off-by: default avatarKailang Yang <kailang@realtek.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 4a4d4a69
Loading
Loading
Loading
Loading
+98 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <sound/core.h>
#include <sound/jack.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_beep.h"
@@ -282,6 +283,12 @@ struct alc_mic_route {
	unsigned char amix_idx;
};
struct alc_jack {
	hda_nid_t nid;
	int type;
	struct snd_jack *jack;
};
#define MUX_IDX_UNDEF	((unsigned char)-1)
struct alc_customize_define {
@@ -357,6 +364,9 @@ struct alc_spec {
	/* PCM information */
	struct hda_pcm pcm_rec[3];	/* used in alc_build_pcms() */
	/* jack detection */
	struct snd_array jacks;
	/* dynamic controls, init_verbs and input_mux */
	struct auto_pin_cfg autocfg;
	struct alc_customize_define cdefine;
@@ -990,6 +1000,91 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
	alc_fix_pll(codec);
}
#ifdef CONFIG_SND_HDA_INPUT_JACK
static void alc_free_jack_priv(struct snd_jack *jack)
{
	struct alc_jack *jacks = jack->private_data;
	jacks->nid = 0;
	jacks->jack = NULL;
}
static int alc_add_jack(struct hda_codec *codec,
		hda_nid_t nid, int type)
{
	struct alc_spec *spec;
	struct alc_jack *jack;
	const char *name;
	int err;
	spec = codec->spec;
	snd_array_init(&spec->jacks, sizeof(*jack), 32);
	jack = snd_array_new(&spec->jacks);
	if (!jack)
		return -ENOMEM;
	jack->nid = nid;
	jack->type = type;
	name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
	err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
	if (err < 0)
		return err;
	jack->jack->private_data = jack;
	jack->jack->private_free = alc_free_jack_priv;
	return 0;
}
static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
	struct alc_spec *spec = codec->spec;
	struct alc_jack *jacks = spec->jacks.list;
	if (jacks) {
		int i;
		for (i = 0; i < spec->jacks.used; i++) {
			if (jacks->nid == nid) {
				unsigned int present;
				present = snd_hda_jack_detect(codec, nid);
				present = (present) ? jacks->type : 0;
				snd_jack_report(jacks->jack, present);
			}
			jacks++;
		}
	}
}
static int alc_init_jacks(struct hda_codec *codec)
{
	struct alc_spec *spec = codec->spec;
	int err;
	unsigned int hp_nid = spec->autocfg.hp_pins[0];
	unsigned int mic_nid = spec->ext_mic.pin;
	err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE);
	if (err < 0)
		return err;
	alc_report_jack(codec, hp_nid);
	err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE);
	if (err < 0)
		return err;
	alc_report_jack(codec, mic_nid);
	return 0;
}
#else
static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
}
static inline int alc_init_jacks(struct hda_codec *codec)
{
	return 0;
}
#endif
static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
{
	struct alc_spec *spec = codec->spec;
@@ -1006,6 +1101,7 @@ static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
			spec->jack_present = 1;
			break;
		}
		alc_report_jack(codec, spec->autocfg.hp_pins[i]);
	}
	mute = spec->jack_present ? HDA_AMP_MUTE : 0;
@@ -1111,6 +1207,7 @@ static void alc_mic_automute(struct hda_codec *codec)
					  AC_VERB_SET_CONNECT_SEL,
					  alive->mux_idx);
	}
	alc_report_jack(codec, spec->ext_mic.pin);
	/* FIXME: analog mixer */
}
@@ -14496,6 +14593,7 @@ static void alc269_auto_init(struct hda_codec *codec)
	alc269_auto_init_hp_out(codec);
	alc269_auto_init_analog_input(codec);
	alc_auto_init_digital(codec);
	alc_init_jacks(codec);
	if (spec->unsol_event)
		alc_inithook(codec);
}