aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/emu10k1/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/emu10k1/io.c')
-rw-r--r--sound/pci/emu10k1/io.c60
1 files changed, 44 insertions, 16 deletions
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index 6702c15fefa3..b5a802bdeb7c 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -25,7 +25,6 @@
25 * 25 *
26 */ 26 */
27 27
28#include <sound/driver.h>
29#include <linux/time.h> 28#include <linux/time.h>
30#include <sound/core.h> 29#include <sound/core.h>
31#include <sound/emu10k1.h> 30#include <sound/emu10k1.h>
@@ -71,6 +70,11 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
71 unsigned long flags; 70 unsigned long flags;
72 unsigned int mask; 71 unsigned int mask;
73 72
73 if (!emu) {
74 snd_printk(KERN_ERR "ptr_write: emu is null!\n");
75 dump_stack();
76 return;
77 }
74 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; 78 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
75 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); 79 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
76 80
@@ -135,15 +139,23 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
135 unsigned int reset, set; 139 unsigned int reset, set;
136 unsigned int reg, tmp; 140 unsigned int reg, tmp;
137 int n, result; 141 int n, result;
142 int err = 0;
143
144 /* This function is not re-entrant, so protect against it. */
145 spin_lock(&emu->spi_lock);
138 if (emu->card_capabilities->ca0108_chip) 146 if (emu->card_capabilities->ca0108_chip)
139 reg = 0x3c; /* PTR20, reg 0x3c */ 147 reg = 0x3c; /* PTR20, reg 0x3c */
140 else { 148 else {
141 /* For other chip types the SPI register 149 /* For other chip types the SPI register
142 * is currently unknown. */ 150 * is currently unknown. */
143 return 1; 151 err = 1;
152 goto spi_write_exit;
153 }
154 if (data > 0xffff) {
155 /* Only 16bit values allowed */
156 err = 1;
157 goto spi_write_exit;
144 } 158 }
145 if (data > 0xffff) /* Only 16bit values allowed */
146 return 1;
147 159
148 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); 160 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
149 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */ 161 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
@@ -161,11 +173,17 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
161 break; 173 break;
162 } 174 }
163 } 175 }
164 if (result) /* Timed out */ 176 if (result) {
165 return 1; 177 /* Timed out */
178 err = 1;
179 goto spi_write_exit;
180 }
166 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data); 181 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
167 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */ 182 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
168 return 0; 183 err = 0;
184spi_write_exit:
185 spin_unlock(&emu->spi_lock);
186 return err;
169} 187}
170 188
171/* The ADC does not support i2c read, so only write is implemented */ 189/* The ADC does not support i2c read, so only write is implemented */
@@ -177,15 +195,17 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
177 int timeout = 0; 195 int timeout = 0;
178 int status; 196 int status;
179 int retry; 197 int retry;
198 int err = 0;
199
180 if ((reg > 0x7f) || (value > 0x1ff)) { 200 if ((reg > 0x7f) || (value > 0x1ff)) {
181 snd_printk(KERN_ERR "i2c_write: invalid values.\n"); 201 snd_printk(KERN_ERR "i2c_write: invalid values.\n");
182 return -EINVAL; 202 return -EINVAL;
183 } 203 }
184 204
205 /* This function is not re-entrant, so protect against it. */
206 spin_lock(&emu->i2c_lock);
207
185 tmp = reg << 25 | value << 16; 208 tmp = reg << 25 | value << 16;
186 // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
187 /* Not sure what this I2C channel controls. */
188 /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */
189 209
190 /* This controls the I2C connected to the WM8775 ADC Codec */ 210 /* This controls the I2C connected to the WM8775 ADC Codec */
191 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); 211 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
@@ -193,17 +213,14 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
193 213
194 for (retry = 0; retry < 10; retry++) { 214 for (retry = 0; retry < 10; retry++) {
195 /* Send the data to i2c */ 215 /* Send the data to i2c */
196 //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0);
197 //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
198 tmp = 0; 216 tmp = 0;
199 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); 217 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
200 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); 218 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
201 219
202 /* Wait till the transaction ends */ 220 /* Wait till the transaction ends */
203 while (1) { 221 while (1) {
204 udelay(10); 222 mdelay(1);
205 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); 223 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
206 // snd_printk("I2C:status=0x%x\n", status);
207 timeout++; 224 timeout++;
208 if ((status & I2C_A_ADC_START) == 0) 225 if ((status & I2C_A_ADC_START) == 0)
209 break; 226 break;
@@ -220,19 +237,26 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
220 237
221 if (retry == 10) { 238 if (retry == 10) {
222 snd_printk(KERN_ERR "Writing to ADC failed!\n"); 239 snd_printk(KERN_ERR "Writing to ADC failed!\n");
223 return -EINVAL; 240 snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n",
241 status, reg, value);
242 /* dump_stack(); */
243 err = -EINVAL;
224 } 244 }
225 245
226 return 0; 246 spin_unlock(&emu->i2c_lock);
247 return err;
227} 248}
228 249
229int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) 250int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
230{ 251{
252 unsigned long flags;
253
231 if (reg > 0x3f) 254 if (reg > 0x3f)
232 return 1; 255 return 1;
233 reg += 0x40; /* 0x40 upwards are registers. */ 256 reg += 0x40; /* 0x40 upwards are registers. */
234 if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ 257 if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
235 return 1; 258 return 1;
259 spin_lock_irqsave(&emu->emu_lock, flags);
236 outl(reg, emu->port + A_IOCFG); 260 outl(reg, emu->port + A_IOCFG);
237 udelay(10); 261 udelay(10);
238 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ 262 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
@@ -240,20 +264,24 @@ int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
240 outl(value, emu->port + A_IOCFG); 264 outl(value, emu->port + A_IOCFG);
241 udelay(10); 265 udelay(10);
242 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ 266 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
267 spin_unlock_irqrestore(&emu->emu_lock, flags);
243 268
244 return 0; 269 return 0;
245} 270}
246 271
247int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value) 272int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
248{ 273{
274 unsigned long flags;
249 if (reg > 0x3f) 275 if (reg > 0x3f)
250 return 1; 276 return 1;
251 reg += 0x40; /* 0x40 upwards are registers. */ 277 reg += 0x40; /* 0x40 upwards are registers. */
278 spin_lock_irqsave(&emu->emu_lock, flags);
252 outl(reg, emu->port + A_IOCFG); 279 outl(reg, emu->port + A_IOCFG);
253 udelay(10); 280 udelay(10);
254 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ 281 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
255 udelay(10); 282 udelay(10);
256 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f); 283 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
284 spin_unlock_irqrestore(&emu->emu_lock, flags);
257 285
258 return 0; 286 return 0;
259} 287}