ALSA: ctxfi: Add support for Creative Titanium HD

Initialise model-specific DAC and ADC parts.
Add controls for output and mic source selection.
Rename some mixer controls according to ControlNames.txt.
Remove Playback switches for Line-in and IEC958-in - these
were controlling the input mute/unmute which affected
capture too.  Use the capture switches to control the
input mute/unmute instead - it's less confusing.
Initialise the WM8775 to invert the left-right clock
to swap the left and right channels of the mic and aux
input.

Signed-off-by: Harry Butterworth <heb1001@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
index c3519ff..388235c 100644
--- a/sound/pci/ctxfi/ctmixer.c
+++ b/sound/pci/ctxfi/ctmixer.c
@@ -86,9 +86,7 @@
 	MIXER_LINEIN_C_S,
 	MIXER_MIC_C_S,
 	MIXER_SPDIFI_C_S,
-	MIXER_LINEIN_P_S,
 	MIXER_SPDIFO_P_S,
-	MIXER_SPDIFI_P_S,
 	MIXER_WAVEF_P_S,
 	MIXER_WAVER_P_S,
 	MIXER_WAVEC_P_S,
@@ -137,11 +135,11 @@
 	},
 	[MIXER_LINEIN_P] = {
 		.ctl = 1,
-		.name = "Line-in Playback Volume",
+		.name = "Line Playback Volume",
 	},
 	[MIXER_LINEIN_C] = {
 		.ctl = 1,
-		.name = "Line-in Capture Volume",
+		.name = "Line Capture Volume",
 	},
 	[MIXER_MIC_P] = {
 		.ctl = 1,
@@ -153,15 +151,15 @@
 	},
 	[MIXER_SPDIFI_P] = {
 		.ctl = 1,
-		.name = "S/PDIF-in Playback Volume",
+		.name = "IEC958 Playback Volume",
 	},
 	[MIXER_SPDIFI_C] = {
 		.ctl = 1,
-		.name = "S/PDIF-in Capture Volume",
+		.name = "IEC958 Capture Volume",
 	},
 	[MIXER_SPDIFO_P] = {
 		.ctl = 1,
-		.name = "S/PDIF-out Playback Volume",
+		.name = "Digital Playback Volume",
 	},
 	[MIXER_WAVEF_P] = {
 		.ctl = 1,
@@ -179,14 +177,13 @@
 		.ctl = 1,
 		.name = "Surround Playback Volume",
 	},
-
 	[MIXER_PCM_C_S] = {
 		.ctl = 1,
 		.name = "PCM Capture Switch",
 	},
 	[MIXER_LINEIN_C_S] = {
 		.ctl = 1,
-		.name = "Line-in Capture Switch",
+		.name = "Line Capture Switch",
 	},
 	[MIXER_MIC_C_S] = {
 		.ctl = 1,
@@ -194,19 +191,11 @@
 	},
 	[MIXER_SPDIFI_C_S] = {
 		.ctl = 1,
-		.name = "S/PDIF-in Capture Switch",
-	},
-	[MIXER_LINEIN_P_S] = {
-		.ctl = 1,
-		.name = "Line-in Playback Switch",
+		.name = "IEC958 Capture Switch",
 	},
 	[MIXER_SPDIFO_P_S] = {
 		.ctl = 1,
-		.name = "S/PDIF-out Playback Switch",
-	},
-	[MIXER_SPDIFI_P_S] = {
-		.ctl = 1,
-		.name = "S/PDIF-in Playback Switch",
+		.name = "Digital Playback Switch",
 	},
 	[MIXER_WAVEF_P_S] = {
 		.ctl = 1,
@@ -236,6 +225,8 @@
 static void
 ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
 
+/* FIXME: this static looks like it would fail if more than one card was */
+/* installed. */
 static struct snd_kcontrol *kctls[2] = {NULL};
 
 static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)
@@ -420,6 +411,77 @@
 	.tlv		= { .p =  ct_vol_db_scale },
 };
 
+static int output_switch_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *info)
+{
+	static const char *const names[3] = {
+	  "FP Headphones", "Headphones", "Speakers"
+	};
+
+	return snd_ctl_enum_info(info, 1, 3, names);
+}
+
+static int output_switch_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.enumerated.item[0] = atc->output_switch_get(atc);
+	return 0;
+}
+
+static int output_switch_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	if (ucontrol->value.enumerated.item[0] > 2)
+		return -EINVAL;
+	return atc->output_switch_put(atc, ucontrol->value.enumerated.item[0]);
+}
+
+static struct snd_kcontrol_new output_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Analog Output Playback Enum",
+	.info = output_switch_info,
+	.get = output_switch_get,
+	.put = output_switch_put,
+};
+
+static int mic_source_switch_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *info)
+{
+	static const char *const names[3] = {
+	  "Mic", "FP Mic", "Aux"
+	};
+
+	return snd_ctl_enum_info(info, 1, 3, names);
+}
+
+static int mic_source_switch_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.enumerated.item[0] = atc->mic_source_switch_get(atc);
+	return 0;
+}
+
+static int mic_source_switch_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	if (ucontrol->value.enumerated.item[0] > 2)
+		return -EINVAL;
+	return atc->mic_source_switch_put(atc,
+					ucontrol->value.enumerated.item[0]);
+}
+
+static struct snd_kcontrol_new mic_source_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Mic Source Capture Enum",
+	.info = mic_source_switch_info,
+	.get = mic_source_switch_get,
+	.put = mic_source_switch_put,
+};
+
 static void
 do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type)
 {
@@ -465,6 +527,7 @@
 static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
 {
 	struct ct_mixer *mixer = atc->mixer;
+	int have_dedicated_mic = atc->have_dedicated_mic(atc);
 
 	/* Do changes in mixer. */
 	if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
@@ -477,8 +540,17 @@
 		}
 	}
 	/* Do changes out of mixer. */
-	if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
-		do_line_mic_switch(atc, type);
+	if (!have_dedicated_mic &&
+	    (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) {
+		if (state)
+			do_line_mic_switch(atc, type);
+		atc->line_in_unmute(atc, state);
+	} else if (have_dedicated_mic && (MIXER_LINEIN_C_S == type))
+		atc->line_in_unmute(atc, state);
+	else if (have_dedicated_mic && (MIXER_MIC_C_S == type))
+		atc->mic_unmute(atc, state);
+	else if (MIXER_SPDIFI_C_S == type)
+		atc->spdif_in_unmute(atc, state);
 	else if (MIXER_WAVEF_P_S == type)
 		atc->line_front_unmute(atc, state);
 	else if (MIXER_WAVES_P_S == type)
@@ -487,12 +559,8 @@
 		atc->line_clfe_unmute(atc, state);
 	else if (MIXER_WAVER_P_S == type)
 		atc->line_rear_unmute(atc, state);
-	else if (MIXER_LINEIN_P_S == type)
-		atc->line_in_unmute(atc, state);
 	else if (MIXER_SPDIFO_P_S == type)
 		atc->spdif_out_unmute(atc, state);
-	else if (MIXER_SPDIFI_P_S == type)
-		atc->spdif_in_unmute(atc, state);
 	else if (MIXER_DIGITAL_IO_S == type)
 		do_digit_io_switch(atc, state);
 
@@ -686,6 +754,7 @@
 
 	ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl =
 					atc->have_digit_io_switch(atc);
+
 	for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) {
 		if (ct_kcontrol_init_table[type].ctl) {
 			swh_ctl.name = ct_kcontrol_init_table[type].name;
@@ -708,6 +777,17 @@
 	if (err)
 		return err;
 
+	if (atc->have_output_switch(atc)) {
+		err = ct_mixer_kcontrol_new(mixer, &output_ctl);
+		if (err)
+			return err;
+	}
+
+	if (atc->have_mic_source_switch(atc)) {
+		err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl);
+		if (err)
+			return err;
+	}
 	atc->line_front_unmute(atc, 1);
 	set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
 	atc->line_surround_unmute(atc, 0);
@@ -719,13 +799,12 @@
 	atc->spdif_out_unmute(atc, 0);
 	set_switch_state(mixer, MIXER_SPDIFO_P_S, 0);
 	atc->line_in_unmute(atc, 0);
-	set_switch_state(mixer, MIXER_LINEIN_P_S, 0);
+	if (atc->have_dedicated_mic(atc))
+		atc->mic_unmute(atc, 0);
 	atc->spdif_in_unmute(atc, 0);
-	set_switch_state(mixer, MIXER_SPDIFI_P_S, 0);
-
-	set_switch_state(mixer, MIXER_PCM_C_S, 1);
-	set_switch_state(mixer, MIXER_LINEIN_C_S, 1);
-	set_switch_state(mixer, MIXER_SPDIFI_C_S, 1);
+	set_switch_state(mixer, MIXER_PCM_C_S, 0);
+	set_switch_state(mixer, MIXER_LINEIN_C_S, 0);
+	set_switch_state(mixer, MIXER_SPDIFI_C_S, 0);
 
 	return 0;
 }