[alsa-devel] [PATCH - Ego Sys Waveterminal 192M 1/1] Update driver to support alsa changes happened since last driver commit. Add TLV support for dB scales. Add sampling rate control.

klem.dev at gmail.com klem.dev at gmail.com
Wed Sep 18 22:15:32 CEST 2013


From: Clement Guedez <klem.dev at gmail.com>


Signed-off-by: Clement Guedez <klem.dev at gmail.com>

diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c
index bcf30a3..286be47 100644
--- a/sound/pci/ice1712/wtm.c
+++ b/sound/pci/ice1712/wtm.c
@@ -4,8 +4,8 @@
  *	Lowlevel functions for Ego Sys Waveterminal 192M
  *
  *		Copyright (c) 2006 Guedez Clement <klem.dev at gmail.com>
- *		Some functions are taken from the Prodigy192 driver
- *		source
+ *		Thanks to the developers of the Prodigy192 driver on which
+ *		I based this driver
  *
  *	This program is free software; you can redistribute it and/or modify
  *	it under the terms of the GNU General Public License as published by
@@ -25,15 +25,25 @@
 
 
 
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 #include <sound/core.h>
 
 #include "ice1712.h"
 #include "envy24ht.h"
 #include "wtm.h"
 #include "stac946x.h"
+#include <sound/tlv.h>
+
+struct wtm_spec {
+	struct ak4114 *ak4114;
+	/* rate change needs atomic mute/unmute of all dacs*/
+	struct mutex mute_mutex;
+};
+
 
 
 /*
@@ -68,6 +78,35 @@ static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg)
 /*
  *	DAC mute control
  */
+static void stac9460_dac_mute_all(struct snd_ice1712 *ice, unsigned char mute,
+				   unsigned char *change)
+{
+	unsigned char new, old;
+	int idx;
+
+	/*stac9460 1*/
+	for (idx = 0; idx < 7; idx++) {
+		if (change[idx]) {
+			old = stac9460_get(ice, idx);
+			new = (~mute << 7 & 0x80) | (old & ~0x80);
+			change[idx] = (new != old);
+			if (change[idx])
+				stac9460_put(ice, idx, new);
+		}
+	}
+
+	/*stac9460 2*/
+	for (idx = 0; idx < 3; idx++) {
+		if (change[idx + 7]) {
+			old = stac9460_2_get(ice, idx);
+			new = (~mute << 7 & 0x80) | (old & ~0x80);
+			change[idx + 7] = (new != old);
+			if (change[idx + 7])
+				stac9460_2_put(ice, idx, new);
+		}
+	}
+}
+
 #define stac9460_dac_mute_info		snd_ctl_boolean_mono_info
 
 static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
@@ -96,10 +135,14 @@ static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	struct wtm_spec *spec = ice->spec;
 	unsigned char new, old;
 	int id, idx;
 	int change;
 
+	mutex_lock(&spec->mute_mutex);
+
+
 	if (kcontrol->private_value) {
 		idx = STAC946X_MASTER_VOLUME;
 		old = stac9460_get(ice, idx);
@@ -127,6 +170,7 @@ static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
 				stac9460_2_put(ice, idx - 6, new);
 		}
 	}
+	mutex_unlock(&spec->mute_mutex);
 	return change;
 }
 
@@ -175,7 +219,7 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
 
 	if (kcontrol->private_value) {
 		idx = STAC946X_MASTER_VOLUME;
-		nvol = ucontrol->value.integer.value[0] & 0x7f;
+		nvol = ucontrol->value.integer.value[0];
 		tmp = stac9460_get(ice, idx);
 		ovol = 0x7f - (tmp & 0x7f);
 		change = (ovol != nvol);
@@ -186,7 +230,7 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
 	} else {
 		id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 		idx = id + STAC946X_LF_VOLUME;
-		nvol = ucontrol->value.integer.value[0] & 0x7f;
+		nvol = ucontrol->value.integer.value[0];
 		if (id < 6)
 			tmp = stac9460_get(ice, idx);
 		else
@@ -339,7 +383,24 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
  * MIC / LINE switch fonction
  */
 
-#define stac9460_mic_sw_info		snd_ctl_boolean_mono_info
+static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[2] = { "Line In", "Mic" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items
+						- 1;
+	strcpy(uinfo->value.enumerated.name,
+		texts[uinfo->value.enumerated.item]);
+
+	return 0;
+}
+
 
 static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
@@ -353,7 +414,7 @@ static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
 		val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
 	else
 		val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
-	ucontrol->value.integer.value[0] = ~val>>7 & 0x1;
+	ucontrol->value.enumerated.item[0] = (val >> 7) & 0x1;
 	return 0;
 }
 
@@ -369,7 +430,7 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
 		old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
 	else
 		old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
-	new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | (old & ~0x80);
+	new = (ucontrol->value.enumerated.item[0] << 7 & 0x80) | (old & ~0x80);
 	change = (new != old);
 	if (change) {
 		if (id == 0)
@@ -380,6 +441,46 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
 	return change;
 }
 
+
+/*
+ * Handler for setting correct codec rate - called when rate change is detected
+ */
+static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate)
+{
+	unsigned char old, new;
+	unsigned char changed[10];
+	struct wtm_spec *spec = ice->spec;
+
+	if (rate == 0)  /* no hint - S/PDIF input is master, simply return */
+		return;
+	else if (rate <= 48000)
+		new = 0x08;     /* 256x, base rate mode */
+	else if (rate <= 96000)
+		new = 0x11;     /* 256x, mid rate mode */
+	else
+		new = 0x12;     /* 128x, high rate mode */
+	old = stac9460_get(ice, STAC946X_MASTER_CLOCKING);
+	if (old == new)
+		return;
+	/* change detected, setting master clock, muting first */
+	/* due to possible conflicts with mute controls - mutexing */
+	mutex_lock(&spec->mute_mutex);
+	/* we have to remember current mute status for each DAC */
+	stac9460_dac_mute_all(ice, 0, changed);
+	/*printk(KERN_DEBUG "Rate change: %d, new MC: 0x%02x\n", rate, new);*/
+	stac9460_put(ice, STAC946X_MASTER_CLOCKING, new);
+	udelay(10);
+	/* unmuting - only originally unmuted dacs -
+	* i.e. those changed when muting */
+	stac9460_dac_mute_all(ice, 1, changed);
+	mutex_unlock(&spec->mute_mutex);
+}
+
+
+
+static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
+
 /*
  * Control tabs
  */
@@ -390,15 +491,19 @@ static struct snd_kcontrol_new stac9640_controls[] = {
 		.info = stac9460_dac_mute_info,
 		.get = stac9460_dac_mute_get,
 		.put = stac9460_dac_mute_put,
-		.private_value = 1
+		.private_value = 1,
+		.tlv = { .p = db_scale_dac }
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
 		.name = "Master Playback Volume",
 		.info = stac9460_dac_vol_info,
 		.get = stac9460_dac_vol_get,
 		.put = stac9460_dac_vol_put,
 		.private_value = 1,
+		.tlv = { .p = db_scale_dac }
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -419,11 +524,14 @@ static struct snd_kcontrol_new stac9640_controls[] = {
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
 		.name = "DAC Volume",
 		.count = 8,
 		.info = stac9460_dac_vol_info,
 		.get = stac9460_dac_vol_get,
 		.put = stac9460_dac_vol_put,
+		.tlv = { .p = db_scale_dac }
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -435,18 +543,40 @@ static struct snd_kcontrol_new stac9640_controls[] = {
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
 		.name = "ADC Volume",
 		.count = 2,
 		.info = stac9460_adc_vol_info,
 		.get = stac9460_adc_vol_get,
 		.put = stac9460_adc_vol_put,
-
+		.tlv = { .p = db_scale_adc }
 	}
 };
 
 
 
 /*INIT*/
+static void stac9460_proc_regs_read(struct snd_info_entry *entry,
+				    struct snd_info_buffer *buffer)
+{
+	struct snd_ice1712 *ice = entry->private_data;
+	int reg, val;
+	/* registers 0x0 - 0x14 */
+	for (reg = 0; reg <= 0x15; reg++) {
+		val = stac9460_get(ice, reg);
+		snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val);
+	}
+}
+
+static void stac9460_proc_init(struct snd_ice1712 *ice)
+{
+	struct snd_info_entry *entry;
+	if (!snd_card_proc_new(ice->card, "stac9460_codec", &entry))
+		snd_info_set_text_ops(entry, ice, stac9460_proc_regs_read);
+}
+
+
 static int wtm_add_controls(struct snd_ice1712 *ice)
 {
 	unsigned int i;
@@ -458,46 +588,64 @@ static int wtm_add_controls(struct snd_ice1712 *ice)
 		if (err < 0)
 			return err;
 	}
+	stac9460_proc_init(ice);
 	return 0;
 }
 
 static int wtm_init(struct snd_ice1712 *ice)
 {
-	static unsigned short stac_inits_prodigy[] = {
+	static unsigned short stac_inits_wtm[] = {
 		STAC946X_RESET, 0,
+		STAC946X_MASTER_CLOCKING, 0x11,
 		(unsigned short)-1
 	};
 	unsigned short *p;
+	struct wtm_spec *spec;
+
 
 	/*WTM 192M*/
 	ice->num_total_dacs = 8;
 	ice->num_total_adcs = 4;
 	ice->force_rdma1 = 1;
+	ice->vt1720 = 0;  /* ice1724, e.g. 23 GPIOs */
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (!spec)
+		return -ENOMEM;
+	ice->spec = spec;
+	mutex_init(&spec->mute_mutex);
 
 	/*initialize codec*/
-	p = stac_inits_prodigy;
+	p = stac_inits_wtm;
 	for (; *p != (unsigned short)-1; p += 2) {
 		stac9460_put(ice, p[0], p[1]);
 		stac9460_2_put(ice, p[0], p[1]);
 	}
+	ice->gpio.set_pro_rate = stac9460_set_rate_val;
 	return 0;
 }
 
 
 static unsigned char wtm_eeprom[] = {
-	0x47,	/*SYSCONF: clock 192KHz, 4ADC, 8DAC */
-	0x80,	/* ACLINK : I2S */
-	0xf8,	/* I2S: vol; 96k, 24bit, 192k */
-	0xc1	/*SPDIF: out-en, spidf ext out*/,
-	0x9f,	/* GPIO_DIR */
-	0xff,	/* GPIO_DIR1 */
-	0x7f,	/* GPIO_DIR2 */
-	0x9f,	/* GPIO_MASK */
-	0xff,	/* GPIO_MASK1 */
-	0x7f,	/* GPIO_MASK2 */
-	0x16,	/* GPIO_STATE */
-	0x80,	/* GPIO_STATE1 */
-	0x00,	/* GPIO_STATE2 */
+	[ICE_EEP2_SYSCONF]     = 0x67,  /* 49MHz crystal, mpu401,
+					 * spdif-in+ 1 stereo ADC,
+					 * 4 stereo DACs
+					 */
+	[ICE_EEP2_ACLINK]      = 0x80,  /* I2S */
+	[ICE_EEP2_I2S]         = 0xf8,  /* vol, 96k, 24bit, 192k */
+	[ICE_EEP2_SPDIF]       = 0xc1,  /* out-en, out-int, spdif-in */
+	[ICE_EEP2_GPIO_DIR]    = 0x9f,
+	[ICE_EEP2_GPIO_DIR1]   = 0xff,
+	[ICE_EEP2_GPIO_DIR2]   = 0x7f,
+	[ICE_EEP2_GPIO_MASK]   = 0x9f,
+	[ICE_EEP2_GPIO_MASK1]  = 0xff,
+	[ICE_EEP2_GPIO_MASK2]  = 0x7f,
+	[ICE_EEP2_GPIO_STATE]  = 0x16,
+	[ICE_EEP2_GPIO_STATE1] = 0x80,
+	[ICE_EEP2_GPIO_STATE2] = 0x00,  /* GPIO20: 0 = CD drive dig. input
+					 * passthrough,
+					 * 1 = SPDIF-OUT from ice1724
+					 */
 };
 
 
-- 
1.7.10.4



More information about the Alsa-devel mailing list