Pull sbs into release branch
[pandora-kernel.git] / sound / pci / hda / patch_sigmatel.c
index 270539a..3f25de7 100644 (file)
@@ -44,6 +44,7 @@ enum {
 
 enum {
        STAC_9205_REF,
+       STAC_M43xx,
        STAC_9205_MODELS
 };
 
@@ -218,7 +219,6 @@ static hda_nid_t stac9205_pin_nids[12] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
        0x0f, 0x14, 0x16, 0x17, 0x18,
        0x21, 0x22,
-       
 };
 
 static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
@@ -334,8 +334,6 @@ static struct snd_kcontrol_new stac9200_mixer[] = {
 };
 
 static struct snd_kcontrol_new stac925x_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Input Source",
@@ -775,7 +773,8 @@ static unsigned int ref9205_pin_configs[12] = {
 };
 
 static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
-       ref9205_pin_configs,
+       [STAC_REF] = ref9205_pin_configs,
+       [STAC_M43xx] = NULL,
 };
 
 static const char *stac9205_models[STAC_9205_MODELS] = {
@@ -786,6 +785,10 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_9205_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01f8,
+                     "Dell Precision", STAC_M43xx),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01ff,
+                     "Dell Precision", STAC_M43xx),
        {} /* terminator */
 };
 
@@ -815,48 +818,56 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
        return 0;
 }
 
+static void stac92xx_set_config_reg(struct hda_codec *codec,
+                                   hda_nid_t pin_nid, unsigned int pin_config)
+{
+       int i;
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
+                           pin_config & 0x000000ff);
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
+                           (pin_config & 0x0000ff00) >> 8);
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
+                           (pin_config & 0x00ff0000) >> 16);
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
+                           pin_config >> 24);
+       i = snd_hda_codec_read(codec, pin_nid, 0,
+                              AC_VERB_GET_CONFIG_DEFAULT,
+                              0x00);   
+       snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
+                   pin_nid, i);
+}
+
 static void stac92xx_set_config_regs(struct hda_codec *codec)
 {
        int i;
        struct sigmatel_spec *spec = codec->spec;
-       unsigned int pin_cfg;
 
-       if (! spec->pin_nids || ! spec->pin_configs)
-               return;
+       if (!spec->pin_configs)
+               return;
 
-       for (i = 0; i < spec->num_pins; i++) {
-               snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
-                                   spec->pin_configs[i] & 0x000000ff);
-               snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
-                                   (spec->pin_configs[i] & 0x0000ff00) >> 8);
-               snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
-                                   (spec->pin_configs[i] & 0x00ff0000) >> 16);
-               snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
-                                   spec->pin_configs[i] >> 24);
-               pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0,
-                                            AC_VERB_GET_CONFIG_DEFAULT,
-                                            0x00);     
-               snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n", spec->pin_nids[i], pin_cfg);
-       }
+       for (i = 0; i < spec->num_pins; i++)
+               stac92xx_set_config_reg(codec, spec->pin_nids[i],
+                                       spec->pin_configs[i]);
 }
 
-static void stac92xx_enable_eapd(struct hda_codec *codec)
+static void stac92xx_enable_gpio_mask(struct hda_codec *codec,
+                                     int gpio_mask, int gpio_data)
 {
-       /* Configure GPIO0 as output */
+       /* Configure GPIOx as output */
        snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_DIRECTION, 0x00000001);
-       /* Configure GPIO0 as CMOS */
+                           AC_VERB_SET_GPIO_DIRECTION, gpio_mask);
+       /* Configure GPIOx as CMOS */
        snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
-       /* Assert GPIO0 high */
+       /* Assert GPIOx */
        snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_DATA, 0x00000001);
-       /* Enable GPIO0 */
+                           AC_VERB_SET_GPIO_DATA, gpio_data);
+       /* Enable GPIOx */
        snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_MASK, 0x00000001);
+                           AC_VERB_SET_GPIO_MASK, gpio_mask);
 }
 
 /*
@@ -1228,7 +1239,7 @@ static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
  * and 9202/925x. For those, dac_nids[] must be hard-coded.
  */
 static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
-                                      const struct auto_pin_cfg *cfg)
+                                      struct auto_pin_cfg *cfg)
 {
        struct sigmatel_spec *spec = codec->spec;
        int i, j, conn_len = 0; 
@@ -1253,6 +1264,13 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
                }
 
                if (j == conn_len) {
+                       if (spec->multiout.num_dacs > 0) {
+                               /* we have already working output pins,
+                                * so let's drop the broken ones again
+                                */
+                               cfg->line_outs = spec->multiout.num_dacs;
+                               break;
+                       }
                        /* error out, no available DAC found */
                        snd_printk(KERN_ERR
                                   "%s: No available DAC for pin 0x%x\n",
@@ -1394,7 +1412,15 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
                        continue;
                add_spec_dacs(spec, nid);
        }
-
+       for (i = 0; i < cfg->line_outs; i++) {
+               nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
+                                       AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+               if (check_in_dac_nids(spec, nid))
+                       nid = 0;
+               if (! nid)
+                       continue;
+               add_spec_dacs(spec, nid);
+       }
        for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
                static const char *pfxs[] = {
                        "Speaker", "External Speaker", "Speaker2",
@@ -1951,7 +1977,7 @@ static int patch_stac9200(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 8;
+       spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
        spec->pin_nids = stac9200_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
                                                        stac9200_models,
@@ -2001,7 +2027,7 @@ static int patch_stac925x(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 8;
+       spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
        spec->pin_nids = stac925x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
                                                        stac925x_models,
@@ -2073,7 +2099,7 @@ static int patch_stac922x(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 10;
+       spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
        spec->pin_nids = stac922x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
                                                        stac922x_models,
@@ -2174,7 +2200,7 @@ static int patch_stac927x(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 14;
+       spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
        spec->pin_nids = stac927x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
                                                        stac927x_models,
@@ -2220,7 +2246,8 @@ static int patch_stac927x(struct hda_codec *codec)
        }
 
        spec->multiout.dac_nids = spec->dac_nids;
-       stac92xx_enable_eapd(codec);
+       /* GPIO0 High = Enable EAPD */
+       stac92xx_enable_gpio_mask(codec, 0x00000001, 0x00000001);
        
        err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
        if (!err) {
@@ -2239,27 +2266,20 @@ static int patch_stac927x(struct hda_codec *codec)
 
        codec->patch_ops = stac92xx_patch_ops;
 
-       /* Fix Mux capture level; max to 2 */
-       snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
-                                 (0 << AC_AMPCAP_OFFSET_SHIFT) |
-                                 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                 (0 << AC_AMPCAP_MUTE_SHIFT));
-
        return 0;
 }
 
 static int patch_stac9205(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
-       int err;
+       int err, gpio_mask, gpio_data;
 
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 14;
+       spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
        spec->pin_nids = stac9205_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
                                                        stac9205_models,
@@ -2289,8 +2309,21 @@ static int patch_stac9205(struct hda_codec *codec)
        spec->mixer = stac9205_mixer;
 
        spec->multiout.dac_nids = spec->dac_nids;
-       stac92xx_enable_eapd(codec);
+       
+       if (spec->board_config == STAC_M43xx) {
+               /* Enable SPDIF in/out */
+               stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
+               stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
+
+               gpio_mask = 0x00000007; /* GPIO0-2 */
+               /* GPIO0 High = EAPD, GPIO1 Low = DRM,
+                * GPIO2 High = Headphone Mute
+                */
+               gpio_data = 0x00000005;
+       } else
+               gpio_mask = gpio_data = 0x00000001; /* GPIO0 High = EAPD */
 
+       stac92xx_enable_gpio_mask(codec, gpio_mask, gpio_data);
        err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
        if (!err) {
                if (spec->board_config < 0) {
@@ -2325,8 +2358,8 @@ static struct hda_input_mux vaio_mux = {
        .num_items = 2,
        .items = {
                /* { "HP", 0x0 }, */
-               { "Line", 0x1 },
-               { "Mic", 0x2 },
+               { "Mic Jack", 0x1 },
+               { "Internal Mic", 0x2 },
                { "PCM", 0x3 },
        }
 };
@@ -2337,7 +2370,7 @@ static struct hda_verb vaio_init[] = {
        {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
        {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
        {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
        {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
        {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
@@ -2353,7 +2386,7 @@ static struct hda_verb vaio_ar_init[] = {
        {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
 /*     {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
        {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
        {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
 /*     {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */