aboutsummaryrefslogtreecommitdiffstats
path: root/sound/arm/aaci.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2011-01-12 18:42:57 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-01-25 16:18:05 -0500
commit250c7a61c35a258e2422b3d55c61bfbad33326be (patch)
tree7d6384c03895828a4052b5f9fbe1c760c8d6092a /sound/arm/aaci.c
parent69058cd6d10423126ab6aeb568f4af2bd34c49fe (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.c42
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,
101static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) 106static 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)