Skip to content

Commit

Permalink
ALSA: AACI: fix timeout duration
Browse files Browse the repository at this point in the history
Relying on the access time of peripherals is unreliable - it depends
on the speed of the CPU and the bus.  On Versatile Express, these
timeouts were expiring, causing the driver to fail.

Add udelay(1) to ensure that they don't expire early, and adjust
timeouts to give a reasonable margin over the response times.

Signed-off-by: Russell King <[email protected]>
  • Loading branch information
Russell King committed Jan 25, 2011
1 parent 69058cd commit 250c7a6
Showing 1 changed file with 23 additions and 19 deletions.
42 changes: 23 additions & 19 deletions sound/arm/aaci.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

#define DRIVER_NAME "aaci-pl041"

#define FRAME_PERIOD_US 21

/*
* PM support is not complete. Turn it off.
*/
Expand Down Expand Up @@ -64,8 +66,8 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
{
struct aaci *aaci = ac97->private_data;
int timeout;
u32 v;
int timeout = 5000;

if (ac97->num >= 4)
return;
Expand All @@ -81,10 +83,13 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
writel(val << 4, aaci->base + AACI_SL2TX);
writel(reg << 12, aaci->base + AACI_SL1TX);

/*
* Wait for the transmission of both slots to complete.
*/
/* Initially, wait one frame period */
udelay(FRAME_PERIOD_US);

/* And then wait an additional eight frame periods for it to be sent */
timeout = FRAME_PERIOD_US * 8;
do {
udelay(1);
v = readl(aaci->base + AACI_SLFR);
} while ((v & (SLFR_1TXB|SLFR_2TXB)) && --timeout);

Expand All @@ -101,9 +106,8 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
{
struct aaci *aaci = ac97->private_data;
int timeout, retries = 10;
u32 v;
int timeout = 5000;
int retries = 10;

if (ac97->num >= 4)
return ~0;
Expand All @@ -117,10 +121,13 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
*/
writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX);

/*
* Wait for the transmission to complete.
*/
/* Initially, wait one frame period */
udelay(FRAME_PERIOD_US);

/* And then wait an additional eight frame periods for it to be sent */
timeout = FRAME_PERIOD_US * 8;
do {
udelay(1);
v = readl(aaci->base + AACI_SLFR);
} while ((v & SLFR_1TXB) && --timeout);

Expand All @@ -130,17 +137,13 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
goto out;
}

/*
* Give the AC'97 codec more than enough time
* to respond. (42us = ~2 frames at 48kHz.)
*/
udelay(42);
/* Now wait for the response frame */
udelay(FRAME_PERIOD_US);

/*
* Wait for slot 2 to indicate data.
*/
timeout = 5000;
/* And then wait an additional eight frame periods for data */
timeout = FRAME_PERIOD_US * 8;
do {
udelay(1);
cond_resched();
v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV);
} while ((v != (SLFR_1RXV|SLFR_2RXV)) && --timeout);
Expand Down Expand Up @@ -179,6 +182,7 @@ aaci_chan_wait_ready(struct aaci_runtime *aacirun, unsigned long mask)
int timeout = 5000;

do {
udelay(1);
val = readl(aacirun->base + AACI_SR);
} while (val & mask && timeout--);
}
Expand Down Expand Up @@ -874,7 +878,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci)
* Give the AC'97 codec more than enough time
* to wake up. (42us = ~2 frames at 48kHz.)
*/
udelay(42);
udelay(FRAME_PERIOD_US * 2);

ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus);
if (ret)
Expand Down

0 comments on commit 250c7a6

Please sign in to comment.