ALSA: hda - Control SPDIF out pin on MacBookPro 11,2
[sfrench/cifs-2.6.git] / sound / pci / hda / patch_cirrus.c
index 18d9725015855c0ce3f33d174a3dfcd55836efeb..fc492ac24caa917c9d3670a37f83cb1d3e0bca95 100644 (file)
@@ -47,6 +47,10 @@ struct cs_spec {
        unsigned int spdif_present:1;
        unsigned int sense_b:1;
        hda_nid_t vendor_nid;
+
+       /* for MBP SPDIF control */
+       int (*spdif_sw_put)(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol);
 };
 
 /* available models with CS420x */
@@ -331,10 +335,21 @@ static int cs_init(struct hda_codec *codec)
        return 0;
 }
 
+static int cs_build_controls(struct hda_codec *codec)
+{
+       int err;
+
+       err = snd_hda_gen_build_controls(codec);
+       if (err < 0)
+               return err;
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
+       return 0;
+}
+
 #define cs_free                snd_hda_gen_free
 
 static const struct hda_codec_ops cs_patch_ops = {
-       .build_controls = snd_hda_gen_build_controls,
+       .build_controls = cs_build_controls,
        .build_pcms = snd_hda_gen_build_pcms,
        .init = cs_init,
        .free = cs_free,
@@ -597,18 +612,27 @@ static int patch_cs420x(struct hda_codec *codec)
  * Its layout is no longer compatible with CS4206/CS4207
  */
 enum {
+       CS4208_MAC_AUTO,
        CS4208_MBA6,
+       CS4208_MBP11,
        CS4208_GPIO0,
 };
 
 static const struct hda_model_fixup cs4208_models[] = {
        { .id = CS4208_GPIO0, .name = "gpio0" },
        { .id = CS4208_MBA6, .name = "mba6" },
+       { .id = CS4208_MBP11, .name = "mbp11" },
        {}
 };
 
 static const struct snd_pci_quirk cs4208_fixup_tbl[] = {
-       /* codec SSID */
+       SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO),
+       {} /* terminator */
+};
+
+/* codec SSID matching */
+static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11),
        SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6),
        SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6),
        {} /* terminator */
@@ -626,6 +650,50 @@ static void cs4208_fixup_gpio0(struct hda_codec *codec,
        }
 }
 
+static const struct hda_fixup cs4208_fixups[];
+
+/* remap the fixup from codec SSID and apply it */
+static void cs4208_fixup_mac(struct hda_codec *codec,
+                            const struct hda_fixup *fix, int action)
+{
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+       snd_hda_pick_fixup(codec, NULL, cs4208_mac_fixup_tbl, cs4208_fixups);
+       if (codec->fixup_id < 0 || codec->fixup_id == CS4208_MAC_AUTO)
+               codec->fixup_id = CS4208_GPIO0; /* default fixup */
+       snd_hda_apply_fixup(codec, action);
+}
+
+static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct cs_spec *spec = codec->spec;
+       hda_nid_t pin = spec->gen.autocfg.dig_out_pins[0];
+       int pinctl = ucontrol->value.integer.value[0] ? PIN_OUT : 0;
+
+       snd_hda_set_pin_ctl_cache(codec, pin, pinctl);
+       return spec->spdif_sw_put(kcontrol, ucontrol);
+}
+
+/* hook the SPDIF switch */
+static void cs4208_fixup_spdif_switch(struct hda_codec *codec,
+                                     const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_BUILD) {
+               struct cs_spec *spec = codec->spec;
+               struct snd_kcontrol *kctl;
+
+               if (!spec->gen.autocfg.dig_out_pins[0])
+                       return;
+               kctl = snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch");
+               if (!kctl)
+                       return;
+               spec->spdif_sw_put = kctl->put;
+               kctl->put = cs4208_spdif_sw_put;
+       }
+}
+
 static const struct hda_fixup cs4208_fixups[] = {
        [CS4208_MBA6] = {
                .type = HDA_FIXUP_PINS,
@@ -633,10 +701,20 @@ static const struct hda_fixup cs4208_fixups[] = {
                .chained = true,
                .chain_id = CS4208_GPIO0,
        },
+       [CS4208_MBP11] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs4208_fixup_spdif_switch,
+               .chained = true,
+               .chain_id = CS4208_GPIO0,
+       },
        [CS4208_GPIO0] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cs4208_fixup_gpio0,
        },
+       [CS4208_MAC_AUTO] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs4208_fixup_mac,
+       },
 };
 
 /* correct the 0dB offset of input pins */
@@ -660,6 +738,8 @@ static int patch_cs4208(struct hda_codec *codec)
                return -ENOMEM;
 
        spec->gen.automute_hook = cs_automute;
+       /* exclude NID 0x10 (HP) from output volumes due to different steps */
+       spec->gen.out_vol_mask = 1ULL << 0x10;
 
        snd_hda_pick_fixup(codec, cs4208_models, cs4208_fixup_tbl,
                           cs4208_fixups);