Commit d5c016b5 authored by Gabriele Martino's avatar Gabriele Martino Committed by Takashi Iwai

ALSA: hda/ca0132: support for Alienware 15 Creative Sound Core3D-EX

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: default avatarGabriele Martino <g.martino@gmx.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent ac397c80
...@@ -43,8 +43,6 @@ ...@@ -43,8 +43,6 @@
#define FLOAT_TWO 0x40000000 #define FLOAT_TWO 0x40000000
#define FLOAT_MINUS_5 0xc0a00000 #define FLOAT_MINUS_5 0xc0a00000
#define UNSOL_TAG_HP 0x10
#define UNSOL_TAG_AMIC1 0x12
#define UNSOL_TAG_DSP 0x16 #define UNSOL_TAG_DSP 0x16
#define DSP_DMA_WRITE_BUFLEN_INIT (1UL<<18) #define DSP_DMA_WRITE_BUFLEN_INIT (1UL<<18)
...@@ -703,8 +701,8 @@ struct ca0132_spec { ...@@ -703,8 +701,8 @@ struct ca0132_spec {
unsigned int num_mixers; unsigned int num_mixers;
const struct hda_verb *base_init_verbs; const struct hda_verb *base_init_verbs;
const struct hda_verb *base_exit_verbs; const struct hda_verb *base_exit_verbs;
const struct hda_verb *init_verbs[5]; const struct hda_verb *chip_init_verbs;
unsigned int num_init_verbs; /* exclude base init verbs */ struct hda_verb *spec_init_verbs;
struct auto_pin_cfg autocfg; struct auto_pin_cfg autocfg;
/* Nodes configurations */ /* Nodes configurations */
...@@ -719,6 +717,8 @@ struct ca0132_spec { ...@@ -719,6 +717,8 @@ struct ca0132_spec {
unsigned int num_inputs; unsigned int num_inputs;
hda_nid_t shared_mic_nid; hda_nid_t shared_mic_nid;
hda_nid_t shared_out_nid; hda_nid_t shared_out_nid;
hda_nid_t unsol_tag_hp;
hda_nid_t unsol_tag_amic1;
/* chip access */ /* chip access */
struct mutex chipio_mutex; /* chip access mutex */ struct mutex chipio_mutex; /* chip access mutex */
...@@ -748,12 +748,26 @@ struct ca0132_spec { ...@@ -748,12 +748,26 @@ struct ca0132_spec {
struct hda_codec *codec; struct hda_codec *codec;
struct delayed_work unsol_hp_work; struct delayed_work unsol_hp_work;
int quirk;
#ifdef ENABLE_TUNING_CONTROLS #ifdef ENABLE_TUNING_CONTROLS
long cur_ctl_vals[TUNING_CTLS_COUNT]; long cur_ctl_vals[TUNING_CTLS_COUNT];
#endif #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),
{}
};
/* /*
* CA0132 codec access * CA0132 codec access
*/ */
...@@ -3224,7 +3238,7 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work) ...@@ -3224,7 +3238,7 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work)
struct hda_jack_tbl *jack; struct hda_jack_tbl *jack;
ca0132_select_out(spec->codec); 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) { if (jack) {
jack->block_report = 0; jack->block_report = 0;
snd_hda_jack_report_sync(spec->codec); snd_hda_jack_report_sync(spec->codec);
...@@ -4414,8 +4428,9 @@ static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb) ...@@ -4414,8 +4428,9 @@ static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
static void ca0132_init_unsol(struct hda_codec *codec) static void ca0132_init_unsol(struct hda_codec *codec)
{ {
snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_HP, hp_callback); struct ca0132_spec *spec = codec->spec;
snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_AMIC1, 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); amic_callback);
snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP, snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP,
ca0132_process_dsp_response); ca0132_process_dsp_response);
...@@ -4476,17 +4491,6 @@ static struct hda_verb ca0132_init_verbs0[] = { ...@@ -4476,17 +4491,6 @@ static struct hda_verb ca0132_init_verbs0[] = {
{} {}
}; };
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},*/
{}
};
static void ca0132_init_chip(struct hda_codec *codec) static void ca0132_init_chip(struct hda_codec *codec)
{ {
struct ca0132_spec *spec = codec->spec; struct ca0132_spec *spec = codec->spec;
...@@ -4566,8 +4570,8 @@ static int ca0132_init(struct hda_codec *codec) ...@@ -4566,8 +4570,8 @@ static int ca0132_init(struct hda_codec *codec)
init_input(codec, cfg->dig_in_pin, spec->dig_in); 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->chip_init_verbs);
snd_hda_sequence_write(codec, spec->init_verbs[i]); snd_hda_sequence_write(codec, spec->spec_init_verbs);
ca0132_select_out(codec); ca0132_select_out(codec);
ca0132_select_mic(codec); ca0132_select_mic(codec);
...@@ -4588,6 +4592,7 @@ static void ca0132_free(struct hda_codec *codec) ...@@ -4588,6 +4592,7 @@ static void ca0132_free(struct hda_codec *codec)
snd_hda_sequence_write(codec, spec->base_exit_verbs); snd_hda_sequence_write(codec, spec->base_exit_verbs);
ca0132_exit_chip(codec); ca0132_exit_chip(codec);
snd_hda_power_down(codec); snd_hda_power_down(codec);
kfree(spec->spec_init_verbs);
kfree(codec->spec); kfree(codec->spec);
} }
...@@ -4614,18 +4619,25 @@ static void ca0132_config(struct hda_codec *codec) ...@@ -4614,18 +4619,25 @@ static void ca0132_config(struct hda_codec *codec)
spec->num_outputs = 2; spec->num_outputs = 2;
spec->out_pins[0] = 0x0b; /* speaker out */ 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->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[0] = 0x7; /* digital mic / analog mic1 */
spec->adcs[1] = 0x8; /* analog mic2 */ spec->adcs[1] = 0x8; /* analog mic2 */
spec->adcs[2] = 0xa; /* what u hear */ spec->adcs[2] = 0xa; /* what u hear */
spec->shared_mic_nid = 0x7;
spec->num_inputs = 3;
spec->input_pins[0] = 0x12; spec->input_pins[0] = 0x12;
spec->input_pins[1] = 0x11; spec->input_pins[1] = 0x11;
spec->input_pins[2] = 0x13; spec->input_pins[2] = 0x13;
spec->shared_mic_nid = 0x7;
spec->unsol_tag_amic1 = spec->input_pins[0];
/* SPDIF I/O */ /* SPDIF I/O */
spec->dig_out = 0x05; spec->dig_out = 0x05;
...@@ -4638,10 +4650,56 @@ static void ca0132_config(struct hda_codec *codec) ...@@ -4638,10 +4650,56 @@ static void ca0132_config(struct hda_codec *codec)
cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; 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) static int patch_ca0132(struct hda_codec *codec)
{ {
struct ca0132_spec *spec; struct ca0132_spec *spec;
int err; int err;
const struct snd_pci_quirk *quirk;
codec_dbg(codec, "patch_ca0132\n"); codec_dbg(codec, "patch_ca0132\n");
...@@ -4651,15 +4709,19 @@ static int patch_ca0132(struct hda_codec *codec) ...@@ -4651,15 +4709,19 @@ static int patch_ca0132(struct hda_codec *codec)
codec->spec = spec; codec->spec = spec;
spec->codec = codec; 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->dsp_state = DSP_DOWNLOAD_INIT;
spec->num_mixers = 1; spec->num_mixers = 1;
spec->mixers[0] = ca0132_mixer; spec->mixers[0] = ca0132_mixer;
spec->base_init_verbs = ca0132_base_init_verbs; spec->base_init_verbs = ca0132_base_init_verbs;
spec->base_exit_verbs = ca0132_base_exit_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); INIT_DELAYED_WORK(&spec->unsol_hp_work, ca0132_unsol_hp_delayed);
...@@ -4667,6 +4729,10 @@ static int patch_ca0132(struct hda_codec *codec) ...@@ -4667,6 +4729,10 @@ static int patch_ca0132(struct hda_codec *codec)
ca0132_config(codec); ca0132_config(codec);
err = ca0132_prepare_verbs(codec);
if (err < 0)
return err;
err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
if (err < 0) if (err < 0)
return err; return err;
......
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