summaryrefslogtreecommitdiffstats
path: root/sound/isa/ad1848
diff options
context:
space:
mode:
authorTrent Piepho <xyzzy@speakeasy.org>2007-09-19 21:20:17 +0200
committerJaroslav Kysela <perex@perex.cz>2007-10-16 16:50:59 +0200
commitfe1b5e874dad88646d344b092d3066cb21b279eb (patch)
treed5181520c738565f2481b5e3e2eaae1cc6a152ff /sound/isa/ad1848
parent[ALSA] ad1848: Fix msleep while atomic (diff)
downloadlinux-fe1b5e874dad88646d344b092d3066cb21b279eb.tar.xz
linux-fe1b5e874dad88646d344b092d3066cb21b279eb.zip
[ALSA] ad1848: simplify MCE down code
The polling loop to check for ACI to go down was more convoluted than it needed to be. New loop should be more efficient and it is a lot simpler. The old loop checked for a timeout before checking for ACI down, which could result in an erroneous timeout. It's only a failure if the timeout expires _and_ ACI is still high. There is nothing wrong with the timeout expiring while the task is sleeping if ACI went low. A polling loop to check for the device to leaving INIT mode is removed. The device must have already left init for the previous ACI loop to have finished. Acked-by: Rene Herman <rene.herman@gmail.com> Signed-off-by: Trent Piepho <xyzzy@speakeasy.org> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/isa/ad1848')
-rw-r--r--sound/isa/ad1848/ad1848_lib.c57
1 files changed, 21 insertions, 36 deletions
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
index 18355fd66cb5..21536b7de608 100644
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -203,9 +203,8 @@ static void snd_ad1848_mce_up(struct snd_ad1848 *chip)
static void snd_ad1848_mce_down(struct snd_ad1848 *chip)
{
- unsigned long flags;
- int timeout;
- unsigned long end_time;
+ unsigned long flags, timeout;
+ int reg;
spin_lock_irqsave(&chip->reg_lock, flags);
for (timeout = 5; timeout > 0; timeout--)
@@ -222,50 +221,36 @@ static void snd_ad1848_mce_down(struct snd_ad1848 *chip)
#endif
chip->mce_bit &= ~AD1848_MCE;
- timeout = inb(AD1848P(chip, REGSEL));
- outb(chip->mce_bit | (timeout & 0x1f), AD1848P(chip, REGSEL));
- if (timeout == 0x80)
+ reg = inb(AD1848P(chip, REGSEL));
+ outb(chip->mce_bit | (reg & 0x1f), AD1848P(chip, REGSEL));
+ if (reg == 0x80)
snd_printk(KERN_WARNING "mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
- if ((timeout & AD1848_MCE) == 0) {
+ if ((reg & AD1848_MCE) == 0) {
spin_unlock_irqrestore(&chip->reg_lock, flags);
return;
}
/*
- * Wait for (possible -- during init auto-calibration may not be set)
- * calibration process to start. Needs upto 5 sample periods on AD1848
- * which at the slowest possible rate of 5.5125 kHz means 907 us.
+ * Wait for auto-calibration (AC) process to finish, i.e. ACI to go low.
+ * It may take up to 5 sample periods (at most 907 us @ 5.5125 kHz) for
+ * the process to _start_, so it is important to wait at least that long
+ * before checking. Otherwise we might think AC has finished when it
+ * has in fact not begun. It could take 128 (no AC) or 384 (AC) cycles
+ * for ACI to drop. This gives a wait of at most 70 ms with a more
+ * typical value of 3-9 ms.
*/
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- msleep(1);
- spin_lock_irqsave(&chip->reg_lock, flags);
-
- snd_printdd("(2) jiffies = %lu\n", jiffies);
-
- end_time = jiffies + msecs_to_jiffies(250);
- while (snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) {
+ timeout = jiffies + msecs_to_jiffies(250);
+ do {
spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (time_after(jiffies, end_time)) {
- snd_printk(KERN_ERR "mce_down - auto calibration time out (2)\n");
- return;
- }
msleep(1);
spin_lock_irqsave(&chip->reg_lock, flags);
- }
-
- snd_printdd("(3) jiffies = %lu\n", jiffies);
-
- end_time = jiffies + msecs_to_jiffies(100);
- while (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (time_after(jiffies, end_time)) {
- snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
- return;
- }
- msleep(1);
- spin_lock_irqsave(&chip->reg_lock, flags);
- }
+ reg = snd_ad1848_in(chip, AD1848_TEST_INIT) &
+ AD1848_CALIB_IN_PROGRESS;
+ } while (reg && time_before(jiffies, timeout));
spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (reg)
+ snd_printk(KERN_ERR
+ "mce_down - auto calibration time out (2)\n");
snd_printdd("(4) jiffies = %lu\n", jiffies);
snd_printd("mce_down - exit = 0x%x\n", inb(AD1848P(chip, REGSEL)));