aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@suse.cz>2004-11-29 11:14:38 +0100
committerJaroslav Kysela <perex@suse.cz>2004-11-29 11:14:38 +0100
commit2346d4b9249d0a23aca2dd7d9ca511208a319294 (patch)
treee1a778f7408a8d2455907862c67ce0f9e511af26 /sound
parentfcfe585fc27a0eafdd55be2d3a54e393d10fc30e (diff)
downloadhistory-2346d4b9249d0a23aca2dd7d9ca511208a319294.tar.gz
[ALSA] AD18xx/19xx resume fix
AC97 Codec Core Added resume callback so that the codec-specific resume code can be called properly. Moved AD-specific initialization code into it. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/ac97/ac97_codec.c107
-rw-r--r--sound/pci/ac97/ac97_local.h2
-rw-r--r--sound/pci/ac97/ac97_patch.c86
3 files changed, 128 insertions, 67 deletions
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index b5c032036f1b50..279ec078f26d32 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -2213,6 +2213,46 @@ void snd_ac97_suspend(ac97_t *ac97)
snd_ac97_powerdown(ac97);
}
+/*
+ * restore ac97 status
+ */
+void snd_ac97_restore_status(ac97_t *ac97)
+{
+ int i;
+
+ for (i = 2; i < 0x7c ; i += 2) {
+ if (i == AC97_POWERDOWN || i == AC97_EXTENDED_ID)
+ continue;
+ /* restore only accessible registers
+ * some chip (e.g. nm256) may hang up when unsupported registers
+ * are accessed..!
+ */
+ if (test_bit(i, ac97->reg_accessed)) {
+ snd_ac97_write(ac97, i, ac97->regs[i]);
+ snd_ac97_read(ac97, i);
+ }
+ }
+}
+
+/*
+ * restore IEC958 status
+ */
+void snd_ac97_restore_iec958(ac97_t *ac97)
+{
+ if (ac97->ext_id & AC97_EI_SPDIF) {
+ if (ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_SPDIF) {
+ /* reset spdif status */
+ snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
+ snd_ac97_write(ac97, AC97_EXTENDED_STATUS, ac97->regs[AC97_EXTENDED_STATUS]);
+ if (ac97->flags & AC97_CS_SPDIF)
+ snd_ac97_write(ac97, AC97_CSR_SPDIF, ac97->regs[AC97_CSR_SPDIF]);
+ else
+ snd_ac97_write(ac97, AC97_SPDIF, ac97->regs[AC97_SPDIF]);
+ snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */
+ }
+ }
+}
+
/**
* snd_ac97_resume - General resume function for AC97 codec
* @ac97: the ac97 instance
@@ -2222,7 +2262,7 @@ void snd_ac97_suspend(ac97_t *ac97)
*/
void snd_ac97_resume(ac97_t *ac97)
{
- int i, is_ad18xx, codec;
+ int i;
if (ac97->bus->ops->reset) {
ac97->bus->ops->reset(ac97);
@@ -2264,66 +2304,11 @@ __reset_ready:
if (ac97->bus->ops->init)
ac97->bus->ops->init(ac97);
- is_ad18xx = (ac97->flags & AC97_AD_MULTI);
- if (is_ad18xx) {
- /* restore the AD18xx codec configurations */
- for (codec = 0; codec < 3; codec++) {
- if (! ac97->spec.ad18xx.id[codec])
- continue;
- /* select single codec */
- snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
- ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
- ac97->bus->ops->write(ac97, AC97_AD_CODEC_CFG, ac97->spec.ad18xx.codec_cfg[codec]);
- }
- /* select all codecs */
- snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
- }
-
- /* restore ac97 status */
- for (i = 2; i < 0x7c ; i += 2) {
- if (i == AC97_POWERDOWN || i == AC97_EXTENDED_ID)
- continue;
- /* restore only accessible registers
- * some chip (e.g. nm256) may hang up when unsupported registers
- * are accessed..!
- */
- if (test_bit(i, ac97->reg_accessed)) {
- if (is_ad18xx) {
- /* handle multi codecs for AD18xx */
- if (i == AC97_PCM) {
- for (codec = 0; codec < 3; codec++) {
- if (! ac97->spec.ad18xx.id[codec])
- continue;
- /* select single codec */
- snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
- ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
- /* update PCM bits */
- ac97->bus->ops->write(ac97, AC97_PCM, ac97->spec.ad18xx.pcmreg[codec]);
- }
- /* select all codecs */
- snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
- continue;
- } else if (i == AC97_AD_TEST ||
- i == AC97_AD_CODEC_CFG ||
- i == AC97_AD_SERIAL_CFG)
- continue; /* ignore */
- }
- snd_ac97_write(ac97, i, ac97->regs[i]);
- snd_ac97_read(ac97, i);
- }
- }
-
- if (ac97->ext_id & AC97_EI_SPDIF) {
- if (ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_SPDIF) {
- /* reset spdif status */
- snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
- snd_ac97_write(ac97, AC97_EXTENDED_STATUS, ac97->regs[AC97_EXTENDED_STATUS]);
- if (ac97->flags & AC97_CS_SPDIF)
- snd_ac97_write(ac97, AC97_CSR_SPDIF, ac97->regs[AC97_CSR_SPDIF]);
- else
- snd_ac97_write(ac97, AC97_SPDIF, ac97->regs[AC97_SPDIF]);
- snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */
- }
+ if (ac97->build_ops->resume)
+ ac97->build_ops->resume(ac97);
+ else {
+ snd_ac97_restore_status(ac97);
+ snd_ac97_restore_iec958(ac97);
}
}
#endif
diff --git a/sound/pci/ac97/ac97_local.h b/sound/pci/ac97/ac97_local.h
index 21b58d759735a1..de412dbe988a23 100644
--- a/sound/pci/ac97/ac97_local.h
+++ b/sound/pci/ac97/ac97_local.h
@@ -49,6 +49,8 @@ int snd_ac97_remove_ctl(ac97_t *ac97, const char *name, const char *suffix);
int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst, const char *suffix);
int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2, const char *suffix);
void snd_ac97_rename_vol_ctl(ac97_t *ac97, const char *src, const char *dst);
+void snd_ac97_restore_status(ac97_t *ac97);
+void snd_ac97_restore_iec958(ac97_t *ac97);
/* ac97_proc.c */
#ifdef CONFIG_PROC_FS
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 3b0b8d683d4e93..08cdd4f853f5aa 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -775,6 +775,69 @@ int patch_conexant(ac97_t * ac97)
/*
* Analog Device AD18xx, AD19xx codecs
*/
+static void ad18xx_resume(ac97_t *ac97)
+{
+ static unsigned short setup_regs[] = {
+ AC97_AD_MISC, AC97_AD_SERIAL_CFG, AC97_AD_JACK_SPDIF,
+ };
+ int i, codec;
+
+ for (i = 0; i < (int)ARRAY_SIZE(setup_regs); i++) {
+ unsigned short reg = setup_regs[i];
+ if (test_bit(reg, ac97->reg_accessed)) {
+ snd_ac97_write(ac97, reg, ac97->regs[reg]);
+ snd_ac97_read(ac97, reg);
+ }
+ }
+
+ if (! (ac97->flags & AC97_AD_MULTI))
+ /* normal restore */
+ snd_ac97_restore_status(ac97);
+ else {
+ /* restore the AD18xx codec configurations */
+ for (codec = 0; codec < 3; codec++) {
+ if (! ac97->spec.ad18xx.id[codec])
+ continue;
+ /* select single codec */
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
+ ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
+ ac97->bus->ops->write(ac97, AC97_AD_CODEC_CFG, ac97->spec.ad18xx.codec_cfg[codec]);
+ }
+ /* select all codecs */
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
+
+ /* restore status */
+ for (i = 2; i < 0x7c ; i += 2) {
+ if (i == AC97_POWERDOWN || i == AC97_EXTENDED_ID)
+ continue;
+ if (test_bit(i, ac97->reg_accessed)) {
+ /* handle multi codecs for AD18xx */
+ if (i == AC97_PCM) {
+ for (codec = 0; codec < 3; codec++) {
+ if (! ac97->spec.ad18xx.id[codec])
+ continue;
+ /* select single codec */
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
+ ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
+ /* update PCM bits */
+ ac97->bus->ops->write(ac97, AC97_PCM, ac97->spec.ad18xx.pcmreg[codec]);
+ }
+ /* select all codecs */
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
+ continue;
+ } else if (i == AC97_AD_TEST ||
+ i == AC97_AD_CODEC_CFG ||
+ i == AC97_AD_SERIAL_CFG)
+ continue; /* ignore */
+ }
+ snd_ac97_write(ac97, i, ac97->regs[i]);
+ snd_ac97_read(ac97, i);
+ }
+ }
+
+ snd_ac97_restore_iec958(ac97);
+}
+
int patch_ad1819(ac97_t * ac97)
{
unsigned short scfg;
@@ -843,6 +906,10 @@ static void patch_ad1881_chained(ac97_t * ac97, int unchained_idx, int cidx1, in
}
}
+static struct snd_ac97_build_ops patch_ad1881_build_ops = {
+ .resume = &ad18xx_resume
+};
+
int patch_ad1881(ac97_t * ac97)
{
static const char cfg_idxs[3][2] = {
@@ -897,6 +964,7 @@ int patch_ad1881(ac97_t * ac97)
ac97->id &= 0xffff0000;
ac97->id |= ac97->spec.ad18xx.id[0];
}
+ ac97->build_ops = &patch_ad1881_build_ops;
return 0;
}
@@ -919,7 +987,8 @@ static int patch_ad1885_specific(ac97_t * ac97)
}
static struct snd_ac97_build_ops patch_ad1885_build_ops = {
- .build_specific = &patch_ad1885_specific
+ .build_specific = &patch_ad1885_specific,
+ .resume = &ad18xx_resume
};
int patch_ad1885(ac97_t * ac97)
@@ -1026,7 +1095,8 @@ static int patch_ad1981a_specific(ac97_t * ac97)
static struct snd_ac97_build_ops patch_ad1981a_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
- .build_specific = patch_ad1981a_specific
+ .build_specific = patch_ad1981a_specific,
+ .resume = ad18xx_resume
};
int patch_ad1981a(ac97_t *ac97)
@@ -1054,7 +1124,8 @@ static int patch_ad1981b_specific(ac97_t *ac97)
static struct snd_ac97_build_ops patch_ad1981b_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
- .build_specific = patch_ad1981b_specific
+ .build_specific = patch_ad1981b_specific,
+ .resume = ad18xx_resume
};
int patch_ad1981b(ac97_t *ac97)
@@ -1169,7 +1240,8 @@ static int patch_ad1888_specific(ac97_t *ac97)
static struct snd_ac97_build_ops patch_ad1888_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
- .build_specific = patch_ad1888_specific
+ .build_specific = patch_ad1888_specific,
+ .resume = ad18xx_resume
};
int patch_ad1888(ac97_t * ac97)
@@ -1203,7 +1275,8 @@ static int patch_ad1980_specific(ac97_t *ac97)
static struct snd_ac97_build_ops patch_ad1980_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
- .build_specific = patch_ad1980_specific
+ .build_specific = patch_ad1980_specific,
+ .resume = ad18xx_resume
};
int patch_ad1980(ac97_t * ac97)
@@ -1229,7 +1302,8 @@ static int patch_ad1985_specific(ac97_t *ac97)
static struct snd_ac97_build_ops patch_ad1985_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
- .build_specific = patch_ad1985_specific
+ .build_specific = patch_ad1985_specific,
+ .resume = ad18xx_resume
};
int patch_ad1985(ac97_t * ac97)