#include <sound/core.h>
#include <sound/wss.h>
#include <sound/pcm_params.h>
+#include <sound/tlv.h>
#include <asm/io.h>
#include <asm/dma.h>
printk(KERN_DEBUG
"CS4231 REGS: INDEX = 0x%02x "
" STATUS = 0x%02x\n",
- wss_inb(chip, CS4231P(REGSEL),
+ wss_inb(chip, CS4231P(REGSEL)),
wss_inb(chip, CS4231P(STATUS)));
printk(KERN_DEBUG
" 0x00: left input = 0x%02x "
for (timeout = 5; timeout > 0; timeout--)
wss_inb(chip, CS4231P(REGSEL));
/* end of cleanup sequence */
- for (timeout = 250;
+ for (timeout = 25000;
timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
timeout--)
udelay(10);
unsigned long flags;
unsigned long end_time;
int timeout;
+ int hw_mask = WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK | WSS_HW_AD1848;
snd_wss_busy_wait(chip);
spin_unlock_irqrestore(&chip->reg_lock, flags);
if (timeout == 0x80)
snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
- if ((timeout & CS4231_MCE) == 0 ||
- !(chip->hardware & (WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK))) {
+ if ((timeout & CS4231_MCE) == 0 || !(chip->hardware & hw_mask))
return;
- }
/*
* Wait for (possible -- during init auto-calibration may not be set)
{
unsigned long flags;
- mute = mute ? 1 : 0;
+ mute = mute ? 0x80 : 0;
spin_lock_irqsave(&chip->reg_lock, flags);
if (chip->calibrate_mute == mute) {
spin_unlock_irqrestore(&chip->reg_lock, flags);
chip->image[CS4231_LOOPBACK]);
}
snd_wss_dout(chip, CS4231_AUX1_LEFT_INPUT,
- mute ? 0x80 : chip->image[CS4231_AUX1_LEFT_INPUT]);
+ mute | chip->image[CS4231_AUX1_LEFT_INPUT]);
snd_wss_dout(chip, CS4231_AUX1_RIGHT_INPUT,
- mute ? 0x80 : chip->image[CS4231_AUX1_RIGHT_INPUT]);
+ mute | chip->image[CS4231_AUX1_RIGHT_INPUT]);
snd_wss_dout(chip, CS4231_AUX2_LEFT_INPUT,
- mute ? 0x80 : chip->image[CS4231_AUX2_LEFT_INPUT]);
+ mute | chip->image[CS4231_AUX2_LEFT_INPUT]);
snd_wss_dout(chip, CS4231_AUX2_RIGHT_INPUT,
- mute ? 0x80 : chip->image[CS4231_AUX2_RIGHT_INPUT]);
+ mute | chip->image[CS4231_AUX2_RIGHT_INPUT]);
snd_wss_dout(chip, CS4231_LEFT_OUTPUT,
- mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]);
+ mute | chip->image[CS4231_LEFT_OUTPUT]);
snd_wss_dout(chip, CS4231_RIGHT_OUTPUT,
- mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]);
- snd_wss_dout(chip, CS4231_LEFT_LINE_IN,
- mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]);
- snd_wss_dout(chip, CS4231_RIGHT_LINE_IN,
- mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]);
- snd_wss_dout(chip, CS4231_MONO_CTRL,
- mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]);
+ mute | chip->image[CS4231_RIGHT_OUTPUT]);
+ if (!(chip->hardware & WSS_HW_AD1848_MASK)) {
+ snd_wss_dout(chip, CS4231_LEFT_LINE_IN,
+ mute | chip->image[CS4231_LEFT_LINE_IN]);
+ snd_wss_dout(chip, CS4231_RIGHT_LINE_IN,
+ mute | chip->image[CS4231_RIGHT_LINE_IN]);
+ snd_wss_dout(chip, CS4231_MONO_CTRL,
+ mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]);
+ }
if (chip->hardware == WSS_HW_INTERWAVE) {
snd_wss_dout(chip, CS4231_LEFT_MIC_INPUT,
- mute ? 0x80 : chip->image[CS4231_LEFT_MIC_INPUT]);
+ mute | chip->image[CS4231_LEFT_MIC_INPUT]);
snd_wss_dout(chip, CS4231_RIGHT_MIC_INPUT,
- mute ? 0x80 : chip->image[CS4231_RIGHT_MIC_INPUT]);
+ mute | chip->image[CS4231_RIGHT_MIC_INPUT]);
snd_wss_dout(chip, CS4231_LINE_LEFT_OUTPUT,
- mute ? 0x80 : chip->image[CS4231_LINE_LEFT_OUTPUT]);
+ mute | chip->image[CS4231_LINE_LEFT_OUTPUT]);
snd_wss_dout(chip, CS4231_LINE_RIGHT_OUTPUT,
- mute ? 0x80 : chip->image[CS4231_LINE_RIGHT_OUTPUT]);
+ mute | chip->image[CS4231_LINE_RIGHT_OUTPUT]);
}
chip->calibrate_mute = mute;
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_up(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
}
- snd_wss_out(chip, CS4231_REC_FORMAT, cdfr);
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT, cdfr);
+ else
+ snd_wss_out(chip, CS4231_REC_FORMAT, cdfr);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_down(chip);
}
snd_wss_mce_up(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
- snd_wss_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]);
+ if (!(chip->hardware & WSS_HW_AD1848_MASK))
+ snd_wss_out(chip, CS4231_REC_FORMAT,
+ chip->image[CS4231_REC_FORMAT]);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_down(chip);
}
/* ok. now enable and ack CODEC IRQ */
spin_lock_irqsave(&chip->reg_lock, flags);
- snd_wss_out(chip, CS4231_IRQ_STATUS,
- CS4231_PLAYBACK_IRQ |
- CS4231_RECORD_IRQ |
- CS4231_TIMER_IRQ);
- snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+ if (!(chip->hardware & WSS_HW_AD1848_MASK)) {
+ snd_wss_out(chip, CS4231_IRQ_STATUS,
+ CS4231_PLAYBACK_IRQ |
+ CS4231_RECORD_IRQ |
+ CS4231_TIMER_IRQ);
+ snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+ }
wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE;
snd_wss_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
- snd_wss_out(chip, CS4231_IRQ_STATUS,
- CS4231_PLAYBACK_IRQ |
- CS4231_RECORD_IRQ |
- CS4231_TIMER_IRQ);
- snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+ if (!(chip->hardware & WSS_HW_AD1848_MASK)) {
+ snd_wss_out(chip, CS4231_IRQ_STATUS,
+ CS4231_PLAYBACK_IRQ |
+ CS4231_RECORD_IRQ |
+ CS4231_TIMER_IRQ);
+ snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+ }
spin_unlock_irqrestore(&chip->reg_lock, flags);
chip->mode = mode;
/* disable IRQ */
spin_lock_irqsave(&chip->reg_lock, flags);
- snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+ if (!(chip->hardware & WSS_HW_AD1848_MASK))
+ snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE;
}
/* clear IRQ again */
- snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+ if (!(chip->hardware & WSS_HW_AD1848_MASK))
+ snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
spin_unlock_irqrestore(&chip->reg_lock, flags);
chip->c_dma_size = size;
chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
- count = snd_wss_get_count(chip->image[CS4231_REC_FORMAT], count) - 1;
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ count = snd_wss_get_count(chip->image[CS4231_PLAYBK_FORMAT],
+ count);
+ else
+ count = snd_wss_get_count(chip->image[CS4231_REC_FORMAT],
+ count);
+ count--;
if (chip->single_dma && chip->hardware != WSS_HW_INTERWAVE) {
snd_wss_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
snd_wss_out(chip, CS4231_PLY_UPR_CNT,
struct snd_wss *chip = dev_id;
unsigned char status;
- status = snd_wss_in(chip, CS4231_IRQ_STATUS);
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ /* pretend it was the only possible irq for AD1848 */
+ status = CS4231_PLAYBACK_IRQ;
+ else
+ status = snd_wss_in(chip, CS4231_IRQ_STATUS);
if (status & CS4231_TIMER_IRQ) {
if (chip->timer)
snd_timer_interrupt(chip->timer, chip->timer->sticks);
}
spin_lock(&chip->reg_lock);
- snd_wss_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
+ status = ~CS4231_ALL_IRQS | ~status;
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ wss_outb(chip, CS4231P(STATUS), 0);
+ else
+ snd_wss_outm(chip, CS4231_IRQ_STATUS, status, 0);
spin_unlock(&chip->reg_lock);
return IRQ_HANDLED;
}
*/
+static int snd_ad1848_probe(struct snd_wss *chip)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+ unsigned long flags;
+ unsigned char r;
+ unsigned short hardware = 0;
+ int err = 0;
+ int i;
+
+ while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
+ if (time_after(jiffies, timeout))
+ return -ENODEV;
+ cond_resched();
+ }
+ spin_lock_irqsave(&chip->reg_lock, flags);
+
+ /* set CS423x MODE 1 */
+ snd_wss_dout(chip, CS4231_MISC_INFO, 0);
+
+ snd_wss_dout(chip, CS4231_RIGHT_INPUT, 0x45); /* 0x55 & ~0x10 */
+ r = snd_wss_in(chip, CS4231_RIGHT_INPUT);
+ if (r != 0x45) {
+ /* RMGE always high on AD1847 */
+ if ((r & ~CS4231_ENABLE_MIC_GAIN) != 0x45) {
+ err = -ENODEV;
+ goto out;
+ }
+ hardware = WSS_HW_AD1847;
+ } else {
+ snd_wss_dout(chip, CS4231_LEFT_INPUT, 0xaa);
+ r = snd_wss_in(chip, CS4231_LEFT_INPUT);
+ /* L/RMGE always low on AT2320 */
+ if ((r | CS4231_ENABLE_MIC_GAIN) != 0xaa) {
+ err = -ENODEV;
+ goto out;
+ }
+ }
+
+ /* clear pending IRQ */
+ wss_inb(chip, CS4231P(STATUS));
+ wss_outb(chip, CS4231P(STATUS), 0);
+ mb();
+
+ if ((chip->hardware & WSS_HW_TYPE_MASK) != WSS_HW_DETECT)
+ goto out;
+
+ if (hardware) {
+ chip->hardware = hardware;
+ goto out;
+ }
+
+ r = snd_wss_in(chip, CS4231_MISC_INFO);
+
+ /* set CS423x MODE 2 */
+ snd_wss_dout(chip, CS4231_MISC_INFO, CS4231_MODE2);
+ for (i = 0; i < 16; i++) {
+ if (snd_wss_in(chip, i) != snd_wss_in(chip, 16 + i)) {
+ /* we have more than 16 registers: check ID */
+ if ((r & 0xf) != 0xa)
+ goto out_mode;
+ /*
+ * on CMI8330, CS4231_VERSION is volume control and
+ * can be set to 0
+ */
+ snd_wss_dout(chip, CS4231_VERSION, 0);
+ r = snd_wss_in(chip, CS4231_VERSION) & 0xe7;
+ if (!r)
+ chip->hardware = WSS_HW_CMI8330;
+ goto out_mode;
+ }
+ }
+ if (r & 0x80)
+ chip->hardware = WSS_HW_CS4248;
+ else
+ chip->hardware = WSS_HW_AD1848;
+out_mode:
+ snd_wss_dout(chip, CS4231_MISC_INFO, 0);
+out:
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ return err;
+}
+
static int snd_wss_probe(struct snd_wss *chip)
{
unsigned long flags;
- int i, id, rev;
+ int i, id, rev, regnum;
unsigned char *ptr;
unsigned int hw;
-#if 0
- snd_wss_debug(chip);
-#endif
- id = 0;
- for (i = 0; i < 50; i++) {
- mb();
- if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- udelay(2000);
- else {
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_wss_out(chip, CS4231_MISC_INFO, CS4231_MODE2);
- id = snd_wss_in(chip, CS4231_MISC_INFO) & 0x0f;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (id == 0x0a)
- break; /* this is valid value */
- }
- }
- snd_printdd("wss: port = 0x%lx, id = 0x%x\n", chip->port, id);
- if (id != 0x0a)
- return -ENODEV; /* no valid device found */
+ id = snd_ad1848_probe(chip);
+ if (id < 0)
+ return id;
hw = chip->hardware;
if ((hw & WSS_HW_TYPE_MASK) == WSS_HW_DETECT) {
+ for (i = 0; i < 50; i++) {
+ mb();
+ if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+ msleep(2);
+ else {
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ snd_wss_out(chip, CS4231_MISC_INFO,
+ CS4231_MODE2);
+ id = snd_wss_in(chip, CS4231_MISC_INFO) & 0x0f;
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (id == 0x0a)
+ break; /* this is valid value */
+ }
+ }
+ snd_printdd("wss: port = 0x%lx, id = 0x%x\n", chip->port, id);
+ if (id != 0x0a)
+ return -ENODEV; /* no valid device found */
+
rev = snd_wss_in(chip, CS4231_VERSION) & 0xe7;
snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev);
if (rev == 0x80) {
mb();
spin_unlock_irqrestore(&chip->reg_lock, flags);
- chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
+ if (!(chip->hardware & WSS_HW_AD1848_MASK))
+ chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
switch (chip->hardware) {
case WSS_HW_INTERWAVE:
chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3;
chip->hardware == WSS_HW_INTERWAVE ? 0xc2 : 0x01;
}
ptr = (unsigned char *) &chip->image;
+ regnum = (chip->hardware & WSS_HW_AD1848_MASK) ? 16 : 32;
snd_wss_mce_down(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
- for (i = 0; i < 32; i++) /* ok.. fill all CS4231 registers */
+ for (i = 0; i < regnum; i++) /* ok.. fill all registers */
snd_wss_out(chip, i, *ptr++);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_up(chip);
runtime->hw = snd_wss_playback;
+ /* hardware limitation of older chipsets */
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ runtime->hw.formats &= ~(SNDRV_PCM_FMTBIT_IMA_ADPCM |
+ SNDRV_PCM_FMTBIT_S16_BE);
+
/* hardware bug in InterWave chipset */
if (chip->hardware == WSS_HW_INTERWAVE && chip->dma1 > 3)
runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW;
runtime->hw = snd_wss_capture;
+ /* hardware limitation of older chipsets */
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ runtime->hw.formats &= ~(SNDRV_PCM_FMTBIT_IMA_ADPCM |
+ SNDRV_PCM_FMTBIT_S16_BE);
+
/* hardware limitation of cheap chips */
if (chip->hardware == WSS_HW_CS4235 ||
- chip->hardware == WSS_HW_CS4239)
- runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
+ chip->hardware == WSS_HW_CS4239 ||
+ chip->hardware == WSS_HW_OPTI93X)
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 |
+ SNDRV_PCM_FMTBIT_S16_LE;
snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);
return 0;
}
+static void snd_wss_thinkpad_twiddle(struct snd_wss *chip, int on)
+{
+ int tmp;
+
+ if (!chip->thinkpad_flag)
+ return;
+
+ outb(0x1c, AD1848_THINKPAD_CTL_PORT1);
+ tmp = inb(AD1848_THINKPAD_CTL_PORT2);
+
+ if (on)
+ /* turn it on */
+ tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT;
+ else
+ /* turn it off */
+ tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT;
+
+ outb(tmp, AD1848_THINKPAD_CTL_PORT2);
+}
+
#ifdef CONFIG_PM
/* lowlevel suspend callback for CS4231 */
for (reg = 0; reg < 32; reg++)
chip->image[reg] = snd_wss_in(chip, reg);
spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (chip->thinkpad_flag)
+ snd_wss_thinkpad_twiddle(chip, 0);
}
/* lowlevel resume callback for CS4231 */
unsigned long flags;
/* int timeout; */
+ if (chip->thinkpad_flag)
+ snd_wss_thinkpad_twiddle(chip, 1);
snd_wss_mce_up(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
for (reg = 0; reg < 32; reg++) {
return "AD1845";
case WSS_HW_OPTI93X:
return "OPTi 93x";
+ case WSS_HW_AD1847:
+ return "AD1847";
+ case WSS_HW_AD1848:
+ return "AD1848";
+ case WSS_HW_CS4248:
+ return "CS4248";
+ case WSS_HW_CMI8330:
+ return "CMI8330/C3D";
default:
return "???";
}
else
memcpy(&chip->image, &snd_wss_original_image,
sizeof(snd_wss_original_image));
+ if (chip->hardware & WSS_HW_AD1848_MASK) {
+ chip->image[CS4231_PIN_CTRL] = 0;
+ chip->image[CS4231_TEST_INIT] = 0;
+ }
*rchip = chip;
return 0;
chip->dma1 = -1;
chip->dma2 = -1;
- chip->res_port = request_region(port, 4, "CS4231");
+ chip->res_port = request_region(port, 4, "WSS");
if (!chip->res_port) {
snd_printk(KERN_ERR "wss: can't grab port 0x%lx\n", port);
snd_wss_free(chip);
chip->cport = cport;
if (!(hwshare & WSS_HWSHARE_IRQ))
if (request_irq(irq, snd_wss_interrupt, IRQF_DISABLED,
- "CS4231", (void *) chip)) {
+ "WSS", (void *) chip)) {
snd_printk(KERN_ERR "wss: can't grab IRQ %d\n", irq);
snd_wss_free(chip);
return -EBUSY;
}
chip->irq = irq;
- if (!(hwshare & WSS_HWSHARE_DMA1) && request_dma(dma1, "CS4231 - 1")) {
+ if (!(hwshare & WSS_HWSHARE_DMA1) && request_dma(dma1, "WSS - 1")) {
snd_printk(KERN_ERR "wss: can't grab DMA1 %d\n", dma1);
snd_wss_free(chip);
return -EBUSY;
}
chip->dma1 = dma1;
if (!(hwshare & WSS_HWSHARE_DMA2) && dma1 != dma2 &&
- dma2 >= 0 && request_dma(dma2, "CS4231 - 2")) {
+ dma2 >= 0 && request_dma(dma2, "WSS - 2")) {
snd_printk(KERN_ERR "wss: can't grab DMA2 %d\n", dma2);
snd_wss_free(chip);
return -EBUSY;
} else
chip->dma2 = dma2;
+ if (hardware == WSS_HW_THINKPAD) {
+ chip->thinkpad_flag = 1;
+ chip->hardware = WSS_HW_DETECT; /* reset */
+ snd_wss_thinkpad_twiddle(chip, 1);
+ }
+
/* global setup */
if (snd_wss_probe(chip) < 0) {
snd_wss_free(chip);
struct snd_pcm *pcm;
int err;
- if ((err = snd_pcm_new(chip->card, "CS4231", device, 1, 1, &pcm)) < 0)
+ err = snd_pcm_new(chip->card, "WSS", device, 1, 1, &pcm);
+ if (err < 0)
return err;
- spin_lock_init(&chip->reg_lock);
- mutex_init(&chip->mce_mutex);
- mutex_init(&chip->open_mutex);
-
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_wss_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_wss_capture_ops);
char **ptexts = texts;
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- snd_assert(chip->card != NULL, return -EINVAL);
+ if (snd_BUG_ON(!chip->card))
+ return -EINVAL;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 2;
uinfo->value.enumerated.items = 4;
val1 <<= shift_left;
val2 <<= shift_right;
spin_lock_irqsave(&chip->reg_lock, flags);
- val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
- val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
- change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
- snd_wss_out(chip, left_reg, val1);
- snd_wss_out(chip, right_reg, val2);
+ if (left_reg != right_reg) {
+ val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
+ val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
+ change = val1 != chip->image[left_reg] ||
+ val2 != chip->image[right_reg];
+ snd_wss_out(chip, left_reg, val1);
+ snd_wss_out(chip, right_reg, val2);
+ } else {
+ mask = (mask << shift_left) | (mask << shift_right);
+ val1 = (chip->image[left_reg] & ~mask) | val1 | val2;
+ change = val1 != chip->image[left_reg];
+ snd_wss_out(chip, left_reg, val1);
+ }
spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
EXPORT_SYMBOL(snd_wss_put_double);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+
+static struct snd_kcontrol_new snd_ad1848_controls[] = {
+WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT,
+ 7, 7, 1, 1),
+WSS_DOUBLE_TLV("PCM Playback Volume", 0,
+ CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
+ db_scale_6bit),
+WSS_DOUBLE("Aux Playback Switch", 0,
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Aux Playback Volume", 0,
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
+WSS_DOUBLE("Aux Playback Switch", 1,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Aux Playback Volume", 1,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
+WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
+ 0, 0, 15, 0, db_scale_rec_gain),
+{
+ .name = "Capture Source",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .info = snd_wss_info_mux,
+ .get = snd_wss_get_mux,
+ .put = snd_wss_put_mux,
+},
+WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
+WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 1, 63, 0,
+ db_scale_6bit),
+};
+
static struct snd_kcontrol_new snd_wss_controls[] = {
WSS_DOUBLE("PCM Playback Switch", 0,
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
unsigned int idx;
int err;
- snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
+ if (snd_BUG_ON(!chip || !chip->pcm))
+ return -EINVAL;
card = chip->card;
if (err < 0)
return err;
}
+ else if (chip->hardware & WSS_HW_AD1848_MASK)
+ for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_ad1848_controls[idx],
+ chip));
+ if (err < 0)
+ return err;
+ }
else
for (idx = 0; idx < ARRAY_SIZE(snd_wss_controls); idx++) {
err = snd_ctl_add(card,
}
EXPORT_SYMBOL(snd_wss_mixer);
+const struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction)
+{
+ return direction == SNDRV_PCM_STREAM_PLAYBACK ?
+ &snd_wss_playback_ops : &snd_wss_capture_ops;
+}
+EXPORT_SYMBOL(snd_wss_get_pcm_ops);
+
/*
* INIT part
*/