[alsa-devel] [PATCH] Support for muting channels DAC with CA0106 - SB0570
Trent Piepho
xyzzy at speakeasy.org
Sun Jul 22 02:10:08 CEST 2007
This patch adds mute controls for the analog output channels. It does this
by sending SPI commands to the DAC on cards like the SB live 24-bit /
Audigy SE that have an SPI DAC.
-------------- next part --------------
# HG changeset patch
# User Trent Piepho <xyzzy at speakeasy.org>
# Date 1185062879 25200
# Node ID 2c3514f4607b69271148337af15be55d3205af70
# Parent 04b7771f7c31709e9d1883264bcde7e34781a590
ca0106: Add analog mute controls for cards with SPI DAC
Add four mute controls for the analog output channels for cards that use
a spi dac, like SB0570 SB Live! 24-bit / Audigy SE. The Wolfson dac
doesn't support muting each channel 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 de-emphasis, DAC power down, phase inversion, and other
features.
diff -r 04b7771f7c31 -r 2c3514f4607b pci/ca0106/ca0106.h
--- a/pci/ca0106/ca0106.h Fri Jul 20 10:52:46 2007 +0200
+++ b/pci/ca0106/ca0106.h Sat Jul 21 17:07:59 2007 -0700
@@ -611,6 +611,8 @@ struct snd_ca0106 {
struct snd_ca_midi midi;
struct snd_ca_midi midi2;
+
+ u16 spi_dac_reg[16];
};
int snd_ca0106_mixer(struct snd_ca0106 *emu);
@@ -627,4 +629,5 @@ void snd_ca0106_ptr_write(struct snd_ca0
int snd_ca0106_i2c_write(struct snd_ca0106 *emu, u32 reg, u32 value);
-
+int snd_ca0106_spi_write(struct snd_ca0106 * emu,
+ unsigned int data);
diff -r 04b7771f7c31 -r 2c3514f4607b pci/ca0106/ca0106_main.c
--- a/pci/ca0106/ca0106_main.c Fri Jul 20 10:52:46 2007 +0200
+++ b/pci/ca0106/ca0106_main.c Sat Jul 21 17:07:59 2007 -0700
@@ -1475,8 +1475,11 @@ static int __devinit snd_ca0106_create(i
int size, n;
size = ARRAY_SIZE(spi_dac_init);
- for (n=0; n < size; n++)
+ for (n=0; n < size; n++) {
snd_ca0106_spi_write(chip, spi_dac_init[n]);
+ if ((spi_dac_init[n]>>9) < ARRAY_SIZE(chip->spi_dac_reg))
+ chip->spi_dac_reg[spi_dac_init[n]>>9] = spi_dac_init[n];
+ }
}
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
diff -r 04b7771f7c31 -r 2c3514f4607b pci/ca0106/ca0106_mixer.c
--- a/pci/ca0106/ca0106_mixer.c Fri Jul 20 10:52:46 2007 +0200
+++ b/pci/ca0106/ca0106_mixer.c Sat Jul 21 17:07:59 2007 -0700
@@ -470,6 +470,41 @@ static int snd_ca0106_i2c_volume_put(str
return change;
}
+static int spi_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+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 >> 9;
+ unsigned int bit = kcontrol->private_value & 0x1ff;
+
+ 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 >> 9;
+ unsigned int bit = kcontrol->private_value & 0x1ff;
+ int ret;
+
+ if (ucontrol->value.integer.value[0])
+ emu->spi_dac_reg[reg] &= ~bit;
+ else
+ 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, \
@@ -560,6 +595,23 @@ static struct snd_kcontrol_new snd_ca010
I2C_VOLUME("Mic Capture Volume", 1),
I2C_VOLUME("Line in Capture Volume", 2),
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<<9) | (1<<bit) \
+}
+
+static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[] __devinitdata = {
+ SPI_SWITCH("Analog Front Playback Switch", 15, 2),
+ SPI_SWITCH("Analog Rear Playback Switch", 9, 3),
+ SPI_SWITCH("Analog Center/LFE Playback Switch", 9, 5),
+ SPI_SWITCH("Analog Side Playback Switch", 9, 4),
};
static int __devinit remove_ctl(struct snd_card *card, const char *name)
@@ -658,6 +710,13 @@ int __devinit snd_ca0106_mixer(struct sn
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;
}
More information about the Alsa-devel
mailing list