logo       

[PATCH] [UBUNTU:sound] Apply various fixes to Sigmatel HDA codecs: msg#00018

Subject: [PATCH] [UBUNTU:sound] Apply various fixes to Sigmatel HDA codecs
UpstreamStatus: Added in upstream pci/hda/patch_sigmatel.c r1.8-r1.18

These fixes from Matt Porter <mporter@xxxxxxxxxxxxxxxxx> affect the
Sigmatel HDA codecs. Among the noteworthy changes are proper support
for non-reference boards (Intel 9xx) and a fixed mute control for the
922x mixer.

Signed-off-by: Daniel T Chen <crimsun@xxxxxxxxxx>

---

 sound/pci/hda/patch_sigmatel.c |  551 ++++++++++++++++++++++++++--------------
 1 files changed, 359 insertions(+), 192 deletions(-)

a7c6c5a4121e8442fdc5d970ea8a09f6fe7a988c
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 33a8ada..adb5a9a 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -4,7 +4,7 @@
  * HD audio interface patch for SigmaTel STAC92xx
  *
  * Copyright (c) 2005 Embedded Alley Solutions, Inc.
- * <matt@xxxxxxxxxxxxxxxxx>
+ * Matt Porter <matt@xxxxxxxxxxxxxxxxx>
  *
  * Based on patch_cmedia.c and patch_realtek.c
  * Copyright (c) 2004 Takashi Iwai <tiwai@xxxxxxx>
@@ -34,21 +34,27 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 
-#undef STAC_TEST
-
 #define NUM_CONTROL_ALLOC      32
 #define STAC_HP_EVENT          0x37
 #define STAC_UNSOL_ENABLE      (AC_USRSP_EN | STAC_HP_EVENT)
 
+#define STAC_REF       0
+#define STAC_D945GTP3  1
+#define STAC_D945GTP5  2
+
 struct sigmatel_spec {
        snd_kcontrol_new_t *mixers[4];
        unsigned int num_mixers;
 
+       int board_config;
        unsigned int surr_switch: 1;
+       unsigned int line_switch: 1;
+       unsigned int mic_switch: 1;
+       unsigned int alt_switch: 1;
 
        /* playback */
        struct hda_multi_out multiout;
-       hda_nid_t dac_nids[4];
+       hda_nid_t dac_nids[5];
 
        /* capture */
        hda_nid_t *adc_nids;
@@ -57,12 +63,10 @@ struct sigmatel_spec {
        unsigned int num_muxes;
        hda_nid_t dig_in_nid;
 
-#ifdef STAC_TEST
        /* pin widgets */
        hda_nid_t *pin_nids;
        unsigned int num_pins;
        unsigned int *pin_configs;
-#endif
 
        /* codec specific stuff */
        struct hda_verb *init;
@@ -70,11 +74,10 @@ struct sigmatel_spec {
 
        /* capture source */
        struct hda_input_mux *input_mux;
-       unsigned int cur_mux[2];
+       unsigned int cur_mux[3];
 
-       /* channel mode */
-       unsigned int num_ch_modes;
-       unsigned int cur_ch_mode;
+       /* i/o switches */
+       unsigned int io_switch[2];
 
        struct hda_pcm pcm_rec[2];      /* PCM information */
 
@@ -105,7 +108,14 @@ static hda_nid_t stac922x_mux_nids[2] = 
         0x12, 0x13,
 };
 
-#ifdef STAC_TEST
+static hda_nid_t stac927x_adc_nids[3] = {
+       0x07, 0x08, 0x09
+};
+
+static hda_nid_t stac927x_mux_nids[3] = {
+       0x15, 0x16, 0x17
+};
+
 static hda_nid_t stac9200_pin_nids[8] = {
        0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
 };
@@ -114,7 +124,12 @@ static hda_nid_t stac922x_pin_nids[10] =
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
        0x0f, 0x10, 0x11, 0x15, 0x1b,
 };
-#endif
+
+static hda_nid_t stac927x_pin_nids[14] = {
+       0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+       0x0f, 0x10, 0x11, 0x12, 0x13,
+       0x14, 0x21, 0x22, 0x23,
+};
 
 static int stac92xx_mux_enum_info(snd_kcontrol_t *kcontrol, 
snd_ctl_elem_info_t *uinfo)
 {
@@ -155,48 +170,11 @@ static struct hda_verb stac922x_core_ini
        {}
 };
 
-static int stac922x_channel_modes[3] = {2, 6, 8};
-
-static int stac922x_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t 
*uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct sigmatel_spec *spec = codec->spec;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = spec->num_ch_modes;
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 
1;
-       sprintf(uinfo->value.enumerated.name, "%dch",
-               stac922x_channel_modes[uinfo->value.enumerated.item]);
-       return 0;
-}
-
-static int stac922x_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t 
*ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct sigmatel_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->cur_ch_mode;
-       return 0;
-}
-
-static int stac922x_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t 
*ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (ucontrol->value.enumerated.item[0] >= spec->num_ch_modes)
-               ucontrol->value.enumerated.item[0] = spec->num_ch_modes;
-       if (ucontrol->value.enumerated.item[0] == spec->cur_ch_mode &&
-           ! codec->in_resume)
-               return 0;
-
-       spec->cur_ch_mode = ucontrol->value.enumerated.item[0];
-       spec->multiout.max_channels = stac922x_channel_modes[spec->cur_ch_mode];
-
-       return 1;
-}
+static struct hda_verb stac927x_core_init[] = {
+       /* set master volume and direct control */
+       { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       {}
+};
 
 static snd_kcontrol_new_t stac9200_mixer[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
@@ -231,14 +209,18 @@ static snd_kcontrol_new_t stac922x_mixer
        { } /* end */
 };
 
-static snd_kcontrol_new_t stac922x_ch_mode_mixer[] = {
+static snd_kcontrol_new_t stac927x_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = stac922x_ch_mode_info,
-               .get = stac922x_ch_mode_get,
-               .put = stac922x_ch_mode_put,
+               .name = "Input Source",
+               .count = 1,
+               .info = stac92xx_mux_enum_info,
+               .get = stac92xx_mux_enum_get,
+               .put = stac92xx_mux_enum_put,
        },
+       HDA_CODEC_VOLUME("InMux Capture Volume", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("InVol Capture Volume", 0x18, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1b, 0x0, HDA_OUTPUT),
        { } /* end */
 };
 
@@ -258,11 +240,6 @@ static int stac92xx_build_controls(struc
                        return err;
        }
 
-       if (spec->surr_switch) {
-               err = snd_hda_add_new_ctls(codec, stac922x_ch_mode_mixer);
-               if (err < 0)
-                       return err;
-       }
        if (spec->multiout.dig_out_nid) {
                err = snd_hda_create_spdif_out_ctls(codec, 
spec->multiout.dig_out_nid);
                if (err < 0)
@@ -276,18 +253,96 @@ static int stac92xx_build_controls(struc
        return 0;       
 }
 
-#ifdef STAC_TEST
-static unsigned int stac9200_pin_configs[8] = {
+static unsigned int ref9200_pin_configs[8] = {
        0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
        0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
 };
 
-static unsigned int stac922x_pin_configs[10] = {
-       0x01014010, 0x01014011, 0x01014012, 0x0221401f,
-       0x01813122, 0x01014014, 0x01441030, 0x01c41030,
+static unsigned int *stac9200_brd_tbl[] = {
+       ref9200_pin_configs,
+};
+
+static struct hda_board_config stac9200_cfg_tbl[] = {
+       { .modelname = "ref",
+         .pci_subvendor = PCI_VENDOR_ID_INTEL,
+         .pci_subdevice = 0x2668,      /* DFI LanParty */
+         .config = STAC_REF },
+       {} /* terminator */
+};
+
+static unsigned int ref922x_pin_configs[10] = {
+       0x01014010, 0x01016011, 0x01012012, 0x0221401f,
+       0x01813122, 0x01011014, 0x01441030, 0x01c41030,
        0x40000100, 0x40000100,
 };
 
+static unsigned int d945gtp3_pin_configs[10] = {
+       0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
+       0x40000100, 0x40000100, 0x40000100, 0x40000100,
+       0x02a19120, 0x40000100,
+};
+
+static unsigned int d945gtp5_pin_configs[10] = {
+       0x0221401f, 0x01011012, 0x01813024, 0x01014010,
+       0x01a19021, 0x01016011, 0x01452130, 0x40000100,
+       0x02a19320, 0x40000100,
+};
+
+static unsigned int *stac922x_brd_tbl[] = {
+       ref922x_pin_configs,
+       d945gtp3_pin_configs,
+       d945gtp5_pin_configs,
+};
+
+static struct hda_board_config stac922x_cfg_tbl[] = {
+       { .modelname = "ref",
+         .pci_subvendor = PCI_VENDOR_ID_INTEL,
+         .pci_subdevice = 0x2668,      /* DFI LanParty */
+         .config = STAC_REF },         /* SigmaTel reference board */
+       { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+         .pci_subdevice = 0x0101,
+         .config = STAC_D945GTP3 },    /* Intel D945GTP - 3 Stack */
+       { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+         .pci_subdevice = 0x0202,
+         .config = STAC_D945GTP3 },    /* Intel D945GNT - 3 Stack, 9221 A1 */
+       { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+         .pci_subdevice = 0x0b0b,
+         .config = STAC_D945GTP3 },    /* Intel D945PSN - 3 Stack, 9221 A1 */
+       { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+         .pci_subdevice = 0x0404,
+         .config = STAC_D945GTP5 },    /* Intel D945GTP - 5 Stack */
+       { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+         .pci_subdevice = 0x0303,
+         .config = STAC_D945GTP5 },    /* Intel D945GNT - 5 Stack */
+       { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+         .pci_subdevice = 0x0013,
+         .config = STAC_D945GTP5 },    /* Intel D955XBK - 5 Stack */
+       { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+         .pci_subdevice = 0x0417,
+         .config = STAC_D945GTP5 },    /* Intel D975XBK - 5 Stack */
+       {} /* terminator */
+};
+
+static unsigned int ref927x_pin_configs[14] = {
+       0x01813122, 0x01a19021, 0x01014010, 0x01016011,
+       0x01012012, 0x01011014, 0x40000100, 0x40000100,
+       0x40000100, 0x40000100, 0x40000100, 0x01441030,
+       0x40000100, 0x40000100, 0x40000100, 0x01441030,
+       0x01c41030, 0x40000100,
+};
+
+static unsigned int *stac927x_brd_tbl[] = {
+       ref927x_pin_configs,
+};
+
+static struct hda_board_config stac927x_cfg_tbl[] = {
+       { .modelname = "ref",
+         .pci_subvendor = PCI_VENDOR_ID_INTEL,
+         .pci_subdevice = 0x2668,      /* DFI LanParty */
+         .config = STAC_REF },         /* SigmaTel reference board */
+       {} /* terminator */
+};
+
 static void stac92xx_set_config_regs(struct hda_codec *codec)
 {
        int i;
@@ -310,10 +365,9 @@ static void stac92xx_set_config_regs(str
                pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0,
                                             AC_VERB_GET_CONFIG_DEFAULT,
                                             0x00);     
-               printk("pin nid %2.2x pin config %8.8x\n", spec->pin_nids[i], 
pin_cfg);
+               snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config 
%8.8x\n", spec->pin_nids[i], pin_cfg);
        }
 }
-#endif
 
 /*
  * Analog playback callbacks
@@ -326,56 +380,6 @@ static int stac92xx_playback_pcm_open(st
        return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
 }
 
-/*
- * set up the i/o for analog out
- * when the digital out is available, copy the front out to digital out, too.
- */
-static int stac92xx_multi_out_analog_prepare(struct hda_codec *codec, struct 
hda_multi_out *mout,
-                                    unsigned int stream_tag,
-                                    unsigned int format,
-                                    snd_pcm_substream_t *substream)
-{
-       hda_nid_t *nids = mout->dac_nids;
-       int chs = substream->runtime->channels;
-       int i;
-
-       down(&codec->spdif_mutex);
-       if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
-               if (chs == 2 &&
-                   snd_hda_is_supported_format(codec, mout->dig_out_nid, 
format) &&
-                   ! (codec->spdif_status & IEC958_AES0_NONAUDIO)) {
-                       mout->dig_out_used = HDA_DIG_ANALOG_DUP;
-                       /* setup digital receiver */
-                       snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
-                                                  stream_tag, 0, format);
-               } else {
-                       mout->dig_out_used = 0;
-                       snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 
0, 0);
-               }
-       }
-       up(&codec->spdif_mutex);
-
-       /* front */
-       snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, 
format);
-       if (mout->hp_nid)
-               /* headphone out will just decode front left/right (stereo) */
-               snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, 
format);
-       /* surrounds */
-       if (mout->max_channels > 2)
-               for (i = 1; i < mout->num_dacs; i++) {
-                       if ((mout->max_channels == 6) && (i == 3))
-                               break;
-                       if (chs >= (i + 1) * 2) /* independent out */
-                               snd_hda_codec_setup_stream(codec, nids[i], 
stream_tag, i * 2,
-                                               format);
-                       else /* copy front */
-                               snd_hda_codec_setup_stream(codec, nids[i], 
stream_tag, 0,
-                                               format);
-               }
-       return 0;
-}
-
-
 static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                         struct hda_codec *codec,
                                         unsigned int stream_tag,
@@ -383,8 +387,7 @@ static int stac92xx_playback_pcm_prepare
                                         snd_pcm_substream_t *substream)
 {
        struct sigmatel_spec *spec = codec->spec;
-       return stac92xx_multi_out_analog_prepare(codec, &spec->multiout, 
stream_tag,
-                                               format, substream);
+       return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 
stream_tag, format, substream);
 }
 
 static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
@@ -471,11 +474,23 @@ static struct hda_pcm_stream stac92xx_pc
        },
 };
 
+static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x06, /* NID to query formats and rates */
+       .ops = {
+               .open = stac92xx_playback_pcm_open,
+               .prepare = stac92xx_playback_pcm_prepare,
+               .cleanup = stac92xx_playback_pcm_cleanup
+       },
+};
+
 static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
        .substreams = 2,
        .channels_min = 2,
        .channels_max = 2,
-       .nid = 0x06, /* NID to query formats and rates */
+       /* NID is set in stac92xx_build_pcms */
        .ops = {
                .prepare = stac92xx_capture_pcm_prepare,
                .cleanup = stac92xx_capture_pcm_cleanup
@@ -493,6 +508,14 @@ static int stac92xx_build_pcms(struct hd
        info->name = "STAC92xx Analog";
        info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
        info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
+
+       if (spec->alt_switch) {
+               codec->num_pcms++;
+               info++;
+               info->name = "STAC92xx Analog Alt";
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK] = 
stac92xx_pcm_analog_alt_playback;
+       }
 
        if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
                codec->num_pcms++;
@@ -511,14 +534,70 @@ static int stac92xx_build_pcms(struct hd
        return 0;
 }
 
+static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, 
int pin_type)
+{
+       snd_hda_codec_write(codec, nid, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+}
+
+static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, struct 
snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct 
snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       int io_idx = kcontrol-> private_value & 0xff;
+
+       ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
+       return 0;
+}
+
+static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct 
snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       hda_nid_t nid = kcontrol->private_value >> 8;
+       int io_idx = kcontrol-> private_value & 0xff;
+       unsigned short val = ucontrol->value.integer.value[0];
+
+       spec->io_switch[io_idx] = val;
+
+       if (val)
+               stac92xx_auto_set_pinctl(codec, nid,
+                               AC_PINCTL_OUT_EN);
+       else
+               stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
+
+       return 1;
+}
+
+#define STAC_CODEC_IO_SWITCH(xname, xpval) \
+       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+         .name = xname, \
+         .index = 0, \
+         .info = stac92xx_io_switch_info, \
+         .get = stac92xx_io_switch_get, \
+         .put = stac92xx_io_switch_put, \
+         .private_value = xpval, \
+}
+
 enum {
        STAC_CTL_WIDGET_VOL,
        STAC_CTL_WIDGET_MUTE,
+       STAC_CTL_WIDGET_IO_SWITCH,
 };
 
 static snd_kcontrol_new_t stac92xx_control_templates[] = {
        HDA_CODEC_VOLUME(NULL, 0, 0, 0),
        HDA_CODEC_MUTE(NULL, 0, 0, 0),
+       STAC_CODEC_IO_SWITCH(NULL, 0),
 };
 
 /* add dynamic controls */
@@ -550,6 +629,60 @@ static int stac92xx_add_control(struct s
        return 0;
 }
 
+/* flag inputs as additional dynamic lineouts */
+static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct 
auto_pin_cfg *cfg)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       switch (cfg->line_outs) {
+               case 3:
+                       /* add line-in as side */
+                       if (cfg->input_pins[AUTO_PIN_LINE]) {
+                               cfg->line_out_pins[3] = 
cfg->input_pins[AUTO_PIN_LINE];
+                               spec->line_switch = 1;
+                               cfg->line_outs++;
+                       }
+                       break;
+               case 2:
+                       /* add line-in as clfe and mic as side */
+                       if (cfg->input_pins[AUTO_PIN_LINE]) {
+                               cfg->line_out_pins[2] = 
cfg->input_pins[AUTO_PIN_LINE];
+                               spec->line_switch = 1;
+                               cfg->line_outs++;
+                       }
+                       if (cfg->input_pins[AUTO_PIN_MIC]) {
+                               cfg->line_out_pins[3] = 
cfg->input_pins[AUTO_PIN_MIC];
+                               spec->mic_switch = 1;
+                               cfg->line_outs++;
+                       }
+                       break;
+               case 1:
+                       /* add line-in as surr and mic as clfe */
+                       if (cfg->input_pins[AUTO_PIN_LINE]) {
+                               cfg->line_out_pins[1] = 
cfg->input_pins[AUTO_PIN_LINE];
+                               spec->line_switch = 1;
+                               cfg->line_outs++;
+                       }
+                       if (cfg->input_pins[AUTO_PIN_MIC]) {
+                               cfg->line_out_pins[2] = 
cfg->input_pins[AUTO_PIN_MIC];
+                               spec->mic_switch = 1;
+                               cfg->line_outs++;
+                       }
+                       break;
+       }
+       return 0;
+}
+
+/*
+ * XXX The line_out pin widget connection list may not be set to the
+ * desired DAC nid. This is the case on 927x where ports A and B can
+ * be routed to several DACs.
+ *
+ * This requires an analysis of the line-out/hp pin configuration
+ * to provide a best fit for pin/DAC configurations that are routable.
+ * For now, 927x DAC4 is not supported and 927x DAC1 output to ports
+ * A and B is not supported.
+ */
 /* fill in the dac_nids table from the parsed pin configuration */
 static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct 
auto_pin_cfg *cfg)
 {
@@ -564,7 +697,12 @@ static int stac92xx_auto_fill_dac_nids(s
                                        AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
        }
 
-       spec->multiout.num_dacs = cfg->line_outs;
+       if (cfg->line_outs)
+               spec->multiout.num_dacs = cfg->line_outs;
+       else if (cfg->hp_pin) {
+               spec->multiout.dac_nids[0] = snd_hda_codec_read(codec, 
cfg->hp_pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+               spec->multiout.num_dacs = 1;
+       }
 
        return 0;
 }
@@ -609,6 +747,15 @@ static int stac92xx_auto_create_multi_ou
                }
        }
 
+       if (spec->line_switch)
+               if ((err = stac92xx_add_control(spec,
+                                               STAC_CTL_WIDGET_IO_SWITCH, 
"Line In as Output Switch", cfg->input_pins[AUTO_PIN_LINE] << 8)) < 0)
+                       return err;
+
+       if (spec->mic_switch)
+               if ((err = stac92xx_add_control(spec, 
STAC_CTL_WIDGET_IO_SWITCH, "Mic as Output Switch", 
(cfg->input_pins[AUTO_PIN_MIC] << 8) | 1)) < 0)
+                       return err;
+
        return 0;
 }
 
@@ -624,7 +771,8 @@ static int stac92xx_auto_create_hp_ctls(
        if (! pin)
                return 0;
 
-       wid_caps = snd_hda_param_read(codec, pin, AC_PAR_AUDIO_WIDGET_CAP);
+       wid_caps = get_wcaps(codec, pin);
+
        if (wid_caps & AC_WCAP_UNSOL_CAP)
                /* Enable unsolicited responses on the HP widget */
                snd_hda_codec_write(codec, pin, 0,
@@ -656,9 +804,6 @@ static int stac92xx_auto_create_hp_ctls(
 static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, 
const struct auto_pin_cfg *cfg)
 {
        struct sigmatel_spec *spec = codec->spec;
-       static char *labels[AUTO_PIN_LAST] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
-       };
        struct hda_input_mux *imux = &spec->private_imux;
        hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
        int i, j, k;
@@ -666,7 +811,10 @@ static int stac92xx_auto_create_analog_i
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                int index = -1;
                if (cfg->input_pins[i]) {
-                       imux->items[imux->num_items].label = labels[i];
+                       /* Enable active pin widget as an input */
+                       stac92xx_auto_set_pinctl(codec, cfg->input_pins[i], 
AC_PINCTL_IN_EN);
+
+                       imux->items[imux->num_items].label = 
auto_pin_cfg_labels[i];
 
                        for (j=0; j<spec->num_muxes; j++) {
                                int num_cons = snd_hda_get_connections(codec, 
spec->mux_nids[j], con_lst, HDA_MAX_NUM_INPUTS);
@@ -686,12 +834,6 @@ static int stac92xx_auto_create_analog_i
        return 0;
 }
 
-static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, 
int pin_type)
-
-{
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 
pin_type);
-}
-
 static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -713,17 +855,21 @@ static void stac92xx_auto_init_hp_out(st
                stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | 
AC_PINCTL_HP_EN);
 }
 
-static int stac922x_parse_auto_config(struct hda_codec *codec)
+static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t 
dig_out, hda_nid_t dig_in)
 {
        struct sigmatel_spec *spec = codec->spec;
        int err;
 
-       if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0)
-               return err;
-       if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
+       if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 
0)
                return err;
        if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin)
                return 0; /* can't find valid pin config */
+       stac92xx_auto_init_multi_out(codec);
+       stac92xx_auto_init_hp_out(codec);
+       if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
+               return err;
+       if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
+               return err;
 
        if ((err = stac92xx_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 
0 ||
            (err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg)) < 0 ||
@@ -731,22 +877,15 @@ static int stac922x_parse_auto_config(st
                return err;
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-       if (spec->multiout.max_channels > 2) {
+       if (spec->multiout.max_channels > 2)
                spec->surr_switch = 1;
-               spec->cur_ch_mode = 1;
-               spec->num_ch_modes = 2;
-               if (spec->multiout.max_channels == 8) {
-                       spec->cur_ch_mode++;
-                       spec->num_ch_modes++;
-               }
-       }
 
        if (spec->autocfg.dig_out_pin) {
-               spec->multiout.dig_out_nid = 0x08;
+               spec->multiout.dig_out_nid = dig_out;
                stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, 
AC_PINCTL_OUT_EN);
        }
        if (spec->autocfg.dig_in_pin) {
-               spec->dig_in_nid = 0x09;
+               spec->dig_in_nid = dig_in;
                stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, 
AC_PINCTL_IN_EN);
        }
 
@@ -763,7 +902,7 @@ static int stac9200_parse_auto_config(st
        struct sigmatel_spec *spec = codec->spec;
        int err;
 
-       if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0)
+       if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 
0)
                return err;
 
        if ((err = stac92xx_auto_create_analog_input_ctls(codec, 
&spec->autocfg)) < 0)
@@ -786,38 +925,12 @@ static int stac9200_parse_auto_config(st
        return 1;
 }
 
-static int stac92xx_init_pstate(struct hda_codec *codec)
-{
-       hda_nid_t nid, nid_start;
-       int nodes;
-
-       snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_POWER_STATE, 0x00);
-
-       nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
-       for (nid = nid_start; nid < nodes + nid_start; nid++) {
-               unsigned int wid_caps = snd_hda_param_read(codec, nid,
-                                                  AC_PAR_AUDIO_WIDGET_CAP);
-               if (wid_caps & AC_WCAP_POWER)
-                       snd_hda_codec_write(codec, nid, 0,
-                                    AC_VERB_SET_POWER_STATE, 0x00);
-       }
-
-       mdelay(100);
-
-       return 0;
-}
-
 static int stac92xx_init(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
 
-       stac92xx_init_pstate(codec);
-
        snd_hda_sequence_write(codec, spec->init);
 
-       stac92xx_auto_init_multi_out(codec);
-       stac92xx_auto_init_hp_out(codec);
-
        return 0;
 }
 
@@ -924,13 +1037,15 @@ static int patch_stac9200(struct hda_cod
                return -ENOMEM;
 
        codec->spec = spec;
-
-#ifdef STAC_TEST
-       spec->pin_nids = stac9200_pin_nids;
-       spec->num_pins = 8;
-       spec->pin_configs = stac9200_pin_configs;
-       stac92xx_set_config_regs(codec);
-#endif
+       spec->board_config = snd_hda_check_board_config(codec, 
stac9200_cfg_tbl);
+       if (spec->board_config < 0)
+               snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, 
using BIOS defaults\n");
+       else {
+               spec->num_pins = 8;
+               spec->pin_nids = stac9200_pin_nids;
+               spec->pin_configs = stac9200_brd_tbl[spec->board_config];
+               stac92xx_set_config_regs(codec);
+       }
        spec->multiout.max_channels = 2;
        spec->multiout.num_dacs = 1;
        spec->multiout.dac_nids = stac9200_dac_nids;
@@ -962,13 +1077,15 @@ static int patch_stac922x(struct hda_cod
                return -ENOMEM;
 
        codec->spec = spec;
-
-#ifdef STAC_TEST
-       spec->num_pins = 10;
-       spec->pin_nids = stac922x_pin_nids;
-       spec->pin_configs = stac922x_pin_configs;
-       stac92xx_set_config_regs(codec);
-#endif
+       spec->board_config = snd_hda_check_board_config(codec, 
stac922x_cfg_tbl);
+       if (spec->board_config < 0)
+               snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, 
using BIOS defaults\n");
+       else {
+               spec->num_pins = 10;
+               spec->pin_nids = stac922x_pin_nids;
+               spec->pin_configs = stac922x_brd_tbl[spec->board_config];
+               stac92xx_set_config_regs(codec);
+       }
        spec->adc_nids = stac922x_adc_nids;
        spec->mux_nids = stac922x_mux_nids;
        spec->num_muxes = 2;
@@ -978,7 +1095,47 @@ static int patch_stac922x(struct hda_cod
 
        spec->multiout.dac_nids = spec->dac_nids;
 
-       err = stac922x_parse_auto_config(codec);
+       err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
+       if (err < 0) {
+               stac92xx_free(codec);
+               return err;
+       }
+
+       codec->patch_ops = stac92xx_patch_ops;
+
+       return 0;
+}
+
+static int patch_stac927x(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       int err;
+
+       spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+       spec->board_config = snd_hda_check_board_config(codec, 
stac927x_cfg_tbl);
+       if (spec->board_config < 0)
+               snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, 
using BIOS defaults\n");
+       else {
+               spec->num_pins = 14;
+               spec->pin_nids = stac927x_pin_nids;
+               spec->pin_configs = stac927x_brd_tbl[spec->board_config];
+               stac92xx_set_config_regs(codec);
+       }
+
+       spec->adc_nids = stac927x_adc_nids;
+       spec->mux_nids = stac927x_mux_nids;
+       spec->num_muxes = 3;
+
+       spec->init = stac927x_core_init;
+       spec->mixer = stac927x_mixer;
+
+       spec->multiout.dac_nids = spec->dac_nids;
+
+       err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
        if (err < 0) {
                stac92xx_free(codec);
                return err;
@@ -1000,5 +1157,15 @@ struct hda_codec_preset snd_hda_preset_s
        { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = 
patch_stac922x },
        { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
        { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
+       { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
+       { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
+       { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
+       { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
+       { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
+       { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
+       { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
+       { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
+       { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
+       { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
        {} /* terminator */
 };
-- 
1.1.3

-- 
Daniel T. Chen            crimsun@xxxxxxxxxx
GPG key:   www.sh.nu/~crimsun/pubkey.gpg.asc

Attachment: pgpu5UNESwXxX.pgp
Description: PGP signature


<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

Recently Viewed:
web.pylons.gene...    hurd.l4/2002-10...    kernel.commits....    user-groups.lin...    yellowdog.gener...    java.drools.use...    security.openva...    package-managem...    linux.debian.us...    qnx.openqnx.dev...    genealogy.gramp...    file-systems.if...    voip.wengophone...    tex.context/200...    ietf.smime/2003...    audio.csound.de...    culture.region....    xfree86.devel/2...    mobile.kannel.u...    distributed.con...    education.engli...    org.user-groups...    bug-tracking.gn...    recreation.bicy...   
Home | blog view | USPTO Patent Archive | advertise | OSDir is an inevitable website. super tiny logo

Free Magazines

Cisco News
Receive a free quarterly e-newsletter with exclusive articles on how Cisco IT uses its own products and solutions to enable the business.
subscribe

Systems Management News, the newspaper for IT systems administration and data center managers! Each issue of Systems Management News is chock-full of news and analysis to help you understand what's happening in your field.
subscribe

The Enterprise Newsweekly eWeek is the essential technology information source for builders of e-business.
subscribe

Oracle Magazine Oracle Magazine contains technology strategy articles, sample code, tips, Oracle and partner news, how to articles for developers and DBAs, and more. Oracle (NASDAQ: ORCL) is the world's largest enterprise software company.
subscribe

Total Telecom Total Telecom is "The Economist of the communications industry".
subscribe