vserver 2.0 rc7
[linux-2.6.git] / sound / oss / ac97_codec.c
index 20a0942..3ecef46 100644 (file)
@@ -71,6 +71,7 @@ static int wolfson_init03(struct ac97_codec * codec);
 static int wolfson_init04(struct ac97_codec * codec);
 static int wolfson_init05(struct ac97_codec * codec);
 static int wolfson_init11(struct ac97_codec * codec);
+static int wolfson_init13(struct ac97_codec * codec);
 static int tritech_init(struct ac97_codec * codec);
 static int tritech_maestro_init(struct ac97_codec * codec);
 static int sigmatel_9708_init(struct ac97_codec *codec);
@@ -107,6 +108,7 @@ static struct ac97_ops wolfson_ops03 = { wolfson_init03, NULL, NULL };
 static struct ac97_ops wolfson_ops04 = { wolfson_init04, NULL, NULL };
 static struct ac97_ops wolfson_ops05 = { wolfson_init05, NULL, NULL };
 static struct ac97_ops wolfson_ops11 = { wolfson_init11, NULL, NULL };
+static struct ac97_ops wolfson_ops13 = { wolfson_init13, NULL, NULL };
 static struct ac97_ops tritech_ops = { tritech_init, NULL, NULL };
 static struct ac97_ops tritech_m_ops = { tritech_maestro_init, NULL, NULL };
 static struct ac97_ops sigmatel_9708_ops = { sigmatel_9708_init, NULL, NULL };
@@ -153,6 +155,7 @@ static const struct {
        {0x43525931, "Cirrus Logic CS4299 rev A", &crystal_digital_ops},
        {0x43525933, "Cirrus Logic CS4299 rev C", &crystal_digital_ops},
        {0x43525934, "Cirrus Logic CS4299 rev D", &crystal_digital_ops},
+       {0x43585430, "CXT48",                   &default_ops,           AC97_DELUDED_MODEM },
        {0x43585442, "CXT66",                   &default_ops,           AC97_DELUDED_MODEM },
        {0x44543031, "Diamond Technology DT0893", &default_ops},
        {0x45838308, "ESS Allegro ES1988",      &null_ops},
@@ -171,6 +174,7 @@ static const struct {
        {0x574D4C05, "Wolfson WM9705/WM9710",   &wolfson_ops05},
        {0x574D4C09, "Wolfson WM9709",          &null_ops},
        {0x574D4C12, "Wolfson WM9711/9712",     &wolfson_ops11},
+       {0x574D4C13, "Wolfson WM9713",  &wolfson_ops13, AC97_DEFAULT_POWER_OFF},
        {0x83847600, "SigmaTel STAC????",       &null_ops},
        {0x83847604, "SigmaTel STAC9701/3/4/5", &null_ops},
        {0x83847605, "SigmaTel STAC9704",       &null_ops},
@@ -798,6 +802,9 @@ EXPORT_SYMBOL(ac97_release_codec);
  *     Currently codec_wait is used to wait for AC97 codec
  *     reset to complete. 
  *
+ *     Some codecs will power down when a register reset is
+ *     performed. We now check for such codecs.
+ *
  *     Returns 1 (true) on success, or 0 (false) on failure.
  */
  
@@ -811,34 +818,17 @@ int ac97_probe_codec(struct ac97_codec *codec)
        struct list_head *l;
        struct ac97_driver *d;
        
-       /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should 
-        * be read zero.
-        *
-        * FIXME: is the following comment outdated?  -jgarzik 
-        * Probing of AC97 in this way is not reliable, it is not even SAFE !!
-        */
-       codec->codec_write(codec, AC97_RESET, 0L);
-
-       /* also according to spec, we wait for codec-ready state */     
+       /* wait for codec-ready state */
        if (codec->codec_wait)
                codec->codec_wait(codec);
        else
                udelay(10);
 
-       if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
-               printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
-                      (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") 
-                      : (codec->id&1 ? "Secondary":  "Primary"));
-               return 0;
-       }
-
-       /* probe for Modem Codec */
-       codec->modem = ac97_check_modem(codec);
-       codec->name = NULL;
-       codec->codec_ops = &default_ops;
-
+       /* will the codec power down if register reset ? */
        id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
        id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
+       codec->name = NULL;
+       codec->codec_ops = &null_ops;
        for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) {
                if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
                        codec->type = ac97_codec_ids[i].id;
@@ -850,9 +840,34 @@ int ac97_probe_codec(struct ac97_codec *codec)
        }
 
        codec->model = (id1 << 16) | id2;
+       if ((codec->flags & AC97_DEFAULT_POWER_OFF) == 0) {
+               /* reset codec and wait for the ready bit before we continue */
+               codec->codec_write(codec, AC97_RESET, 0L);
+               if (codec->codec_wait)
+                       codec->codec_wait(codec);
+               else
+                       udelay(10);
+       }
+
+       /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should
+        * be read zero.
+        *
+        * FIXME: is the following comment outdated?  -jgarzik
+        * Probing of AC97 in this way is not reliable, it is not even SAFE !!
+        */
+       if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
+               printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
+                      (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary")
+                      : (codec->id&1 ? "Secondary":  "Primary"));
+               return 0;
+       }
        
+       /* probe for Modem Codec */
+       codec->modem = ac97_check_modem(codec);
+
+       /* enable SPDIF */
        f = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-       if(f & 4)
+       if((codec->codec_ops == &null_ops) && (f & 4))
                codec->codec_ops = &default_digital_ops;
        
        /* A device which thinks its a modem but isnt */
@@ -921,11 +936,6 @@ static int ac97_init_mixer(struct ac97_codec *codec)
        codec->recmask_io = ac97_recmask_io;
        codec->mixer_ioctl = ac97_mixer_ioctl;
 
-       /* codec specific initialization for 4-6 channel output or secondary codec stuff */
-       if (codec->codec_ops->init != NULL) {
-               codec->codec_ops->init(codec);
-       }
-
        /* initialize mixer channel volumes */
        for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
                struct mixer_defaults *md = &mixer_defaults[i];
@@ -936,6 +946,11 @@ static int ac97_init_mixer(struct ac97_codec *codec)
                ac97_set_mixer(codec, md->mixer, md->value);
        }
 
+       /* codec specific initialization for 4-6 channel output or secondary codec stuff */
+       if (codec->codec_ops->init != NULL) {
+               codec->codec_ops->init(codec);
+       }
+
        /*
         *      Volume is MUTE only on this device. We have to initialise
         *      it but its useless beyond that.
@@ -1091,6 +1106,19 @@ static int wolfson_init11(struct ac97_codec * codec)
        return 0;
 }
 
+/* WM9713 */
+static int wolfson_init13(struct ac97_codec * codec)
+{
+       codec->codec_write(codec, AC97_RECORD_GAIN, 0x00a0);
+       codec->codec_write(codec, AC97_POWER_CONTROL, 0x0000);
+       codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0xDA00);
+       codec->codec_write(codec, AC97_EXTEND_MODEM_STAT, 0x3810);
+       codec->codec_write(codec, AC97_PHONE_VOL, 0x0808);
+       codec->codec_write(codec, AC97_PCBEEP_VOL, 0x0808);
+
+       return 0;
+}
+
 static int tritech_init(struct ac97_codec * codec)
 {
        codec->codec_write(codec, 0x26, 0x0300);