These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / sound / pci / hda / patch_ca0132.c
index 4a4e7b2..9ceb2bc 100644 (file)
@@ -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 @@ 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 */
@@ -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 */
@@ -748,12 +748,41 @@ 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 hda_pintbl alienware_pincfgs[] = {
+       { 0x0b, 0x90170110 }, /* Builtin Speaker */
+       { 0x0c, 0x411111f0 }, /* N/A */
+       { 0x0d, 0x411111f0 }, /* N/A */
+       { 0x0e, 0x411111f0 }, /* N/A */
+       { 0x0f, 0x0321101f }, /* HP */
+       { 0x10, 0x411111f0 }, /* Headset?  disabled for now */
+       { 0x11, 0x03a11021 }, /* Mic */
+       { 0x12, 0xd5a30140 }, /* Builtin Mic */
+       { 0x13, 0x411111f0 }, /* N/A */
+       { 0x18, 0x411111f0 }, /* N/A */
+       {}
+};
+
+static const struct snd_pci_quirk ca0132_quirks[] = {
+       SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE),
+       SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE),
+       {}
+};
+
 /*
  * CA0132 codec access
  */
@@ -2052,11 +2081,8 @@ static int dma_convert_to_hda_format(struct hda_codec *codec,
 {
        unsigned int format_val;
 
-       format_val = snd_hda_calc_stream_format(codec,
-                               sample_rate,
-                               channels,
-                               SNDRV_PCM_FORMAT_S32_LE,
-                               32, 0);
+       format_val = snd_hdac_calc_stream_format(sample_rate,
+                               channels, SNDRV_PCM_FORMAT_S32_LE, 32, 0);
 
        if (hda_format)
                *hda_format = (unsigned short)format_val;
@@ -2648,13 +2674,13 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
 
        do {
                if (dspload_is_loaded(codec)) {
-                       pr_info("ca0132 DOWNLOAD OK :-) DSP IS RUNNING.\n");
+                       codec_info(codec, "ca0132 DSP downloaded and running\n");
                        return true;
                }
                msleep(20);
        } while (time_before(jiffies, timeout));
 
-       pr_err("ca0132 DOWNLOAD FAILED!!! DSP IS NOT RUNNING.\n");
+       codec_err(codec, "ca0132 failed to download DSP\n");
        return false;
 }
 
@@ -3136,7 +3162,7 @@ static int ca0132_select_out(struct hda_codec *codec)
        auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
 
        if (auto_jack)
-               jack_present = snd_hda_jack_detect(codec, spec->out_pins[1]);
+               jack_present = snd_hda_jack_detect(codec, spec->unsol_tag_hp);
        else
                jack_present =
                        spec->vnode_lswitch[VNID_HP_SEL - VNODE_START_NID];
@@ -3227,7 +3253,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);
@@ -3298,7 +3324,7 @@ static int ca0132_select_mic(struct hda_codec *codec)
        auto_jack = spec->vnode_lswitch[VNID_AMIC1_ASEL - VNODE_START_NID];
 
        if (auto_jack)
-               jack_present = snd_hda_jack_detect(codec, spec->input_pins[0]);
+               jack_present = snd_hda_jack_detect(codec, spec->unsol_tag_amic1);
        else
                jack_present =
                        spec->vnode_lswitch[VNID_AMIC1_SEL - VNODE_START_NID];
@@ -4350,7 +4376,7 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
 
        dsp_os_image = (struct dsp_image_seg *)(fw_entry->data);
        if (dspload_image(codec, dsp_os_image, 0, 0, true, 0)) {
-               pr_err("ca0132 dspload_image failed.\n");
+               codec_err(codec, "ca0132 DSP load image failed\n");
                goto exit_download;
        }
 
@@ -4401,13 +4427,16 @@ static void ca0132_process_dsp_response(struct hda_codec *codec,
 static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
 {
        struct ca0132_spec *spec = codec->spec;
+       struct hda_jack_tbl *tbl;
 
        /* Delay enabling the HP amp, to let the mic-detection
         * state machine run.
         */
        cancel_delayed_work_sync(&spec->unsol_hp_work);
        schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500));
-       cb->tbl->block_report = 1;
+       tbl = snd_hda_jack_tbl_get(codec, cb->nid);
+       if (tbl)
+               tbl->block_report = 1;
 }
 
 static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
@@ -4417,8 +4446,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);
@@ -4479,17 +4509,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;
@@ -4569,8 +4588,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);
@@ -4591,6 +4610,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);
 }
 
@@ -4615,36 +4635,106 @@ static void ca0132_config(struct hda_codec *codec)
        spec->multiout.num_dacs = 3;
        spec->multiout.max_channels = 2;
 
-       spec->num_outputs = 2;
-       spec->out_pins[0] = 0x0b; /* speaker out */
-       spec->out_pins[1] = 0x10; /* headphone out */
-       spec->shared_out_nid = 0x2;
+       if (spec->quirk == QUIRK_ALIENWARE) {
+               codec_dbg(codec, "ca0132_config: QUIRK_ALIENWARE applied.\n");
+               snd_hda_apply_pincfgs(codec, alienware_pincfgs);
+
+               spec->num_outputs = 2;
+               spec->out_pins[0] = 0x0b; /* speaker out */
+               spec->out_pins[1] = 0x0f;
+               spec->shared_out_nid = 0x2;
+               spec->unsol_tag_hp = 0x0f;
+
+               spec->adcs[0] = 0x7; /* digital mic / analog mic1 */
+               spec->adcs[1] = 0x8; /* analog mic2 */
+               spec->adcs[2] = 0xa; /* what u hear */
+
+               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 = 0x11;
+       } else {
+               spec->num_outputs = 2;
+               spec->out_pins[0] = 0x0b; /* speaker out */
+               spec->out_pins[1] = 0x10; /* headphone out */
+               spec->shared_out_nid = 0x2;
+               spec->unsol_tag_hp = spec->out_pins[1];
+
+               spec->adcs[0] = 0x7; /* digital mic / analog mic1 */
+               spec->adcs[1] = 0x8; /* analog mic2 */
+               spec->adcs[2] = 0xa; /* what u hear */
+
+               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;
+               spec->multiout.dig_out_nid = spec->dig_out;
+               cfg->dig_out_pins[0] = 0x0c;
+               cfg->dig_outs = 1;
+               cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF;
+               spec->dig_in = 0x09;
+               cfg->dig_in_pin = 0x0e;
+               cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
+       }
+}
 
-       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;
+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;
 
-       spec->input_pins[0] = 0x12;
-       spec->input_pins[1] = 0x11;
-       spec->input_pins[2] = 0x13;
+       /* 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;
 
-       /* SPDIF I/O */
-       spec->dig_out = 0x05;
-       spec->multiout.dig_out_nid = spec->dig_out;
-       cfg->dig_out_pins[0] = 0x0c;
-       cfg->dig_outs = 1;
-       cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF;
-       spec->dig_in = 0x09;
-       cfg->dig_in_pin = 0x0e;
-       cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
+       /* 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 +4744,23 @@ static int patch_ca0132(struct hda_codec *codec)
        codec->spec = spec;
        spec->codec = codec;
 
+       codec->patch_ops = ca0132_patch_ops;
+       codec->pcm_format_first = 1;
+       codec->no_sticky_stream = 1;
+
+       /* 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,13 +4768,13 @@ static int patch_ca0132(struct hda_codec *codec)
 
        ca0132_config(codec);
 
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+       err = ca0132_prepare_verbs(codec);
        if (err < 0)
                return err;
 
-       codec->patch_ops = ca0132_patch_ops;
-       codec->pcm_format_first = 1;
-       codec->no_sticky_stream = 1;
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+       if (err < 0)
+               return err;
 
        return 0;
 }
@@ -4684,18 +4782,17 @@ static int patch_ca0132(struct hda_codec *codec)
 /*
  * patch entries
  */
-static struct hda_codec_preset snd_hda_preset_ca0132[] = {
-       { .id = 0x11020011, .name = "CA0132",     .patch = patch_ca0132 },
+static struct hda_device_id snd_hda_id_ca0132[] = {
+       HDA_CODEC_ENTRY(0x11020011, "CA0132", patch_ca0132),
        {} /* terminator */
 };
-
-MODULE_ALIAS("snd-hda-codec-id:11020011");
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0132);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Creative Sound Core3D codec");
 
 static struct hda_codec_driver ca0132_driver = {
-       .preset = snd_hda_preset_ca0132,
+       .id = snd_hda_id_ca0132,
 };
 
 module_hda_codec_driver(ca0132_driver);