Skip to content

Commit

Permalink
ALSA: hda/ca0132: support for Alienware 15 Creative Sound Core3D-EX
Browse files Browse the repository at this point in the history
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>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Gabriele Martino authored and Takashi Iwai committed May 19, 2015
1 parent ac397c8 commit d5c016b
Showing 1 changed file with 92 additions and 26 deletions.
118 changes: 92 additions & 26 deletions sound/pci/hda/patch_ca0132.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -703,8 +701,8 @@ struct ca0132_spec {
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 */
Expand All @@ -719,6 +717,8 @@ struct ca0132_spec {
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 */
Expand Down Expand Up @@ -748,12 +748,26 @@ struct ca0132_spec {

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

/*
* CA0132 codec access
*/
Expand Down Expand Up @@ -3224,7 +3238,7 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work)
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);
Expand Down Expand Up @@ -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)
{
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);
Expand Down Expand Up @@ -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)
{
struct ca0132_spec *spec = codec->spec;
Expand Down Expand Up @@ -4566,8 +4570,8 @@ static int ca0132_init(struct hda_codec *codec)

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);
Expand All @@ -4588,6 +4592,7 @@ static void ca0132_free(struct hda_codec *codec)
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);
}

Expand All @@ -4614,18 +4619,25 @@ static void ca0132_config(struct hda_codec *codec)

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;
Expand All @@ -4638,10 +4650,56 @@ static void ca0132_config(struct hda_codec *codec)
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");

Expand All @@ -4651,22 +4709,30 @@ static int patch_ca0132(struct hda_codec *codec)
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);

ca0132_init_chip(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);
if (err < 0)
return err;
Expand Down

0 comments on commit d5c016b

Please sign in to comment.