Commit 81ff6ee4 authored by Jaroslav Kysela's avatar Jaroslav Kysela Committed by Linus Torvalds

[PATCH] ALSA update [5/10] - 2002/07/17

  - AD1816A - fixed MIC playback volume
  - OPL3SA2 - fixed non-ISA PnP build
  - AC'97 code - 1st version of separated codec specific code
parent 40290333
/* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc2"
#define CONFIG_SND_DATE " (Sun Jul 14 21:30:57 2002 UTC)"
#define CONFIG_SND_DATE " (Wed Jul 17 10:56:41 2002 UTC)"
......@@ -20,6 +20,7 @@
#define __NO_VERSION__
#include <sound/driver.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/time.h>
......
......@@ -908,7 +908,7 @@ AD1816A_DOUBLE("Synth Playback Volume", AD1816A_SYNTH_GAIN_ATT, 8, 0, 31, 1),
AD1816A_DOUBLE("FM Playback Switch", AD1816A_FM_ATT, 15, 7, 1, 1),
AD1816A_DOUBLE("FM Playback Volume", AD1816A_FM_ATT, 8, 0, 63, 1),
AD1816A_SINGLE("Mic Playback Switch", AD1816A_MIC_GAIN_ATT, 15, 1, 1),
AD1816A_SINGLE("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 63, 1),
AD1816A_SINGLE("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 31, 1),
AD1816A_SINGLE("Mic Boost", AD1816A_MIC_GAIN_ATT, 14, 1, 0),
AD1816A_DOUBLE("Video Playback Switch", AD1816A_VID_GAIN_ATT, 15, 7, 1, 1),
AD1816A_DOUBLE("Video Playback Volume", AD1816A_VID_GAIN_ATT, 8, 0, 31, 1),
......
......@@ -71,9 +71,11 @@ MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_enable, "Enable OPL3-SA soundcard.");
MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
#ifdef __ISAPNP__
MODULE_PARM(snd_isapnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_isapnp, "ISA PnP detection for specified soundcard.");
MODULE_PARM_SYNTAX(snd_isapnp, SNDRV_ISAPNP_DESC);
#endif
MODULE_PARM(snd_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
MODULE_PARM_DESC(snd_port, "Port # for OPL3-SA driver.");
MODULE_PARM_SYNTAX(snd_port, SNDRV_ENABLED ",allows:{{0xf86},{0x370},{0x100}},dialog:list");
......
......@@ -5,7 +5,7 @@
export-objs := ac97_codec.o ak4531_codec.o
snd-ac97-codec-objs := ac97_codec.o
snd-ac97-codec-objs := ac97_codec.o ac97_patch.o
snd-ak4531-codec-objs := ak4531_codec.o
# Toplevel Module Dependency
......
......@@ -31,6 +31,8 @@
#include <sound/ac97_codec.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
#include "ac97_id.h"
#include "ac97_patch.h"
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("Universal interface for Audio Codec '97");
......@@ -51,21 +53,6 @@ MODULE_PARM_SYNTAX(enable_loopback, SNDRV_BOOLEAN_FALSE_DESC);
static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97);
static void snd_ac97_proc_done(ac97_t * ac97);
static int patch_wolfson00(ac97_t * ac97);
static int patch_wolfson03(ac97_t * ac97);
static int patch_wolfson04(ac97_t * ac97);
static int patch_tritech_tr28028(ac97_t * ac97);
static int patch_sigmatel_stac9708(ac97_t * ac97);
static int patch_sigmatel_stac9721(ac97_t * ac97);
static int patch_sigmatel_stac9744(ac97_t * ac97);
static int patch_sigmatel_stac9756(ac97_t * ac97);
static int patch_cirrus_cs4299(ac97_t * ac97);
static int patch_cirrus_spdif(ac97_t * ac97);
static int patch_conexant(ac97_t * ac97);
static int patch_ad1819(ac97_t * ac97);
static int patch_ad1881(ac97_t * ac97);
static int patch_ad1886(ac97_t * ac97);
typedef struct {
unsigned int id;
unsigned int mask;
......@@ -107,6 +94,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x41445360, 0xffffffff, "AD1885", patch_ad1881 },
{ 0x41445361, 0xffffffff, "AD1886", patch_ad1886 },
{ 0x41445362, 0xffffffff, "AD1887", patch_ad1881 },
{ 0x41445372, 0xffffffff, "AD1981A", NULL },
{ 0x414c4300, 0xfffffff0, "RL5306", NULL },
{ 0x414c4310, 0xfffffff0, "RL5382", NULL },
{ 0x414c4320, 0xfffffff0, "RL5383", NULL },
......@@ -151,27 +139,6 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0, 0, NULL, NULL }
};
#define AC97_ID_AK4540 0x414b4d00
#define AC97_ID_AK4542 0x414b4d01
#define AC97_ID_AD1819 0x41445303
#define AC97_ID_AD1881 0x41445340
#define AC97_ID_AD1881A 0x41445348
#define AC97_ID_AD1885 0x41445360
#define AC97_ID_AD1886 0x41445361
#define AC97_ID_AD1887 0x41445362
#define AC97_ID_TR28028 0x54524108
#define AC97_ID_STAC9700 0x83847600
#define AC97_ID_STAC9704 0x83847604
#define AC97_ID_STAC9705 0x83847605
#define AC97_ID_STAC9708 0x83847608
#define AC97_ID_STAC9721 0x83847609
#define AC97_ID_STAC9744 0x83847644
#define AC97_ID_STAC9756 0x83847656
#define AC97_ID_CS4297A 0x43525910
#define AC97_ID_CS4299 0x43525930
#define AC97_ID_CS4201 0x43525948
#define AC97_ID_CS4205 0x43525958
static const char *snd_ac97_stereo_enhancements[] =
{
/* 0 */ "No 3D Stereo Enhancement",
......@@ -1850,283 +1817,6 @@ static void snd_ac97_proc_done(ac97_t * ac97)
}
}
/*
* Chip specific initialization
*/
static int patch_wolfson00(ac97_t * ac97)
{
/* This sequence is suspect because it was designed for
the WM9704, and is known to fail when applied to the
WM9707. If you're having trouble initializing a
WM9700, this is the place to start looking.
Randolph Bentson <bentson@holmsjoen.com> */
// WM9701A
snd_ac97_write_cache(ac97, 0x72, 0x0808);
snd_ac97_write_cache(ac97, 0x74, 0x0808);
// patch for DVD noise
snd_ac97_write_cache(ac97, 0x5a, 0x0200);
// init vol
snd_ac97_write_cache(ac97, 0x70, 0x0808);
snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
return 0;
}
static int patch_wolfson03(ac97_t * ac97)
{
/* This is known to work for the ViewSonic ViewPad 1000
Randolph Bentson <bentson@holmsjoen.com> */
// WM9703/9707
snd_ac97_write_cache(ac97, 0x72, 0x0808);
snd_ac97_write_cache(ac97, 0x20, 0x8000);
return 0;
}
static int patch_wolfson04(ac97_t * ac97)
{
// WM9704
snd_ac97_write_cache(ac97, 0x72, 0x0808);
snd_ac97_write_cache(ac97, 0x74, 0x0808);
// patch for DVD noise
snd_ac97_write_cache(ac97, 0x5a, 0x0200);
// init vol
snd_ac97_write_cache(ac97, 0x70, 0x0808);
snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
return 0;
}
static int patch_tritech_tr28028(ac97_t * ac97)
{
snd_ac97_write_cache(ac97, 0x26, 0x0300);
snd_ac97_write_cache(ac97, 0x26, 0x0000);
snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
snd_ac97_write_cache(ac97, AC97_SPDIF, 0x0000);
return 0;
}
static int patch_sigmatel_stac9708(ac97_t * ac97)
{
unsigned int codec72, codec6c;
codec72 = snd_ac97_read(ac97, AC97_SIGMATEL_BIAS2) & 0x8000;
codec6c = snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG);
if ((codec72==0) && (codec6c==0)) {
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x1000);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0007);
} else if ((codec72==0x8000) && (codec6c==0)) {
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x1001);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_DAC2INVERT, 0x0008);
} else if ((codec72==0x8000) && (codec6c==0x0080)) {
/* nothing */
}
snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
return 0;
}
static int patch_sigmatel_stac9721(ac97_t * ac97)
{
if (snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) == 0) {
// patch for SigmaTel
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x4000);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0002);
}
snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
return 0;
}
static int patch_sigmatel_stac9744(ac97_t * ac97)
{
// patch for SigmaTel
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000); /* is this correct? --jk */
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0002);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
return 0;
}
static int patch_sigmatel_stac9756(ac97_t * ac97)
{
// patch for SigmaTel
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000); /* is this correct? --jk */
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0002);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
return 0;
}
static int patch_cirrus_spdif(ac97_t * ac97)
{
/* Basically, the cs4201/cs4205/cs4297a has non-standard sp/dif registers.
WHY CAN'T ANYONE FOLLOW THE BLOODY SPEC? *sigh*
- sp/dif EA ID is not set, but sp/dif is always present.
- enable/disable is spdif register bit 15.
- sp/dif control register is 0x68. differs from AC97:
- valid is bit 14 (vs 15)
- no DRS
- only 44.1/48k [00 = 48, 01=44,1] (AC97 is 00=44.1, 10=48)
- sp/dif ssource select is in 0x5e bits 0,1.
*/
ac97->flags |= AC97_CS_SPDIF;
ac97->ext_id |= AC97_EA_SPDIF; /* force the detection of spdif */
snd_ac97_write_cache(ac97, AC97_CSR_ACMODE, 0x0080);
return 0;
}
static int patch_cirrus_cs4299(ac97_t * ac97)
{
/* force the detection of PC Beep */
ac97->flags |= AC97_HAS_PC_BEEP;
return patch_cirrus_spdif(ac97);
}
static int patch_conexant(ac97_t * ac97)
{
ac97->flags |= AC97_CX_SPDIF;
ac97->ext_id |= AC97_EA_SPDIF; /* force the detection of spdif */
return 0;
}
static int patch_ad1819(ac97_t * ac97)
{
// patch for Analog Devices
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000); /* select all codecs */
return 0;
}
static unsigned short patch_ad1881_unchained(ac97_t * ac97, int idx, unsigned short mask)
{
unsigned short val;
// test for unchained codec
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, mask);
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000); /* ID0C, ID1C, SDIE = off */
val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
if ((val & 0xff40) != 0x5340)
return 0;
ac97->spec.ad18xx.unchained[idx] = mask;
ac97->spec.ad18xx.id[idx] = val;
return mask;
}
static int patch_ad1881_chained1(ac97_t * ac97, int idx, unsigned short codec_bits)
{
static int cfg_bits[3] = { 1<<12, 1<<14, 1<<13 };
unsigned short val;
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, cfg_bits[idx]);
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0004); // SDIE
val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
if ((val & 0xff40) != 0x5340)
return 0;
if (codec_bits)
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, codec_bits);
ac97->spec.ad18xx.chained[idx] = cfg_bits[idx];
ac97->spec.ad18xx.id[idx] = val;
return 1;
}
static void patch_ad1881_chained(ac97_t * ac97, int unchained_idx, int cidx1, int cidx2)
{
// already detected?
if (ac97->spec.ad18xx.unchained[cidx1] || ac97->spec.ad18xx.chained[cidx1])
cidx1 = -1;
if (ac97->spec.ad18xx.unchained[cidx2] || ac97->spec.ad18xx.chained[cidx2])
cidx2 = -1;
if (cidx1 < 0 && cidx2 < 0)
return;
// test for chained codecs
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[unchained_idx]);
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0002); // ID1C
if (cidx1 >= 0) {
if (patch_ad1881_chained1(ac97, cidx1, 0x0006)) // SDIE | ID1C
patch_ad1881_chained1(ac97, cidx2, 0);
else if (patch_ad1881_chained1(ac97, cidx2, 0x0006)) // SDIE | ID1C
patch_ad1881_chained1(ac97, cidx1, 0);
} else if (cidx2 >= 0) {
patch_ad1881_chained1(ac97, cidx2, 0);
}
}
static int patch_ad1881(ac97_t * ac97)
{
static const char cfg_idxs[3][2] = {
{2, 1},
{0, 2},
{0, 1}
};
// patch for Analog Devices
unsigned short codecs[3];
int idx, num;
init_MUTEX(&ac97->spec.ad18xx.mutex);
codecs[0] = patch_ad1881_unchained(ac97, 0, (1<<12));
codecs[1] = patch_ad1881_unchained(ac97, 1, (1<<14));
codecs[2] = patch_ad1881_unchained(ac97, 2, (1<<13));
snd_runtime_check(codecs[0] | codecs[1] | codecs[2], goto __end);
for (idx = 0; idx < 3; idx++)
if (ac97->spec.ad18xx.unchained[idx])
patch_ad1881_chained(ac97, idx, cfg_idxs[idx][0], cfg_idxs[idx][1]);
if (ac97->spec.ad18xx.id[1]) {
ac97->flags |= AC97_AD_MULTI;
ac97->scaps |= AC97_SCAP_SURROUND_DAC;
}
if (ac97->spec.ad18xx.id[2]) {
ac97->flags |= AC97_AD_MULTI;
ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;
}
__end:
/* select all codecs */
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
/* check if only one codec is present */
for (idx = num = 0; idx < 3; idx++)
if (ac97->spec.ad18xx.id[idx])
num++;
if (num == 1) {
/* ok, deselect all ID bits */
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000);
}
/* required for AD1886/AD1885 combination */
ac97->ext_id = snd_ac97_read(ac97, AC97_EXTENDED_ID);
if (ac97->spec.ad18xx.id[0]) {
ac97->id &= 0xffff0000;
ac97->id |= ac97->spec.ad18xx.id[0];
}
return 0;
}
static int patch_ad1886(ac97_t * ac97)
{
patch_ad1881(ac97);
/* Presario700 workaround */
/* for Jack Sense/SPDIF Register misetting causing */
snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010);
return 0;
}
/*
* PCM support
*/
......
/*
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
* Universal interface for Audio Codec '97
*
* For more details look to AC '97 component specification revision 2.2
* by Intel Corporation (http://developer.intel.com).
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#define AC97_ID_AK4540 0x414b4d00
#define AC97_ID_AK4542 0x414b4d01
#define AC97_ID_AD1819 0x41445303
#define AC97_ID_AD1881 0x41445340
#define AC97_ID_AD1881A 0x41445348
#define AC97_ID_AD1885 0x41445360
#define AC97_ID_AD1886 0x41445361
#define AC97_ID_AD1887 0x41445362
#define AC97_ID_TR28028 0x54524108
#define AC97_ID_STAC9700 0x83847600
#define AC97_ID_STAC9704 0x83847604
#define AC97_ID_STAC9705 0x83847605
#define AC97_ID_STAC9708 0x83847608
#define AC97_ID_STAC9721 0x83847609
#define AC97_ID_STAC9744 0x83847644
#define AC97_ID_STAC9756 0x83847656
#define AC97_ID_CS4297A 0x43525910
#define AC97_ID_CS4299 0x43525930
#define AC97_ID_CS4201 0x43525948
#define AC97_ID_CS4205 0x43525958
/*
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
* Universal interface for Audio Codec '97
*
* For more details look to AC '97 component specification revision 2.2
* by Intel Corporation (http://developer.intel.com).
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
/*
* Chip specific initialization
*/
int patch_wolfson00(ac97_t * ac97)
{
/* This sequence is suspect because it was designed for
the WM9704, and is known to fail when applied to the
WM9707. If you're having trouble initializing a
WM9700, this is the place to start looking.
Randolph Bentson <bentson@holmsjoen.com> */
// WM9701A
snd_ac97_write_cache(ac97, 0x72, 0x0808);
snd_ac97_write_cache(ac97, 0x74, 0x0808);
// patch for DVD noise
snd_ac97_write_cache(ac97, 0x5a, 0x0200);
// init vol
snd_ac97_write_cache(ac97, 0x70, 0x0808);
snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
return 0;
}
int patch_wolfson03(ac97_t * ac97)
{
/* This is known to work for the ViewSonic ViewPad 1000
Randolph Bentson <bentson@holmsjoen.com> */
// WM9703/9707
snd_ac97_write_cache(ac97, 0x72, 0x0808);
snd_ac97_write_cache(ac97, 0x20, 0x8000);
return 0;
}
int patch_wolfson04(ac97_t * ac97)
{
// WM9704
snd_ac97_write_cache(ac97, 0x72, 0x0808);
snd_ac97_write_cache(ac97, 0x74, 0x0808);
// patch for DVD noise
snd_ac97_write_cache(ac97, 0x5a, 0x0200);
// init vol
snd_ac97_write_cache(ac97, 0x70, 0x0808);
snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
return 0;
}
int patch_tritech_tr28028(ac97_t * ac97)
{
snd_ac97_write_cache(ac97, 0x26, 0x0300);
snd_ac97_write_cache(ac97, 0x26, 0x0000);
snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
snd_ac97_write_cache(ac97, AC97_SPDIF, 0x0000);
return 0;
}
int patch_sigmatel_stac9708(ac97_t * ac97)
{
unsigned int codec72, codec6c;
codec72 = snd_ac97_read(ac97, AC97_SIGMATEL_BIAS2) & 0x8000;
codec6c = snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG);
if ((codec72==0) && (codec6c==0)) {
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x1000);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0007);
} else if ((codec72==0x8000) && (codec6c==0)) {
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x1001);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_DAC2INVERT, 0x0008);
} else if ((codec72==0x8000) && (codec6c==0x0080)) {
/* nothing */
}
snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
return 0;
}
int patch_sigmatel_stac9721(ac97_t * ac97)
{
if (snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) == 0) {
// patch for SigmaTel
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x4000);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0002);
}
snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
return 0;
}
int patch_sigmatel_stac9744(ac97_t * ac97)
{
// patch for SigmaTel
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000); /* is this correct? --jk */
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0002);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
return 0;
}
int patch_sigmatel_stac9756(ac97_t * ac97)
{
// patch for SigmaTel
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000); /* is this correct? --jk */
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0002);
snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
return 0;
}
int patch_cirrus_spdif(ac97_t * ac97)
{
/* Basically, the cs4201/cs4205/cs4297a has non-standard sp/dif registers.
WHY CAN'T ANYONE FOLLOW THE BLOODY SPEC? *sigh*
- sp/dif EA ID is not set, but sp/dif is always present.
- enable/disable is spdif register bit 15.
- sp/dif control register is 0x68. differs from AC97:
- valid is bit 14 (vs 15)
- no DRS
- only 44.1/48k [00 = 48, 01=44,1] (AC97 is 00=44.1, 10=48)
- sp/dif ssource select is in 0x5e bits 0,1.
*/
ac97->flags |= AC97_CS_SPDIF;
ac97->ext_id |= AC97_EA_SPDIF; /* force the detection of spdif */
snd_ac97_write_cache(ac97, AC97_CSR_ACMODE, 0x0080);
return 0;
}
int patch_cirrus_cs4299(ac97_t * ac97)
{
/* force the detection of PC Beep */
ac97->flags |= AC97_HAS_PC_BEEP;
return patch_cirrus_spdif(ac97);
}
int patch_conexant(ac97_t * ac97)
{
ac97->flags |= AC97_CX_SPDIF;
ac97->ext_id |= AC97_EA_SPDIF; /* force the detection of spdif */
return 0;
}
int patch_ad1819(ac97_t * ac97)
{
// patch for Analog Devices
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000); /* select all codecs */
return 0;
}
static unsigned short patch_ad1881_unchained(ac97_t * ac97, int idx, unsigned short mask)
{
unsigned short val;
// test for unchained codec
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, mask);
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000); /* ID0C, ID1C, SDIE = off */
val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
if ((val & 0xff40) != 0x5340)
return 0;
ac97->spec.ad18xx.unchained[idx] = mask;
ac97->spec.ad18xx.id[idx] = val;
return mask;
}
static int patch_ad1881_chained1(ac97_t * ac97, int idx, unsigned short codec_bits)
{
static int cfg_bits[3] = { 1<<12, 1<<14, 1<<13 };
unsigned short val;
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, cfg_bits[idx]);
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0004); // SDIE
val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
if ((val & 0xff40) != 0x5340)
return 0;
if (codec_bits)
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, codec_bits);
ac97->spec.ad18xx.chained[idx] = cfg_bits[idx];
ac97->spec.ad18xx.id[idx] = val;
return 1;
}
static void patch_ad1881_chained(ac97_t * ac97, int unchained_idx, int cidx1, int cidx2)
{
// already detected?
if (ac97->spec.ad18xx.unchained[cidx1] || ac97->spec.ad18xx.chained[cidx1])
cidx1 = -1;
if (ac97->spec.ad18xx.unchained[cidx2] || ac97->spec.ad18xx.chained[cidx2])
cidx2 = -1;
if (cidx1 < 0 && cidx2 < 0)
return;
// test for chained codecs
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[unchained_idx]);
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0002); // ID1C
if (cidx1 >= 0) {
if (patch_ad1881_chained1(ac97, cidx1, 0x0006)) // SDIE | ID1C
patch_ad1881_chained1(ac97, cidx2, 0);
else if (patch_ad1881_chained1(ac97, cidx2, 0x0006)) // SDIE | ID1C
patch_ad1881_chained1(ac97, cidx1, 0);
} else if (cidx2 >= 0) {
patch_ad1881_chained1(ac97, cidx2, 0);
}
}
int patch_ad1881(ac97_t * ac97)
{
static const char cfg_idxs[3][2] = {
{2, 1},
{0, 2},
{0, 1}
};
// patch for Analog Devices
unsigned short codecs[3];
int idx, num;
init_MUTEX(&ac97->spec.ad18xx.mutex);
codecs[0] = patch_ad1881_unchained(ac97, 0, (1<<12));
codecs[1] = patch_ad1881_unchained(ac97, 1, (1<<14));
codecs[2] = patch_ad1881_unchained(ac97, 2, (1<<13));
snd_runtime_check(codecs[0] | codecs[1] | codecs[2], goto __end);
for (idx = 0; idx < 3; idx++)
if (ac97->spec.ad18xx.unchained[idx])
patch_ad1881_chained(ac97, idx, cfg_idxs[idx][0], cfg_idxs[idx][1]);
if (ac97->spec.ad18xx.id[1]) {
ac97->flags |= AC97_AD_MULTI;
ac97->scaps |= AC97_SCAP_SURROUND_DAC;
}
if (ac97->spec.ad18xx.id[2]) {
ac97->flags |= AC97_AD_MULTI;
ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;
}
__end:
/* select all codecs */
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
/* check if only one codec is present */
for (idx = num = 0; idx < 3; idx++)
if (ac97->spec.ad18xx.id[idx])
num++;
if (num == 1) {
/* ok, deselect all ID bits */
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000);
}
/* required for AD1886/AD1885 combination */
ac97->ext_id = snd_ac97_read(ac97, AC97_EXTENDED_ID);
if (ac97->spec.ad18xx.id[0]) {
ac97->id &= 0xffff0000;
ac97->id |= ac97->spec.ad18xx.id[0];
}
return 0;
}
int patch_ad1886(ac97_t * ac97)
{
patch_ad1881(ac97);
/* Presario700 workaround */
/* for Jack Sense/SPDIF Register misetting causing */
snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010);
return 0;
}
/*
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
* Universal interface for Audio Codec '97
*
* For more details look to AC '97 component specification revision 2.2
* by Intel Corporation (http://developer.intel.com).
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
int patch_wolfson00(ac97_t * ac97);
int patch_wolfson03(ac97_t * ac97);
int patch_wolfson04(ac97_t * ac97);
int patch_tritech_tr28028(ac97_t * ac97);
int patch_sigmatel_stac9708(ac97_t * ac97);
int patch_sigmatel_stac9721(ac97_t * ac97);
int patch_sigmatel_stac9744(ac97_t * ac97);
int patch_sigmatel_stac9756(ac97_t * ac97);
int patch_cirrus_cs4299(ac97_t * ac97);
int patch_cirrus_spdif(ac97_t * ac97);
int patch_conexant(ac97_t * ac97);
int patch_ad1819(ac97_t * ac97);
int patch_ad1881(ac97_t * ac97);
int patch_ad1886(ac97_t * ac97);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment