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