Merge branch 'topic/section-fix' into for-linus
[pandora-kernel.git] / sound / pci / hda / patch_sigmatel.c
index 26d8707..42f944b 100644 (file)
@@ -151,6 +151,7 @@ enum {
        STAC_D965_REF,
        STAC_D965_3ST,
        STAC_D965_5ST,
+       STAC_D965_5ST_NO_FP,
        STAC_DELL_3ST,
        STAC_DELL_BIOS,
        STAC_927X_MODELS
@@ -669,62 +670,6 @@ static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid)
        return vref;
 }
 
-static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned int new_vref;
-       unsigned int error;
-
-       if (ucontrol->value.enumerated.item[0] == 0)
-               new_vref = AC_PINCTL_VREF_80;
-       else if (ucontrol->value.enumerated.item[0] == 1)
-               new_vref = AC_PINCTL_VREF_GRD;
-       else
-               new_vref = AC_PINCTL_VREF_HIZ;
-
-       if (new_vref != stac92xx_vref_get(codec, kcontrol->private_value)) {
-               error = stac92xx_vref_set(codec,
-                                       kcontrol->private_value, new_vref);
-               return error;
-       }
-
-       return 0;
-}
-
-static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned int vref = stac92xx_vref_get(codec, kcontrol->private_value);
-       if (vref == AC_PINCTL_VREF_80)
-               ucontrol->value.enumerated.item[0] = 0;
-       else if (vref == AC_PINCTL_VREF_GRD)
-               ucontrol->value.enumerated.item[0] = 1;
-       else if (vref == AC_PINCTL_VREF_HIZ)
-               ucontrol->value.enumerated.item[0] = 2;
-
-       return 0;
-}
-
-static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_info *uinfo)
-{
-       static char *texts[] = {
-               "Mic In", "Line In", "Line Out"
-       };
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->value.enumerated.items = 3;
-       uinfo->count = 1;
-       if (uinfo->value.enumerated.item >= 3)
-               uinfo->value.enumerated.item = 2;
-       strcpy(uinfo->value.enumerated.name,
-               texts[uinfo->value.enumerated.item]);
-
-       return 0;
-}
-
 static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -2261,6 +2206,13 @@ static unsigned int d965_5st_pin_configs[14] = {
        0x40000100, 0x40000100
 };
 
+static unsigned int d965_5st_no_fp_pin_configs[14] = {
+       0x40000100, 0x40000100, 0x0181304e, 0x01014010,
+       0x01a19040, 0x01011012, 0x01016011, 0x40000100,
+       0x40000100, 0x40000100, 0x40000100, 0x01442070,
+       0x40000100, 0x40000100
+};
+
 static unsigned int dell_3st_pin_configs[14] = {
        0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
        0x01111212, 0x01116211, 0x01813050, 0x01112214,
@@ -2273,6 +2225,7 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
        [STAC_D965_REF]  = ref927x_pin_configs,
        [STAC_D965_3ST]  = d965_3st_pin_configs,
        [STAC_D965_5ST]  = d965_5st_pin_configs,
+       [STAC_D965_5ST_NO_FP]  = d965_5st_no_fp_pin_configs,
        [STAC_DELL_3ST]  = dell_3st_pin_configs,
        [STAC_DELL_BIOS] = NULL,
 };
@@ -2283,6 +2236,7 @@ static const char *stac927x_models[STAC_927X_MODELS] = {
        [STAC_D965_REF]         = "ref",
        [STAC_D965_3ST]         = "3stack",
        [STAC_D965_5ST]         = "5stack",
+       [STAC_D965_5ST_NO_FP]   = "5stack-no-fp",
        [STAC_DELL_3ST]         = "dell-3stack",
        [STAC_DELL_BIOS]        = "dell-bios",
 };
@@ -2642,7 +2596,8 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
        return 0;
 }
 
-static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int stac92xx_get_default_vref(struct hda_codec *codec,
+                                       hda_nid_t nid)
 {
        unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
        pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
@@ -2696,15 +2651,108 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
-#define stac92xx_io_switch_info                snd_ctl_boolean_mono_info
+static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       int i;
+       static char *texts[] = {
+               "Mic In", "Line In", "Line Out"
+       };
+
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       hda_nid_t nid = kcontrol->private_value;
+
+       if (nid == spec->mic_switch || nid == spec->line_switch)
+               i = 3;
+       else
+               i = 2;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->value.enumerated.items = i;
+       uinfo->count = 1;
+       if (uinfo->value.enumerated.item >= i)
+               uinfo->value.enumerated.item = i-1;
+       strcpy(uinfo->value.enumerated.name,
+               texts[uinfo->value.enumerated.item]);
+
+       return 0;
+}
+
+static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       unsigned int vref = stac92xx_vref_get(codec, nid);
+
+       if (vref == stac92xx_get_default_vref(codec, nid))
+               ucontrol->value.enumerated.item[0] = 0;
+       else if (vref == AC_PINCTL_VREF_GRD)
+               ucontrol->value.enumerated.item[0] = 1;
+       else if (vref == AC_PINCTL_VREF_HIZ)
+               ucontrol->value.enumerated.item[0] = 2;
+
+       return 0;
+}
+
+static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int new_vref = 0;
+       unsigned int error;
+       hda_nid_t nid = kcontrol->private_value;
+
+       if (ucontrol->value.enumerated.item[0] == 0)
+               new_vref = stac92xx_get_default_vref(codec, nid);
+       else if (ucontrol->value.enumerated.item[0] == 1)
+               new_vref = AC_PINCTL_VREF_GRD;
+       else if (ucontrol->value.enumerated.item[0] == 2)
+               new_vref = AC_PINCTL_VREF_HIZ;
+       else
+               return 0;
+
+       if (new_vref != stac92xx_vref_get(codec, nid)) {
+               error = stac92xx_vref_set(codec, nid, new_vref);
+               return error;
+       }
+
+       return 0;
+}
+
+static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[2];
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (kcontrol->private_value == spec->line_switch)
+               texts[0] = "Line In";
+       else
+               texts[0] = "Mic In";
+       texts[1] = "Line Out";
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->value.enumerated.items = 2;
+       uinfo->count = 1;
+
+       if (uinfo->value.enumerated.item >= 2)
+               uinfo->value.enumerated.item = 1;
+       strcpy(uinfo->value.enumerated.name,
+               texts[uinfo->value.enumerated.item]);
+
+       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;
+       hda_nid_t nid = kcontrol->private_value;
+       int io_idx = (nid == spec->mic_switch) ? 1 : 0;
 
-       ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
+       ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx];
        return 0;
 }
 
@@ -2712,9 +2760,9 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
 {
         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];
+       hda_nid_t nid = kcontrol->private_value;
+       int io_idx = (nid == spec->mic_switch) ? 1 : 0;
+       unsigned short val = !!ucontrol->value.enumerated.item[0];
 
        spec->io_switch[io_idx] = val;
 
@@ -2723,7 +2771,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
        else {
                unsigned int pinctl = AC_PINCTL_IN_EN;
                if (io_idx) /* set VREF for mic */
-                       pinctl |= stac92xx_get_vref(codec, nid);
+                       pinctl |= stac92xx_get_default_vref(codec, nid);
                stac92xx_auto_set_pinctl(codec, nid, pinctl);
        }
 
@@ -2881,6 +2929,34 @@ static struct snd_kcontrol_new stac_input_src_temp = {
        .put = stac92xx_mux_enum_put,
 };
 
+static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
+                                               hda_nid_t nid, int idx)
+{
+       int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       int control = 0;
+       struct sigmatel_spec *spec = codec->spec;
+       char name[22];
+
+       if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) {
+               if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
+                       && nid == spec->line_switch)
+                       control = STAC_CTL_WIDGET_IO_SWITCH;
+               else if (snd_hda_query_pin_caps(codec, nid)
+                       & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT))
+                       control = STAC_CTL_WIDGET_DC_BIAS;
+               else if (nid == spec->mic_switch)
+                       control = STAC_CTL_WIDGET_IO_SWITCH;
+       }
+
+       if (control) {
+               strcpy(name, auto_pin_cfg_labels[idx]);
+               return stac92xx_add_control(codec->spec, control,
+                                       strcat(name, " Jack Mode"), nid);
+       }
+
+       return 0;
+}
+
 static int stac92xx_add_input_source(struct sigmatel_spec *spec)
 {
        struct snd_kcontrol_new *knew;
@@ -3243,7 +3319,9 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                                               const struct auto_pin_cfg *cfg)
 {
        struct sigmatel_spec *spec = codec->spec;
+       hda_nid_t nid;
        int err;
+       int idx;
 
        err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins,
                                    spec->multiout.dac_nids,
@@ -3260,20 +3338,13 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                        return err;
        }
 
-       if (spec->line_switch) {
-               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
-                                          "Line In as Output Switch",
-                                          spec->line_switch << 8);
-               if (err < 0)
-                       return err;
-       }
-
-       if (spec->mic_switch) {
-               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS,
-                                          "Mic Jack Mode",
-                                          spec->mic_switch);
-               if (err < 0)
-                       return err;
+       for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) {
+               nid = cfg->input_pins[idx];
+               if (nid) {
+                       err = stac92xx_add_jack_mode_control(codec, nid, idx);
+                       if (err < 0)
+                               return err;
+               }
        }
 
        return 0;
@@ -4183,7 +4254,7 @@ static int stac92xx_init(struct hda_codec *codec)
                        unsigned int pinctl, conf;
                        if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
                                /* for mic pins, force to initialize */
-                               pinctl = stac92xx_get_vref(codec, nid);
+                               pinctl = stac92xx_get_default_vref(codec, nid);
                                pinctl |= AC_PINCTL_IN_EN;
                                stac92xx_auto_set_pinctl(codec, nid, pinctl);
                        } else {
@@ -4656,9 +4727,9 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec,
        if (nid == 0x10) {
                if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
                    HDA_AMP_MUTE)
-                       spec->gpio_data |= spec->gpio_led; /* white */
-               else
                        spec->gpio_data &= ~spec->gpio_led; /* orange */
+               else
+                       spec->gpio_data |= spec->gpio_led; /* white */
 
                stac_gpio_set(codec, spec->gpio_mask,
                              spec->gpio_dir,
@@ -5304,6 +5375,15 @@ again:
        if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
                snd_hda_sequence_write_cache(codec, unmute_init);
 
+       /* Some HP machines seem to have unstable codec communications
+        * especially with ATI fglrx driver.  For recovering from the
+        * CORB/RIRB stall, allow the BUS reset and keep always sync
+        */
+       if (spec->board_config == STAC_HP_DV5) {
+               codec->bus->sync_write = 1;
+               codec->bus->allow_bus_reset = 1;
+       }
+
        spec->aloopback_ctl = stac92hd71bxx_loopback;
        spec->aloopback_mask = 0x50;
        spec->aloopback_shift = 0;