ALSA: hda - Give standard "Bass Speaker" mixer for 2.1 speakers
[pandora-kernel.git] / sound / pci / hda / patch_cirrus.c
index fcfc9f0..794b0da 100644 (file)
@@ -68,6 +68,7 @@ struct cs_spec {
 
        unsigned int hp_detect:1;
        unsigned int mic_detect:1;
+       unsigned int speaker_2_1:1;
        /* CS421x */
        unsigned int spdif_detect:1;
        unsigned int sense_b:1;
@@ -101,8 +102,8 @@ enum {
 #define CS420X_VENDOR_NID      0x11
 #define CS_DIG_OUT1_PIN_NID    0x10
 #define CS_DIG_OUT2_PIN_NID    0x15
-#define CS_DMIC1_PIN_NID       0x12
-#define CS_DMIC2_PIN_NID       0x0e
+#define CS_DMIC1_PIN_NID       0x0e
+#define CS_DMIC2_PIN_NID       0x12
 
 /* coef indices */
 #define IDX_SPDIF_STAT         0x0000
@@ -443,6 +444,9 @@ static int parse_output(struct hda_codec *codec)
        spec->multiout.dac_nids = spec->dac_nid;
        spec->multiout.max_channels = i * 2;
 
+       if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && i == 2)
+               spec->speaker_2_1 = 1; /* assume 2.1 speakers */
+
        /* add HP and speakers */
        extra_nids = 0;
        for (i = 0; i < cfg->hp_outs; i++) {
@@ -632,7 +636,9 @@ static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx,
                index = idx;
                break;
        case AUTO_PIN_SPEAKER_OUT:
-               if (num_ctls > 1)
+               if (spec->speaker_2_1)
+                       name = idx ? "Bass Speaker" : "Speaker";
+               else if (num_ctls > 1)
                        name = speakers[idx];
                else
                        name = "Speaker";
@@ -873,8 +879,9 @@ static int build_digital_output(struct hda_codec *codec)
        if (!spec->multiout.dig_out_nid)
                return 0;
 
-       err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid,
-                                           spec->multiout.dig_out_nid);
+       err = snd_hda_create_dig_out_ctls(codec, spec->multiout.dig_out_nid,
+                                         spec->multiout.dig_out_nid,
+                                         spec->pcm_rec[1].pcm_type);
        if (err < 0)
                return err;
        err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
@@ -897,7 +904,7 @@ static int build_digital_input(struct hda_codec *codec)
  * HP/SPK/SPDIF
  */
 
-static void cs_automute(struct hda_codec *codec)
+static void cs_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl)
 {
        struct cs_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
@@ -973,7 +980,7 @@ static void cs_automute(struct hda_codec *codec)
  * Switch max 3 inputs of a single ADC (nid 3)
 */
 
-static void cs_automic(struct hda_codec *codec)
+static void cs_automic(struct hda_codec *codec, struct hda_jack_tbl *tbl)
 {
        struct cs_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
@@ -1035,7 +1042,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_jack_detect_enable(codec, nid, HP_EVENT);
+                       snd_hda_jack_detect_enable_callback(codec, nid, HP_EVENT, cs_automute);
                        spec->hp_detect = 1;
                }
        }
@@ -1046,7 +1053,7 @@ static void init_output(struct hda_codec *codec)
 
        /* SPDIF is enabled on presence detect for CS421x */
        if (spec->hp_detect || spec->spdif_detect)
-               cs_automute(codec);
+               cs_automute(codec, NULL);
 }
 
 static void init_input(struct hda_codec *codec)
@@ -1070,26 +1077,30 @@ 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_jack_detect_enable(codec, pin, MIC_EVENT);
+                       snd_hda_jack_detect_enable_callback(codec, pin, MIC_EVENT, cs_automic);
        }
        /* CS420x has multiple ADC, CS421x has single ADC */
        if (spec->vendor_nid == CS420X_VENDOR_NID) {
                change_cur_input(codec, spec->cur_input, 1);
                if (spec->mic_detect)
-                       cs_automic(codec);
+                       cs_automic(codec, NULL);
 
                coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */
+               cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
+
+               coef = cs_vendor_coef_get(codec, IDX_BEEP_CFG);
                if (is_active_pin(codec, CS_DMIC2_PIN_NID))
-                       coef |= 0x0500; /* DMIC2 2 chan on, GPIO1 off */
+                       coef |= 1 << 4; /* DMIC2 2 chan on, GPIO1 off */
                if (is_active_pin(codec, CS_DMIC1_PIN_NID))
-                       coef |= 0x1800; /* DMIC1 2 chan on, GPIO0 off
+                       coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off
                                         * No effect if SPDIF_OUT2 is
                                         * selected in IDX_SPDIF_CTL.
                                        */
-               cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
+
+               cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef);
        } else {
                if (spec->mic_detect)
-                       cs_automic(codec);
+                       cs_automic(codec, NULL);
                else  {
                        spec->cur_adc = spec->adc_nid[spec->cur_input];
                        cs_update_input_select(codec);
@@ -1107,7 +1118,7 @@ static const struct hda_verb cs_coef_init_verbs[] = {
          | 0x0400 /* Disable Coefficient Auto increment */
          )},
        /* Beep */
-       {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG},
+       {0x11, AC_VERB_SET_COEF_INDEX, IDX_BEEP_CFG},
        {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */
 
        {} /* terminator */
@@ -1243,28 +1254,16 @@ static void cs_free(struct hda_codec *codec)
        struct cs_spec *spec = codec->spec;
        kfree(spec->capture_bind[0]);
        kfree(spec->capture_bind[1]);
+       snd_hda_gen_free(&spec->gen);
        kfree(codec->spec);
 }
 
-static void cs_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       switch (snd_hda_jack_get_action(codec, res >> 26)) {
-       case HP_EVENT:
-               cs_automute(codec);
-               break;
-       case MIC_EVENT:
-               cs_automic(codec);
-               break;
-       }
-       snd_hda_jack_report_sync(codec);
-}
-
 static const struct hda_codec_ops cs_patch_ops = {
        .build_controls = cs_build_controls,
        .build_pcms = cs_build_pcms,
        .init = cs_init,
        .free = cs_free,
-       .unsol_event = cs_unsol_event,
+       .unsol_event = snd_hda_jack_unsol_event,
 };
 
 static int cs_parse_auto_config(struct hda_codec *codec)
@@ -1439,6 +1438,7 @@ static int patch_cs420x(struct hda_codec *codec)
        if (!spec)
                return -ENOMEM;
        codec->spec = spec;
+       snd_hda_gen_init(&spec->gen);
 
        spec->vendor_nid = CS420X_VENDOR_NID;
 
@@ -1457,7 +1457,7 @@ static int patch_cs420x(struct hda_codec *codec)
        return 0;
 
  error:
-       kfree(codec->spec);
+       cs_free(codec);
        codec->spec = NULL;
        return err;
 }
@@ -1674,7 +1674,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_jack_detect_enable(codec, nid, SPDIF_EVENT);
+                       snd_hda_jack_detect_enable_callback(codec, nid, SPDIF_EVENT, cs_automute);
                        spec->spdif_detect = 1;
                }
        }
@@ -1739,8 +1739,7 @@ static int cs421x_mux_enum_put(struct snd_kcontrol *kcontrol,
 
 }
 
-static struct snd_kcontrol_new cs421x_capture_source = {
-
+static const struct snd_kcontrol_new cs421x_capture_source = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Capture Source",
        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
@@ -1889,21 +1888,6 @@ static int cs421x_build_controls(struct hda_codec *codec)
        return 0;
 }
 
-static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       switch (snd_hda_jack_get_action(codec, res >> 26)) {
-       case HP_EVENT:
-       case SPDIF_EVENT:
-               cs_automute(codec);
-               break;
-
-       case MIC_EVENT:
-               cs_automic(codec);
-               break;
-       }
-       snd_hda_jack_report_sync(codec);
-}
-
 static int parse_cs421x_input(struct hda_codec *codec)
 {
        struct cs_spec *spec = codec->spec;
@@ -1972,12 +1956,12 @@ static int cs421x_suspend(struct hda_codec *codec)
 }
 #endif
 
-static struct hda_codec_ops cs421x_patch_ops = {
+static const struct hda_codec_ops cs421x_patch_ops = {
        .build_controls = cs421x_build_controls,
        .build_pcms = cs_build_pcms,
        .init = cs421x_init,
        .free = cs_free,
-       .unsol_event = cs421x_unsol_event,
+       .unsol_event = snd_hda_jack_unsol_event,
 #ifdef CONFIG_PM
        .suspend = cs421x_suspend,
 #endif
@@ -1992,6 +1976,7 @@ static int patch_cs4210(struct hda_codec *codec)
        if (!spec)
                return -ENOMEM;
        codec->spec = spec;
+       snd_hda_gen_init(&spec->gen);
 
        spec->vendor_nid = CS4210_VENDOR_NID;
 
@@ -2017,7 +2002,7 @@ static int patch_cs4210(struct hda_codec *codec)
        return 0;
 
  error:
-       kfree(codec->spec);
+       cs_free(codec);
        codec->spec = NULL;
        return err;
 }
@@ -2031,6 +2016,7 @@ static int patch_cs4213(struct hda_codec *codec)
        if (!spec)
                return -ENOMEM;
        codec->spec = spec;
+       snd_hda_gen_init(&spec->gen);
 
        spec->vendor_nid = CS4213_VENDOR_NID;
 
@@ -2042,7 +2028,7 @@ static int patch_cs4213(struct hda_codec *codec)
        return 0;
 
  error:
-       kfree(codec->spec);
+       cs_free(codec);
        codec->spec = NULL;
        return err;
 }