patch-2.4.4 linux/drivers/sound/ac97_codec.c
Next file: linux/drivers/sound/aci.c
Previous file: linux/drivers/sound/Makefile
Back to the patch index
Back to the overall index
- Lines: 334
- Date:
Thu Apr 19 22:58:20 2001
- Orig file:
v2.4.3/linux/drivers/sound/ac97_codec.c
- Orig date:
Thu Dec 7 00:21:37 2000
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c
@@ -20,6 +20,16 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
+ **************************************************************************
+ *
+ * The Intel Audio Codec '97 specification is available at the Intel
+ * audio homepage: http://developer.intel.com/ial/scalableplatforms/audio/
+ *
+ * The specification itself is currently available at:
+ * ftp://download.intel.com/ial/scalableplatforms/ac97r22.pdf
+ *
+ **************************************************************************
+ *
* History
* v0.4 Mar 15 2000 Ollie Lho
* dual codecs support verified with 4 channels output
@@ -49,41 +59,61 @@
static int ac97_init_mixer(struct ac97_codec *codec);
-static int sigmatel_init(struct ac97_codec *codec);
+static int wolfson_init(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);
+static int sigmatel_9721_init(struct ac97_codec *codec);
+static int sigmatel_9744_init(struct ac97_codec *codec);
static int enable_eapd(struct ac97_codec *codec);
-#define arraysize(x) (sizeof(x)/sizeof((x)[0]))
-
-static struct {
- unsigned int id;
+/* sorted by vendor/device id */
+static const struct {
+ u32 id;
char *name;
int (*init) (struct ac97_codec *codec);
} ac97_codec_ids[] = {
- {0x414B4D00, "Asahi Kasei AK4540 rev 0", NULL},
- {0x414B4D01, "Asahi Kasei AK4540 rev 1", NULL},
- {0x41445340, "Analog Devices AD1881" , NULL},
- {0x41445360, "Analog Devices AD1885" , enable_eapd},
- {0x43525900, "Cirrus Logic CS4297" , NULL},
- {0x43525903, "Cirrus Logic CS4297" , NULL},
- {0x43525913, "Cirrus Logic CS4297A" , NULL},
- {0x43525923, "Cirrus Logic CS4298" , NULL},
- {0x4352592B, "Cirrus Logic CS4294" , NULL},
- {0x43525931, "Cirrus Logic CS4299" , NULL},
- {0x43525934, "Cirrus Logic CS4299" , NULL},
- {0x4e534331, "National Semiconductor LM4549" , NULL},
- {0x53494c22, "Silicon Laboratory Si3036" , NULL},
- {0x53494c23, "Silicon Laboratory Si3038" , NULL},
- {0x83847600, "SigmaTel STAC????" , NULL},
+ {0x41445303, "Analog Devices AD1819", NULL},
+ {0x41445340, "Analog Devices AD1881", NULL},
+ {0x41445348, "Analog Devices AD1881A", NULL},
+ {0x41445460, "Analog Devices AD1885", enable_eapd},
+ {0x414B4D00, "Asahi Kasei AK4540", NULL},
+ {0x414B4D01, "Asahi Kasei AK4542", NULL},
+ {0x414B4D02, "Asahi Kasei AK4543", NULL},
+ {0x414C4710, "ALC200/200P", NULL},
+ {0x43525900, "Cirrus Logic CS4297", enable_eapd},
+ {0x43525903, "Cirrus Logic CS4297", enable_eapd},
+ {0x43525913, "Cirrus Logic CS4297A rev A", enable_eapd},
+ {0x43525914, "Cirrus Logic CS4297A rev B", NULL},
+ {0x43525923, "Cirrus Logic CS4298", NULL},
+ {0x4352592B, "Cirrus Logic CS4294", NULL},
+ {0x4352592D, "Cirrus Logic CS4294", NULL},
+ {0x43525931, "Cirrus Logic CS4299 rev A", NULL},
+ {0x43525933, "Cirrus Logic CS4299 rev C", NULL},
+ {0x43525934, "Cirrus Logic CS4299 rev D", NULL},
+ {0x45838308, "ESS Allegro ES1988", NULL},
+ {0x49434511, "ICE1232", NULL}, /* I hope --jk */
+ {0x4e534331, "National Semiconductor LM4549", NULL},
+ {0x53494c22, "Silicon Laboratory Si3036", NULL},
+ {0x53494c23, "Silicon Laboratory Si3038", NULL},
+ {0x545200FF, "TriTech TR?????", tritech_maestro_init},
+ {0x54524102, "TriTech TR28022", NULL},
+ {0x54524103, "TriTech TR28023", NULL},
+ {0x54524106, "TriTech TR28026", NULL},
+ {0x54524108, "TriTech TR28028", tritech_init},
+ {0x54524123, "TriTech TR?????", NULL},
+ {0x574D4C00, "Wolfson WM9704", wolfson_init},
+ {0x574D4C03, "Wolfson WM9703/9704", wolfson_init},
+ {0x574D4C04, "Wolfson WM9704 (quad)", wolfson_init},
+ {0x83847600, "SigmaTel STAC????", NULL},
{0x83847604, "SigmaTel STAC9701/3/4/5", NULL},
- {0x83847605, "SigmaTel STAC9704" , NULL},
- {0x83847608, "SigmaTel STAC9708" , NULL},
- {0x83847609, "SigmaTel STAC9721/23" , sigmatel_init},
- {0x54524103, "TriTech TR?????" , NULL},
- {0x54524106, "TriTech TR28026" , NULL},
- {0x54524108, "TriTech TR28028" , NULL},
- {0x54524123, "TriTech TR?????" , NULL},
- {0x574D4C00, "Wolfson WM9704" , NULL},
- {0x00000000, NULL, NULL}
+ {0x83847605, "SigmaTel STAC9704", NULL},
+ {0x83847608, "SigmaTel STAC9708", sigmatel_9708_init},
+ {0x83847609, "SigmaTel STAC9721/23", sigmatel_9721_init},
+ {0x83847644, "SigmaTel STAC9744/45", sigmatel_9744_init},
+ {0x83847656, "SigmaTel STAC9756/57", sigmatel_9744_init},
+ {0x83847684, "SigmaTel STAC9783/84?", NULL},
+ {0,}
};
static const char *ac97_stereo_enhancements[] =
@@ -175,10 +205,10 @@
AC97_REC_LINE,
AC97_REC_STEREO, /* combination of all enabled outputs.. */
AC97_REC_MONO, /*.. or the mono equivalent */
- AC97_REC_PHONE
+ AC97_REC_PHONE
};
-static unsigned int ac97_rm2oss[] = {
+static const unsigned int ac97_rm2oss[] = {
[AC97_REC_MIC] = SOUND_MIXER_MIC,
[AC97_REC_CD] = SOUND_MIXER_CD,
[AC97_REC_VIDEO] = SOUND_MIXER_VIDEO,
@@ -189,7 +219,7 @@
};
/* indexed by bit position */
-static unsigned int ac97_oss_rm[] = {
+static const unsigned int ac97_oss_rm[] = {
[SOUND_MIXER_MIC] = AC97_REC_MIC,
[SOUND_MIXER_CD] = AC97_REC_CD,
[SOUND_MIXER_VIDEO] = AC97_REC_VIDEO,
@@ -431,13 +461,13 @@
return 0;
}
- if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+ if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
return -EINVAL;
if (cmd == OSS_GETVERSION)
return put_user(SOUND_VERSION, (int *)arg);
- if (_IOC_DIR(cmd) == _IOC_READ) {
+ if (_SIOC_DIR(cmd) == _SIOC_READ) {
switch (_IOC_NR(cmd)) {
case SOUND_MIXER_RECSRC: /* give them the current record source */
if (!codec->recmask_io) {
@@ -477,7 +507,7 @@
return put_user(val, (int *)arg);
}
- if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) {
+ if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) {
codec->modcnt++;
if (get_user(val, (int *)arg))
return -EFAULT;
@@ -640,7 +670,7 @@
id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
- for (i = 0; i < arraysize(ac97_codec_ids); i++) {
+ 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;
codec->name = ac97_codec_ids[i].name;
@@ -691,7 +721,7 @@
codec->codec_init(codec);
}
- /* initilize mixer channel volumes */
+ /* initialize mixer channel volumes */
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
struct mixer_defaults *md = &mixer_defaults[i];
if (md->mixer == -1)
@@ -704,40 +734,151 @@
return 1;
}
-static int sigmatel_init(struct ac97_codec * codec)
+#define AC97_SIGMATEL_ANALOG 0x6c /* Analog Special */
+#define AC97_SIGMATEL_DAC2INVERT 0x6e
+#define AC97_SIGMATEL_BIAS1 0x70
+#define AC97_SIGMATEL_BIAS2 0x72
+#define AC97_SIGMATEL_MULTICHN 0x74 /* Multi-Channel programming */
+#define AC97_SIGMATEL_CIC1 0x76
+#define AC97_SIGMATEL_CIC2 0x78
+
+
+static int sigmatel_9708_init(struct ac97_codec * codec)
+{
+ u16 codec72, codec6c;
+
+ codec72 = codec->codec_read(codec, AC97_SIGMATEL_BIAS2) & 0x8000;
+ codec6c = codec->codec_read(codec, AC97_SIGMATEL_ANALOG);
+
+ if ((codec72==0) && (codec6c==0)) {
+ codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
+ codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1000);
+ codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
+ codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0007);
+ } else if ((codec72==0x8000) && (codec6c==0)) {
+ codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
+ codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1001);
+ codec->codec_write(codec, AC97_SIGMATEL_DAC2INVERT, 0x0008);
+ } else if ((codec72==0x8000) && (codec6c==0x0080)) {
+ /* nothing */
+ }
+ codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
+ return 0;
+}
+
+
+static int sigmatel_9721_init(struct ac97_codec * codec)
{
/* Only set up secondary codec */
if (codec->id == 0)
- return 1;
+ return 0;
codec->codec_write(codec, AC97_SURROUND_MASTER, 0L);
/* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link
sloc 3,4 = 0x01, slot 7,8 = 0x00, */
- codec->codec_write(codec, 0x74, 0x00);
+ codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x00);
/* we don't have the crystal when we are on an AMR card, so use
BIT_CLK as our clock source. Write the magic word ABBA and read
back to enable register 0x78 */
- codec->codec_write(codec, 0x76, 0xabba);
- codec->codec_read(codec, 0x76);
+ codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
+ codec->codec_read(codec, AC97_SIGMATEL_CIC1);
/* sync all the clocks*/
- codec->codec_write(codec, 0x78, 0x3802);
+ codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x3802);
- return 1;
+ return 0;
+}
+
+
+static int sigmatel_9744_init(struct ac97_codec * codec)
+{
+ // patch for SigmaTel
+ codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
+ codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x0000); // is this correct? --jk
+ codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
+ codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0002);
+ codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
+ return 0;
+}
+
+
+static int wolfson_init(struct ac97_codec * codec)
+{
+ codec->codec_write(codec, 0x72, 0x0808);
+ codec->codec_write(codec, 0x74, 0x0808);
+
+ // patch for DVD noise
+ codec->codec_write(codec, 0x5a, 0x0200);
+
+ // init vol as PCM vol
+ codec->codec_write(codec, 0x70,
+ codec->codec_read(codec, AC97_PCMOUT_VOL));
+
+ codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
+ return 0;
+}
+
+
+static int tritech_init(struct ac97_codec * codec)
+{
+ codec->codec_write(codec, 0x26, 0x0300);
+ codec->codec_write(codec, 0x26, 0x0000);
+ codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
+ codec->codec_write(codec, AC97_RESERVED_3A, 0x0000);
+ return 0;
+}
+
+
+/* copied from drivers/sound/maestro.c */
+static int tritech_maestro_init(struct ac97_codec * codec)
+{
+ /* no idea what this does */
+ codec->codec_write(codec, 0x2A, 0x0001);
+ codec->codec_write(codec, 0x2C, 0x0000);
+ codec->codec_write(codec, 0x2C, 0XFFFF);
+ return 0;
}
+
/*
- * Bring up an AD1885
+ * External AMP management for EAPD using codecs
+ * (CS4279A, AD1885, ...)
*/
-
+
static int enable_eapd(struct ac97_codec * codec)
{
codec->codec_write(codec, AC97_POWER_CONTROL,
codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000);
return 0;
}
+
+
+/* copied from drivers/sound/maestro.c */
+#if 0 /* there has been 1 person on the planet with a pt101 that we
+ know of. If they care, they can put this back in :) */
+static int pt101_init(struct ac97_codec * codec)
+{
+ printk(KERN_INFO "ac97_codec: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
+ /* who knows.. */
+ codec->codec_write(codec, 0x2A, 0x0001);
+ codec->codec_write(codec, 0x2C, 0x0000);
+ codec->codec_write(codec, 0x2C, 0xFFFF);
+ codec->codec_write(codec, 0x10, 0x9F1F);
+ codec->codec_write(codec, 0x12, 0x0808);
+ codec->codec_write(codec, 0x14, 0x9F1F);
+ codec->codec_write(codec, 0x16, 0x9F1F);
+ codec->codec_write(codec, 0x18, 0x0404);
+ codec->codec_write(codec, 0x1A, 0x0000);
+ codec->codec_write(codec, 0x1C, 0x0000);
+ codec->codec_write(codec, 0x02, 0x0404);
+ codec->codec_write(codec, 0x04, 0x0808);
+ codec->codec_write(codec, 0x0C, 0x801F);
+ codec->codec_write(codec, 0x0E, 0x801F);
+ return 0;
+}
+#endif
EXPORT_SYMBOL(ac97_read_proc);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)