diff options
author | Jaroslav Kysela <perex@suse.cz> | 2004-11-29 11:14:38 +0100 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2004-11-29 11:14:38 +0100 |
commit | 2346d4b9249d0a23aca2dd7d9ca511208a319294 (patch) | |
tree | e1a778f7408a8d2455907862c67ce0f9e511af26 /sound | |
parent | fcfe585fc27a0eafdd55be2d3a54e393d10fc30e (diff) | |
download | history-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.c | 107 | ||||
-rw-r--r-- | sound/pci/ac97/ac97_local.h | 2 | ||||
-rw-r--r-- | sound/pci/ac97/ac97_patch.c | 86 |
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) |