[alsa-devel] [PATCH] Support for muting channels DAC with CA0106 - SB0570

Trent Piepho xyzzy at speakeasy.org
Tue Jul 24 01:43:14 CEST 2007


On Mon, 23 Jul 2007, Takashi Iwai wrote:
> At Sat, 21 Jul 2007 17:10:08 -0700 (PDT),
> Thanks, the patch looks almost fine, but please fix the following
> minor issues:
>
> - Try to avoid a magic number, e.g. >> 9.

Ok, I added a bunch of the fields from the WM8768 datasheet that could be
useful.

> - put callback should return 0 for non-changed value, a positive
>   (usually 1) when the value is changed, and a negative error code for
>   errors.

It will now return 0 if the value wasn't changed and also not do the
unnecessary spi write.

> - Try to keep lines within 80 chars (to follow the standard coding
>   style).  I know that other codes there are not, but don't care now.
>   We'll fix them later, too.

Also done.  The loops that add the controls have long lines that didn't
wrap well.  So I made a second patch that converts the loop I added plus
the two existing loops into a macro, which IMHO looks a lot nicer and
reduces code duplication.

I also upped the version numbers and used snd_ctl_boolean_mono_info.
-------------- next part --------------
# HG changeset patch
# User Trent Piepho <xyzzy at speakeasy.org>
# Date 1185228660 25200
# Node ID 87a07ac27d0cd5f7ce391f3f52229b6516efb3bc
# Parent  c30a197f63c386c9478fa242d78dd3efe7165adb
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 at speakeasy.org>

diff -r c30a197f63c3 -r 87a07ac27d0c pci/ca0106/ca0106.h
--- a/pci/ca0106/ca0106.h	Mon Jul 23 20:30:22 2007 +0100
+++ b/pci/ca0106/ca0106.h	Mon Jul 23 15:11:00 2007 -0700
@@ -1,7 +1,7 @@
 /*
  *  Copyright (c) 2004 James Courtier-Dutton <James at superbug.demon.co.uk>
  *  Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
- *  Version: 0.0.21
+ *  Version: 0.0.22
  *
  *  FEATURES currently supported:
  *    See ca0106_main.c for features.
@@ -47,6 +47,8 @@
  *    Added GPIO info for SB Live 24bit.
  *  0.0.21
  *   Implement support for Line-in capture on SB Live 24bit.
+ *  0.0.22
+ *    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:
@@ -552,6 +554,44 @@
 #define CONTROL_CENTER_LFE_CHANNEL 1
 #define CONTROL_UNKNOWN_CHANNEL 2
 
+
+/* Based on WM8768 Datasheet Rev 4.2 page 32 */
+#define SPI_REG_MASK	0x1ff	/* 16-bit SPI writes have a 7-bit address */
+#define SPI_REG_SHIFT	9	/* followed by 9 bits of data */
+
+/* They really do label the bit for the 4th channel "4" and not "3" */
+#define SPI_DMUTE0_REG		9
+#define SPI_DMUTE1_REG		9
+#define SPI_DMUTE2_REG		9
+#define SPI_DMUTE4_REG		15
+#define SPI_DMUTE0_BIT		3
+#define SPI_DMUTE1_BIT		4
+#define SPI_DMUTE2_BIT		5
+#define SPI_DMUTE4_BIT		2
+
+#define SPI_PHASE0_REG		3
+#define SPI_PHASE1_REG		3
+#define SPI_PHASE2_REG		3
+#define SPI_PHASE4_REG		15
+#define SPI_PHASE0_BIT		6
+#define SPI_PHASE1_BIT		7
+#define SPI_PHASE2_BIT		8
+#define SPI_PHASE4_BIT		3
+
+#define SPI_PDWN_REG		2	/* power down all DACs */
+#define SPI_PDWN_BIT		2
+#define SPI_DACD0_REG		10	/* power down individual DACs */
+#define SPI_DACD1_REG		10
+#define SPI_DACD2_REG		10
+#define SPI_DACD4_REG		15
+#define SPI_DACD0_BIT		1
+#define SPI_DACD1_BIT		2
+#define SPI_DACD2_BIT		3
+#define SPI_DACD4_BIT		1
+
+#define SPI_PWRDNALL_REG	10	/* power down everything */
+#define SPI_PWRDNALL_BIT	4
+
 #include "ca_midi.h"
 
 struct snd_ca0106;
@@ -611,6 +651,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 +669,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 c30a197f63c3 -r 87a07ac27d0c pci/ca0106/ca0106_main.c
--- a/pci/ca0106/ca0106_main.c	Mon Jul 23 20:30:22 2007 +0100
+++ b/pci/ca0106/ca0106_main.c	Mon Jul 23 15:11:00 2007 -0700
@@ -1,7 +1,7 @@
 /*
  *  Copyright (c) 2004 James Courtier-Dutton <James at superbug.demon.co.uk>
  *  Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
- *  Version: 0.0.23
+ *  Version: 0.0.24
  *
  *  FEATURES currently supported:
  *    Front, Rear and Center/LFE.
@@ -79,6 +79,8 @@
  *    Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901
  *  0.0.23
  *    Implement support for Line-in capture on SB Live 24bit.
+ *  0.0.24
+ *    Add support for mute control on SB Live 24bit (cards w/ SPI DAC)
  *
  *  BUGS:
  *    Some stability problems when unloading the snd-ca0106 kernel module.
@@ -1484,8 +1486,13 @@ 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++) {
+			int reg = spi_dac_init[n] >> SPI_REG_SHIFT;
+
 			snd_ca0106_spi_write(chip, spi_dac_init[n]);
+			if (reg < ARRAY_SIZE(chip->spi_dac_reg))
+				chip->spi_dac_reg[reg] = spi_dac_init[n];
+		}
 	}
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
diff -r c30a197f63c3 -r 87a07ac27d0c pci/ca0106/ca0106_mixer.c
--- a/pci/ca0106/ca0106_mixer.c	Mon Jul 23 20:30:22 2007 +0100
+++ b/pci/ca0106/ca0106_mixer.c	Mon Jul 23 15:11:00 2007 -0700
@@ -1,7 +1,7 @@
 /*
  *  Copyright (c) 2004 James Courtier-Dutton <James at 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 at nc.rr.com>
@@ -460,6 +462,42 @@ static int snd_ca0106_i2c_volume_put(str
 	}
 
 	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) \
@@ -552,6 +590,28 @@ 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<<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)
@@ -650,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;
 }
 
-------------- next part --------------
# HG changeset patch
# User Trent Piepho <xyzzy at speakeasy.org>
# Date 1185229288 25200
# Node ID 677282fd6bcc15373480eefb52b763b363d940ee
# Parent  87a07ac27d0cd5f7ce391f3f52229b6516efb3bc
ca0106: replaced control add sequences with macro

Turn a rather long lined for loop that is duplicated multiple times into a
macro.

Signed-off-by: Trent Piepho <xyzzy at speakeasy.org>

diff -r 87a07ac27d0c -r 677282fd6bcc pci/ca0106/ca0106_mixer.c
--- a/pci/ca0106/ca0106_mixer.c	Mon Jul 23 15:11:00 2007 -0700
+++ b/pci/ca0106/ca0106_mixer.c	Mon Jul 23 15:21:28 2007 -0700
@@ -643,6 +643,13 @@ static int __devinit rename_ctl(struct s
 	return -ENOENT;
 }
 
+#define ADD_CTLS(ctls)							\
+	for (i = 0; i < ARRAY_SIZE(ctls); i++) {			\
+		err = snd_ctl_add(card, snd_ctl_new1(&ctls[i], emu));	\
+		if (err < 0)						\
+			return err;					\
+	}								\
+
 int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
 {
 	int i, err;
@@ -692,17 +699,9 @@ int __devinit snd_ca0106_mixer(struct sn
 		rename_ctl(card, c[0], c[1]);
 #endif
 
-	for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_ctls); i++) {
-		err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_ctls[i], emu));
-		if (err < 0)
-			return err;
-	}
+	ADD_CTLS(snd_ca0106_volume_ctls);
 	if (emu->details->i2c_adc == 1) {
-		for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_i2c_adc_ctls); i++) {
-			err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_i2c_adc_ctls[i], emu));
-			if (err < 0)
-				return err;
-		}
+		ADD_CTLS(snd_ca0106_volume_i2c_adc_ctls);
 		if (emu->details->gpio_type == 1)
 			err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
 		else  /* gpio_type == 2 */
@@ -710,13 +709,8 @@ 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;
-		}
-	}
+	if (emu->details->spi_dac == 1)
+		ADD_CTLS(snd_ca0106_volume_spi_dac_ctls);
         return 0;
 }
 


More information about the Alsa-devel mailing list