aboutsummaryrefslogtreecommitdiffstats
path: root/sound/arm
diff options
context:
space:
mode:
Diffstat (limited to 'sound/arm')
-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)