aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2005-12-12 09:41:47 -0500
committerJaroslav Kysela <perex@suse.cz>2006-01-03 06:30:51 -0500
commitea265c0a433fda15fb69b9fd733e0ea4215c216e (patch)
tree56873a5de0850fd6b03d76bda9502e6d3107e6e9
parentaa1e77e691025149908f7641e77de93ffd7f1188 (diff)
[ALSA] make the pxa2xx-ac97 module more robust against PXA27x bugs
Modules: ARM PXA2XX driver The SDONE and CDONE interrupt on the PXA27x might become unusable in some conditions. Let's use an hybrid approach (interrupt with timeout) to have the best possible behavior in all conditions. Also let's not care about CAR_CAIP anymore. This is useless. Signed-off-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/arm/pxa2xx-ac97.c39
1 files changed, 22 insertions, 17 deletions
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index dda64beb202b..3acbc6023d19 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -37,39 +37,47 @@ static DECLARE_MUTEX(car_mutex);
37static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); 37static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
38static volatile long gsr_bits; 38static volatile long gsr_bits;
39 39
40/*
41 * Beware PXA27x bugs:
42 *
43 * o Slot 12 read from modem space will hang controller.
44 * o CDONE, SDONE interrupt fails after any slot 12 IO.
45 *
46 * We therefore have an hybrid approach for waiting on SDONE (interrupt or
47 * 1 jiffy timeout if interrupt never comes).
48 */
49
40static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg) 50static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
41{ 51{
42 unsigned short val = -1; 52 unsigned short val = -1;
43 volatile u32 *reg_addr; 53 volatile u32 *reg_addr;
44 54
45 down(&car_mutex); 55 down(&car_mutex);
46 if (CAR & CAR_CAIP) {
47 printk(KERN_CRIT"%s: CAR_CAIP already set\n", __FUNCTION__);
48 goto out;
49 }
50 56
51 /* set up primary or secondary codec space */ 57 /* set up primary or secondary codec space */
52 reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE; 58 reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
53 reg_addr += (reg >> 1); 59 reg_addr += (reg >> 1);
54 60
55 /* start read access across the ac97 link */ 61 /* start read access across the ac97 link */
62 GSR = GSR_CDONE | GSR_SDONE;
56 gsr_bits = 0; 63 gsr_bits = 0;
57 val = *reg_addr; 64 val = *reg_addr;
58 if (reg == AC97_GPIO_STATUS) 65 if (reg == AC97_GPIO_STATUS)
59 goto out; 66 goto out;
60 wait_event_timeout(gsr_wq, gsr_bits & GSR_SDONE, 1); 67 if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 &&
61 if (!gsr_bits & GSR_SDONE) { 68 !((GSR | gsr_bits) & GSR_SDONE)) {
62 printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n", 69 printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",
63 __FUNCTION__, reg, gsr_bits); 70 __FUNCTION__, reg, GSR | gsr_bits);
64 val = -1; 71 val = -1;
65 goto out; 72 goto out;
66 } 73 }
67 74
68 /* valid data now */ 75 /* valid data now */
76 GSR = GSR_CDONE | GSR_SDONE;
69 gsr_bits = 0; 77 gsr_bits = 0;
70 val = *reg_addr; 78 val = *reg_addr;
71 /* but we've just started another cycle... */ 79 /* but we've just started another cycle... */
72 wait_event_timeout(gsr_wq, gsr_bits & GSR_SDONE, 1); 80 wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
73 81
74out: up(&car_mutex); 82out: up(&car_mutex);
75 return val; 83 return val;
@@ -81,22 +89,19 @@ static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigne
81 89
82 down(&car_mutex); 90 down(&car_mutex);
83 91
84 if (CAR & CAR_CAIP) {
85 printk(KERN_CRIT "%s: CAR_CAIP already set\n", __FUNCTION__);
86 goto out;
87 }
88
89 /* set up primary or secondary codec space */ 92 /* set up primary or secondary codec space */
90 reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE; 93 reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
91 reg_addr += (reg >> 1); 94 reg_addr += (reg >> 1);
95
96 GSR = GSR_CDONE | GSR_SDONE;
92 gsr_bits = 0; 97 gsr_bits = 0;
93 *reg_addr = val; 98 *reg_addr = val;
94 wait_event_timeout(gsr_wq, gsr_bits & GSR_CDONE, 1); 99 if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 &&
95 if (!gsr_bits & GSR_SDONE) 100 !((GSR | gsr_bits) & GSR_CDONE))
96 printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n", 101 printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
97 __FUNCTION__, reg, gsr_bits); 102 __FUNCTION__, reg, GSR | gsr_bits);
98 103
99out: up(&car_mutex); 104 up(&car_mutex);
100} 105}
101 106
102static void pxa2xx_ac97_reset(struct snd_ac97 *ac97) 107static void pxa2xx_ac97_reset(struct snd_ac97 *ac97)