diff mbox

Intel HDA / ca0132: support for Alienware 15 Creative Sound Core3D-EX

Message ID 555A3A41.2010505@gmx.com (mailing list archive)
State New, archived
Headers show

Commit Message

Gabriele Martino May 18, 2015, 7:15 p.m. UTC
This patch adds quirks detection to the Creative CA0132 codec, and the
quirk for Alienware 15 (2015).
Some quirks may need different pin configuration, so the relevant
compile-time configuration has been removed.
The pin configuration and related initialization verbs are generated at
runtime instead, in ca0132_config() and ca0132_prepare_verbs().

Signed-off-by: Gabriele Martino <g.martino@gmx.com>

Comments

Takashi Iwai May 19, 2015, 4:59 a.m. UTC | #1
At Mon, 18 May 2015 21:15:13 +0200,
Gabriele Martino wrote:
> 
> This patch adds quirks detection to the Creative CA0132 codec, and the
> quirk for Alienware 15 (2015).
> Some quirks may need different pin configuration, so the relevant
> compile-time configuration has been removed.
> The pin configuration and related initialization verbs are generated at
> runtime instead, in ca0132_config() and ca0132_prepare_verbs().
> 
> Signed-off-by: Gabriele Martino <g.martino@gmx.com>

Applied, thanks.


Takashi

> 
> diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
> index 4a4e7b2..1c7a9ec 100644
> --- a/sound/pci/hda/patch_ca0132.c
> +++ b/sound/pci/hda/patch_ca0132.c
> @@ -43,8 +43,6 @@
>  #define FLOAT_TWO	0x40000000
>  #define FLOAT_MINUS_5	0xc0a00000
>  
> -#define UNSOL_TAG_HP	0x10
> -#define UNSOL_TAG_AMIC1	0x12
>  #define UNSOL_TAG_DSP	0x16
>  
>  #define DSP_DMA_WRITE_BUFLEN_INIT (1UL<<18)
> @@ -703,8 +701,8 @@
>  	unsigned int num_mixers;
>  	const struct hda_verb *base_init_verbs;
>  	const struct hda_verb *base_exit_verbs;
> -	const struct hda_verb *init_verbs[5];
> -	unsigned int num_init_verbs;  /* exclude base init verbs */
> +	const struct hda_verb *chip_init_verbs;
> +	struct hda_verb *spec_init_verbs;
>  	struct auto_pin_cfg autocfg;
>  
>  	/* Nodes configurations */
> @@ -719,6 +717,8 @@
>  	unsigned int num_inputs;
>  	hda_nid_t shared_mic_nid;
>  	hda_nid_t shared_out_nid;
> +	hda_nid_t unsol_tag_hp;
> +	hda_nid_t unsol_tag_amic1;
>  
>  	/* chip access */
>  	struct mutex chipio_mutex; /* chip access mutex */
> @@ -748,10 +748,24 @@
>  
>  	struct hda_codec *codec;
>  	struct delayed_work unsol_hp_work;
> +	int quirk;
>  
>  #ifdef ENABLE_TUNING_CONTROLS
>  	long cur_ctl_vals[TUNING_CTLS_COUNT];
>  #endif
> +};
> +
> +/*
> + * CA0132 quirks table
> + */
> +enum {
> +	QUIRK_NONE,
> +	QUIRK_ALIENWARE,
> +};
> +
> +static const struct snd_pci_quirk ca0132_quirks[] = {
> +	SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15", QUIRK_ALIENWARE),
> +	{}
>  };
>  
>  /*
> @@ -3227,7 +3241,7 @@
>  	struct hda_jack_tbl *jack;
>  
>  	ca0132_select_out(spec->codec);
> -	jack = snd_hda_jack_tbl_get(spec->codec, UNSOL_TAG_HP);
> +	jack = snd_hda_jack_tbl_get(spec->codec, spec->unsol_tag_hp);
>  	if (jack) {
>  		jack->block_report = 0;
>  		snd_hda_jack_report_sync(spec->codec);
> @@ -4417,8 +4431,9 @@
>  
>  static void ca0132_init_unsol(struct hda_codec *codec)
>  {
> -	snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_HP, hp_callback);
> -	snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_AMIC1,
> +	struct ca0132_spec *spec = codec->spec;
> +	snd_hda_jack_detect_enable_callback(codec, spec->unsol_tag_hp, hp_callback);
> +	snd_hda_jack_detect_enable_callback(codec, spec->unsol_tag_amic1,
>  					    amic_callback);
>  	snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP,
>  					    ca0132_process_dsp_response);
> @@ -4476,17 +4491,6 @@
>  	{0x15, 0x5E8, 0xC9},
>  	{0x15, 0x717, 0x0D},
>  	{0x15, 0x718, 0x20},
> -	{}
> -};
> -
> -static struct hda_verb ca0132_init_verbs1[] = {
> -	{0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_HP},
> -	{0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_AMIC1},
> -	/* config EAPD */
> -	{0x0b, 0x78D, 0x00},
> -	/*{0x0b, AC_VERB_SET_EAPD_BTLENABLE, 0x02},*/
> -	/*{0x10, 0x78D, 0x02},*/
> -	/*{0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x02},*/
>  	{}
>  };
>  
> @@ -4569,8 +4573,8 @@
>  
>  	init_input(codec, cfg->dig_in_pin, spec->dig_in);
>  
> -	for (i = 0; i < spec->num_init_verbs; i++)
> -		snd_hda_sequence_write(codec, spec->init_verbs[i]);
> +	snd_hda_sequence_write(codec, spec->chip_init_verbs);
> +	snd_hda_sequence_write(codec, spec->spec_init_verbs);
>  
>  	ca0132_select_out(codec);
>  	ca0132_select_mic(codec);
> @@ -4591,6 +4595,7 @@
>  	snd_hda_sequence_write(codec, spec->base_exit_verbs);
>  	ca0132_exit_chip(codec);
>  	snd_hda_power_down(codec);
> +	kfree(spec->spec_init_verbs);
>  	kfree(codec->spec);
>  }
>  
> @@ -4617,18 +4622,26 @@
>  
>  	spec->num_outputs = 2;
>  	spec->out_pins[0] = 0x0b; /* speaker out */
> -	spec->out_pins[1] = 0x10; /* headphone out */
> +	if (spec->quirk == QUIRK_ALIENWARE) {
> +		codec_dbg(codec, "ca0132_config: QUIRK_ALIENWARE applied.\n");
> +		spec->out_pins[1] = 0x0f;
> +	}
> +	else{
> +		spec->out_pins[1] = 0x10; /* headphone out */
> +	}
>  	spec->shared_out_nid = 0x2;
> +	spec->unsol_tag_hp = spec->out_pins[1];
>  
> -	spec->num_inputs = 3;
>  	spec->adcs[0] = 0x7; /* digital mic / analog mic1 */
>  	spec->adcs[1] = 0x8; /* analog mic2 */
>  	spec->adcs[2] = 0xa; /* what u hear */
> -	spec->shared_mic_nid = 0x7;
>  
> +	spec->num_inputs = 3;
>  	spec->input_pins[0] = 0x12;
>  	spec->input_pins[1] = 0x11;
>  	spec->input_pins[2] = 0x13;
> +	spec->shared_mic_nid = 0x7;
> +	spec->unsol_tag_amic1 = spec->input_pins[0];
>  
>  	/* SPDIF I/O */
>  	spec->dig_out = 0x05;
> @@ -4641,10 +4654,56 @@
>  	cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
>  }
>  
> +static int ca0132_prepare_verbs(struct hda_codec *codec)
> +{
> +/* Verbs + terminator (an empty element) */
> +#define NUM_SPEC_VERBS 4
> +	struct ca0132_spec *spec = codec->spec;
> +
> +	spec->chip_init_verbs = ca0132_init_verbs0;
> +	spec->spec_init_verbs = kzalloc(sizeof(struct hda_verb) * NUM_SPEC_VERBS, GFP_KERNEL);
> +	if (!spec->spec_init_verbs)
> +		return -ENOMEM;
> +
> +	/* HP jack autodetection */
> +	spec->spec_init_verbs[0].nid = spec->unsol_tag_hp;
> +	spec->spec_init_verbs[0].param = AC_VERB_SET_UNSOLICITED_ENABLE;
> +	spec->spec_init_verbs[0].verb = AC_USRSP_EN | spec->unsol_tag_hp;
> +
> +	/* MIC1 jack autodetection */
> +	spec->spec_init_verbs[1].nid = spec->unsol_tag_amic1;
> +	spec->spec_init_verbs[1].param = AC_VERB_SET_UNSOLICITED_ENABLE;
> +	spec->spec_init_verbs[1].verb = AC_USRSP_EN | spec->unsol_tag_amic1;
> +
> +	/* config EAPD */
> +	spec->spec_init_verbs[2].nid = 0x0b;
> +	spec->spec_init_verbs[2].param = 0x78D;
> +	spec->spec_init_verbs[2].verb = 0x00;
> +
> +	/* Previously commented configuration */
> +	/*
> +	spec->spec_init_verbs[3].nid = 0x0b;
> +	spec->spec_init_verbs[3].param = AC_VERB_SET_EAPD_BTLENABLE;
> +	spec->spec_init_verbs[3].verb = 0x02;
> +
> +	spec->spec_init_verbs[4].nid = 0x10;
> +	spec->spec_init_verbs[4].param = 0x78D;
> +	spec->spec_init_verbs[4].verb = 0x02;
> +
> +	spec->spec_init_verbs[5].nid = 0x10;
> +	spec->spec_init_verbs[5].param = AC_VERB_SET_EAPD_BTLENABLE;
> +	spec->spec_init_verbs[5].verb = 0x02;
> +	*/
> +
> +	/* Terminator: spec->spec_init_verbs[NUM_SPEC_VERBS-1] */
> +	return 0;
> +}
> +
>  static int patch_ca0132(struct hda_codec *codec)
>  {
>  	struct ca0132_spec *spec;
>  	int err;
> +	const struct snd_pci_quirk *quirk;
>  
>  	codec_dbg(codec, "patch_ca0132\n");
>  
> @@ -4654,15 +4713,19 @@
>  	codec->spec = spec;
>  	spec->codec = codec;
>  
> +	/* Detect codec quirk */
> +	quirk = snd_pci_quirk_lookup(codec->bus->pci, ca0132_quirks);
> +	if (quirk)
> +		spec->quirk = quirk->value;
> +	else
> +		spec->quirk = QUIRK_NONE;
> +
>  	spec->dsp_state = DSP_DOWNLOAD_INIT;
>  	spec->num_mixers = 1;
>  	spec->mixers[0] = ca0132_mixer;
>  
>  	spec->base_init_verbs = ca0132_base_init_verbs;
>  	spec->base_exit_verbs = ca0132_base_exit_verbs;
> -	spec->init_verbs[0] = ca0132_init_verbs0;
> -	spec->init_verbs[1] = ca0132_init_verbs1;
> -	spec->num_init_verbs = 2;
>  
>  	INIT_DELAYED_WORK(&spec->unsol_hp_work, ca0132_unsol_hp_delayed);
>  
> @@ -4670,6 +4733,10 @@
>  
>  	ca0132_config(codec);
>  
> +	err = ca0132_prepare_verbs(codec);
> +	if (err < 0)
> +		return err;
> +
>  	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
>  	if (err < 0)
>  		return err;
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
diff mbox

Patch

diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 4a4e7b2..1c7a9ec 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -43,8 +43,6 @@ 
 #define FLOAT_TWO	0x40000000
 #define FLOAT_MINUS_5	0xc0a00000
 
-#define UNSOL_TAG_HP	0x10
-#define UNSOL_TAG_AMIC1	0x12
 #define UNSOL_TAG_DSP	0x16
 
 #define DSP_DMA_WRITE_BUFLEN_INIT (1UL<<18)
@@ -703,8 +701,8 @@ 
 	unsigned int num_mixers;
 	const struct hda_verb *base_init_verbs;
 	const struct hda_verb *base_exit_verbs;
-	const struct hda_verb *init_verbs[5];
-	unsigned int num_init_verbs;  /* exclude base init verbs */
+	const struct hda_verb *chip_init_verbs;
+	struct hda_verb *spec_init_verbs;
 	struct auto_pin_cfg autocfg;
 
 	/* Nodes configurations */
@@ -719,6 +717,8 @@ 
 	unsigned int num_inputs;
 	hda_nid_t shared_mic_nid;
 	hda_nid_t shared_out_nid;
+	hda_nid_t unsol_tag_hp;
+	hda_nid_t unsol_tag_amic1;
 
 	/* chip access */
 	struct mutex chipio_mutex; /* chip access mutex */
@@ -748,10 +748,24 @@ 
 
 	struct hda_codec *codec;
 	struct delayed_work unsol_hp_work;
+	int quirk;
 
 #ifdef ENABLE_TUNING_CONTROLS
 	long cur_ctl_vals[TUNING_CTLS_COUNT];
 #endif
+};
+
+/*
+ * CA0132 quirks table
+ */
+enum {
+	QUIRK_NONE,
+	QUIRK_ALIENWARE,
+};
+
+static const struct snd_pci_quirk ca0132_quirks[] = {
+	SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15", QUIRK_ALIENWARE),
+	{}
 };
 
 /*
@@ -3227,7 +3241,7 @@ 
 	struct hda_jack_tbl *jack;
 
 	ca0132_select_out(spec->codec);
-	jack = snd_hda_jack_tbl_get(spec->codec, UNSOL_TAG_HP);
+	jack = snd_hda_jack_tbl_get(spec->codec, spec->unsol_tag_hp);
 	if (jack) {
 		jack->block_report = 0;
 		snd_hda_jack_report_sync(spec->codec);
@@ -4417,8 +4431,9 @@ 
 
 static void ca0132_init_unsol(struct hda_codec *codec)
 {
-	snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_HP, hp_callback);
-	snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_AMIC1,
+	struct ca0132_spec *spec = codec->spec;
+	snd_hda_jack_detect_enable_callback(codec, spec->unsol_tag_hp, hp_callback);
+	snd_hda_jack_detect_enable_callback(codec, spec->unsol_tag_amic1,
 					    amic_callback);
 	snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP,
 					    ca0132_process_dsp_response);
@@ -4476,17 +4491,6 @@ 
 	{0x15, 0x5E8, 0xC9},
 	{0x15, 0x717, 0x0D},
 	{0x15, 0x718, 0x20},
-	{}
-};
-
-static struct hda_verb ca0132_init_verbs1[] = {
-	{0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_HP},
-	{0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_AMIC1},
-	/* config EAPD */
-	{0x0b, 0x78D, 0x00},
-	/*{0x0b, AC_VERB_SET_EAPD_BTLENABLE, 0x02},*/
-	/*{0x10, 0x78D, 0x02},*/
-	/*{0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x02},*/
 	{}
 };
 
@@ -4569,8 +4573,8 @@ 
 
 	init_input(codec, cfg->dig_in_pin, spec->dig_in);
 
-	for (i = 0; i < spec->num_init_verbs; i++)
-		snd_hda_sequence_write(codec, spec->init_verbs[i]);
+	snd_hda_sequence_write(codec, spec->chip_init_verbs);
+	snd_hda_sequence_write(codec, spec->spec_init_verbs);
 
 	ca0132_select_out(codec);
 	ca0132_select_mic(codec);
@@ -4591,6 +4595,7 @@ 
 	snd_hda_sequence_write(codec, spec->base_exit_verbs);
 	ca0132_exit_chip(codec);
 	snd_hda_power_down(codec);
+	kfree(spec->spec_init_verbs);
 	kfree(codec->spec);
 }
 
@@ -4617,18 +4622,26 @@ 
 
 	spec->num_outputs = 2;
 	spec->out_pins[0] = 0x0b; /* speaker out */
-	spec->out_pins[1] = 0x10; /* headphone out */
+	if (spec->quirk == QUIRK_ALIENWARE) {
+		codec_dbg(codec, "ca0132_config: QUIRK_ALIENWARE applied.\n");
+		spec->out_pins[1] = 0x0f;
+	}
+	else{
+		spec->out_pins[1] = 0x10; /* headphone out */
+	}
 	spec->shared_out_nid = 0x2;
+	spec->unsol_tag_hp = spec->out_pins[1];
 
-	spec->num_inputs = 3;
 	spec->adcs[0] = 0x7; /* digital mic / analog mic1 */
 	spec->adcs[1] = 0x8; /* analog mic2 */
 	spec->adcs[2] = 0xa; /* what u hear */
-	spec->shared_mic_nid = 0x7;
 
+	spec->num_inputs = 3;
 	spec->input_pins[0] = 0x12;
 	spec->input_pins[1] = 0x11;
 	spec->input_pins[2] = 0x13;
+	spec->shared_mic_nid = 0x7;
+	spec->unsol_tag_amic1 = spec->input_pins[0];
 
 	/* SPDIF I/O */
 	spec->dig_out = 0x05;
@@ -4641,10 +4654,56 @@ 
 	cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
 }
 
+static int ca0132_prepare_verbs(struct hda_codec *codec)
+{
+/* Verbs + terminator (an empty element) */
+#define NUM_SPEC_VERBS 4
+	struct ca0132_spec *spec = codec->spec;
+
+	spec->chip_init_verbs = ca0132_init_verbs0;
+	spec->spec_init_verbs = kzalloc(sizeof(struct hda_verb) * NUM_SPEC_VERBS, GFP_KERNEL);
+	if (!spec->spec_init_verbs)
+		return -ENOMEM;
+
+	/* HP jack autodetection */
+	spec->spec_init_verbs[0].nid = spec->unsol_tag_hp;
+	spec->spec_init_verbs[0].param = AC_VERB_SET_UNSOLICITED_ENABLE;
+	spec->spec_init_verbs[0].verb = AC_USRSP_EN | spec->unsol_tag_hp;
+
+	/* MIC1 jack autodetection */
+	spec->spec_init_verbs[1].nid = spec->unsol_tag_amic1;
+	spec->spec_init_verbs[1].param = AC_VERB_SET_UNSOLICITED_ENABLE;
+	spec->spec_init_verbs[1].verb = AC_USRSP_EN | spec->unsol_tag_amic1;
+
+	/* config EAPD */
+	spec->spec_init_verbs[2].nid = 0x0b;
+	spec->spec_init_verbs[2].param = 0x78D;
+	spec->spec_init_verbs[2].verb = 0x00;
+
+	/* Previously commented configuration */
+	/*
+	spec->spec_init_verbs[3].nid = 0x0b;
+	spec->spec_init_verbs[3].param = AC_VERB_SET_EAPD_BTLENABLE;
+	spec->spec_init_verbs[3].verb = 0x02;
+
+	spec->spec_init_verbs[4].nid = 0x10;
+	spec->spec_init_verbs[4].param = 0x78D;
+	spec->spec_init_verbs[4].verb = 0x02;
+
+	spec->spec_init_verbs[5].nid = 0x10;
+	spec->spec_init_verbs[5].param = AC_VERB_SET_EAPD_BTLENABLE;
+	spec->spec_init_verbs[5].verb = 0x02;
+	*/
+
+	/* Terminator: spec->spec_init_verbs[NUM_SPEC_VERBS-1] */
+	return 0;
+}
+
 static int patch_ca0132(struct hda_codec *codec)
 {
 	struct ca0132_spec *spec;
 	int err;
+	const struct snd_pci_quirk *quirk;
 
 	codec_dbg(codec, "patch_ca0132\n");
 
@@ -4654,15 +4713,19 @@ 
 	codec->spec = spec;
 	spec->codec = codec;
 
+	/* Detect codec quirk */
+	quirk = snd_pci_quirk_lookup(codec->bus->pci, ca0132_quirks);
+	if (quirk)
+		spec->quirk = quirk->value;
+	else
+		spec->quirk = QUIRK_NONE;
+
 	spec->dsp_state = DSP_DOWNLOAD_INIT;
 	spec->num_mixers = 1;
 	spec->mixers[0] = ca0132_mixer;
 
 	spec->base_init_verbs = ca0132_base_init_verbs;
 	spec->base_exit_verbs = ca0132_base_exit_verbs;
-	spec->init_verbs[0] = ca0132_init_verbs0;
-	spec->init_verbs[1] = ca0132_init_verbs1;
-	spec->num_init_verbs = 2;
 
 	INIT_DELAYED_WORK(&spec->unsol_hp_work, ca0132_unsol_hp_delayed);
 
@@ -4670,6 +4733,10 @@ 
 
 	ca0132_config(codec);
 
+	err = ca0132_prepare_verbs(codec);
+	if (err < 0)
+		return err;
+
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
 	if (err < 0)
 		return err;