[ALSA] ad1848: simplify MCE down code
Trent Piepho [Wed, 19 Sep 2007 19:20:17 +0000 (21:20 +0200)]
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>

sound/isa/ad1848/ad1848_lib.c

index 18355fd..21536b7 100644 (file)
@@ -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)));