ALSA: hda - Add digital-mic support to ALC262 auto model
[pandora-kernel.git] / sound / pci / hda / patch_realtek.c
index 8cebe26..3345331 100644 (file)
@@ -224,6 +224,7 @@ enum {
        ALC883_ACER,
        ALC883_ACER_ASPIRE,
        ALC888_ACER_ASPIRE_4930G,
+       ALC888_ACER_ASPIRE_6530G,
        ALC888_ACER_ASPIRE_8930G,
        ALC883_MEDION,
        ALC883_MEDION_MD2,
@@ -249,13 +250,6 @@ enum {
        ALC883_MODEL_LAST,
 };
 
-/* styles of capture selection */
-enum {
-       CAPT_MUX = 0,   /* only mux based */
-       CAPT_MIX,       /* only mixer based */
-       CAPT_1MUX_MIX,  /* first mux and other mixers */
-};
-
 /* for GPIO Poll */
 #define GPIO_MASK      0x03
 
@@ -305,7 +299,6 @@ struct alc_spec {
        hda_nid_t *adc_nids;
        hda_nid_t *capsrc_nids;
        hda_nid_t dig_in_nid;           /* digital-in NID; optional */
-       int capture_style;              /* capture style (CAPT_*) */
 
        /* capture source */
        unsigned int num_mux_defs;
@@ -419,12 +412,13 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
        unsigned int mux_idx;
        hda_nid_t nid = spec->capsrc_nids ?
                spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
+       unsigned int type;
 
        mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
        imux = &spec->input_mux[mux_idx];
 
-       if (spec->capture_style &&
-           !(spec->capture_style == CAPT_1MUX_MIX && !adc_idx)) {
+       type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+       if (type == AC_WID_AUD_MIX) {
                /* Matrix-mixer style (e.g. ALC882) */
                unsigned int *cur_val = &spec->cur_mux[adc_idx];
                unsigned int i, idx;
@@ -1470,6 +1464,25 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
        { }
 };
 
+/*
+ * ALC888 Acer Aspire 6530G model
+ */
+
+static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
+/* Bias voltage on for external mic port */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
+/* Enable unsolicited event for HP jack */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+/* Enable speaker output */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+/* Enable headphone output */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       { }
+};
+
 /*
  * ALC889 Acer Aspire 8930G model
  */
@@ -1544,6 +1557,25 @@ static struct hda_input_mux alc888_2_capture_sources[2] = {
        }
 };
 
+static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
+       /* Interal mic only available on one ADC */
+       {
+               .num_items = 3,
+               .items = {
+                       { "Ext Mic", 0x0 },
+                       { "CD", 0x4 },
+                       { "Int Mic", 0xb },
+               },
+       },
+       {
+               .num_items = 2,
+               .items = {
+                       { "Ext Mic", 0x0 },
+                       { "CD", 0x4 },
+               },
+       }
+};
+
 static struct hda_input_mux alc889_capture_sources[3] = {
        /* Digital mic only available on first "ADC" */
        {
@@ -7518,7 +7550,6 @@ static int patch_alc882(struct hda_codec *codec)
        spec->stream_digital_playback = &alc882_pcm_digital_playback;
        spec->stream_digital_capture = &alc882_pcm_digital_capture;
 
-       spec->capture_style = CAPT_MIX; /* matrix-style capture */
        if (!spec->adc_nids && spec->input_mux) {
                /* check whether NID 0x07 is valid */
                unsigned int wcap = get_wcaps(codec, 0x07);
@@ -8153,6 +8184,19 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("LFE Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
 static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -8978,6 +9022,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
        [ALC883_ACER]           = "acer",
        [ALC883_ACER_ASPIRE]    = "acer-aspire",
        [ALC888_ACER_ASPIRE_4930G]      = "acer-aspire-4930g",
+       [ALC888_ACER_ASPIRE_6530G]      = "acer-aspire-6530g",
        [ALC888_ACER_ASPIRE_8930G]      = "acer-aspire-8930g",
        [ALC883_MEDION]         = "medion",
        [ALC883_MEDION_MD2]     = "medion-md2",
@@ -9021,7 +9066,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
                ALC888_ACER_ASPIRE_4930G),
        SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
-               ALC888_ACER_ASPIRE_4930G),
+               ALC888_ACER_ASPIRE_6530G),
        /* default Acer -- disabled as it causes more problems.
         *    model=auto should work fine now
         */
@@ -9256,6 +9301,24 @@ static struct alc_config_preset alc883_presets[] = {
                .unsol_event = alc_automute_amp_unsol_event,
                .init_hook = alc888_acer_aspire_4930g_init_hook,
        },
+       [ALC888_ACER_ASPIRE_6530G] = {
+               .mixers = { alc888_acer_aspire_6530_mixer },
+               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
+                               alc888_acer_aspire_6530g_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
+               .adc_nids = alc883_adc_nids_rev,
+               .capsrc_nids = alc883_capsrc_nids_rev,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .num_mux_defs =
+                       ARRAY_SIZE(alc888_2_capture_sources),
+               .input_mux = alc888_acer_aspire_6530_sources,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc888_acer_aspire_4930g_init_hook,
+       },
        [ALC888_ACER_ASPIRE_8930G] = {
                .mixers = { alc888_base_mixer,
                                alc883_chmode_mixer },
@@ -9710,7 +9773,6 @@ static int patch_alc883(struct hda_codec *codec)
                }
                if (!spec->capsrc_nids)
                        spec->capsrc_nids = alc883_capsrc_nids;
-               spec->capture_style = CAPT_MIX; /* matrix-style capture */
                spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
                break;
        case 0x10ec0889:
@@ -9720,8 +9782,6 @@ static int patch_alc883(struct hda_codec *codec)
                }
                if (!spec->capsrc_nids)
                        spec->capsrc_nids = alc889_capsrc_nids;
-               spec->capture_style = CAPT_1MUX_MIX; /* 1mux/Nmix-style
-                                                       capture */
                break;
        default:
                if (!spec->num_adc_nids) {
@@ -9730,7 +9790,6 @@ static int patch_alc883(struct hda_codec *codec)
                }
                if (!spec->capsrc_nids)
                        spec->capsrc_nids = alc883_capsrc_nids;
-               spec->capture_style = CAPT_MIX; /* matrix-style capture */
                break;
        }
 
@@ -10842,9 +10901,27 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
        return 0;
 }
 
-/* identical with ALC880 */
-#define alc262_auto_create_analog_input_ctls \
-       alc880_auto_create_analog_input_ctls
+static int alc262_auto_create_analog_input_ctls(struct alc_spec *spec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       int err;
+
+       err = alc880_auto_create_analog_input_ctls(spec, cfg);
+       if (err < 0)
+               return err;
+       /* digital-mic input pin is excluded in alc880_auto_create..()
+        * because it's under 0x18
+        */
+       if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
+           cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
+               struct hda_input_mux *imux = &spec->private_imux[0];
+               imux->items[imux->num_items].label = "Int Mic";
+               imux->items[imux->num_items].index = 0x09;
+               imux->num_items++;
+       }
+       return 0;
+}
+
 
 /*
  * generic initialization of ADC, input mixers and output mixers
@@ -11261,6 +11338,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
        SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
+       SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
        SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
                           ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
@@ -11468,6 +11546,7 @@ static struct alc_config_preset alc262_presets[] = {
                .capsrc_nids = alc262_dmic_capsrc_nids,
                .dac_nids = alc262_dac_nids,
                .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
+               .num_adc_nids = 1, /* single ADC */
                .dig_out_nid = ALC262_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
@@ -11569,21 +11648,36 @@ static int patch_alc262(struct hda_codec *codec)
        spec->stream_digital_playback = &alc262_pcm_digital_playback;
        spec->stream_digital_capture = &alc262_pcm_digital_capture;
 
-       spec->capture_style = CAPT_MIX;
        if (!spec->adc_nids && spec->input_mux) {
-               /* check whether NID 0x07 is valid */
-               unsigned int wcap = get_wcaps(codec, 0x07);
-
-               /* get type */
-               wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-               if (wcap != AC_WID_AUD_IN) {
-                       spec->adc_nids = alc262_adc_nids_alt;
-                       spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
-                       spec->capsrc_nids = alc262_capsrc_nids_alt;
+               int i;
+               /* check whether the digital-mic has to be supported */
+               for (i = 0; i < spec->input_mux->num_items; i++) {
+                       if (spec->input_mux->items[i].index >= 9)
+                               break;
+               }
+               if (i < spec->input_mux->num_items) {
+                       /* use only ADC0 */
+                       spec->adc_nids = alc262_dmic_adc_nids;
+                       spec->num_adc_nids = 1;
+                       spec->capsrc_nids = alc262_dmic_capsrc_nids;
                } else {
-                       spec->adc_nids = alc262_adc_nids;
-                       spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
-                       spec->capsrc_nids = alc262_capsrc_nids;
+                       /* all analog inputs */
+                       /* check whether NID 0x07 is valid */
+                       unsigned int wcap = get_wcaps(codec, 0x07);
+
+                       /* get type */
+                       wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+                       if (wcap != AC_WID_AUD_IN) {
+                               spec->adc_nids = alc262_adc_nids_alt;
+                               spec->num_adc_nids =
+                                       ARRAY_SIZE(alc262_adc_nids_alt);
+                               spec->capsrc_nids = alc262_capsrc_nids_alt;
+                       } else {
+                               spec->adc_nids = alc262_adc_nids;
+                               spec->num_adc_nids =
+                                       ARRAY_SIZE(alc262_adc_nids);
+                               spec->capsrc_nids = alc262_capsrc_nids;
+                       }
                }
        }
        if (!spec->cap_mixer && !spec->no_analog)
@@ -13173,26 +13267,8 @@ static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
        return 0;
 }
 
-static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       int err;
-
-       err = alc880_auto_create_analog_input_ctls(spec, cfg);
-       if (err < 0)
-               return err;
-       /* digital-mic input pin is excluded in alc880_auto_create..()
-        * because it's under 0x18
-        */
-       if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
-           cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
-               struct hda_input_mux *imux = &spec->private_imux[0];
-               imux->items[imux->num_items].label = "Int Mic";
-               imux->items[imux->num_items].index = 0x05;
-               imux->num_items++;
-       }
-       return 0;
-}
+#define alc269_auto_create_analog_input_ctls \
+       alc262_auto_create_analog_input_ctls
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc269_loopbacks       alc880_loopbacks
@@ -15483,7 +15559,6 @@ static int patch_alc861vd(struct hda_codec *codec)
        spec->adc_nids = alc861vd_adc_nids;
        spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
        spec->capsrc_nids = alc861vd_capsrc_nids;
-       spec->capture_style = CAPT_MIX;
 
        set_capture_mixer(spec);
        set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
@@ -17403,7 +17478,6 @@ static int patch_alc662(struct hda_codec *codec)
        spec->adc_nids = alc662_adc_nids;
        spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
        spec->capsrc_nids = alc662_capsrc_nids;
-       spec->capture_style = CAPT_MIX;
 
        if (!spec->cap_mixer)
                set_capture_mixer(spec);