summaryrefslogtreecommitdiff
path: root/sound/pci/ca0106/ca0106_mixer.c
diff options
context:
space:
mode:
authorTrent Piepho <xyzzy@speakeasy.org>2007-07-24 12:06:16 +0200
committerJaroslav Kysela <perex@perex.cz>2007-10-16 15:57:55 +0200
commitb18cd538a92247307247a53f57c477edbcedbb79 (patch)
tree0fd32216c26bc78f95be8b8f56052e370f7f7f43 /sound/pci/ca0106/ca0106_mixer.c
parent69b311a4dabc9163288be1fe993cb7db47541e67 (diff)
[ALSA] ca0106: Add analog mute controls for cards with SPI DAC
Add four mute controls for the analog output channels for cards that use an SPI DAC, like the SB0570 SB Live! 24-bit / Audigy SE. The Wolfson DAC doesn't support muting left/right so the controls are mono. The chip state struct gets a 32-byte array to act as a shadow of the spi dac registers. Only two registers are used for mute, but more would be needed for analog gain, de-emphasis, DAC power down, phase inversion, and other features. Signed-off-by: Trent Piepho <xyzzy@speakeasy.org> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci/ca0106/ca0106_mixer.c')
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c69
1 files changed, 68 insertions, 1 deletions
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index a135b9c4c3c8..7fbfe17438b4 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
* Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
- * Version: 0.0.17
+ * Version: 0.0.18
*
* FEATURES currently supported:
* See ca0106_main.c for features.
@@ -39,6 +39,8 @@
* Modified Copyright message.
* 0.0.17
* Implement Mic and Line in Capture.
+ * 0.0.18
+ * Add support for mute control on SB Live 24bit (cards w/ SPI DAC)
*
* This code was initally based on code from ALSA's emu10k1x.c which is:
* Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
@@ -462,6 +464,42 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
return change;
}
+#define spi_mute_info snd_ctl_boolean_mono_info
+
+static int spi_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT;
+ unsigned int bit = kcontrol->private_value & SPI_REG_MASK;
+
+ ucontrol->value.integer.value[0] = !(emu->spi_dac_reg[reg] & bit);
+ return 0;
+}
+
+static int spi_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT;
+ unsigned int bit = kcontrol->private_value & SPI_REG_MASK;
+ int ret;
+
+ ret = emu->spi_dac_reg[reg] & bit;
+ if (ucontrol->value.integer.value[0]) {
+ if (!ret) /* bit already cleared, do nothing */
+ return 0;
+ emu->spi_dac_reg[reg] &= ~bit;
+ } else {
+ if (ret) /* bit already set, do nothing */
+ return 0;
+ emu->spi_dac_reg[reg] |= bit;
+ }
+
+ ret = snd_ca0106_spi_write(emu, emu->spi_dac_reg[reg]);
+ return ret ? -1 : 1;
+}
+
#define CA_VOLUME(xname,chid,reg) \
{ \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -554,6 +592,28 @@ static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata =
I2C_VOLUME("Aux Capture Volume", 3),
};
+#define SPI_SWITCH(xname,reg,bit) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = spi_mute_info, \
+ .get = spi_mute_get, \
+ .put = spi_mute_put, \
+ .private_value = (reg<<SPI_REG_SHIFT) | (1<<bit) \
+}
+
+static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[]
+__devinitdata = {
+ SPI_SWITCH("Analog Front Playback Switch",
+ SPI_DMUTE4_REG, SPI_DMUTE4_BIT),
+ SPI_SWITCH("Analog Rear Playback Switch",
+ SPI_DMUTE0_REG, SPI_DMUTE0_BIT),
+ SPI_SWITCH("Analog Center/LFE Playback Switch",
+ SPI_DMUTE2_REG, SPI_DMUTE2_BIT),
+ SPI_SWITCH("Analog Side Playback Switch",
+ SPI_DMUTE1_REG, SPI_DMUTE1_BIT),
+};
+
static int __devinit remove_ctl(struct snd_card *card, const char *name)
{
struct snd_ctl_elem_id id;
@@ -650,6 +710,13 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
if (err < 0)
return err;
}
+ if (emu->details->spi_dac == 1) {
+ for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_spi_dac_ctls); i++) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_spi_dac_ctls[i], emu));
+ if (err < 0)
+ return err;
+ }
+ }
return 0;
}