diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-01-12 18:42:57 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-01-25 16:18:05 -0500 |
commit | 250c7a61c35a258e2422b3d55c61bfbad33326be (patch) | |
tree | 7d6384c03895828a4052b5f9fbe1c760c8d6092a /sound/arm/aaci.c | |
parent | 69058cd6d10423126ab6aeb568f4af2bd34c49fe (diff) |
ALSA: AACI: fix timeout duration
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 <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'sound/arm/aaci.c')
-rw-r--r-- | sound/arm/aaci.c | 42 |
1 files changed, 23 insertions, 19 deletions
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 21ff6296d160..24d3013c0231 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c | |||
@@ -30,6 +30,8 @@ | |||
30 | 30 | ||
31 | #define DRIVER_NAME "aaci-pl041" | 31 | #define DRIVER_NAME "aaci-pl041" |
32 | 32 | ||
33 | #define FRAME_PERIOD_US 21 | ||
34 | |||
33 | /* | 35 | /* |
34 | * PM support is not complete. Turn it off. | 36 | * PM support is not complete. Turn it off. |
35 | */ | 37 | */ |
@@ -64,8 +66,8 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | |||
64 | unsigned short val) | 66 | unsigned short val) |
65 | { | 67 | { |
66 | struct aaci *aaci = ac97->private_data; | 68 | struct aaci *aaci = ac97->private_data; |
69 | int timeout; | ||
67 | u32 v; | 70 | u32 v; |
68 | int timeout = 5000; | ||
69 | 71 | ||
70 | if (ac97->num >= 4) | 72 | if (ac97->num >= 4) |
71 | return; | 73 | return; |
@@ -81,10 +83,13 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | |||
81 | writel(val << 4, aaci->base + AACI_SL2TX); | 83 | writel(val << 4, aaci->base + AACI_SL2TX); |
82 | writel(reg << 12, aaci->base + AACI_SL1TX); | 84 | writel(reg << 12, aaci->base + AACI_SL1TX); |
83 | 85 | ||
84 | /* | 86 | /* Initially, wait one frame period */ |
85 | * Wait for the transmission of both slots to complete. | 87 | udelay(FRAME_PERIOD_US); |
86 | */ | 88 | |
89 | /* And then wait an additional eight frame periods for it to be sent */ | ||
90 | timeout = FRAME_PERIOD_US * 8; | ||
87 | do { | 91 | do { |
92 | udelay(1); | ||
88 | v = readl(aaci->base + AACI_SLFR); | 93 | v = readl(aaci->base + AACI_SLFR); |
89 | } while ((v & (SLFR_1TXB|SLFR_2TXB)) && --timeout); | 94 | } while ((v & (SLFR_1TXB|SLFR_2TXB)) && --timeout); |
90 | 95 | ||
@@ -101,9 +106,8 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | |||
101 | static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | 106 | static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) |
102 | { | 107 | { |
103 | struct aaci *aaci = ac97->private_data; | 108 | struct aaci *aaci = ac97->private_data; |
109 | int timeout, retries = 10; | ||
104 | u32 v; | 110 | u32 v; |
105 | int timeout = 5000; | ||
106 | int retries = 10; | ||
107 | 111 | ||
108 | if (ac97->num >= 4) | 112 | if (ac97->num >= 4) |
109 | return ~0; | 113 | return ~0; |
@@ -117,10 +121,13 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | |||
117 | */ | 121 | */ |
118 | writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX); | 122 | writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX); |
119 | 123 | ||
120 | /* | 124 | /* Initially, wait one frame period */ |
121 | * Wait for the transmission to complete. | 125 | udelay(FRAME_PERIOD_US); |
122 | */ | 126 | |
127 | /* And then wait an additional eight frame periods for it to be sent */ | ||
128 | timeout = FRAME_PERIOD_US * 8; | ||
123 | do { | 129 | do { |
130 | udelay(1); | ||
124 | v = readl(aaci->base + AACI_SLFR); | 131 | v = readl(aaci->base + AACI_SLFR); |
125 | } while ((v & SLFR_1TXB) && --timeout); | 132 | } while ((v & SLFR_1TXB) && --timeout); |
126 | 133 | ||
@@ -130,17 +137,13 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | |||
130 | goto out; | 137 | goto out; |
131 | } | 138 | } |
132 | 139 | ||
133 | /* | 140 | /* Now wait for the response frame */ |
134 | * Give the AC'97 codec more than enough time | 141 | udelay(FRAME_PERIOD_US); |
135 | * to respond. (42us = ~2 frames at 48kHz.) | ||
136 | */ | ||
137 | udelay(42); | ||
138 | 142 | ||
139 | /* | 143 | /* And then wait an additional eight frame periods for data */ |
140 | * Wait for slot 2 to indicate data. | 144 | timeout = FRAME_PERIOD_US * 8; |
141 | */ | ||
142 | timeout = 5000; | ||
143 | do { | 145 | do { |
146 | udelay(1); | ||
144 | cond_resched(); | 147 | cond_resched(); |
145 | v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV); | 148 | v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV); |
146 | } while ((v != (SLFR_1RXV|SLFR_2RXV)) && --timeout); | 149 | } while ((v != (SLFR_1RXV|SLFR_2RXV)) && --timeout); |
@@ -179,6 +182,7 @@ aaci_chan_wait_ready(struct aaci_runtime *aacirun, unsigned long mask) | |||
179 | int timeout = 5000; | 182 | int timeout = 5000; |
180 | 183 | ||
181 | do { | 184 | do { |
185 | udelay(1); | ||
182 | val = readl(aacirun->base + AACI_SR); | 186 | val = readl(aacirun->base + AACI_SR); |
183 | } while (val & mask && timeout--); | 187 | } while (val & mask && timeout--); |
184 | } | 188 | } |
@@ -874,7 +878,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci) | |||
874 | * Give the AC'97 codec more than enough time | 878 | * Give the AC'97 codec more than enough time |
875 | * to wake up. (42us = ~2 frames at 48kHz.) | 879 | * to wake up. (42us = ~2 frames at 48kHz.) |
876 | */ | 880 | */ |
877 | udelay(42); | 881 | udelay(FRAME_PERIOD_US * 2); |
878 | 882 | ||
879 | ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus); | 883 | ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus); |
880 | if (ret) | 884 | if (ret) |