io.c (15507B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 4 * Creative Labs, Inc. 5 * Routines for control of EMU10K1 chips 6 * 7 * BUGS: 8 * -- 9 * 10 * TODO: 11 * -- 12 */ 13 14#include <linux/time.h> 15#include <sound/core.h> 16#include <sound/emu10k1.h> 17#include <linux/delay.h> 18#include <linux/export.h> 19#include "p17v.h" 20 21unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) 22{ 23 unsigned long flags; 24 unsigned int regptr, val; 25 unsigned int mask; 26 27 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; 28 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); 29 30 if (reg & 0xff000000) { 31 unsigned char size, offset; 32 33 size = (reg >> 24) & 0x3f; 34 offset = (reg >> 16) & 0x1f; 35 mask = ((1 << size) - 1) << offset; 36 37 spin_lock_irqsave(&emu->emu_lock, flags); 38 outl(regptr, emu->port + PTR); 39 val = inl(emu->port + DATA); 40 spin_unlock_irqrestore(&emu->emu_lock, flags); 41 42 return (val & mask) >> offset; 43 } else { 44 spin_lock_irqsave(&emu->emu_lock, flags); 45 outl(regptr, emu->port + PTR); 46 val = inl(emu->port + DATA); 47 spin_unlock_irqrestore(&emu->emu_lock, flags); 48 return val; 49 } 50} 51 52EXPORT_SYMBOL(snd_emu10k1_ptr_read); 53 54void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data) 55{ 56 unsigned int regptr; 57 unsigned long flags; 58 unsigned int mask; 59 60 if (snd_BUG_ON(!emu)) 61 return; 62 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; 63 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); 64 65 if (reg & 0xff000000) { 66 unsigned char size, offset; 67 68 size = (reg >> 24) & 0x3f; 69 offset = (reg >> 16) & 0x1f; 70 mask = ((1 << size) - 1) << offset; 71 data = (data << offset) & mask; 72 73 spin_lock_irqsave(&emu->emu_lock, flags); 74 outl(regptr, emu->port + PTR); 75 data |= inl(emu->port + DATA) & ~mask; 76 outl(data, emu->port + DATA); 77 spin_unlock_irqrestore(&emu->emu_lock, flags); 78 } else { 79 spin_lock_irqsave(&emu->emu_lock, flags); 80 outl(regptr, emu->port + PTR); 81 outl(data, emu->port + DATA); 82 spin_unlock_irqrestore(&emu->emu_lock, flags); 83 } 84} 85 86EXPORT_SYMBOL(snd_emu10k1_ptr_write); 87 88unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, 89 unsigned int reg, 90 unsigned int chn) 91{ 92 unsigned long flags; 93 unsigned int regptr, val; 94 95 regptr = (reg << 16) | chn; 96 97 spin_lock_irqsave(&emu->emu_lock, flags); 98 outl(regptr, emu->port + 0x20 + PTR); 99 val = inl(emu->port + 0x20 + DATA); 100 spin_unlock_irqrestore(&emu->emu_lock, flags); 101 return val; 102} 103 104void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, 105 unsigned int reg, 106 unsigned int chn, 107 unsigned int data) 108{ 109 unsigned int regptr; 110 unsigned long flags; 111 112 regptr = (reg << 16) | chn; 113 114 spin_lock_irqsave(&emu->emu_lock, flags); 115 outl(regptr, emu->port + 0x20 + PTR); 116 outl(data, emu->port + 0x20 + DATA); 117 spin_unlock_irqrestore(&emu->emu_lock, flags); 118} 119 120int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, 121 unsigned int data) 122{ 123 unsigned int reset, set; 124 unsigned int reg, tmp; 125 int n, result; 126 int err = 0; 127 128 /* This function is not re-entrant, so protect against it. */ 129 spin_lock(&emu->spi_lock); 130 if (emu->card_capabilities->ca0108_chip) 131 reg = 0x3c; /* PTR20, reg 0x3c */ 132 else { 133 /* For other chip types the SPI register 134 * is currently unknown. */ 135 err = 1; 136 goto spi_write_exit; 137 } 138 if (data > 0xffff) { 139 /* Only 16bit values allowed */ 140 err = 1; 141 goto spi_write_exit; 142 } 143 144 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); 145 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */ 146 set = reset | 0x10000; /* Set xxx1xxxx */ 147 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data); 148 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */ 149 snd_emu10k1_ptr20_write(emu, reg, 0, set | data); 150 result = 1; 151 /* Wait for status bit to return to 0 */ 152 for (n = 0; n < 100; n++) { 153 udelay(10); 154 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); 155 if (!(tmp & 0x10000)) { 156 result = 0; 157 break; 158 } 159 } 160 if (result) { 161 /* Timed out */ 162 err = 1; 163 goto spi_write_exit; 164 } 165 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data); 166 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */ 167 err = 0; 168spi_write_exit: 169 spin_unlock(&emu->spi_lock); 170 return err; 171} 172 173/* The ADC does not support i2c read, so only write is implemented */ 174int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, 175 u32 reg, 176 u32 value) 177{ 178 u32 tmp; 179 int timeout = 0; 180 int status; 181 int retry; 182 int err = 0; 183 184 if ((reg > 0x7f) || (value > 0x1ff)) { 185 dev_err(emu->card->dev, "i2c_write: invalid values.\n"); 186 return -EINVAL; 187 } 188 189 /* This function is not re-entrant, so protect against it. */ 190 spin_lock(&emu->i2c_lock); 191 192 tmp = reg << 25 | value << 16; 193 194 /* This controls the I2C connected to the WM8775 ADC Codec */ 195 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); 196 tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */ 197 198 for (retry = 0; retry < 10; retry++) { 199 /* Send the data to i2c */ 200 tmp = 0; 201 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); 202 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); 203 204 /* Wait till the transaction ends */ 205 while (1) { 206 mdelay(1); 207 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); 208 timeout++; 209 if ((status & I2C_A_ADC_START) == 0) 210 break; 211 212 if (timeout > 1000) { 213 dev_warn(emu->card->dev, 214 "emu10k1:I2C:timeout status=0x%x\n", 215 status); 216 break; 217 } 218 } 219 //Read back and see if the transaction is successful 220 if ((status & I2C_A_ADC_ABORT) == 0) 221 break; 222 } 223 224 if (retry == 10) { 225 dev_err(emu->card->dev, "Writing to ADC failed!\n"); 226 dev_err(emu->card->dev, "status=0x%x, reg=%d, value=%d\n", 227 status, reg, value); 228 /* dump_stack(); */ 229 err = -EINVAL; 230 } 231 232 spin_unlock(&emu->i2c_lock); 233 return err; 234} 235 236int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) 237{ 238 unsigned long flags; 239 240 if (reg > 0x3f) 241 return 1; 242 reg += 0x40; /* 0x40 upwards are registers. */ 243 if (value > 0x3f) /* 0 to 0x3f are values */ 244 return 1; 245 spin_lock_irqsave(&emu->emu_lock, flags); 246 outl(reg, emu->port + A_IOCFG); 247 udelay(10); 248 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ 249 udelay(10); 250 outl(value, emu->port + A_IOCFG); 251 udelay(10); 252 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ 253 spin_unlock_irqrestore(&emu->emu_lock, flags); 254 255 return 0; 256} 257 258int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value) 259{ 260 unsigned long flags; 261 if (reg > 0x3f) 262 return 1; 263 reg += 0x40; /* 0x40 upwards are registers. */ 264 spin_lock_irqsave(&emu->emu_lock, flags); 265 outl(reg, emu->port + A_IOCFG); 266 udelay(10); 267 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ 268 udelay(10); 269 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f); 270 spin_unlock_irqrestore(&emu->emu_lock, flags); 271 272 return 0; 273} 274 275/* Each Destination has one and only one Source, 276 * but one Source can feed any number of Destinations simultaneously. 277 */ 278int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src) 279{ 280 snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) ); 281 snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) ); 282 snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) ); 283 snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) ); 284 285 return 0; 286} 287 288void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) 289{ 290 unsigned long flags; 291 unsigned int enable; 292 293 spin_lock_irqsave(&emu->emu_lock, flags); 294 enable = inl(emu->port + INTE) | intrenb; 295 outl(enable, emu->port + INTE); 296 spin_unlock_irqrestore(&emu->emu_lock, flags); 297} 298 299void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb) 300{ 301 unsigned long flags; 302 unsigned int enable; 303 304 spin_lock_irqsave(&emu->emu_lock, flags); 305 enable = inl(emu->port + INTE) & ~intrenb; 306 outl(enable, emu->port + INTE); 307 spin_unlock_irqrestore(&emu->emu_lock, flags); 308} 309 310void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum) 311{ 312 unsigned long flags; 313 unsigned int val; 314 315 spin_lock_irqsave(&emu->emu_lock, flags); 316 /* voice interrupt */ 317 if (voicenum >= 32) { 318 outl(CLIEH << 16, emu->port + PTR); 319 val = inl(emu->port + DATA); 320 val |= 1 << (voicenum - 32); 321 } else { 322 outl(CLIEL << 16, emu->port + PTR); 323 val = inl(emu->port + DATA); 324 val |= 1 << voicenum; 325 } 326 outl(val, emu->port + DATA); 327 spin_unlock_irqrestore(&emu->emu_lock, flags); 328} 329 330void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum) 331{ 332 unsigned long flags; 333 unsigned int val; 334 335 spin_lock_irqsave(&emu->emu_lock, flags); 336 /* voice interrupt */ 337 if (voicenum >= 32) { 338 outl(CLIEH << 16, emu->port + PTR); 339 val = inl(emu->port + DATA); 340 val &= ~(1 << (voicenum - 32)); 341 } else { 342 outl(CLIEL << 16, emu->port + PTR); 343 val = inl(emu->port + DATA); 344 val &= ~(1 << voicenum); 345 } 346 outl(val, emu->port + DATA); 347 spin_unlock_irqrestore(&emu->emu_lock, flags); 348} 349 350void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum) 351{ 352 unsigned long flags; 353 354 spin_lock_irqsave(&emu->emu_lock, flags); 355 /* voice interrupt */ 356 if (voicenum >= 32) { 357 outl(CLIPH << 16, emu->port + PTR); 358 voicenum = 1 << (voicenum - 32); 359 } else { 360 outl(CLIPL << 16, emu->port + PTR); 361 voicenum = 1 << voicenum; 362 } 363 outl(voicenum, emu->port + DATA); 364 spin_unlock_irqrestore(&emu->emu_lock, flags); 365} 366 367void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum) 368{ 369 unsigned long flags; 370 unsigned int val; 371 372 spin_lock_irqsave(&emu->emu_lock, flags); 373 /* voice interrupt */ 374 if (voicenum >= 32) { 375 outl(HLIEH << 16, emu->port + PTR); 376 val = inl(emu->port + DATA); 377 val |= 1 << (voicenum - 32); 378 } else { 379 outl(HLIEL << 16, emu->port + PTR); 380 val = inl(emu->port + DATA); 381 val |= 1 << voicenum; 382 } 383 outl(val, emu->port + DATA); 384 spin_unlock_irqrestore(&emu->emu_lock, flags); 385} 386 387void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum) 388{ 389 unsigned long flags; 390 unsigned int val; 391 392 spin_lock_irqsave(&emu->emu_lock, flags); 393 /* voice interrupt */ 394 if (voicenum >= 32) { 395 outl(HLIEH << 16, emu->port + PTR); 396 val = inl(emu->port + DATA); 397 val &= ~(1 << (voicenum - 32)); 398 } else { 399 outl(HLIEL << 16, emu->port + PTR); 400 val = inl(emu->port + DATA); 401 val &= ~(1 << voicenum); 402 } 403 outl(val, emu->port + DATA); 404 spin_unlock_irqrestore(&emu->emu_lock, flags); 405} 406 407void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum) 408{ 409 unsigned long flags; 410 411 spin_lock_irqsave(&emu->emu_lock, flags); 412 /* voice interrupt */ 413 if (voicenum >= 32) { 414 outl(HLIPH << 16, emu->port + PTR); 415 voicenum = 1 << (voicenum - 32); 416 } else { 417 outl(HLIPL << 16, emu->port + PTR); 418 voicenum = 1 << voicenum; 419 } 420 outl(voicenum, emu->port + DATA); 421 spin_unlock_irqrestore(&emu->emu_lock, flags); 422} 423 424void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum) 425{ 426 unsigned long flags; 427 unsigned int sol; 428 429 spin_lock_irqsave(&emu->emu_lock, flags); 430 /* voice interrupt */ 431 if (voicenum >= 32) { 432 outl(SOLEH << 16, emu->port + PTR); 433 sol = inl(emu->port + DATA); 434 sol |= 1 << (voicenum - 32); 435 } else { 436 outl(SOLEL << 16, emu->port + PTR); 437 sol = inl(emu->port + DATA); 438 sol |= 1 << voicenum; 439 } 440 outl(sol, emu->port + DATA); 441 spin_unlock_irqrestore(&emu->emu_lock, flags); 442} 443 444void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum) 445{ 446 unsigned long flags; 447 unsigned int sol; 448 449 spin_lock_irqsave(&emu->emu_lock, flags); 450 /* voice interrupt */ 451 if (voicenum >= 32) { 452 outl(SOLEH << 16, emu->port + PTR); 453 sol = inl(emu->port + DATA); 454 sol &= ~(1 << (voicenum - 32)); 455 } else { 456 outl(SOLEL << 16, emu->port + PTR); 457 sol = inl(emu->port + DATA); 458 sol &= ~(1 << voicenum); 459 } 460 outl(sol, emu->port + DATA); 461 spin_unlock_irqrestore(&emu->emu_lock, flags); 462} 463 464void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait) 465{ 466 volatile unsigned count; 467 unsigned int newtime = 0, curtime; 468 469 curtime = inl(emu->port + WC) >> 6; 470 while (wait-- > 0) { 471 count = 0; 472 while (count++ < 16384) { 473 newtime = inl(emu->port + WC) >> 6; 474 if (newtime != curtime) 475 break; 476 } 477 if (count > 16384) 478 break; 479 curtime = newtime; 480 } 481} 482 483unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg) 484{ 485 struct snd_emu10k1 *emu = ac97->private_data; 486 unsigned long flags; 487 unsigned short val; 488 489 spin_lock_irqsave(&emu->emu_lock, flags); 490 outb(reg, emu->port + AC97ADDRESS); 491 val = inw(emu->port + AC97DATA); 492 spin_unlock_irqrestore(&emu->emu_lock, flags); 493 return val; 494} 495 496void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data) 497{ 498 struct snd_emu10k1 *emu = ac97->private_data; 499 unsigned long flags; 500 501 spin_lock_irqsave(&emu->emu_lock, flags); 502 outb(reg, emu->port + AC97ADDRESS); 503 outw(data, emu->port + AC97DATA); 504 spin_unlock_irqrestore(&emu->emu_lock, flags); 505} 506 507/* 508 * convert rate to pitch 509 */ 510 511unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate) 512{ 513 static const u32 logMagTable[128] = { 514 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2, 515 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5, 516 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081, 517 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191, 518 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7, 519 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829, 520 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e, 521 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26, 522 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d, 523 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885, 524 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899, 525 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c, 526 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3, 527 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3, 528 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83, 529 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df 530 }; 531 static const char logSlopeTable[128] = { 532 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58, 533 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53, 534 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f, 535 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b, 536 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47, 537 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, 538 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41, 539 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 540 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 541 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 542 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37, 543 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35, 544 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34, 545 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32, 546 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, 547 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f 548 }; 549 int i; 550 551 if (rate == 0) 552 return 0; /* Bail out if no leading "1" */ 553 rate *= 11185; /* Scale 48000 to 0x20002380 */ 554 for (i = 31; i > 0; i--) { 555 if (rate & 0x80000000) { /* Detect leading "1" */ 556 return (((unsigned int) (i - 15) << 20) + 557 logMagTable[0x7f & (rate >> 24)] + 558 (0x7f & (rate >> 17)) * 559 logSlopeTable[0x7f & (rate >> 24)]); 560 } 561 rate <<= 1; 562 } 563 564 return 0; /* Should never reach this point */ 565} 566