diff options
Diffstat (limited to 'sound/pci/emu10k1/io.c')
| -rw-r--r-- | sound/pci/emu10k1/io.c | 60 |
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; |
| 184 | spi_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 | ||
| 229 | int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) | 250 | int 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 | ||
| 247 | int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value) | 272 | int 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 | } |
