]> git.karo-electronics.de Git - linux-beck.git/blobdiff - sound/pci/hda/patch_cirrus.c
Merge branch 'test/hda-jack' into topic/hda
[linux-beck.git] / sound / pci / hda / patch_cirrus.c
index 2fbab8e29576bb236ce51fd5f4050bc0283843b6..acfb64534bf09672228e0e4d59394166c833cf42 100644 (file)
@@ -26,6 +26,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_jack.h"
 #include <sound/tlv.h>
 
 /*
@@ -58,6 +59,8 @@ struct cs_spec {
        unsigned int gpio_mask;
        unsigned int gpio_dir;
        unsigned int gpio_data;
+       unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */
+       unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */
 
        struct hda_pcm pcm_rec[2];      /* PCM information */
 
@@ -76,6 +79,7 @@ enum {
        CS420X_MBP53,
        CS420X_MBP55,
        CS420X_IMAC27,
+       CS420X_APPLE,
        CS420X_AUTO,
        CS420X_MODELS
 };
@@ -718,8 +722,9 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
        if (uinfo->value.enumerated.item >= spec->num_inputs)
                uinfo->value.enumerated.item = spec->num_inputs - 1;
        idx = spec->input_idx[uinfo->value.enumerated.item];
-       strcpy(uinfo->value.enumerated.name,
-              hda_get_input_pin_label(codec, cfg->inputs[idx].pin, 1));
+       snd_hda_get_pin_label(codec, cfg->inputs[idx].pin, cfg,
+                             uinfo->value.enumerated.name,
+                             sizeof(uinfo->value.enumerated.name), NULL);
        return 0;
 }
 
@@ -928,10 +933,9 @@ static void cs_automute(struct hda_codec *codec)
                                        spdif_present ? 0 : PIN_OUT);
                }
        }
-       if (spec->board_config == CS420X_MBP53 ||
-           spec->board_config == CS420X_MBP55 ||
-           spec->board_config == CS420X_IMAC27) {
-               unsigned int gpio = hp_present ? 0x02 : 0x08;
+       if (spec->gpio_eapd_hp) {
+               unsigned int gpio = hp_present ?
+                       spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
                snd_hda_codec_write(codec, 0x01, 0,
                                    AC_VERB_SET_GPIO_DATA, gpio);
        }
@@ -1025,9 +1029,7 @@ static void init_output(struct hda_codec *codec)
                if (!cfg->speaker_outs)
                        continue;
                if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_UNSOLICITED_ENABLE,
-                                           AC_USRSP_EN | HP_EVENT);
+                       snd_hda_jack_detect_enable(codec, nid, HP_EVENT);
                        spec->hp_detect = 1;
                }
        }
@@ -1068,9 +1070,7 @@ static void init_input(struct hda_codec *codec)
                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                    AMP_IN_MUTE(spec->adc_idx[i]));
                if (spec->mic_detect && spec->automic_idx == i)
-                       snd_hda_codec_write(codec, pin, 0,
-                                           AC_VERB_SET_UNSOLICITED_ENABLE,
-                                           AC_USRSP_EN | MIC_EVENT);
+                       snd_hda_jack_detect_enable(codec, pin, MIC_EVENT);
        }
        /* specific to CS421x */
        if (spec->vendor_nid == CS421X_VENDOR_NID) {
@@ -1198,11 +1198,14 @@ static int cs_init(struct hda_codec *codec)
        init_output(codec);
        init_input(codec);
        init_digital(codec);
+       snd_hda_jack_report_sync(codec);
+
        return 0;
 }
 
 static int cs_build_controls(struct hda_codec *codec)
 {
+       struct cs_spec *spec = codec->spec;
        int err;
 
        err = build_output(codec);
@@ -1217,7 +1220,15 @@ static int cs_build_controls(struct hda_codec *codec)
        err = build_digital_input(codec);
        if (err < 0)
                return err;
-       return cs_init(codec);
+       err = cs_init(codec);
+       if (err < 0)
+               return err;
+
+       err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       return 0;
 }
 
 static void cs_free(struct hda_codec *codec)
@@ -1230,7 +1241,7 @@ static void cs_free(struct hda_codec *codec)
 
 static void cs_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       switch ((res >> 26) & 0x7f) {
+       switch (snd_hda_jack_get_action(codec, res >> 26)) {
        case HP_EVENT:
                cs_automute(codec);
                break;
@@ -1238,6 +1249,7 @@ static void cs_unsol_event(struct hda_codec *codec, unsigned int res)
                cs_automic(codec);
                break;
        }
+       snd_hda_jack_report_sync(codec);
 }
 
 static const struct hda_codec_ops cs_patch_ops = {
@@ -1276,6 +1288,7 @@ static const char * const cs420x_models[CS420X_MODELS] = {
        [CS420X_MBP53] = "mbp53",
        [CS420X_MBP55] = "mbp55",
        [CS420X_IMAC27] = "imac27",
+       [CS420X_APPLE] = "apple",
        [CS420X_AUTO] = "auto",
 };
 
@@ -1285,7 +1298,13 @@ static const struct snd_pci_quirk cs420x_cfg_tbl[] = {
        SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
        SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
        SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
-       SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
+       /* this conflicts with too many other models */
+       /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/
+       {} /* terminator */
+};
+
+static const struct snd_pci_quirk cs420x_codec_cfg_tbl[] = {
+       SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
        {} /* terminator */
 };
 
@@ -1367,6 +1386,10 @@ static int patch_cs420x(struct hda_codec *codec)
        spec->board_config =
                snd_hda_check_board_config(codec, CS420X_MODELS,
                                           cs420x_models, cs420x_cfg_tbl);
+       if (spec->board_config < 0)
+               spec->board_config =
+                       snd_hda_check_board_codec_sid_config(codec,
+                               CS420X_MODELS, NULL, cs420x_codec_cfg_tbl);
        if (spec->board_config >= 0)
                fix_pincfg(codec, spec->board_config, cs_pincfgs);
 
@@ -1374,10 +1397,11 @@ static int patch_cs420x(struct hda_codec *codec)
        case CS420X_IMAC27:
        case CS420X_MBP53:
        case CS420X_MBP55:
-               /* GPIO1 = headphones */
-               /* GPIO3 = speakers */
-               spec->gpio_mask = 0x0a;
-               spec->gpio_dir = 0x0a;
+       case CS420X_APPLE:
+               spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
+               spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
+               spec->gpio_mask = spec->gpio_dir =
+                       spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
                break;
        }
 
@@ -1588,10 +1612,7 @@ static void init_cs421x_digital(struct hda_codec *codec)
                if (!cfg->speaker_outs)
                        continue;
                if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
-
-                       snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_UNSOLICITED_ENABLE,
-                                   AC_USRSP_EN | SPDIF_EVENT);
+                       snd_hda_jack_detect_enable(codec, nid, SPDIF_EVENT);
                        spec->spdif_detect = 1;
                }
        }
@@ -1618,6 +1639,7 @@ static int cs421x_init(struct hda_codec *codec)
        init_output(codec);
        init_input(codec);
        init_cs421x_digital(codec);
+       snd_hda_jack_report_sync(codec);
 
        return 0;
 }
@@ -1793,6 +1815,7 @@ static int build_cs421x_output(struct hda_codec *codec)
 
 static int cs421x_build_controls(struct hda_codec *codec)
 {
+       struct cs_spec *spec = codec->spec;
        int err;
 
        err = build_cs421x_output(codec);
@@ -1804,12 +1827,20 @@ static int cs421x_build_controls(struct hda_codec *codec)
        err = build_digital_output(codec);
        if (err < 0)
                return err;
-       return cs421x_init(codec);
+       err =  cs421x_init(codec);
+       if (err < 0)
+               return err;
+
+       err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       return 0;
 }
 
 static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       switch ((res >> 26) & 0x3f) {
+       switch (snd_hda_jack_get_action(codec, res >> 26)) {
        case HP_EVENT:
        case SPDIF_EVENT:
                cs_automute(codec);
@@ -1819,6 +1850,7 @@ static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res)
                cs_automic(codec);
                break;
        }
+       snd_hda_jack_report_sync(codec);
 }
 
 static int parse_cs421x_input(struct hda_codec *codec)