Add a heuristic to test if an audio CODEC's AC97_REG_POWER register supports
the AC97_POWER_ANL bit. The heuristic simply checks if AC97_REG_POWER's AC97_POWER_MIXER bit can be set, implying the CODEC can control power to its mixer. If the bit reads back as zero after we set it, assume ANL is reserved. Without this patch, some CODECs (e.g. Philips UCB1400) will experience long delays during attach and resume while the driver waits for a bit which will never set. Thanks to jmcneill@ for reviewing this WRT AC97 modem power control.
This commit is contained in:
parent
2393bb4272
commit
32bd2f7d95
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ac97.c,v 1.73 2005/04/12 21:11:43 jmcneill Exp $ */
|
||||
/* $NetBSD: ac97.c,v 1.74 2005/05/11 13:13:11 scw Exp $ */
|
||||
/* $OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $ */
|
||||
|
||||
/*
|
||||
@ -63,7 +63,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.73 2005/04/12 21:11:43 jmcneill Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.74 2005/05/11 13:13:11 scw Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -377,6 +377,7 @@ struct ac97_softc {
|
||||
enum ac97_host_flags host_flags;
|
||||
unsigned int ac97_clock; /* usually 48000 */
|
||||
#define AC97_STANDARD_CLOCK 48000U
|
||||
uint16_t power_all;
|
||||
uint16_t caps; /* -> AC97_REG_RESET */
|
||||
uint16_t ext_id; /* -> AC97_REG_EXT_AUDIO_ID */
|
||||
uint16_t ext_mid; /* -> AC97_REG_EXT_MODEM_ID */
|
||||
@ -840,28 +841,27 @@ ac97_restore_shadow(struct ac97_codec_if *self)
|
||||
|
||||
as = (struct ac97_softc *) self;
|
||||
|
||||
/* make sure chip is fully operational */
|
||||
#define AC97_POWER_ALL (AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC \
|
||||
| AC97_POWER_ADC)
|
||||
for (idx = 50000; idx >= 0; idx--) {
|
||||
ac97_read(as, AC97_REG_POWER, &val);
|
||||
if ((val & AC97_POWER_ALL) == AC97_POWER_ALL)
|
||||
break;
|
||||
DELAY(10);
|
||||
}
|
||||
#undef AC97_POWER_ALL
|
||||
if (as->type == AC97_CODEC_TYPE_AUDIO) {
|
||||
/* make sure chip is fully operational */
|
||||
for (idx = 50000; idx >= 0; idx--) {
|
||||
ac97_read(as, AC97_REG_POWER, &val);
|
||||
if ((val & as->power_all) == as->power_all)
|
||||
break;
|
||||
DELAY(10);
|
||||
}
|
||||
|
||||
/*
|
||||
* actually try changing a value!
|
||||
* The default value of AC97_REG_MASTER_VOLUME is 0x8000.
|
||||
*/
|
||||
for (idx = 50000; idx >= 0; idx--) {
|
||||
ac97_write(as, AC97_REG_MASTER_VOLUME, 0x1010);
|
||||
ac97_read(as, AC97_REG_MASTER_VOLUME, &val);
|
||||
if (val == 0x1010)
|
||||
break;
|
||||
DELAY(10);
|
||||
}
|
||||
/*
|
||||
* actually try changing a value!
|
||||
* The default value of AC97_REG_MASTER_VOLUME is 0x8000.
|
||||
*/
|
||||
for (idx = 50000; idx >= 0; idx--) {
|
||||
ac97_write(as, AC97_REG_MASTER_VOLUME, 0x1010);
|
||||
ac97_read(as, AC97_REG_MASTER_VOLUME, &val);
|
||||
if (val == 0x1010)
|
||||
break;
|
||||
DELAY(10);
|
||||
}
|
||||
}
|
||||
|
||||
for (idx = 0; idx < SOURCE_INFO_SIZE(as); idx++) {
|
||||
if (as->type == AC97_CODEC_TYPE_MODEM)
|
||||
@ -1080,19 +1080,35 @@ ac97_attach_type(struct ac97_host_if *host_if, struct device *sc_dev, int type)
|
||||
|
||||
if (host_if->flags)
|
||||
as->host_flags = host_if->flags(host_if->arg);
|
||||
|
||||
/*
|
||||
* Assume codec has all four power bits.
|
||||
* XXXSCW: what to do for modems?
|
||||
*/
|
||||
as->power_all = AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC |
|
||||
AC97_POWER_ADC;
|
||||
if (as->type == AC97_CODEC_TYPE_AUDIO) {
|
||||
host_if->write(host_if->arg, AC97_REG_RESET, 0);
|
||||
|
||||
/*
|
||||
* Power-up everything except the analogue mixer.
|
||||
* If this codec doesn't support analogue mixer power-down,
|
||||
* AC97_POWER_MIXER will read back as zero.
|
||||
*/
|
||||
host_if->write(host_if->arg, AC97_REG_POWER, AC97_POWER_MIXER);
|
||||
ac97_read(as, AC97_REG_POWER, &val);
|
||||
if ((val & AC97_POWER_MIXER) == 0) {
|
||||
/* Codec doesn't support analogue mixer power-down */
|
||||
as->power_all &= ~AC97_POWER_ANL;
|
||||
}
|
||||
host_if->write(host_if->arg, AC97_REG_POWER, 0);
|
||||
|
||||
#define AC97_POWER_ALL (AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC \
|
||||
| AC97_POWER_ADC)
|
||||
for (i = 500000; i >= 0; i--) {
|
||||
ac97_read(as, AC97_REG_POWER, &val);
|
||||
if ((val & AC97_POWER_ALL) == AC97_POWER_ALL)
|
||||
if ((val & as->power_all) == as->power_all)
|
||||
break;
|
||||
DELAY(1);
|
||||
}
|
||||
#undef AC97_POWER_ALL
|
||||
} else if (as->type == AC97_CODEC_TYPE_MODEM) {
|
||||
host_if->write(host_if->arg, AC97_REG_EXT_MODEM_ID, 0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user