]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - sound/pci/ac97/ac97_patch.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog
[linux-2.6-omap-h63xx.git] / sound / pci / ac97 / ac97_patch.c
index bfc2fed16da3a0208a6a5be3d146a81032ecffd1..3eac0f86266ce54e0bd3a0ff2aa26bc07038081b 100644 (file)
  *
  */
 
-#include <sound/driver.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/control.h>
-#include <sound/tlv.h>
-#include <sound/ac97_codec.h>
-#include "ac97_patch.h"
-#include "ac97_id.h"
 #include "ac97_local.h"
+#include "ac97_patch.h"
 
 /*
  *  Chip specific initialization
@@ -390,7 +378,7 @@ static struct snd_ac97_build_ops patch_yamaha_ymf753_ops = {
        .build_post_spdif = patch_yamaha_ymf753_post_spdif
 };
 
-int patch_yamaha_ymf753(struct snd_ac97 * ac97)
+static int patch_yamaha_ymf753(struct snd_ac97 * ac97)
 {
        /* Patch for Yamaha YMF753, Copyright (c) by David Shust, dshust@shustring.com.
           This chip has nonstandard and extended behaviour with regard to its S/PDIF output.
@@ -436,7 +424,7 @@ static struct snd_ac97_build_ops patch_wolfson_wm9703_ops = {
        .build_specific = patch_wolfson_wm9703_specific,
 };
 
-int patch_wolfson03(struct snd_ac97 * ac97)
+static int patch_wolfson03(struct snd_ac97 * ac97)
 {
        ac97->build_ops = &patch_wolfson_wm9703_ops;
        return 0;
@@ -467,7 +455,7 @@ static struct snd_ac97_build_ops patch_wolfson_wm9704_ops = {
        .build_specific = patch_wolfson_wm9704_specific,
 };
 
-int patch_wolfson04(struct snd_ac97 * ac97)
+static int patch_wolfson04(struct snd_ac97 * ac97)
 {
        /* WM9704M/9704Q */
        ac97->build_ops = &patch_wolfson_wm9704_ops;
@@ -489,7 +477,7 @@ static struct snd_ac97_build_ops patch_wolfson_wm9705_ops = {
        .build_specific = patch_wolfson_wm9705_specific,
 };
 
-int patch_wolfson05(struct snd_ac97 * ac97)
+static int patch_wolfson05(struct snd_ac97 * ac97)
 {
        /* WM9705, WM9710 */
        ac97->build_ops = &patch_wolfson_wm9705_ops;
@@ -625,7 +613,7 @@ static struct snd_ac97_build_ops patch_wolfson_wm9711_ops = {
        .build_specific = patch_wolfson_wm9711_specific,
 };
 
-int patch_wolfson11(struct snd_ac97 * ac97)
+static int patch_wolfson11(struct snd_ac97 * ac97)
 {
        /* WM9711, WM9712 */
        ac97->build_ops = &patch_wolfson_wm9711_ops;
@@ -824,7 +812,7 @@ static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
 #endif
 };
 
-int patch_wolfson13(struct snd_ac97 * ac97)
+static int patch_wolfson13(struct snd_ac97 * ac97)
 {
        /* WM9713, WM9714 */
        ac97->build_ops = &patch_wolfson_wm9713_ops;
@@ -844,7 +832,7 @@ int patch_wolfson13(struct snd_ac97 * ac97)
 /*
  * Tritech codec
  */
-int patch_tritech_tr28028(struct snd_ac97 * ac97)
+static int patch_tritech_tr28028(struct snd_ac97 * ac97)
 {
        snd_ac97_write_cache(ac97, 0x26, 0x0300);
        snd_ac97_write_cache(ac97, 0x26, 0x0000);
@@ -922,7 +910,7 @@ static struct snd_ac97_build_ops patch_sigmatel_stac9700_ops = {
        .build_specific = patch_sigmatel_stac97xx_specific
 };
 
-int patch_sigmatel_stac9700(struct snd_ac97 * ac97)
+static int patch_sigmatel_stac9700(struct snd_ac97 * ac97)
 {
        ac97->build_ops = &patch_sigmatel_stac9700_ops;
        return 0;
@@ -969,7 +957,7 @@ static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = {
        .build_specific = patch_sigmatel_stac9708_specific
 };
 
-int patch_sigmatel_stac9708(struct snd_ac97 * ac97)
+static int patch_sigmatel_stac9708(struct snd_ac97 * ac97)
 {
        unsigned int codec72, codec6c;
 
@@ -995,7 +983,7 @@ int patch_sigmatel_stac9708(struct snd_ac97 * ac97)
        return 0;
 }
 
-int patch_sigmatel_stac9721(struct snd_ac97 * ac97)
+static int patch_sigmatel_stac9721(struct snd_ac97 * ac97)
 {
        ac97->build_ops = &patch_sigmatel_stac9700_ops;
        if (snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) == 0) {
@@ -1009,7 +997,7 @@ int patch_sigmatel_stac9721(struct snd_ac97 * ac97)
        return 0;
 }
 
-int patch_sigmatel_stac9744(struct snd_ac97 * ac97)
+static int patch_sigmatel_stac9744(struct snd_ac97 * ac97)
 {
        // patch for SigmaTel
        ac97->build_ops = &patch_sigmatel_stac9700_ops;
@@ -1021,7 +1009,7 @@ int patch_sigmatel_stac9744(struct snd_ac97 * ac97)
        return 0;
 }
 
-int patch_sigmatel_stac9756(struct snd_ac97 * ac97)
+static int patch_sigmatel_stac9756(struct snd_ac97 * ac97)
 {
        // patch for SigmaTel
        ac97->build_ops = &patch_sigmatel_stac9700_ops;
@@ -1198,7 +1186,7 @@ static struct snd_ac97_build_ops patch_sigmatel_stac9758_ops = {
        .build_specific = patch_sigmatel_stac9758_specific
 };
 
-int patch_sigmatel_stac9758(struct snd_ac97 * ac97)
+static int patch_sigmatel_stac9758(struct snd_ac97 * ac97)
 {
        static unsigned short regs[4] = {
                AC97_SIGMATEL_OUTSEL,
@@ -1272,7 +1260,7 @@ static struct snd_ac97_build_ops patch_cirrus_ops = {
        .build_spdif = patch_cirrus_build_spdif
 };
 
-int patch_cirrus_spdif(struct snd_ac97 * ac97)
+static int patch_cirrus_spdif(struct snd_ac97 * ac97)
 {
        /* Basically, the cs4201/cs4205/cs4297a has non-standard sp/dif registers.
           WHY CAN'T ANYONE FOLLOW THE BLOODY SPEC?  *sigh*
@@ -1293,7 +1281,7 @@ int patch_cirrus_spdif(struct snd_ac97 * ac97)
        return 0;
 }
 
-int patch_cirrus_cs4299(struct snd_ac97 * ac97)
+static int patch_cirrus_cs4299(struct snd_ac97 * ac97)
 {
        /* force the detection of PC Beep */
        ac97->flags |= AC97_HAS_PC_BEEP;
@@ -1329,7 +1317,7 @@ static struct snd_ac97_build_ops patch_conexant_ops = {
        .build_spdif = patch_conexant_build_spdif
 };
 
-int patch_conexant(struct snd_ac97 * ac97)
+static int patch_conexant(struct snd_ac97 * ac97)
 {
        ac97->build_ops = &patch_conexant_ops;
        ac97->flags |= AC97_CX_SPDIF;
@@ -1338,7 +1326,7 @@ int patch_conexant(struct snd_ac97 * ac97)
        return 0;
 }
 
-int patch_cx20551(struct snd_ac97 *ac97)
+static int patch_cx20551(struct snd_ac97 *ac97)
 {
        snd_ac97_update_bits(ac97, 0x5c, 0x01, 0x01);
        return 0;
@@ -1430,7 +1418,7 @@ static const struct snd_ac97_res_table ad1819_restbl[] = {
        { } /* terminator */
 };
 
-int patch_ad1819(struct snd_ac97 * ac97)
+static int patch_ad1819(struct snd_ac97 * ac97)
 {
        unsigned short scfg;
 
@@ -1507,7 +1495,7 @@ static struct snd_ac97_build_ops patch_ad1881_build_ops = {
 #endif
 };
 
-int patch_ad1881(struct snd_ac97 * ac97)
+static int patch_ad1881(struct snd_ac97 * ac97)
 {
        static const char cfg_idxs[3][2] = {
                {2, 1},
@@ -1595,7 +1583,7 @@ static struct snd_ac97_build_ops patch_ad1885_build_ops = {
 #endif
 };
 
-int patch_ad1885(struct snd_ac97 * ac97)
+static int patch_ad1885(struct snd_ac97 * ac97)
 {
        patch_ad1881(ac97);
        /* This is required to deal with the Intel D815EEAL2 */
@@ -1622,7 +1610,7 @@ static struct snd_ac97_build_ops patch_ad1886_build_ops = {
 #endif
 };
 
-int patch_ad1886(struct snd_ac97 * ac97)
+static int patch_ad1886(struct snd_ac97 * ac97)
 {
        patch_ad1881(ac97);
        /* Presario700 workaround */
@@ -1790,6 +1778,8 @@ static const struct snd_kcontrol_new snd_ac97_ad1981x_jack_sense[] = {
  * (SS vendor << 16 | device)
  */
 static unsigned int ad1981_jacks_blacklist[] = {
+       0x10140523, /* Thinkpad R40 */
+       0x10140534, /* Thinkpad X31 */
        0x10140537, /* Thinkpad T41p */
        0x10140554, /* Thinkpad T42p/R50p */
        0 /* end */
@@ -1842,7 +1832,7 @@ static void check_ad1981_hp_jack_sense(struct snd_ac97 *ac97)
                snd_ac97_update_bits(ac97, AC97_AD_JACK_SPDIF, 1<<11, 1<<11);
 }
 
-int patch_ad1981a(struct snd_ac97 *ac97)
+static int patch_ad1981a(struct snd_ac97 *ac97)
 {
        patch_ad1881(ac97);
        ac97->build_ops = &patch_ad1981a_build_ops;
@@ -1875,7 +1865,7 @@ static struct snd_ac97_build_ops patch_ad1981b_build_ops = {
 #endif
 };
 
-int patch_ad1981b(struct snd_ac97 *ac97)
+static int patch_ad1981b(struct snd_ac97 *ac97)
 {
        patch_ad1881(ac97);
        ac97->build_ops = &patch_ad1981b_build_ops;
@@ -1960,9 +1950,11 @@ static int snd_ac97_ad1888_downmix_put(struct snd_kcontrol *kcontrol, struct snd
 static void ad1888_update_jacks(struct snd_ac97 *ac97)
 {
        unsigned short val = 0;
-       if (! is_shared_linein(ac97))
+       /* clear LODIS if shared jack is to be used for Surround out */
+       if (is_shared_linein(ac97))
                val |= (1 << 12);
-       if (! is_shared_micin(ac97))
+       /* clear CLDIS if shared jack is to be used for C/LFE out */
+       if (is_shared_micin(ac97))
                val |= (1 << 11);
        /* shared Line-In */
        snd_ac97_update_bits(ac97, AC97_AD_MISC, (1 << 11) | (1 << 12), val);
@@ -2010,7 +2002,7 @@ static struct snd_ac97_build_ops patch_ad1888_build_ops = {
        .update_jacks = ad1888_update_jacks,
 };
 
-int patch_ad1888(struct snd_ac97 * ac97)
+static int patch_ad1888(struct snd_ac97 * ac97)
 {
        unsigned short misc;
        
@@ -2048,7 +2040,7 @@ static struct snd_ac97_build_ops patch_ad1980_build_ops = {
        .update_jacks = ad1888_update_jacks,
 };
 
-int patch_ad1980(struct snd_ac97 * ac97)
+static int patch_ad1980(struct snd_ac97 * ac97)
 {
        patch_ad1888(ac97);
        ac97->build_ops = &patch_ad1980_build_ops;
@@ -2134,8 +2126,9 @@ static const struct snd_kcontrol_new snd_ac97_ad1985_controls[] = {
 static void ad1985_update_jacks(struct snd_ac97 *ac97)
 {
        ad1888_update_jacks(ac97);
+       /* clear OMS if shared jack is to be used for C/LFE out */
        snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 1 << 9,
-                            is_shared_micin(ac97) ? 0 : 1 << 9);
+                            is_shared_micin(ac97) ? 1 << 9 : 0);
 }
 
 static int patch_ad1985_specific(struct snd_ac97 *ac97)
@@ -2163,7 +2156,7 @@ static struct snd_ac97_build_ops patch_ad1985_build_ops = {
        .update_jacks = ad1985_update_jacks,
 };
 
-int patch_ad1985(struct snd_ac97 * ac97)
+static int patch_ad1985(struct snd_ac97 * ac97)
 {
        unsigned short misc;
        
@@ -2416,9 +2409,9 @@ static void ad1986_update_jacks(struct snd_ac97 *ac97)
        unsigned short ser_val;
 
        /* disable SURROUND and CENTER/LFE if not surround mode */
-       if (! is_surround_on(ac97))
+       if (!is_surround_on(ac97))
                misc_val |= AC97_AD1986_SODIS;
-       if (! is_clfe_on(ac97))
+       if (!is_clfe_on(ac97))
                misc_val |= AC97_AD1986_CLDIS;
 
        /* select line input (default=LINE_IN, SURROUND or MIC_1/2) */
@@ -2463,7 +2456,7 @@ static struct snd_ac97_build_ops patch_ad1986_build_ops = {
        .update_jacks = ad1986_update_jacks,
 };
 
-int patch_ad1986(struct snd_ac97 * ac97)
+static int patch_ad1986(struct snd_ac97 * ac97)
 {
        patch_ad1881(ac97);
        ac97->build_ops = &patch_ad1986_build_ops;
@@ -2556,7 +2549,7 @@ static struct snd_ac97_build_ops patch_alc650_ops = {
        .update_jacks = alc650_update_jacks
 };
 
-int patch_alc650(struct snd_ac97 * ac97)
+static int patch_alc650(struct snd_ac97 * ac97)
 {
        unsigned short val;
 
@@ -2708,7 +2701,7 @@ static struct snd_ac97_build_ops patch_alc655_ops = {
        .update_jacks = alc655_update_jacks
 };
 
-int patch_alc655(struct snd_ac97 * ac97)
+static int patch_alc655(struct snd_ac97 * ac97)
 {
        unsigned int val;
 
@@ -2734,6 +2727,7 @@ int patch_alc655(struct snd_ac97 * ac97)
                    (ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */
                     ac97->subsystem_device == 0x0161 || /* LG K1 Express */
                     ac97->subsystem_device == 0x0351 || /* MSI L725 laptop */
+                    ac97->subsystem_device == 0x0471 || /* MSI L720 laptop */
                     ac97->subsystem_device == 0x0061))  /* MSI S250 laptop */
                        val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */
                else
@@ -2810,7 +2804,7 @@ static struct snd_ac97_build_ops patch_alc850_ops = {
        .update_jacks = alc850_update_jacks
 };
 
-int patch_alc850(struct snd_ac97 *ac97)
+static int patch_alc850(struct snd_ac97 *ac97)
 {
        ac97->build_ops = &patch_alc850_ops;
 
@@ -2870,7 +2864,7 @@ static struct snd_ac97_build_ops patch_cm9738_ops = {
        .update_jacks = cm9738_update_jacks
 };
 
-int patch_cm9738(struct snd_ac97 * ac97)
+static int patch_cm9738(struct snd_ac97 * ac97)
 {
        ac97->build_ops = &patch_cm9738_ops;
        /* FIXME: can anyone confirm below? */
@@ -2962,7 +2956,7 @@ static struct snd_ac97_build_ops patch_cm9739_ops = {
        .update_jacks = cm9739_update_jacks
 };
 
-int patch_cm9739(struct snd_ac97 * ac97)
+static int patch_cm9739(struct snd_ac97 * ac97)
 {
        unsigned short val;
 
@@ -3136,7 +3130,7 @@ static struct snd_ac97_build_ops patch_cm9761_ops = {
        .update_jacks = cm9761_update_jacks
 };
 
-int patch_cm9761(struct snd_ac97 *ac97)
+static int patch_cm9761(struct snd_ac97 *ac97)
 {
        unsigned short val;
 
@@ -3231,7 +3225,7 @@ static struct snd_ac97_build_ops patch_cm9780_ops = {
        .build_post_spdif = patch_cm9761_post_spdif     /* identical with CM9761 */
 };
 
-int patch_cm9780(struct snd_ac97 *ac97)
+static int patch_cm9780(struct snd_ac97 *ac97)
 {
        unsigned short val;
 
@@ -3274,7 +3268,7 @@ static struct snd_ac97_build_ops patch_vt1616_ops = {
        .build_specific = patch_vt1616_specific
 };
 
-int patch_vt1616(struct snd_ac97 * ac97)
+static int patch_vt1616(struct snd_ac97 * ac97)
 {
        ac97->build_ops = &patch_vt1616_ops;
        return 0;
@@ -3283,16 +3277,111 @@ int patch_vt1616(struct snd_ac97 * ac97)
 /*
  * VT1617A codec
  */
+
+/*
+ * unfortunately, the vt1617a stashes the twiddlers required for
+ * nooding the i/o jacks on 2 different regs. * thameans that we cant
+ * use the easy way provided by AC97_ENUM_DOUBLE() we have to write
+ * are own funcs.
+ *
+ * NB: this is absolutely and utterly different from the vt1618. dunno
+ * about the 1616.
+ */
+
+/* copied from ac97_surround_jack_mode_info() */
+static int snd_ac97_vt1617a_smart51_info(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_info *uinfo)
+{
+       /* ordering in this list reflects vt1617a docs for Reg 20 and
+        * 7a and Table 6 that lays out the matrix NB WRT Table6: SM51
+        * is SM51EN *AND* it's Bit14, not Bit15 so the table is very
+        * counter-intuitive */ 
+
+       static const char* texts[] = { "LineIn Mic1", "LineIn Mic1 Mic3",
+                                      "Surr LFE/C Mic3", "LineIn LFE/C Mic3",
+                                      "LineIn Mic2", "LineIn Mic2 Mic1",
+                                      "Surr LFE Mic1", "Surr LFE Mic1 Mic2"};
+       return ac97_enum_text_info(kcontrol, uinfo, texts, 8);
+}
+
+static int snd_ac97_vt1617a_smart51_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ushort usSM51, usMS;  
+
+       struct snd_ac97 *pac97;
+       
+       pac97 = snd_kcontrol_chip(kcontrol); /* grab codec handle */
+
+       /* grab our desirec bits, then mash them together in a manner
+        * consistent with Table 6 on page 17 in the 1617a docs */
+       usSM51 = snd_ac97_read(pac97, 0x7a) >> 14;
+       usMS   = snd_ac97_read(pac97, 0x20) >> 8;
+  
+       ucontrol->value.enumerated.item[0] = (usSM51 << 1) + usMS;
+
+       return 0;
+}
+
+static int snd_ac97_vt1617a_smart51_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ushort usSM51, usMS, usReg;  
+
+       struct snd_ac97 *pac97;
+
+       pac97 = snd_kcontrol_chip(kcontrol); /* grab codec handle */
+
+       usSM51 = ucontrol->value.enumerated.item[0] >> 1;
+       usMS   = ucontrol->value.enumerated.item[0] &  1;
+
+       /* push our values into the register - consider that things will be left
+        * in a funky state if the write fails */
+
+       usReg = snd_ac97_read(pac97, 0x7a);
+       snd_ac97_write_cache(pac97, 0x7a, (usReg & 0x3FFF) + (usSM51 << 14));
+       usReg = snd_ac97_read(pac97, 0x20);
+       snd_ac97_write_cache(pac97, 0x20, (usReg & 0xFEFF) + (usMS   <<  8));
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new snd_ac97_controls_vt1617a[] = {
+
+       AC97_SINGLE("Center/LFE Exchange", 0x5a, 8, 1, 0),
+       /*
+        * These are used to enable/disable surround sound on motherboards
+        * that have 3 bidirectional analog jacks
+        */
+       {
+               .iface         = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name          = "Smart 5.1 Select",
+               .info          = snd_ac97_vt1617a_smart51_info,
+               .get           = snd_ac97_vt1617a_smart51_get,
+               .put           = snd_ac97_vt1617a_smart51_put,
+       },
+};
+
 int patch_vt1617a(struct snd_ac97 * ac97)
 {
-       /* bring analog power consumption to normal, like WinXP driver
-        * for EPIA SP
+       int err = 0;
+
+       /* we choose to not fail out at this point, but we tell the
+          caller when we return */
+
+       err = patch_build_controls(ac97, &snd_ac97_controls_vt1617a[0],
+                                  ARRAY_SIZE(snd_ac97_controls_vt1617a));
+
+       /* bring analog power consumption to normal by turning off the
+        * headphone amplifier, like WinXP driver for EPIA SP
         */
        snd_ac97_write_cache(ac97, 0x5c, 0x20);
        ac97->ext_id |= AC97_EI_SPDIF;  /* force the detection of spdif */
        ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
        ac97->build_ops = &patch_vt1616_ops;
-       return 0;
+
+       return err;
 }
 
 /*
@@ -3333,7 +3422,7 @@ static struct snd_ac97_build_ops patch_it2646_ops = {
        .update_jacks = it2646_update_jacks
 };
 
-int patch_it2646(struct snd_ac97 * ac97)
+static int patch_it2646(struct snd_ac97 * ac97)
 {
        ac97->build_ops = &patch_it2646_ops;
        /* full DAC volume */
@@ -3366,7 +3455,7 @@ static struct snd_ac97_build_ops patch_si3036_ops = {
        .build_specific = patch_si3036_specific,
 };
 
-int mpatch_si3036(struct snd_ac97 * ac97)
+static int mpatch_si3036(struct snd_ac97 * ac97)
 {
        ac97->build_ops = &patch_si3036_ops;
        snd_ac97_write_cache(ac97, 0x5c, 0xf210 );
@@ -3398,7 +3487,7 @@ static struct snd_ac97_res_table lm4550_restbl[] = {
        { } /* terminator */
 };
 
-int patch_lm4550(struct snd_ac97 *ac97)
+static int patch_lm4550(struct snd_ac97 *ac97)
 {
        ac97->res_table = lm4550_restbl;
        return 0;
@@ -3433,7 +3522,7 @@ static struct snd_ac97_build_ops patch_ucb1400_ops = {
        .build_specific = patch_ucb1400_specific,
 };
 
-int patch_ucb1400(struct snd_ac97 * ac97)
+static int patch_ucb1400(struct snd_ac97 * ac97)
 {
        ac97->build_ops = &patch_ucb1400_ops;
        /* enable headphone driver and smart low power mode by default */