[RFC] Add dB scale information to AK4xxx codec

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

the below is a patch to add dB scale information to ak4xxx-adda module
used by ice1712 and ice1724 drivers.

Could someone check whether this works, at least, it doesn't cause any
regressions?  I could test some but not all these.

The patch is to the latest ALSA HG version with linear volume TLV.

Also, I found an error in AK5365 capture gain and fixed in this patch.
Now there are two capture volume controls, "Capture Volume" and
"Capture Gain Volume".  The former is the attenuation up to 0dB, the
latter is IPGA (independent gain) in AK4524/4528.  Jochen, please
try this patch with your revo 5.1 board.


Thanks,

Takashi

diff -r 61bfe5b3a7ae include/ak4xxx-adda.h
--- a/include/ak4xxx-adda.h	Fri Aug 25 13:11:26 2006 +0200
+++ b/include/ak4xxx-adda.h	Fri Aug 25 17:12:57 2006 +0200
@@ -44,9 +44,7 @@ struct snd_akm4xxx {
 	unsigned int num_adcs;			/* AK4524 or AK4528 ADCs */
 	unsigned int num_dacs;			/* AK4524 or AK4528 DACs */
 	unsigned char images[AK4XXX_IMAGE_SIZE]; /* saved register image */
-	unsigned char ipga_gain[AK4XXX_MAX_CHIPS][2]; /* saved register image
-						       * for IPGA (AK4528)
-						       */
+	unsigned char volumes[AK4XXX_IMAGE_SIZE]; /* saved volume values */
 	unsigned long private_value[AK4XXX_MAX_CHIPS];	/* helper for driver */
 	void *private_data[AK4XXX_MAX_CHIPS];		/* helper for driver */
 	/* template should fill the following fields */
@@ -73,9 +71,18 @@ int snd_akm4xxx_build_controls(struct sn
 	(ak)->images[(chip) * 16 + (reg)]
 #define snd_akm4xxx_set(ak,chip,reg,val) \
 	((ak)->images[(chip) * 16 + (reg)] = (val))
+#define snd_akm4xxx_get_vol(ak,chip,reg) \
+	(ak)->volumes[(chip) * 16 + (reg)]
+#define snd_akm4xxx_set_vol(ak,chip,reg,val) \
+	((ak)->volumes[(chip) * 16 + (reg)] = (val))
+
+/* Warning: IPGA is tricky - we assume the addr + 4 is unused
+ *   so far, it's OK for all AK codecs with IPGA:
+ *   AK4524, AK4528 and EK5365
+ */
 #define snd_akm4xxx_get_ipga(ak,chip,reg) \
-	(ak)->ipga_gain[chip][(reg)-4]
+	snd_akm4xxx_get_vol(ak, chip, (reg) + 4)
 #define snd_akm4xxx_set_ipga(ak,chip,reg,val) \
-	((ak)->ipga_gain[chip][(reg)-4] = (val))
+	snd_akm4xxx_set_vol(ak, chip, (reg) + 4, val)
 
 #endif /* __SOUND_AK4XXX_ADDA_H */
diff -r 61bfe5b3a7ae i2c/other/ak4xxx-adda.c
--- a/i2c/other/ak4xxx-adda.c	Fri Aug 25 13:11:26 2006 +0200
+++ b/i2c/other/ak4xxx-adda.c	Fri Aug 25 17:18:00 2006 +0200
@@ -28,6 +28,7 @@
 #include <linux/init.h>
 #include <sound/core.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/ak4xxx-adda.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@xxxxxxx>, Takashi Iwai <tiwai@xxxxxxx>");
@@ -41,11 +42,12 @@ void snd_akm4xxx_write(struct snd_akm4xx
 	ak->ops.write(ak, chip, reg, val);
 
 	/* save the data */
-	if (ak->type == SND_AK4524 || ak->type == SND_AK4528) {
+	if (ak->type == SND_AK4524 || ak->type == SND_AK4528 ||
+	    ak->type == SND_AK5365) {
 		if ((reg != 0x04 && reg != 0x05) || (val & 0x80) == 0)
 			snd_akm4xxx_set(ak, chip, reg, val);
 		else
-			snd_akm4xxx_set_ipga(ak, chip, reg, val);
+			snd_akm4xxx_set_ipga(ak, chip, reg, val & 0x7f);
 	} else {
 		/* AK4529, or else */
 		snd_akm4xxx_set(ak, chip, reg, val);
@@ -78,7 +80,7 @@ static void ak4524_reset(struct snd_akm4
 		/* IPGA */
 		for (reg = 0x04; reg < 0x06; reg++)
 			snd_akm4xxx_write(ak, chip, reg,
-					  snd_akm4xxx_get_ipga(ak, chip, reg));
+					  snd_akm4xxx_get_ipga(ak, chip, reg) | 0x80);
 	}
 }
 
@@ -143,6 +145,39 @@ void snd_akm4xxx_reset(struct snd_akm4xx
 }
 
 EXPORT_SYMBOL(snd_akm4xxx_reset);
+
+
+/*
+ * Volume conversion table for non-linear volumes
+ * from -63.5dB (mute) to 0dB step 0.5dB
+ *
+ * Used for AK4524 input/ouput attenuation, AK4528, and
+ * AK5365 input attenuation
+ */
+static unsigned char vol_cvt_datt[128] = {
+	0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
+	0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
+	0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
+	0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f,
+	0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
+	0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c,
+	0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23,
+	0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d,
+	0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+	0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40,
+	0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a,
+	0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54,
+	0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f,
+	0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69,
+	0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73,
+	0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f,
+};
+
+static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
+static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
+static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
+static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
+static DECLARE_TLV_DB_SCALE(db_scale_ipga, 0, 50, 0);
 
 /*
  * initialize all the ak4xxx chips
@@ -284,12 +319,14 @@ EXPORT_SYMBOL(snd_akm4xxx_init);
 
 #define AK_GET_CHIP(val)		(((val) >> 8) & 0xff)
 #define AK_GET_ADDR(val)		((val) & 0xff)
-#define AK_GET_SHIFT(val)		(((val) >> 16) & 0x3f)
+#define AK_GET_SHIFT(val)		(((val) >> 16) & 0x1f)
+#define AK_GET_VOL_CVT(val)		(((val) >> 21) & 1)
 #define AK_GET_NEEDSMSB(val)		(((val) >> 22) & 1)
 #define AK_GET_INVERT(val)		(((val) >> 23) & 1)
 #define AK_GET_MASK(val)		(((val) >> 24) & 0xff)
 #define AK_COMPOSE(chip,addr,shift,mask) \
 	(((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
+#define AK_VOL_CVT 			(1<<21)
 #define AK_NEEDSMSB 			(1<<22)
 #define AK_INVERT 			(1<<23)
 
@@ -311,14 +348,8 @@ static int snd_akm4xxx_volume_get(struct
 	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
 	int chip = AK_GET_CHIP(kcontrol->private_value);
 	int addr = AK_GET_ADDR(kcontrol->private_value);
-	int needsmsb = AK_GET_NEEDSMSB(kcontrol->private_value);
-	int invert = AK_GET_INVERT(kcontrol->private_value);
-	unsigned int mask = AK_GET_MASK(kcontrol->private_value);
-	unsigned char val = snd_akm4xxx_get(ak, chip, addr);
-
-	if (needsmsb)
-		val &= 0x7f;
-	ucontrol->value.integer.value[0] = invert ? mask - val : val;
+
+	ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
 	return 0;
 }
 
@@ -328,20 +359,22 @@ static int snd_akm4xxx_volume_put(struct
 	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
 	int chip = AK_GET_CHIP(kcontrol->private_value);
 	int addr = AK_GET_ADDR(kcontrol->private_value);
-	int needsmsb = AK_GET_NEEDSMSB(kcontrol->private_value);
-	int invert = AK_GET_INVERT(kcontrol->private_value);
 	unsigned int mask = AK_GET_MASK(kcontrol->private_value);
-	unsigned char nval = ucontrol->value.integer.value[0] % (mask+1);
-	int change;
-
-	if (invert)
+	unsigned char nval;
+
+	nval = ucontrol->value.integer.value[0] % (mask+1);
+	if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
+		return 0;
+
+	snd_akm4xxx_set_vol(ak, chip, addr, nval);
+	if (AK_GET_VOL_CVT(kcontrol->private_value))
+		nval = vol_cvt_datt[nval];
+	if (AK_GET_INVERT(kcontrol->private_value))
 		nval = mask - nval;
-	if (needsmsb)
+	if (AK_GET_NEEDSMSB(kcontrol->private_value))
 		nval |= 0x80;
-	change = snd_akm4xxx_get(ak, chip, addr) != nval;
-	if (change)
-		snd_akm4xxx_write(ak, chip, addr, nval);
-	return change;
+	snd_akm4xxx_write(ak, chip, addr, nval);
+	return 1;
 }
 
 static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
@@ -362,66 +395,55 @@ static int snd_akm4xxx_stereo_volume_get
 	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
 	int chip = AK_GET_CHIP(kcontrol->private_value);
 	int addr = AK_GET_ADDR(kcontrol->private_value);
+
+	ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
+	ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1);
+	return 0;
+}
+
+static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+	int chip = AK_GET_CHIP(kcontrol->private_value);
+	int addr = AK_GET_ADDR(kcontrol->private_value);
+	int vol_cvt = AK_GET_VOL_CVT(kcontrol->private_value);
 	int needsmsb = AK_GET_NEEDSMSB(kcontrol->private_value);
 	int invert = AK_GET_INVERT(kcontrol->private_value);
 	unsigned int mask = AK_GET_MASK(kcontrol->private_value);
-	unsigned char val;
-
-	val = snd_akm4xxx_get(ak, chip, addr);
-	if (needsmsb)
-		val &= 0x7f;
-	ucontrol->value.integer.value[0] = invert ? mask - val : val;
-
-	val = snd_akm4xxx_get(ak, chip, addr+1);
-	if (needsmsb)
-		val &= 0x7f;
-	ucontrol->value.integer.value[1] = invert ? mask - val : val;
-
-	return 0;
-}
-
-static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
-					 struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
-	int chip = AK_GET_CHIP(kcontrol->private_value);
-	int addr = AK_GET_ADDR(kcontrol->private_value);
-	int needsmsb = AK_GET_NEEDSMSB(kcontrol->private_value);
-	int invert = AK_GET_INVERT(kcontrol->private_value);
-	unsigned int mask = AK_GET_MASK(kcontrol->private_value);
-	unsigned char nval = ucontrol->value.integer.value[0] % (mask+1);
-	int change0, change1;
-
-	if (invert)
-		nval = mask - nval;
-	if (needsmsb)
-		nval |= 0x80;
-	change0 = snd_akm4xxx_get(ak, chip, addr) != nval;
-	if (change0)
+	unsigned char nval;
+	int change = 0;
+
+	nval = ucontrol->value.integer.value[0] % (mask+1);
+	if (snd_akm4xxx_get_vol(ak, chip, addr) != nval) {
+		change = 1;
+		snd_akm4xxx_set_vol(ak, chip, addr, nval);
+		if (vol_cvt)
+			nval = vol_cvt_datt[nval];
+		if (invert)
+			nval = mask - nval;
+		if (needsmsb)
+			nval |= 0x80;
 		snd_akm4xxx_write(ak, chip, addr, nval);
+	}
 
 	nval = ucontrol->value.integer.value[1] % (mask+1);
-	if (invert)
-		nval = mask - nval;
-	if (needsmsb)
-		nval |= 0x80;
-	change1 = snd_akm4xxx_get(ak, chip, addr+1) != nval;
-	if (change1)
-		snd_akm4xxx_write(ak, chip, addr+1, nval);
-
-
-	return change0 || change1;
-}
-
-static int snd_akm4xxx_ipga_gain_info(struct snd_kcontrol *kcontrol,
-				      struct snd_ctl_elem_info *uinfo)
-{
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 36;
-	return 0;
-}
+	if (snd_akm4xxx_get_vol(ak, chip, addr + 1) != nval) {
+		change = 1;
+		snd_akm4xxx_set_vol(ak, chip, addr + 1, nval);
+		if (vol_cvt)
+			nval = vol_cvt_datt[nval];
+		if (invert)
+			nval = mask - nval;
+		if (needsmsb)
+			nval |= 0x80;
+		snd_akm4xxx_write(ak, chip, addr + 1, nval);
+	}
+
+	return change;
+}
+
+#define snd_akm4xxx_ipga_gain_info	snd_akm4xxx_volume_info
 
 static int snd_akm4xxx_ipga_gain_get(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
@@ -429,8 +451,9 @@ static int snd_akm4xxx_ipga_gain_get(str
 	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
 	int chip = AK_GET_CHIP(kcontrol->private_value);
 	int addr = AK_GET_ADDR(kcontrol->private_value);
+
 	ucontrol->value.integer.value[0] =
-		snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f;
+		snd_akm4xxx_get_ipga(ak, chip, addr);
 	return 0;
 }
 
@@ -440,10 +463,57 @@ static int snd_akm4xxx_ipga_gain_put(str
 	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
 	int chip = AK_GET_CHIP(kcontrol->private_value);
 	int addr = AK_GET_ADDR(kcontrol->private_value);
-	unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80;
-	int change = snd_akm4xxx_get_ipga(ak, chip, addr) != nval;
-	if (change)
-		snd_akm4xxx_write(ak, chip, addr, nval);
+	unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+	unsigned char nval;
+
+	nval = ucontrol->value.integer.value[0] % (mask + 1);
+	if (snd_akm4xxx_get_ipga(ak, chip, addr) == nval)
+		return 0;
+	snd_akm4xxx_set_ipga(ak, chip, addr, nval);
+	snd_akm4xxx_write(ak, chip, addr, nval | 0x80); /* need MSB */
+	return 1;
+}
+
+#define snd_akm4xxx_stereo_gain_info	snd_akm4xxx_stereo_volume_info
+
+static int snd_akm4xxx_stereo_gain_get(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+	int chip = AK_GET_CHIP(kcontrol->private_value);
+	int addr = AK_GET_ADDR(kcontrol->private_value);
+
+	ucontrol->value.integer.value[0] =
+		snd_akm4xxx_get_ipga(ak, chip, addr);
+	ucontrol->value.integer.value[1] =
+		snd_akm4xxx_get_ipga(ak, chip, addr + 1);
+	return 0;
+}
+
+static int snd_akm4xxx_stereo_gain_put(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+	int chip = AK_GET_CHIP(kcontrol->private_value);
+	int addr = AK_GET_ADDR(kcontrol->private_value);
+	unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+	unsigned char nval;
+	int change = 0;
+
+	nval = ucontrol->value.integer.value[0] % (mask + 1);
+	if (snd_akm4xxx_get_ipga(ak, chip, addr) != nval) {
+		change = 1;
+		snd_akm4xxx_set_ipga(ak, chip, addr, nval);
+		snd_akm4xxx_write(ak, chip, addr, nval | 0x80); /* need MSB */
+	}
+
+	nval = ucontrol->value.integer.value[1] % (mask+1);
+	if (snd_akm4xxx_get_ipga(ak, chip, addr + 1) != nval) {
+		change = 1;
+		snd_akm4xxx_set_ipga(ak, chip, addr + 1, nval);
+		snd_akm4xxx_write(ak, chip, addr + 1, nval | 0x80);
+	}
+
 	return change;
 }
 
@@ -586,35 +656,43 @@ int snd_akm4xxx_build_controls(struct sn
 		case SND_AK4524:
 			/* register 6 & 7 */
 			ctl->private_value =
-				AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127);
+				AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
+				AK_VOL_CVT;
+			ctl->tlv.p = db_scale_vol_datt;
 			break;
 		case SND_AK4528:
 			/* register 4 & 5 */
 			ctl->private_value =
-				AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127);
+				AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
+				AK_VOL_CVT;
+			ctl->tlv.p = db_scale_vol_datt;
 			break;
 		case SND_AK4529: {
 			/* registers 2-7 and b,c */
 			int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
 			ctl->private_value =
 				AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
+			ctl->tlv.p = db_scale_8bit;
 			break;
 		}
 		case SND_AK4355:
 			/* register 4-9, chip #0 only */
 			ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255);
+			ctl->tlv.p = db_scale_8bit;
 			break;
 		case SND_AK4358: {
 			/* register 4-9 and 11-12, chip #0 only */
 			int  addr = idx < 6 ? idx + 4 : idx + 5;
 			ctl->private_value =
 				AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
+			ctl->tlv.p = db_scale_7bit;
 			break;
 		}
 		case SND_AK4381:
 			/* register 3 & 4 */
 			ctl->private_value =
 				AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
+			ctl->tlv.p = db_scale_linear;
 			break;
 		default:
 			err = -EINVAL;
@@ -624,7 +702,8 @@ int snd_akm4xxx_build_controls(struct sn
 		ctl->private_data = ak;
 		err = snd_ctl_add(ak->card,
 				  snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
-					      SNDRV_CTL_ELEM_ACCESS_WRITE));
+					      SNDRV_CTL_ELEM_ACCESS_WRITE |
+					      SNDRV_CTL_ELEM_ACCESS_TLV_READ));
 		if (err < 0)
 			goto __error;
 
@@ -642,11 +721,14 @@ int snd_akm4xxx_build_controls(struct sn
 		ctl->put = snd_akm4xxx_volume_put;
 		/* register 4 & 5 */
 		ctl->private_value =
-			AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127);
+			AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
+			AK_VOL_CVT;
 		ctl->private_data = ak;
+		ctl->tlv.p = db_scale_vol_datt;
 		err = snd_ctl_add(ak->card,
 				  snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
-					      SNDRV_CTL_ELEM_ACCESS_WRITE));
+					      SNDRV_CTL_ELEM_ACCESS_WRITE |
+					      SNDRV_CTL_ELEM_ACCESS_TLV_READ));
 		if (err < 0)
 			goto __error;
 
@@ -659,11 +741,13 @@ int snd_akm4xxx_build_controls(struct sn
 		ctl->get = snd_akm4xxx_ipga_gain_get;
 		ctl->put = snd_akm4xxx_ipga_gain_put;
 		/* register 4 & 5 */
-		ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0);
+		ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 36);
 		ctl->private_data = ak;
+		ctl->tlv.p = db_scale_ipga;
 		err = snd_ctl_add(ak->card,
 				  snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
-					      SNDRV_CTL_ELEM_ACCESS_WRITE));
+					      SNDRV_CTL_ELEM_ACCESS_WRITE |
+					      SNDRV_CTL_ELEM_ACCESS_TLV_READ));
 		if (err < 0)
 			goto __error;
 	}
@@ -681,13 +765,33 @@ int snd_akm4xxx_build_controls(struct sn
 		ctl->get = snd_akm4xxx_stereo_volume_get;
 		ctl->put = snd_akm4xxx_stereo_volume_put;
 		/* Registers 4 & 5 (see AK5365 data sheet, pages 34 and 35):
-		 * valid values are from 0x00 (mute) to 0x98 (+12dB).  */
+		 * valid values are from 0x00 (mute) to 0x7f (0dB)  */
 		ctl->private_value =
-			AK_COMPOSE(0, 4, 0, 0x98);
+			AK_COMPOSE(0, 4, 0, 127) | AK_VOL_CVT;
 		ctl->private_data = ak;
+		ctl->tlv.p = db_scale_vol_datt;
 		err = snd_ctl_add(ak->card,
 				  snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
 					      SNDRV_CTL_ELEM_ACCESS_WRITE));
+		if (err < 0)
+			goto __error;
+
+		memset(ctl, 0, sizeof(*ctl));
+		strcpy(ctl->id.name, "Capture Gain Volume");
+		ctl->id.index = ak->idx_offset * 2;
+		ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		ctl->count = 1;
+		ctl->info = snd_akm4xxx_stereo_gain_info;
+		ctl->get = snd_akm4xxx_stereo_gain_get;
+		ctl->put = snd_akm4xxx_stereo_gain_put;
+		/* register 4 & 5 - IPGA */
+		ctl->private_value = AK_COMPOSE(0, 4, 0, 24);
+		ctl->private_data = ak;
+		ctl->tlv.p = db_scale_ipga;
+		err = snd_ctl_add(ak->card,
+				  snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
+					      SNDRV_CTL_ELEM_ACCESS_WRITE |
+					      SNDRV_CTL_ELEM_ACCESS_TLV_READ));
 		if (err < 0)
 			goto __error;
 

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux