Alsa-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868
@ 2011-05-30 13:22 Harry Butterworth
  2011-06-03 15:44 ` Takashi Iwai
  2011-06-05  4:35 ` Marshall DeBerry
  0 siblings, 2 replies; 11+ messages in thread
From: Harry Butterworth @ 2011-05-30 13:22 UTC (permalink / raw)
  To: Alsa-devel

[-- Attachment #1: Type: text/plain, Size: 1147 bytes --]

Hello folks,

    I bought an X-Fi Titanium HD thinking it would work with the ctxfi
driver but it is a new card and has a few differences from the earlier
cards.  Creative technical support have been quite helpful in
answering my questions.  This email is a heads-up to let you know that
I'm doing some work on the driver.

    I'm not finished yet.  In particular the PLL initialization still
does not work reliably, the capture source selection is a bit broken
and one of the ADC chips is being driven out-of-spec when the card is
run at 192kHz.

    I have attached the current state of my changes which are enough
to get the Titanium HD card working but the patch shouldn't be applied
because my hack at the PLL code and a couple of other bits may break
existing cards.  I have been working against the ALSA 1.0.24 release
so this is a patch against 1.0.24.

    I'm waiting for creative to answer my questions about the PLL
initialization and correct setup for 196kHz operation.  Once I get the
answers I'll try to fix the issues and submit a cleaner patch.

    Comments on the current version are welcome.

Harry

[-- Attachment #2: Titanium-HD --]
[-- Type: application/octet-stream, Size: 36520 bytes --]

diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/ct20k2reg.h
--- a/alsa-kernel/pci/ctxfi/ct20k2reg.h	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ct20k2reg.h	Mon May 30 20:29:07 2011 +0800
@@ -55,6 +55,7 @@
 /* GPIO Registers */
 #define GPIO_DATA           0x1B7020
 #define GPIO_CTRL           0x1B7024
+#define GPIO_EXT_DATA       0x1B70A0
 
 /* Virtual memory registers */
 #define VMEM_PTPAL          0x1C6300 /* 0x1C6300 + (16 * Chn) */
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/ctatc.c
--- a/alsa-kernel/pci/ctxfi/ctatc.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctatc.c	Mon May 30 20:29:07 2011 +0800
@@ -30,7 +30,6 @@
 #include <sound/asoundef.h>
 
 #define MONO_SUM_SCALE	0x19a8	/* 2^(-0.5) in 14-bit floating format */
-#define DAIONUM		7
 #define MAX_MULTI_CHN	8
 
 #define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \
@@ -53,6 +52,8 @@
 static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = {
 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760,
 		      "SB0760", CTSB0760),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270,
+		      "SB1270", CTSB1270),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801,
 		      "SB0880", CTSB0880),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802,
@@ -75,6 +76,7 @@
 	[CTSB0760]	= "SB076x",
 	[CTHENDRIX]	= "Hendrix",
 	[CTSB0880]	= "SB0880",
+	[CTSB1270]      = "SB1270",
 	[CT20K2_UNKNOWN] = "Unknown",
 };
 
@@ -459,12 +461,12 @@
 				apcm->substream->runtime->rate);
 	*n_srcc = 0;
 
-	if (1 == atc->msr) {
+	if (1 == atc->msr) { /* FIXME: do we really need SRC here if pitch==1 */
 		*n_srcc = apcm->substream->runtime->channels;
 		conf[0].pitch = pitch;
 		conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1;
 		conf[0].vo = 1;
-	} else if (2 == atc->msr) {
+	} else if (2 <= atc->msr) {
 		if (0x8000000 < pitch) {
 			/* Need two-stage SRCs, SRCIMPs and
 			 * AMIXERs for converting format */
@@ -977,6 +979,55 @@
 	return hw->have_digit_io_switch(hw);
 }
 
+static int atc_have_dedicated_mic(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->have_dedicated_mic(hw);
+}
+
+static int atc_have_output_switch(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->have_output_switch(hw);
+}
+
+static int atc_output_switch_get(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->output_switch_get(hw);
+}
+
+static int atc_output_switch_put(struct ct_atc *atc,int position)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->output_switch_put(hw,position);
+}
+
+static int atc_have_mic_source_switch(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->have_mic_source_switch(hw);
+}
+
+static int atc_mic_source_switch_get(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->mic_source_switch_get(hw);
+}
+
+static int atc_mic_source_switch_put(struct ct_atc *atc,int position)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->mic_source_switch_put(hw,position);
+}
+
 static int atc_select_digit_io(struct ct_atc *atc)
 {
 	struct hw *hw = atc->hw;
@@ -1045,6 +1096,11 @@
 	return atc_daio_unmute(atc, state, LINEIM);
 }
 
+static int atc_mic_unmute(struct ct_atc *atc, unsigned char state)
+{
+	return atc_daio_unmute(atc, state, MIC);
+}
+
 static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
 {
 	return atc_daio_unmute(atc, state, SPDIFOO);
@@ -1331,17 +1387,20 @@
 	struct srcimp_mgr *srcimp_mgr;
 	struct sum_desc sum_dsc = {0};
 	struct sum_mgr *sum_mgr;
-	int err, i;
+	int err, i, num_srcs, num_daios;
 
-	atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL);
+	num_daios = ( ( atc->model == CTSB1270 ) ? 8 : 7 );
+	num_srcs = ( ( atc->model == CTSB1270 ) ? 6 : 4 );
+
+	atc->daios = kzalloc(sizeof(void *)*num_daios, GFP_KERNEL);
 	if (!atc->daios)
 		return -ENOMEM;
 
-	atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+	atc->srcs = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL);
 	if (!atc->srcs)
 		return -ENOMEM;
 
-	atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+	atc->srcimps = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL);
 	if (!atc->srcimps)
 		return -ENOMEM;
 
@@ -1351,8 +1410,9 @@
 
 	daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
 	da_desc.msr = atc->msr;
-	for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) {
-		da_desc.type = i;
+	for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
+		da_desc.type = (atc->model != CTSB073X) ? i :
+			     ( ( i == SPDIFIO ) ? SPDIFI1 : i );
 		err = daio_mgr->get_daio(daio_mgr, &da_desc,
 					(struct daio **)&atc->daios[i]);
 		if (err) {
@@ -1362,23 +1422,12 @@
 		}
 		atc->n_daio++;
 	}
-	if (atc->model == CTSB073X)
-		da_desc.type = SPDIFI1;
-	else
-		da_desc.type = SPDIFIO;
-	err = daio_mgr->get_daio(daio_mgr, &da_desc,
-				(struct daio **)&atc->daios[i]);
-	if (err) {
-		printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n");
-		return err;
-	}
-	atc->n_daio++;
 
 	src_mgr = atc->rsc_mgrs[SRC];
 	src_dsc.multi = 1;
 	src_dsc.msr = atc->msr;
 	src_dsc.mode = ARCRW;
-	for (i = 0, atc->n_src = 0; i < (2*2); i++) {
+	for (i = 0, atc->n_src = 0; i < num_srcs; i++) {
 		err = src_mgr->get_src(src_mgr, &src_dsc,
 					(struct src **)&atc->srcs[i]);
 		if (err)
@@ -1388,8 +1437,8 @@
 	}
 
 	srcimp_mgr = atc->rsc_mgrs[SRCIMP];
-	srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */
-	for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) {
+	srcimp_dsc.msr = 8;
+	for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) {
 		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
 					(struct srcimp **)&atc->srcimps[i]);
 		if (err)
@@ -1397,15 +1446,6 @@
 
 		atc->n_srcimp++;
 	}
-	srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */
-	for (i = 0; i < (2*1); i++) {
-		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
-				(struct srcimp **)&atc->srcimps[2*1+i]);
-		if (err)
-			return err;
-
-		atc->n_srcimp++;
-	}
 
 	sum_mgr = atc->rsc_mgrs[SUM];
 	sum_dsc.msr = atc->msr;
@@ -1488,6 +1528,18 @@
 	src = atc->srcs[3];
 	mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
 
+	if(atc->model == CTSB1270){
+	        /* Titanium HD has a dedicated ADC for the Mic. */
+		dai = container_of(atc->daios[MIC], struct dai, daio);
+		atc_connect_dai(atc->rsc_mgrs[SRC], dai,
+			(struct src **)&atc->srcs[4],
+			(struct srcimp **)&atc->srcimps[4]);
+		src = atc->srcs[4];
+		mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc);
+		src = atc->srcs[5];
+		mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc);
+	}
+
 	dai = container_of(atc->daios[SPDIFIO], struct dai, daio);
 	atc_connect_dai(atc->rsc_mgrs[SRC], dai,
 			(struct src **)&atc->srcs[0],
@@ -1606,12 +1658,20 @@
 	.line_clfe_unmute = atc_line_clfe_unmute,
 	.line_rear_unmute = atc_line_rear_unmute,
 	.line_in_unmute = atc_line_in_unmute,
+	.mic_unmute = atc_mic_unmute,
 	.spdif_out_unmute = atc_spdif_out_unmute,
 	.spdif_in_unmute = atc_spdif_in_unmute,
 	.spdif_out_get_status = atc_spdif_out_get_status,
 	.spdif_out_set_status = atc_spdif_out_set_status,
 	.spdif_out_passthru = atc_spdif_out_passthru,
 	.have_digit_io_switch = atc_have_digit_io_switch,
+	.have_dedicated_mic = atc_have_dedicated_mic,
+	.have_output_switch = atc_have_output_switch,
+	.output_switch_get = atc_output_switch_get,
+	.output_switch_put = atc_output_switch_put,
+	.have_mic_source_switch = atc_have_mic_source_switch,
+	.mic_source_switch_get = atc_mic_source_switch_get,
+	.mic_source_switch_put = atc_mic_source_switch_put,
 #ifdef CONFIG_PM
 	.suspend = atc_suspend,
 	.resume = atc_resume,
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/ctatc.h
--- a/alsa-kernel/pci/ctxfi/ctatc.h	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctatc.h	Mon May 30 20:29:07 2011 +0800
@@ -115,12 +115,20 @@
 	int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
+	int (*mic_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
 	int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
 	int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
 	int (*have_digit_io_switch)(struct ct_atc *atc);
+	int (*have_dedicated_mic)(struct ct_atc *atc);
+	int (*have_output_switch)(struct ct_atc *atc);
+	int (*output_switch_get)(struct ct_atc *atc);
+	int (*output_switch_put)(struct ct_atc *atc,int position);
+	int (*have_mic_source_switch)(struct ct_atc *atc);
+	int (*mic_source_switch_get)(struct ct_atc *atc);
+	int (*mic_source_switch_put)(struct ct_atc *atc,int position);
 
 	/* Don't touch! Used for internal object. */
 	void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/ctdaio.c
--- a/alsa-kernel/pci/ctxfi/ctdaio.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctdaio.c	Mon May 30 20:29:07 2011 +0800
@@ -22,20 +22,9 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 
-#define DAIO_RESOURCE_NUM	NUM_DAIOTYP
 #define DAIO_OUT_MAX		SPDIFOO
 
-union daio_usage {
-	struct {
-		unsigned short lineo1:1;
-		unsigned short lineo2:1;
-		unsigned short lineo3:1;
-		unsigned short lineo4:1;
-		unsigned short spdifoo:1;
-		unsigned short lineim:1;
-		unsigned short spdifio:1;
-		unsigned short spdifi1:1;
-	} bf;
+struct daio_usage {
 	unsigned short data;
 };
 
@@ -61,6 +50,7 @@
 	[LINEO3] = {.left = 0x50, .right = 0x51},
 	[LINEO4] = {.left = 0x70, .right = 0x71},
 	[LINEIM] = {.left = 0x45, .right = 0xc5},
+	[MIC]	 = {.left = 0x55, .right = 0xd5},
 	[SPDIFOO] = {.left = 0x00, .right = 0x01},
 	[SPDIFIO] = {.left = 0x05, .right = 0x85},
 };
@@ -138,6 +128,7 @@
 		case LINEO3:	return 5;
 		case LINEO4:	return 6;
 		case LINEIM:	return 4;
+		case MIC:	return 5;
 		default:	return -EINVAL;
 		}
 	default:
@@ -517,17 +508,17 @@
 
 static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
 {
-	if (((union daio_usage *)mgr->rscs)->data & (0x1 << type))
+	if (((struct daio_usage *)mgr->rscs)->data & (0x1 << type))
 		return -ENOENT;
 
-	((union daio_usage *)mgr->rscs)->data |= (0x1 << type);
+	((struct daio_usage *)mgr->rscs)->data |= (0x1 << type);
 
 	return 0;
 }
 
 static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
 {
-	((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
+	((struct daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
 
 	return 0;
 }
@@ -710,7 +701,7 @@
 	if (!daio_mgr)
 		return -ENOMEM;
 
-	err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw);
+	err = rsc_mgr_init(&daio_mgr->mgr, DAIO, NUM_DAIOTYP, hw);
 	if (err)
 		goto error1;
 
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/ctdaio.h
--- a/alsa-kernel/pci/ctxfi/ctdaio.h	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctdaio.h	Mon May 30 20:29:07 2011 +0800
@@ -33,6 +33,7 @@
 	SPDIFOO,	/* S/PDIF Out (Flexijack/Optical) */
 	LINEIM,
 	SPDIFIO,	/* S/PDIF In (Flexijack/Optical) on the card */
+	MIC,		/* Dedicated mic on Titanium HD */
 	SPDIFI1,	/* S/PDIF In on internal Drive Bay */
 	NUM_DAIOTYP
 };
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/cthardware.h
--- a/alsa-kernel/pci/ctxfi/cthardware.h	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/cthardware.h	Mon May 30 20:29:07 2011 +0800
@@ -39,6 +39,7 @@
 	CT20K2_MODEL_FIRST = CTSB0760,
 	CTHENDRIX,
 	CTSB0880,
+	CTSB1270,
 	CT20K2_UNKNOWN,
 	NUM_CTCARDS		/* This should always be the last */
 };
@@ -71,6 +72,13 @@
 	int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
 	int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
 	int (*have_digit_io_switch)(struct hw *hw);
+	int (*have_dedicated_mic)(struct hw *hw);
+	int (*have_output_switch)(struct hw *hw);
+	int (*output_switch_get)(struct hw *hw);
+	int (*output_switch_put)(struct hw *hw,int position);
+	int (*have_mic_source_switch)(struct hw *hw);
+	int (*mic_source_switch_get)(struct hw *hw);
+	int (*mic_source_switch_put)(struct hw *hw,int position);
 
 	/* SRC operations */
 	int (*src_rsc_get_ctrl_blk)(void **rblk);
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/cthw20k1.c
--- a/alsa-kernel/pci/ctxfi/cthw20k1.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/cthw20k1.c	Mon May 30 20:29:07 2011 +0800
@@ -1783,6 +1783,21 @@
 	return !(hw->model == CTSB073X || hw->model == CTUAA);
 }
 
+static int hw_have_dedicated_mic(struct hw *hw)
+{
+	return 0;
+}
+
+static int hw_have_output_switch(struct hw *hw)
+{
+	return 0;
+}
+
+static int hw_have_mic_source_switch(struct hw *hw)
+{
+	return 0;
+}
+
 #define CTLBITS(a, b, c, d)	(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
 
 #define UAA_CFG_PWRSTATUS	0x44
@@ -2173,6 +2188,9 @@
 	.is_adc_source_selected = hw_is_adc_input_selected,
 	.select_adc_source = hw_adc_input_select,
 	.have_digit_io_switch = hw_have_digit_io_switch,
+	.have_dedicated_mic = hw_have_dedicated_mic,
+	.have_output_switch = hw_have_output_switch,
+	.have_mic_source_switch = hw_have_mic_source_switch,
 #ifdef CONFIG_PM
 	.suspend = hw_suspend,
 	.resume = hw_resume,
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/cthw20k2.c
--- a/alsa-kernel/pci/ctxfi/cthw20k2.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/cthw20k2.c	Mon May 30 20:29:07 2011 +0800
@@ -8,7 +8,7 @@
  * @File	cthw20k2.c
  *
  * @Brief
- * This file contains the implementation of hardware access methord for 20k2.
+ * This file contains the implementation of hardware access method for 20k2.
  *
  * @Author	Liu Chun
  * @Date 	May 14 2008
@@ -38,6 +38,8 @@
 	unsigned char dev_id;
 	unsigned char addr_size;
 	unsigned char data_size;
+
+        int mic_source;
 };
 
 static u32 hw_read_20kx(struct hw *hw, u32 reg);
@@ -1163,17 +1165,28 @@
 		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101);
 		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
 	} else if (2 == info->msr) {
-		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
-		/* Specify all playing 96khz
-		 * EA [0]	- Enabled
-		 * RTA [4:5]	- 96kHz
-		 * EB [8]	- Enabled
-		 * RTB [12:13]	- 96kHz
-		 * EC [16]	- Enabled
-		 * RTC [20:21]	- 96kHz
-		 * ED [24]	- Enabled
-		 * RTD [28:29]	- 96kHz */
-		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
+	        if(hw->model != CTSB1270){
+			hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
+			/* Specify all playing 96khz
+		 	 * EA [0]	- Enabled
+			 * RTA [4:5]	- 96kHz
+		 	 * EB [8]	- Enabled
+		 	 * RTB [12:13]	- 96kHz
+		 	 * EC [16]	- Enabled
+		 	 * RTC [20:21]	- 96kHz
+		 	 * ED [24]	- Enabled
+		 	 * RTD [28:29]	- 96kHz */
+			hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
+			hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+		} else {
+                        /* PCM4220 on Titanium HD is different HEB FIXME */
+			hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11011111);
+			hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
+			hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+		}
+	} else if ((4 == info->msr) && (hw->model == CTSB1270)) {
+		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111);
+		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
 		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
 	} else {
 		printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n");
@@ -1182,6 +1195,8 @@
 
 	for (i = 0; i < 8; i++) {
 		if (i <= 3) {
+			/* This comment looks wrong since loop is over 4  */
+			/* channels and emu20k2 supports 4 spdif IOs. HEB */
 			/* 1st 3 channels are SPDIFs (SB0960) */
 			if (i == 3)
 				data = 0x1001001;
@@ -1206,12 +1221,16 @@
 
 			hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B);
 		} else {
+			/* Again, loop is over 4 channels not 5. HEB */
 			/* Next 5 channels are I2S (SB0960) */
 			data = 0x11;
 			hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data);
 			if (2 == info->msr) {
 				/* Four channels per sample period */
 				data |= 0x1000;
+			} else if (4 == info->msr) {
+	                        /* FIXME: check this against the chip spec */
+				data |= 0x2000;
 			}
 			hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data);
 		}
@@ -1292,57 +1311,65 @@
 
 static int hw_pll_init(struct hw *hw, unsigned int rsr)
 {
+	/* The previous verion of this wasn't reliably initializing the */
+	/* PLL when the rsr was 44100.  It was overshooting to 48000.   */
+	/* I have increased the delay from 40ms to 100ms, changed the   */
+	/* initial frequency setting for 44100 to be a bit lower to try */
+	/* to avoid overshoot and put in a loop to retry the whole      */
+	/* procedure if it fails.                                       */
+
 	unsigned int pllenb;
 	unsigned int pllctl;
 	unsigned int pllstat;
-	int i;
-
-	pllenb = 0xB;
-	hw_write_20kx(hw, PLL_ENB, pllenb);
-	pllctl = 0x20D00000;
-	set_field(&pllctl, PLLCTL_FD, 16 - 4);
-	hw_write_20kx(hw, PLL_CTL, pllctl);
-	mdelay(40);
-	pllctl = hw_read_20kx(hw, PLL_CTL);
-	set_field(&pllctl, PLLCTL_B, 0);
-	if (48000 == rsr) {
-		set_field(&pllctl, PLLCTL_FD, 16 - 2);
-		set_field(&pllctl, PLLCTL_RD, 1 - 1);
-	} else { /* 44100 */
-		set_field(&pllctl, PLLCTL_FD, 147 - 2);
-		set_field(&pllctl, PLLCTL_RD, 10 - 1);
+	int i, ok;
+	for( i = 0, ok = 0; (i < 5) && !ok; i++ ){
+                /* Try disabling the pll first to see if that helps. */
+                pllenb = hw_read_20kx(hw, PLL_ENB);
+		hw_write_20kx(hw, PLL_ENB, (pllenb & (~0x07)));
+
+		pllctl = 0x20D00000;
+		if (48000 == rsr)
+		  set_field(&pllctl, PLLCTL_FD, 16 - 4);
+		else
+		  set_field(&pllctl, PLLCTL_FD, 15 - 4);
+		hw_write_20kx(hw, PLL_CTL, pllctl);
+
+                pllenb = 0xB;
+		hw_write_20kx(hw, PLL_ENB, pllenb);
+
+		mdelay(100);
+
+		pllctl = hw_read_20kx(hw, PLL_CTL);
+		set_field(&pllctl, PLLCTL_B, 0);
+		if (48000 == rsr) {
+		  set_field(&pllctl, PLLCTL_FD, 16 - 2);
+		  set_field(&pllctl, PLLCTL_RD, 1 - 1);
+		} else { /* 44100 */
+		  set_field(&pllctl, PLLCTL_FD, 147 - 2);
+		  set_field(&pllctl, PLLCTL_RD, 10 - 1);
+		}
+		hw_write_20kx(hw, PLL_CTL, pllctl);
+
+		mdelay(100);
+
+		pllstat = hw_read_20kx(hw, PLL_STAT);
+
+		ok = (!get_field(pllstat, PLLSTAT_PD)	&&
+ 	            (get_field(pllstat, PLLSTAT_B)   ==
+		     get_field(pllctl, PLLCTL_B))       &&
+		    (get_field(pllstat, PLLSTAT_CCS) ==
+		     get_field(pllctl, PLLCTL_SRC))     &&
+		    (get_field(pllstat, PLLSTAT_CRD) ==
+		     get_field(pllctl, PLLCTL_RD))      &&
+	            (get_field(pllstat, PLLSTAT_CFD) ==
+		     get_field(pllctl, PLLCTL_FD)));
 	}
-	hw_write_20kx(hw, PLL_CTL, pllctl);
-	mdelay(40);
-	for (i = 0; i < 1000; i++) {
-		pllstat = hw_read_20kx(hw, PLL_STAT);
-		if (get_field(pllstat, PLLSTAT_PD))
-			continue;
-
-		if (get_field(pllstat, PLLSTAT_B) !=
-					get_field(pllctl, PLLCTL_B))
-			continue;
-
-		if (get_field(pllstat, PLLSTAT_CCS) !=
-					get_field(pllctl, PLLCTL_SRC))
-			continue;
-
-		if (get_field(pllstat, PLLSTAT_CRD) !=
-					get_field(pllctl, PLLCTL_RD))
-			continue;
-
-		if (get_field(pllstat, PLLSTAT_CFD) !=
-					get_field(pllctl, PLLCTL_FD))
-			continue;
-
-		break;
-	}
-	if (i >= 1000) {
-		printk(KERN_ALERT "ctxfi: PLL initialization failed!!!\n");
-		return -EBUSY;
-	}
-
-	return 0;
+
+	if( !ok || ( i > 1 ))
+	        printk(KERN_ALERT "ctxfi: PLL init rsr:%d %d/%d OK.\n",
+				  rsr, ok, i );
+
+	return ok ? 0 : -EBUSY;
 }
 
 static int hw_auto_init(struct hw *hw)
@@ -1557,7 +1584,7 @@
 
 	hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
 	hw20k2_i2c_wait_data_ready(hw);
-	/* Dummy write to trigger the write oprtation */
+	/* Dummy write to trigger the write operation */
 	hw_write_20kx(hw, I2C_IF_WDATA, 0);
 	hw20k2_i2c_wait_data_ready(hw);
 
@@ -1568,6 +1595,32 @@
 	return 0;
 }
 
+static void hw_dac_stop(struct hw *hw)
+{
+        u32 data;
+
+        data = hw_read_20kx(hw, GPIO_DATA);
+	data &= 0xFFFFFFFD;
+	hw_write_20kx(hw, GPIO_DATA, data);
+	mdelay(10);
+}
+
+static void hw_dac_start(struct hw *hw)
+{
+        u32 data;
+
+        data = hw_read_20kx(hw, GPIO_DATA);
+	data |= 0x2;
+	hw_write_20kx(hw, GPIO_DATA, data);
+	mdelay(50);
+}
+
+static void hw_dac_reset(struct hw *hw)
+{
+        hw_dac_stop(hw);
+        hw_dac_start(hw);
+}
+
 static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
 {
 	int err;
@@ -1594,6 +1647,21 @@
 				   0x00000000   /* Vol Control B4 */
 				 };
 
+	if(hw->model == CTSB1270){
+                hw_dac_stop(hw);
+		data = hw_read_20kx(hw, GPIO_DATA);
+		data &= ~0x0600;
+		if (1 == info->msr)
+			data |= 0x0000; /* Single Speed Mode 0-50kHz */
+		else if (2 == info->msr)
+			data |= 0x0200; /* Double Speed Mode 50-100kHz */
+		else
+			data |= 0x0600; /* Quad Speed Mode 100-200kHz */
+		hw_write_20kx(hw, GPIO_DATA, data);
+                hw_dac_start(hw);
+		return 0;
+	}
+
 	/* Set DAC reset bit as output */
 	data = hw_read_20kx(hw, GPIO_CTRL);
 	data |= 0x02;
@@ -1606,23 +1674,8 @@
 	for (i = 0; i < 2; i++) {
 		/* Reset DAC twice just in-case the chip
 		 * didn't initialized properly */
-		data = hw_read_20kx(hw, GPIO_DATA);
-		/* GPIO data bit 1 */
-		data &= 0xFFFFFFFD;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(10);
-		data |= 0x2;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(50);
-
-		/* Reset the 2nd time */
-		data &= 0xFFFFFFFD;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(10);
-		data |= 0x2;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(50);
-
+                hw_dac_reset(hw);
+	        hw_dac_reset(hw);
 		if (hw20k2_i2c_read(hw, CS4382_MC1,  &cs_read.mode_control_1))
 			continue;
 
@@ -1725,7 +1778,11 @@
 static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
 {
 	u32 data;
-
+	if(hw->model == CTSB1270){
+	  /* Titanium HD has two ADC chips, one for line in and one for MIC.*/
+	  /* We don't need to switch the ADC input. */
+	  return 1;
+	}
 	data = hw_read_20kx(hw, GPIO_DATA);
 	switch (type) {
 	case ADC_MICIN:
@@ -1740,31 +1797,33 @@
 	return data;
 }
 
+static void hw_wm8775_input_select(struct hw *hw, u32 input, u32 gain)
+{
+        u32 adcmc = ((u32)1 << input) | 0x100; /* Link L+R gain... */
+
+        hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, adcmc),
+				MAKE_WM8775_DATA(adcmc));
+        hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, gain),
+				MAKE_WM8775_DATA(gain));
+        /* ...so there should be no need for the following. */
+        hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, gain),
+				MAKE_WM8775_DATA(gain));
+}
+
 static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
 {
 	u32 data;
-
 	data = hw_read_20kx(hw, GPIO_DATA);
 	switch (type) {
 	case ADC_MICIN:
 		data |= (0x1 << 14);
 		hw_write_20kx(hw, GPIO_DATA, data);
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
-				MAKE_WM8775_DATA(0x101)); /* Mic-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
-				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
-				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
+                hw_wm8775_input_select(hw,0,0xE7); /* Mic, 12dB */
 		break;
 	case ADC_LINEIN:
 		data &= ~(0x1 << 14);
 		hw_write_20kx(hw, GPIO_DATA, data);
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
-				MAKE_WM8775_DATA(0x102)); /* Line-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
+                hw_wm8775_input_select(hw,1,0xCF); /* Line-in, 0dB */
 		break;
 	default:
 		break;
@@ -1776,7 +1835,7 @@
 static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
 {
 	int err;
-	u32 mux = 2, data, ctl;
+	u32 data, ctl;
 
 	/*  Set ADC reset bit as output */
 	data = hw_read_20kx(hw, GPIO_CTRL);
@@ -1793,16 +1852,37 @@
 	/* Make ADC in normal operation */
 	data = hw_read_20kx(hw, GPIO_DATA);
 	data &= ~(0x1 << 15);
+	/* FIXME? This didn't actually do a reset! */
+	hw_write_20kx(hw, GPIO_DATA, data);
+
+	if(hw->model == CTSB1270){
+		/* Set up the PCM4220 ADC on Titanium HD */
+		data &= ~0x0C;
+		if (1 == info->msr)
+			data |= 0x00; /* Single Speed Mode 32-50kHz */
+		else if (2 == info->msr)
+			data |= 0x08; /* Double Speed Mode 50-108kHz */
+		else
+		 	data |= 0x04; /* Quad Speed Mode 108kHz-216kHz */
+		hw_write_20kx(hw, GPIO_DATA, data);
+	}
+
 	mdelay(10);
 	data |= (0x1 << 15);
 	hw_write_20kx(hw, GPIO_DATA, data);
 	mdelay(50);
 
+	/* HEB FIXME - break previous cards and not required anyway? */
+        hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_IC, 0x26),
+			 MAKE_WM8775_DATA(0x26));
+
 	/* Set the master mode (256fs) */
 	if (1 == info->msr) {
+		/* slave mode, 128x oversampling 256fs */
 		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02),
 						MAKE_WM8775_DATA(0x02));
-	} else if (2 == info->msr) {
+	} else if ((2 == info->msr) || (4 == info->msr)){
+		/* slave mode, 64x oversampling, 256fs */
 		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A),
 						MAKE_WM8775_DATA(0x0A));
 	} else {
@@ -1812,45 +1892,18 @@
 		goto error;
 	}
 
-	/* Configure GPIO bit 14 change to line-in/mic-in */
-	ctl = hw_read_20kx(hw, GPIO_CTRL);
-	ctl |= 0x1 << 14;
-	hw_write_20kx(hw, GPIO_CTRL, ctl);
-
-	/* Check using Mic-in or Line-in */
-	data = hw_read_20kx(hw, GPIO_DATA);
-
-	if (mux == 1) {
-		/* Configures GPIO data to select Mic-in */
-		data |= 0x1 << 14;
-		hw_write_20kx(hw, GPIO_DATA, data);
-
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
-				MAKE_WM8775_DATA(0x101)); /* Mic-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
-				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
-				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
-	} else if (mux == 2) {
-		/* Configures GPIO data to select Line-in */
-		data &= ~(0x1 << 14);
-		hw_write_20kx(hw, GPIO_DATA, data);
-
-		/* Setup ADC */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
-				MAKE_WM8775_DATA(0x102)); /* Line-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
+	if(hw->model != CTSB1270){
+		/* Configure GPIO bit 14 change to line-in/mic-in */
+		ctl = hw_read_20kx(hw, GPIO_CTRL);
+		ctl |= 0x1 << 14;
+		hw_write_20kx(hw, GPIO_CTRL, ctl);
+
+		hw_adc_input_select(hw, ADC_LINEIN);
 	} else {
-		printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n");
-		err = -EINVAL;
-		goto error;
+                hw_wm8775_input_select(hw, 0, 0xCF);
 	}
 
 	return 0;
-
 error:
 	hw20k2_i2c_uninit(hw);
 	return err;
@@ -1861,6 +1914,102 @@
 	return 0;
 }
 
+static int hw_have_dedicated_mic(struct hw *hw)
+{
+	return hw->model == CTSB1270;
+}
+
+static int hw_have_output_switch(struct hw *hw)
+{
+	return hw->model == CTSB1270;
+}
+
+static int hw_output_switch_get(struct hw *hw)
+{
+	u32 data = hw_read_20kx(hw, GPIO_EXT_DATA);
+
+	switch(data&0x30){
+	case 0x00:
+	     return 0;
+	case 0x10:
+	     return 1;
+	case 0x20:
+	     return 2;
+	default:
+	     return 3;
+	}
+}
+
+static int hw_output_switch_put(struct hw *hw,int position)
+{
+        u32 data;
+
+        if( position == hw_output_switch_get(hw) )
+	    return 0;
+
+	/* Mute line and headphones (intended for anti-pop). */
+        data = hw_read_20kx(hw, GPIO_DATA);
+	data |= (0x03 << 11);
+	hw_write_20kx(hw, GPIO_DATA, data);
+
+	data = hw_read_20kx(hw, GPIO_EXT_DATA) & ~0x30;
+	switch(position){
+	case 0:
+	        break;
+	case 1:
+	        data |= 0x10;
+	        break;
+	default:
+	        data |= 0x20;
+	}
+	hw_write_20kx(hw, GPIO_EXT_DATA, data);
+
+	/* Unmute line and headphones. */
+        data = hw_read_20kx(hw, GPIO_DATA);
+	data &= ~(0x03 << 11);
+	hw_write_20kx(hw, GPIO_DATA, data);
+
+	return 1;
+}
+
+static int hw_have_mic_source_switch(struct hw *hw)
+{
+	return hw->model == CTSB1270;
+}
+
+static int hw_mic_source_switch_get(struct hw *hw)
+{
+	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+
+        return hw20k2->mic_source;
+}
+
+static int hw_mic_source_switch_put(struct hw *hw,int position)
+{
+	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+
+        if( position == hw20k2->mic_source )
+	    return 0;
+
+	switch (position) {
+	case 0:
+                hw_wm8775_input_select(hw, 0, 0xCF); /* Mic, 0dB */
+		break;
+	case 1:
+	        hw_wm8775_input_select(hw, 1, 0xCF); /* FP Mic, 0dB */
+		break;
+	case 2:
+	        hw_wm8775_input_select(hw, 3, 0xCF); /* Aux Ext, 0dB */
+		break;
+	default:
+                return 0;
+	}
+
+        hw20k2->mic_source = position;
+
+	return 1;
+}
+
 static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id)
 {
 	struct hw *hw = dev_id;
@@ -2015,13 +2164,16 @@
 	/* Reset all SRC pending interrupts */
 	hw_write_20kx(hw, SRC_IP, 0);
 
-	/* TODO: detect the card ID and configure GPIO accordingly. */
-	/* Configures GPIO (0xD802 0x98028) */
-	/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
-	/* Configures GPIO (SB0880) */
-	/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
-	hw_write_20kx(hw, GPIO_CTRL, 0xD802);
-
+	if(hw->model != CTSB1270){
+		/* TODO: detect the card ID and configure GPIO accordingly. */
+		/* Configures GPIO (0xD802 0x98028) */
+		/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
+		/* Configures GPIO (SB0880) */
+		/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
+		hw_write_20kx(hw, GPIO_CTRL, 0xD802);
+	} else {
+		hw_write_20kx(hw, GPIO_CTRL, 0x9E5F);
+	}
 	/* Enable audio ring */
 	hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01);
 
@@ -2099,6 +2251,13 @@
 	.is_adc_source_selected = hw_is_adc_input_selected,
 	.select_adc_source = hw_adc_input_select,
 	.have_digit_io_switch = hw_have_digit_io_switch,
+	.have_dedicated_mic = hw_have_dedicated_mic,
+	.have_output_switch = hw_have_output_switch,
+	.output_switch_get = hw_output_switch_get,
+	.output_switch_put = hw_output_switch_put,
+	.have_mic_source_switch = hw_have_mic_source_switch,
+	.mic_source_switch_get = hw_mic_source_switch_get,
+	.mic_source_switch_put = hw_mic_source_switch_put,
 #ifdef CONFIG_PM
 	.suspend = hw_suspend,
 	.resume = hw_resume,
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/ctmixer.c
--- a/alsa-kernel/pci/ctxfi/ctmixer.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctmixer.c	Mon May 30 20:29:07 2011 +0800
@@ -179,7 +179,6 @@
 		.ctl = 1,
 		.name = "Surround Playback Volume",
 	},
-
 	[MIXER_PCM_C_S] = {
 		.ctl = 1,
 		.name = "PCM Capture Switch",
@@ -236,6 +235,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 +421,76 @@
 	.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", "Front 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)
 {
@@ -477,8 +548,15 @@
 		}
 	}
 	/* Do changes out of mixer. */
-	if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
-		do_line_mic_switch(atc, type);
+	if (!atc->have_dedicated_mic(atc) &&
+		state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
+	    do_line_mic_switch(atc, type);
+	else if (atc->have_dedicated_mic(atc) && (MIXER_LINEIN_C_S == type))
+	     	atc->line_in_unmute(atc, state);
+	else if (atc->have_dedicated_mic(atc) && (MIXER_MIC_C_S == type))
+	     	atc->mic_unmute(atc, state);
+	else if (atc->have_dedicated_mic(atc) && (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)
@@ -695,6 +773,11 @@
 
 	ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl =
 					atc->have_digit_io_switch(atc);
+	ct_kcontrol_init_table[MIXER_LINEIN_P_S].ctl =
+					!atc->have_dedicated_mic(atc);
+	ct_kcontrol_init_table[MIXER_SPDIFI_P_S].ctl =
+					!atc->have_dedicated_mic(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;
@@ -717,6 +800,14 @@
 	if (err)
 		return err;
 
+	if(atc->have_output_switch(atc))
+		if( (err = ct_mixer_kcontrol_new(mixer, &output_ctl)) )
+			return err;
+
+	if(atc->have_mic_source_switch(atc))
+		if( (err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl)) )
+			return err;
+
 	atc->line_front_unmute(atc, 1);
 	set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
 	atc->line_surround_unmute(atc, 0);
@@ -728,10 +819,13 @@
 	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))
+		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);
-
+	if(!atc->have_dedicated_mic(atc))
+		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);
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/xfi.c
--- a/alsa-kernel/pci/ctxfi/xfi.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/xfi.c	Mon May 30 20:29:07 2011 +0800
@@ -80,11 +80,11 @@
 		       "are 48000 and 44100, Value 48000 is assumed.\n");
 		reference_rate = 48000;
 	}
-	if ((multiple != 1) && (multiple != 2)) {
+	if ((multiple != 1) && (multiple != 2) && (multiple != 4)) {
 		printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n",
 		       multiple);
 		printk(KERN_ERR "ctxfi: The valid values for multiple are "
-		       "1 and 2, Value 2 is assumed.\n");
+		       "1, 2 and 4, Value 2 is assumed.\n");
 		multiple = 2;
 	}
 	err = ct_atc_create(card, pci, reference_rate, multiple,
diff -r 1cc948641567 -r cb1f8f63d000 include/pci_ids_compat.h.in
--- a/include/pci_ids_compat.h.in	Sun Apr 24 12:13:08 2011 +0800
+++ b/include/pci_ids_compat.h.in	Mon May 30 20:29:07 2011 +0800
@@ -314,6 +314,10 @@
 #define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX	0x6000
 #endif
 
+#ifndef PCI_SUBDEVICE_ID_CREATIVE_SB1270
+#define PCI_SUBDEVICE_ID_CREATIVE_SB1270 0x0062
+#endif
+
 /* ice1712 */
 #ifndef PCI_VENDOR_ID_ICE
 #define PCI_VENDOR_ID_ICE		0x1412

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868
       [not found] <BANLkTikkMNPZ02ZmPtrJSmSEWi8nkfXsag@mail.gmail.com>
@ 2011-06-03 12:26 ` Harry Butterworth
  0 siblings, 0 replies; 11+ messages in thread
From: Harry Butterworth @ 2011-06-03 12:26 UTC (permalink / raw)
  To: Alsa-devel

[-- Attachment #1: Type: text/plain, Size: 383 bytes --]

Here's a second version of this patch (against 1.0.24) which fixes the
input source selection and reverts the PLL hacks.

The PLL initialization for 44100Hz is still unreliable.  I'm posting
this so the Creative tech support can use it to debug the PLL init
code.

Still not to be applied - I'll do another version against the git
repository once we have the PLL init sorted.

Harry

[-- Attachment #2: Titanium-HD-0.2.patch --]
[-- Type: text/x-patch, Size: 35101 bytes --]

diff -r 1cc948641567 -r 3267ad0ba1d7 alsa-kernel/pci/ctxfi/ct20k2reg.h
--- a/alsa-kernel/pci/ctxfi/ct20k2reg.h	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ct20k2reg.h	Fri Jun 03 20:04:47 2011 +0800
@@ -55,6 +55,7 @@
 /* GPIO Registers */
 #define GPIO_DATA           0x1B7020
 #define GPIO_CTRL           0x1B7024
+#define GPIO_EXT_DATA       0x1B70A0
 
 /* Virtual memory registers */
 #define VMEM_PTPAL          0x1C6300 /* 0x1C6300 + (16 * Chn) */
diff -r 1cc948641567 -r 3267ad0ba1d7 alsa-kernel/pci/ctxfi/ctatc.c
--- a/alsa-kernel/pci/ctxfi/ctatc.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctatc.c	Fri Jun 03 20:04:47 2011 +0800
@@ -30,7 +30,6 @@
 #include <sound/asoundef.h>
 
 #define MONO_SUM_SCALE	0x19a8	/* 2^(-0.5) in 14-bit floating format */
-#define DAIONUM		7
 #define MAX_MULTI_CHN	8
 
 #define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \
@@ -53,6 +52,8 @@
 static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = {
 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760,
 		      "SB0760", CTSB0760),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270,
+		      "SB1270", CTSB1270),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801,
 		      "SB0880", CTSB0880),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802,
@@ -75,6 +76,7 @@
 	[CTSB0760]	= "SB076x",
 	[CTHENDRIX]	= "Hendrix",
 	[CTSB0880]	= "SB0880",
+	[CTSB1270]      = "SB1270",
 	[CT20K2_UNKNOWN] = "Unknown",
 };
 
@@ -459,12 +461,12 @@
 				apcm->substream->runtime->rate);
 	*n_srcc = 0;
 
-	if (1 == atc->msr) {
+	if (1 == atc->msr) { /* FIXME: do we really need SRC here if pitch==1 */
 		*n_srcc = apcm->substream->runtime->channels;
 		conf[0].pitch = pitch;
 		conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1;
 		conf[0].vo = 1;
-	} else if (2 == atc->msr) {
+	} else if (2 <= atc->msr) {
 		if (0x8000000 < pitch) {
 			/* Need two-stage SRCs, SRCIMPs and
 			 * AMIXERs for converting format */
@@ -977,6 +979,55 @@
 	return hw->have_digit_io_switch(hw);
 }
 
+static int atc_have_dedicated_mic(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->have_dedicated_mic(hw);
+}
+
+static int atc_have_output_switch(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->have_output_switch(hw);
+}
+
+static int atc_output_switch_get(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->output_switch_get(hw);
+}
+
+static int atc_output_switch_put(struct ct_atc *atc,int position)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->output_switch_put(hw,position);
+}
+
+static int atc_have_mic_source_switch(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->have_mic_source_switch(hw);
+}
+
+static int atc_mic_source_switch_get(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->mic_source_switch_get(hw);
+}
+
+static int atc_mic_source_switch_put(struct ct_atc *atc,int position)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->mic_source_switch_put(hw,position);
+}
+
 static int atc_select_digit_io(struct ct_atc *atc)
 {
 	struct hw *hw = atc->hw;
@@ -1045,6 +1096,11 @@
 	return atc_daio_unmute(atc, state, LINEIM);
 }
 
+static int atc_mic_unmute(struct ct_atc *atc, unsigned char state)
+{
+	return atc_daio_unmute(atc, state, MIC);
+}
+
 static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
 {
 	return atc_daio_unmute(atc, state, SPDIFOO);
@@ -1331,17 +1387,20 @@
 	struct srcimp_mgr *srcimp_mgr;
 	struct sum_desc sum_dsc = {0};
 	struct sum_mgr *sum_mgr;
-	int err, i;
+	int err, i, num_srcs, num_daios;
 
-	atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL);
+	num_daios = ( ( atc->model == CTSB1270 ) ? 8 : 7 );
+	num_srcs = ( ( atc->model == CTSB1270 ) ? 6 : 4 );
+
+	atc->daios = kzalloc(sizeof(void *)*num_daios, GFP_KERNEL);
 	if (!atc->daios)
 		return -ENOMEM;
 
-	atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+	atc->srcs = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL);
 	if (!atc->srcs)
 		return -ENOMEM;
 
-	atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+	atc->srcimps = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL);
 	if (!atc->srcimps)
 		return -ENOMEM;
 
@@ -1351,8 +1410,9 @@
 
 	daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
 	da_desc.msr = atc->msr;
-	for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) {
-		da_desc.type = i;
+	for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
+		da_desc.type = (atc->model != CTSB073X) ? i :
+			     ( ( i == SPDIFIO ) ? SPDIFI1 : i );
 		err = daio_mgr->get_daio(daio_mgr, &da_desc,
 					(struct daio **)&atc->daios[i]);
 		if (err) {
@@ -1362,23 +1422,12 @@
 		}
 		atc->n_daio++;
 	}
-	if (atc->model == CTSB073X)
-		da_desc.type = SPDIFI1;
-	else
-		da_desc.type = SPDIFIO;
-	err = daio_mgr->get_daio(daio_mgr, &da_desc,
-				(struct daio **)&atc->daios[i]);
-	if (err) {
-		printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n");
-		return err;
-	}
-	atc->n_daio++;
 
 	src_mgr = atc->rsc_mgrs[SRC];
 	src_dsc.multi = 1;
 	src_dsc.msr = atc->msr;
 	src_dsc.mode = ARCRW;
-	for (i = 0, atc->n_src = 0; i < (2*2); i++) {
+	for (i = 0, atc->n_src = 0; i < num_srcs; i++) {
 		err = src_mgr->get_src(src_mgr, &src_dsc,
 					(struct src **)&atc->srcs[i]);
 		if (err)
@@ -1388,8 +1437,8 @@
 	}
 
 	srcimp_mgr = atc->rsc_mgrs[SRCIMP];
-	srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */
-	for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) {
+	srcimp_dsc.msr = 8;
+	for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) {
 		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
 					(struct srcimp **)&atc->srcimps[i]);
 		if (err)
@@ -1397,15 +1446,6 @@
 
 		atc->n_srcimp++;
 	}
-	srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */
-	for (i = 0; i < (2*1); i++) {
-		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
-				(struct srcimp **)&atc->srcimps[2*1+i]);
-		if (err)
-			return err;
-
-		atc->n_srcimp++;
-	}
 
 	sum_mgr = atc->rsc_mgrs[SUM];
 	sum_dsc.msr = atc->msr;
@@ -1488,6 +1528,18 @@
 	src = atc->srcs[3];
 	mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
 
+	if(atc->model == CTSB1270){
+	        /* Titanium HD has a dedicated ADC for the Mic. */
+		dai = container_of(atc->daios[MIC], struct dai, daio);
+		atc_connect_dai(atc->rsc_mgrs[SRC], dai,
+			(struct src **)&atc->srcs[4],
+			(struct srcimp **)&atc->srcimps[4]);
+		src = atc->srcs[4];
+		mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc);
+		src = atc->srcs[5];
+		mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc);
+	}
+
 	dai = container_of(atc->daios[SPDIFIO], struct dai, daio);
 	atc_connect_dai(atc->rsc_mgrs[SRC], dai,
 			(struct src **)&atc->srcs[0],
@@ -1606,12 +1658,20 @@
 	.line_clfe_unmute = atc_line_clfe_unmute,
 	.line_rear_unmute = atc_line_rear_unmute,
 	.line_in_unmute = atc_line_in_unmute,
+	.mic_unmute = atc_mic_unmute,
 	.spdif_out_unmute = atc_spdif_out_unmute,
 	.spdif_in_unmute = atc_spdif_in_unmute,
 	.spdif_out_get_status = atc_spdif_out_get_status,
 	.spdif_out_set_status = atc_spdif_out_set_status,
 	.spdif_out_passthru = atc_spdif_out_passthru,
 	.have_digit_io_switch = atc_have_digit_io_switch,
+	.have_dedicated_mic = atc_have_dedicated_mic,
+	.have_output_switch = atc_have_output_switch,
+	.output_switch_get = atc_output_switch_get,
+	.output_switch_put = atc_output_switch_put,
+	.have_mic_source_switch = atc_have_mic_source_switch,
+	.mic_source_switch_get = atc_mic_source_switch_get,
+	.mic_source_switch_put = atc_mic_source_switch_put,
 #ifdef CONFIG_PM
 	.suspend = atc_suspend,
 	.resume = atc_resume,
diff -r 1cc948641567 -r 3267ad0ba1d7 alsa-kernel/pci/ctxfi/ctatc.h
--- a/alsa-kernel/pci/ctxfi/ctatc.h	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctatc.h	Fri Jun 03 20:04:47 2011 +0800
@@ -115,12 +115,20 @@
 	int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
+	int (*mic_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
 	int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
 	int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
 	int (*have_digit_io_switch)(struct ct_atc *atc);
+	int (*have_dedicated_mic)(struct ct_atc *atc);
+	int (*have_output_switch)(struct ct_atc *atc);
+	int (*output_switch_get)(struct ct_atc *atc);
+	int (*output_switch_put)(struct ct_atc *atc,int position);
+	int (*have_mic_source_switch)(struct ct_atc *atc);
+	int (*mic_source_switch_get)(struct ct_atc *atc);
+	int (*mic_source_switch_put)(struct ct_atc *atc,int position);
 
 	/* Don't touch! Used for internal object. */
 	void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */
diff -r 1cc948641567 -r 3267ad0ba1d7 alsa-kernel/pci/ctxfi/ctdaio.c
--- a/alsa-kernel/pci/ctxfi/ctdaio.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctdaio.c	Fri Jun 03 20:04:47 2011 +0800
@@ -22,20 +22,9 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 
-#define DAIO_RESOURCE_NUM	NUM_DAIOTYP
 #define DAIO_OUT_MAX		SPDIFOO
 
-union daio_usage {
-	struct {
-		unsigned short lineo1:1;
-		unsigned short lineo2:1;
-		unsigned short lineo3:1;
-		unsigned short lineo4:1;
-		unsigned short spdifoo:1;
-		unsigned short lineim:1;
-		unsigned short spdifio:1;
-		unsigned short spdifi1:1;
-	} bf;
+struct daio_usage {
 	unsigned short data;
 };
 
@@ -61,6 +50,7 @@
 	[LINEO3] = {.left = 0x50, .right = 0x51},
 	[LINEO4] = {.left = 0x70, .right = 0x71},
 	[LINEIM] = {.left = 0x45, .right = 0xc5},
+	[MIC]	 = {.left = 0x55, .right = 0xd5},
 	[SPDIFOO] = {.left = 0x00, .right = 0x01},
 	[SPDIFIO] = {.left = 0x05, .right = 0x85},
 };
@@ -138,6 +128,7 @@
 		case LINEO3:	return 5;
 		case LINEO4:	return 6;
 		case LINEIM:	return 4;
+		case MIC:	return 5;
 		default:	return -EINVAL;
 		}
 	default:
@@ -517,17 +508,17 @@
 
 static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
 {
-	if (((union daio_usage *)mgr->rscs)->data & (0x1 << type))
+	if (((struct daio_usage *)mgr->rscs)->data & (0x1 << type))
 		return -ENOENT;
 
-	((union daio_usage *)mgr->rscs)->data |= (0x1 << type);
+	((struct daio_usage *)mgr->rscs)->data |= (0x1 << type);
 
 	return 0;
 }
 
 static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
 {
-	((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
+	((struct daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
 
 	return 0;
 }
@@ -710,7 +701,7 @@
 	if (!daio_mgr)
 		return -ENOMEM;
 
-	err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw);
+	err = rsc_mgr_init(&daio_mgr->mgr, DAIO, NUM_DAIOTYP, hw);
 	if (err)
 		goto error1;
 
diff -r 1cc948641567 -r 3267ad0ba1d7 alsa-kernel/pci/ctxfi/ctdaio.h
--- a/alsa-kernel/pci/ctxfi/ctdaio.h	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctdaio.h	Fri Jun 03 20:04:47 2011 +0800
@@ -33,6 +33,7 @@
 	SPDIFOO,	/* S/PDIF Out (Flexijack/Optical) */
 	LINEIM,
 	SPDIFIO,	/* S/PDIF In (Flexijack/Optical) on the card */
+	MIC,		/* Dedicated mic on Titanium HD */
 	SPDIFI1,	/* S/PDIF In on internal Drive Bay */
 	NUM_DAIOTYP
 };
diff -r 1cc948641567 -r 3267ad0ba1d7 alsa-kernel/pci/ctxfi/cthardware.h
--- a/alsa-kernel/pci/ctxfi/cthardware.h	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/cthardware.h	Fri Jun 03 20:04:47 2011 +0800
@@ -39,6 +39,7 @@
 	CT20K2_MODEL_FIRST = CTSB0760,
 	CTHENDRIX,
 	CTSB0880,
+	CTSB1270,
 	CT20K2_UNKNOWN,
 	NUM_CTCARDS		/* This should always be the last */
 };
@@ -71,6 +72,13 @@
 	int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
 	int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
 	int (*have_digit_io_switch)(struct hw *hw);
+	int (*have_dedicated_mic)(struct hw *hw);
+	int (*have_output_switch)(struct hw *hw);
+	int (*output_switch_get)(struct hw *hw);
+	int (*output_switch_put)(struct hw *hw,int position);
+	int (*have_mic_source_switch)(struct hw *hw);
+	int (*mic_source_switch_get)(struct hw *hw);
+	int (*mic_source_switch_put)(struct hw *hw,int position);
 
 	/* SRC operations */
 	int (*src_rsc_get_ctrl_blk)(void **rblk);
diff -r 1cc948641567 -r 3267ad0ba1d7 alsa-kernel/pci/ctxfi/cthw20k1.c
--- a/alsa-kernel/pci/ctxfi/cthw20k1.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/cthw20k1.c	Fri Jun 03 20:04:47 2011 +0800
@@ -1783,6 +1783,21 @@
 	return !(hw->model == CTSB073X || hw->model == CTUAA);
 }
 
+static int hw_have_dedicated_mic(struct hw *hw)
+{
+	return 0;
+}
+
+static int hw_have_output_switch(struct hw *hw)
+{
+	return 0;
+}
+
+static int hw_have_mic_source_switch(struct hw *hw)
+{
+	return 0;
+}
+
 #define CTLBITS(a, b, c, d)	(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
 
 #define UAA_CFG_PWRSTATUS	0x44
@@ -2173,6 +2188,9 @@
 	.is_adc_source_selected = hw_is_adc_input_selected,
 	.select_adc_source = hw_adc_input_select,
 	.have_digit_io_switch = hw_have_digit_io_switch,
+	.have_dedicated_mic = hw_have_dedicated_mic,
+	.have_output_switch = hw_have_output_switch,
+	.have_mic_source_switch = hw_have_mic_source_switch,
 #ifdef CONFIG_PM
 	.suspend = hw_suspend,
 	.resume = hw_resume,
diff -r 1cc948641567 -r 3267ad0ba1d7 alsa-kernel/pci/ctxfi/cthw20k2.c
--- a/alsa-kernel/pci/ctxfi/cthw20k2.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/cthw20k2.c	Fri Jun 03 20:04:47 2011 +0800
@@ -8,7 +8,7 @@
  * @File	cthw20k2.c
  *
  * @Brief
- * This file contains the implementation of hardware access methord for 20k2.
+ * This file contains the implementation of hardware access method for 20k2.
  *
  * @Author	Liu Chun
  * @Date 	May 14 2008
@@ -38,6 +38,8 @@
 	unsigned char dev_id;
 	unsigned char addr_size;
 	unsigned char data_size;
+
+        int mic_source;
 };
 
 static u32 hw_read_20kx(struct hw *hw, u32 reg);
@@ -1163,17 +1165,28 @@
 		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101);
 		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
 	} else if (2 == info->msr) {
-		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
-		/* Specify all playing 96khz
-		 * EA [0]	- Enabled
-		 * RTA [4:5]	- 96kHz
-		 * EB [8]	- Enabled
-		 * RTB [12:13]	- 96kHz
-		 * EC [16]	- Enabled
-		 * RTC [20:21]	- 96kHz
-		 * ED [24]	- Enabled
-		 * RTD [28:29]	- 96kHz */
-		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
+	        if(hw->model != CTSB1270){
+			hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
+			/* Specify all playing 96khz
+		 	 * EA [0]	- Enabled
+			 * RTA [4:5]	- 96kHz
+		 	 * EB [8]	- Enabled
+		 	 * RTB [12:13]	- 96kHz
+		 	 * EC [16]	- Enabled
+		 	 * RTC [20:21]	- 96kHz
+		 	 * ED [24]	- Enabled
+		 	 * RTD [28:29]	- 96kHz */
+			hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
+			hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+		} else {
+                        /* PCM4220 on Titanium HD is different HEB FIXME */
+			hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11011111);
+			hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
+			hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+		}
+	} else if ((4 == info->msr) && (hw->model == CTSB1270)) {
+		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111);
+		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
 		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
 	} else {
 		printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n");
@@ -1182,6 +1195,8 @@
 
 	for (i = 0; i < 8; i++) {
 		if (i <= 3) {
+			/* This comment looks wrong since loop is over 4  */
+			/* channels and emu20k2 supports 4 spdif IOs. HEB */
 			/* 1st 3 channels are SPDIFs (SB0960) */
 			if (i == 3)
 				data = 0x1001001;
@@ -1206,12 +1221,16 @@
 
 			hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B);
 		} else {
+			/* Again, loop is over 4 channels not 5. HEB */
 			/* Next 5 channels are I2S (SB0960) */
 			data = 0x11;
 			hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data);
 			if (2 == info->msr) {
 				/* Four channels per sample period */
 				data |= 0x1000;
+			} else if (4 == info->msr) {
+	                        /* FIXME: check this against the chip spec */
+				data |= 0x2000;
 			}
 			hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data);
 		}
@@ -1557,7 +1576,7 @@
 
 	hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
 	hw20k2_i2c_wait_data_ready(hw);
-	/* Dummy write to trigger the write oprtation */
+	/* Dummy write to trigger the write operation */
 	hw_write_20kx(hw, I2C_IF_WDATA, 0);
 	hw20k2_i2c_wait_data_ready(hw);
 
@@ -1568,6 +1587,32 @@
 	return 0;
 }
 
+static void hw_dac_stop(struct hw *hw)
+{
+        u32 data;
+
+        data = hw_read_20kx(hw, GPIO_DATA);
+	data &= 0xFFFFFFFD;
+	hw_write_20kx(hw, GPIO_DATA, data);
+	mdelay(10);
+}
+
+static void hw_dac_start(struct hw *hw)
+{
+        u32 data;
+
+        data = hw_read_20kx(hw, GPIO_DATA);
+	data |= 0x2;
+	hw_write_20kx(hw, GPIO_DATA, data);
+	mdelay(50);
+}
+
+static void hw_dac_reset(struct hw *hw)
+{
+        hw_dac_stop(hw);
+        hw_dac_start(hw);
+}
+
 static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
 {
 	int err;
@@ -1594,6 +1639,21 @@
 				   0x00000000   /* Vol Control B4 */
 				 };
 
+	if(hw->model == CTSB1270){
+                hw_dac_stop(hw);
+		data = hw_read_20kx(hw, GPIO_DATA);
+		data &= ~0x0600;
+		if (1 == info->msr)
+			data |= 0x0000; /* Single Speed Mode 0-50kHz */
+		else if (2 == info->msr)
+			data |= 0x0200; /* Double Speed Mode 50-100kHz */
+		else
+			data |= 0x0600; /* Quad Speed Mode 100-200kHz */
+		hw_write_20kx(hw, GPIO_DATA, data);
+                hw_dac_start(hw);
+		return 0;
+	}
+
 	/* Set DAC reset bit as output */
 	data = hw_read_20kx(hw, GPIO_CTRL);
 	data |= 0x02;
@@ -1606,23 +1666,8 @@
 	for (i = 0; i < 2; i++) {
 		/* Reset DAC twice just in-case the chip
 		 * didn't initialized properly */
-		data = hw_read_20kx(hw, GPIO_DATA);
-		/* GPIO data bit 1 */
-		data &= 0xFFFFFFFD;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(10);
-		data |= 0x2;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(50);
-
-		/* Reset the 2nd time */
-		data &= 0xFFFFFFFD;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(10);
-		data |= 0x2;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(50);
-
+                hw_dac_reset(hw);
+	        hw_dac_reset(hw);
 		if (hw20k2_i2c_read(hw, CS4382_MC1,  &cs_read.mode_control_1))
 			continue;
 
@@ -1725,7 +1770,11 @@
 static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
 {
 	u32 data;
-
+	if(hw->model == CTSB1270){
+	  /* Titanium HD has two ADC chips, one for line in and one for MIC.*/
+	  /* We don't need to switch the ADC input. */
+	  return 1;
+	}
 	data = hw_read_20kx(hw, GPIO_DATA);
 	switch (type) {
 	case ADC_MICIN:
@@ -1740,31 +1789,33 @@
 	return data;
 }
 
+static void hw_wm8775_input_select(struct hw *hw, u32 input, u32 gain)
+{
+        u32 adcmc = ((u32)1 << input) | 0x100; /* Link L+R gain... */
+
+        hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, adcmc),
+				MAKE_WM8775_DATA(adcmc));
+        hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, gain),
+				MAKE_WM8775_DATA(gain));
+        /* ...so there should be no need for the following. */
+        hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, gain),
+				MAKE_WM8775_DATA(gain));
+}
+
 static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
 {
 	u32 data;
-
 	data = hw_read_20kx(hw, GPIO_DATA);
 	switch (type) {
 	case ADC_MICIN:
 		data |= (0x1 << 14);
 		hw_write_20kx(hw, GPIO_DATA, data);
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
-				MAKE_WM8775_DATA(0x101)); /* Mic-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
-				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
-				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
+                hw_wm8775_input_select(hw,0,0xE7); /* Mic, 12dB */
 		break;
 	case ADC_LINEIN:
 		data &= ~(0x1 << 14);
 		hw_write_20kx(hw, GPIO_DATA, data);
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
-				MAKE_WM8775_DATA(0x102)); /* Line-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
+                hw_wm8775_input_select(hw,1,0xCF); /* Line-in, 0dB */
 		break;
 	default:
 		break;
@@ -1776,7 +1827,7 @@
 static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
 {
 	int err;
-	u32 mux = 2, data, ctl;
+	u32 data, ctl;
 
 	/*  Set ADC reset bit as output */
 	data = hw_read_20kx(hw, GPIO_CTRL);
@@ -1793,16 +1844,37 @@
 	/* Make ADC in normal operation */
 	data = hw_read_20kx(hw, GPIO_DATA);
 	data &= ~(0x1 << 15);
+	/* FIXME? This didn't actually do a reset! */
+	hw_write_20kx(hw, GPIO_DATA, data);
+
+	if(hw->model == CTSB1270){
+		/* Set up the PCM4220 ADC on Titanium HD */
+		data &= ~0x0C;
+		if (1 == info->msr)
+			data |= 0x00; /* Single Speed Mode 32-50kHz */
+		else if (2 == info->msr)
+			data |= 0x08; /* Double Speed Mode 50-108kHz */
+		else
+		 	data |= 0x04; /* Quad Speed Mode 108kHz-216kHz */
+		hw_write_20kx(hw, GPIO_DATA, data);
+	}
+
 	mdelay(10);
 	data |= (0x1 << 15);
 	hw_write_20kx(hw, GPIO_DATA, data);
 	mdelay(50);
 
+	/* HEB FIXME - break previous cards and not required anyway? */
+        hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_IC, 0x26),
+			 MAKE_WM8775_DATA(0x26));
+
 	/* Set the master mode (256fs) */
 	if (1 == info->msr) {
+		/* slave mode, 128x oversampling 256fs */
 		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02),
 						MAKE_WM8775_DATA(0x02));
-	} else if (2 == info->msr) {
+	} else if ((2 == info->msr) || (4 == info->msr)){
+		/* slave mode, 64x oversampling, 256fs */
 		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A),
 						MAKE_WM8775_DATA(0x0A));
 	} else {
@@ -1812,45 +1884,18 @@
 		goto error;
 	}
 
-	/* Configure GPIO bit 14 change to line-in/mic-in */
-	ctl = hw_read_20kx(hw, GPIO_CTRL);
-	ctl |= 0x1 << 14;
-	hw_write_20kx(hw, GPIO_CTRL, ctl);
-
-	/* Check using Mic-in or Line-in */
-	data = hw_read_20kx(hw, GPIO_DATA);
-
-	if (mux == 1) {
-		/* Configures GPIO data to select Mic-in */
-		data |= 0x1 << 14;
-		hw_write_20kx(hw, GPIO_DATA, data);
-
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
-				MAKE_WM8775_DATA(0x101)); /* Mic-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
-				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
-				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
-	} else if (mux == 2) {
-		/* Configures GPIO data to select Line-in */
-		data &= ~(0x1 << 14);
-		hw_write_20kx(hw, GPIO_DATA, data);
-
-		/* Setup ADC */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
-				MAKE_WM8775_DATA(0x102)); /* Line-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
+	if(hw->model != CTSB1270){
+		/* Configure GPIO bit 14 change to line-in/mic-in */
+		ctl = hw_read_20kx(hw, GPIO_CTRL);
+		ctl |= 0x1 << 14;
+		hw_write_20kx(hw, GPIO_CTRL, ctl);
+
+		hw_adc_input_select(hw, ADC_LINEIN);
 	} else {
-		printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n");
-		err = -EINVAL;
-		goto error;
+                hw_wm8775_input_select(hw, 0, 0xCF);
 	}
 
 	return 0;
-
 error:
 	hw20k2_i2c_uninit(hw);
 	return err;
@@ -1861,6 +1906,102 @@
 	return 0;
 }
 
+static int hw_have_dedicated_mic(struct hw *hw)
+{
+	return hw->model == CTSB1270;
+}
+
+static int hw_have_output_switch(struct hw *hw)
+{
+	return hw->model == CTSB1270;
+}
+
+static int hw_output_switch_get(struct hw *hw)
+{
+	u32 data = hw_read_20kx(hw, GPIO_EXT_DATA);
+
+	switch(data&0x30){
+	case 0x00:
+	     return 0;
+	case 0x10:
+	     return 1;
+	case 0x20:
+	     return 2;
+	default:
+	     return 3;
+	}
+}
+
+static int hw_output_switch_put(struct hw *hw,int position)
+{
+        u32 data;
+
+        if( position == hw_output_switch_get(hw) )
+	    return 0;
+
+	/* Mute line and headphones (intended for anti-pop). */
+        data = hw_read_20kx(hw, GPIO_DATA);
+	data |= (0x03 << 11);
+	hw_write_20kx(hw, GPIO_DATA, data);
+
+	data = hw_read_20kx(hw, GPIO_EXT_DATA) & ~0x30;
+	switch(position){
+	case 0:
+	        break;
+	case 1:
+	        data |= 0x10;
+	        break;
+	default:
+	        data |= 0x20;
+	}
+	hw_write_20kx(hw, GPIO_EXT_DATA, data);
+
+	/* Unmute line and headphones. */
+        data = hw_read_20kx(hw, GPIO_DATA);
+	data &= ~(0x03 << 11);
+	hw_write_20kx(hw, GPIO_DATA, data);
+
+	return 1;
+}
+
+static int hw_have_mic_source_switch(struct hw *hw)
+{
+	return hw->model == CTSB1270;
+}
+
+static int hw_mic_source_switch_get(struct hw *hw)
+{
+	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+
+        return hw20k2->mic_source;
+}
+
+static int hw_mic_source_switch_put(struct hw *hw,int position)
+{
+	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+
+        if( position == hw20k2->mic_source )
+	    return 0;
+
+	switch (position) {
+	case 0:
+                hw_wm8775_input_select(hw, 0, 0xCF); /* Mic, 0dB */
+		break;
+	case 1:
+	        hw_wm8775_input_select(hw, 1, 0xCF); /* FP Mic, 0dB */
+		break;
+	case 2:
+	        hw_wm8775_input_select(hw, 3, 0xCF); /* Aux Ext, 0dB */
+		break;
+	default:
+                return 0;
+	}
+
+        hw20k2->mic_source = position;
+
+	return 1;
+}
+
 static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id)
 {
 	struct hw *hw = dev_id;
@@ -2015,13 +2156,16 @@
 	/* Reset all SRC pending interrupts */
 	hw_write_20kx(hw, SRC_IP, 0);
 
-	/* TODO: detect the card ID and configure GPIO accordingly. */
-	/* Configures GPIO (0xD802 0x98028) */
-	/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
-	/* Configures GPIO (SB0880) */
-	/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
-	hw_write_20kx(hw, GPIO_CTRL, 0xD802);
-
+	if(hw->model != CTSB1270){
+		/* TODO: detect the card ID and configure GPIO accordingly. */
+		/* Configures GPIO (0xD802 0x98028) */
+		/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
+		/* Configures GPIO (SB0880) */
+		/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
+		hw_write_20kx(hw, GPIO_CTRL, 0xD802);
+	} else {
+		hw_write_20kx(hw, GPIO_CTRL, 0x9E5F);
+	}
 	/* Enable audio ring */
 	hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01);
 
@@ -2099,6 +2243,13 @@
 	.is_adc_source_selected = hw_is_adc_input_selected,
 	.select_adc_source = hw_adc_input_select,
 	.have_digit_io_switch = hw_have_digit_io_switch,
+	.have_dedicated_mic = hw_have_dedicated_mic,
+	.have_output_switch = hw_have_output_switch,
+	.output_switch_get = hw_output_switch_get,
+	.output_switch_put = hw_output_switch_put,
+	.have_mic_source_switch = hw_have_mic_source_switch,
+	.mic_source_switch_get = hw_mic_source_switch_get,
+	.mic_source_switch_put = hw_mic_source_switch_put,
 #ifdef CONFIG_PM
 	.suspend = hw_suspend,
 	.resume = hw_resume,
diff -r 1cc948641567 -r 3267ad0ba1d7 alsa-kernel/pci/ctxfi/ctmixer.c
--- a/alsa-kernel/pci/ctxfi/ctmixer.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctmixer.c	Fri Jun 03 20:04:47 2011 +0800
@@ -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,76 @@
 	.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)
 {
@@ -477,8 +538,18 @@
 		}
 	}
 	/* Do changes out of mixer. */
-	if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
-		do_line_mic_switch(atc, type);
+	if (!atc->have_dedicated_mic(atc) &&
+	    (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 (atc->have_dedicated_mic(atc) && (MIXER_LINEIN_C_S == type))
+	     	atc->line_in_unmute(atc, state);
+	else if (atc->have_dedicated_mic(atc) && (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 +558,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);
 
@@ -695,6 +762,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;
@@ -717,6 +785,14 @@
 	if (err)
 		return err;
 
+	if(atc->have_output_switch(atc))
+		if( (err = ct_mixer_kcontrol_new(mixer, &output_ctl)) )
+			return err;
+
+	if(atc->have_mic_source_switch(atc))
+		if( (err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl)) )
+			return err;
+
 	atc->line_front_unmute(atc, 1);
 	set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
 	atc->line_surround_unmute(atc, 0);
@@ -728,13 +804,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;
 }
diff -r 1cc948641567 -r 3267ad0ba1d7 alsa-kernel/pci/ctxfi/xfi.c
--- a/alsa-kernel/pci/ctxfi/xfi.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/xfi.c	Fri Jun 03 20:04:47 2011 +0800
@@ -80,11 +80,11 @@
 		       "are 48000 and 44100, Value 48000 is assumed.\n");
 		reference_rate = 48000;
 	}
-	if ((multiple != 1) && (multiple != 2)) {
+	if ((multiple != 1) && (multiple != 2) && (multiple != 4)) {
 		printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n",
 		       multiple);
 		printk(KERN_ERR "ctxfi: The valid values for multiple are "
-		       "1 and 2, Value 2 is assumed.\n");
+		       "1, 2 and 4, Value 2 is assumed.\n");
 		multiple = 2;
 	}
 	err = ct_atc_create(card, pci, reference_rate, multiple,
diff -r 1cc948641567 -r 3267ad0ba1d7 include/pci_ids_compat.h.in
--- a/include/pci_ids_compat.h.in	Sun Apr 24 12:13:08 2011 +0800
+++ b/include/pci_ids_compat.h.in	Fri Jun 03 20:04:47 2011 +0800
@@ -314,6 +314,10 @@
 #define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX	0x6000
 #endif
 
+#ifndef PCI_SUBDEVICE_ID_CREATIVE_SB1270
+#define PCI_SUBDEVICE_ID_CREATIVE_SB1270 0x0062
+#endif
+
 /* ice1712 */
 #ifndef PCI_VENDOR_ID_ICE
 #define PCI_VENDOR_ID_ICE		0x1412

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868
  2011-05-30 13:22 Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868 Harry Butterworth
@ 2011-06-03 15:44 ` Takashi Iwai
  2011-06-11 10:35   ` Harry Butterworth
       [not found]   ` <BANLkTinovea9fE1Hxey83W+WAiYGBv600Q@mail.gmail.com>
  2011-06-05  4:35 ` Marshall DeBerry
  1 sibling, 2 replies; 11+ messages in thread
From: Takashi Iwai @ 2011-06-03 15:44 UTC (permalink / raw)
  To: Harry Butterworth; +Cc: Alsa-devel

At Mon, 30 May 2011 21:22:07 +0800,
Harry Butterworth wrote:
> 
> Hello folks,
> 
>     I bought an X-Fi Titanium HD thinking it would work with the ctxfi
> driver but it is a new card and has a few differences from the earlier
> cards.  Creative technical support have been quite helpful in
> answering my questions.  This email is a heads-up to let you know that
> I'm doing some work on the driver.
> 
>     I'm not finished yet.  In particular the PLL initialization still
> does not work reliably, the capture source selection is a bit broken
> and one of the ADC chips is being driven out-of-spec when the card is
> run at 192kHz.
> 
>     I have attached the current state of my changes which are enough
> to get the Titanium HD card working but the patch shouldn't be applied
> because my hack at the PLL code and a couple of other bits may break
> existing cards.  I have been working against the ALSA 1.0.24 release
> so this is a patch against 1.0.24.
> 
>     I'm waiting for creative to answer my questions about the PLL
> initialization and correct setup for 196kHz operation.  Once I get the
> answers I'll try to fix the issues and submit a cleaner patch.

Thanks for your work.  It's good to know that the model actually works
somehow indeed.

A few comment about the patch:

- Instead of adding have_dedicated_mic and have_output_switch
  callbacks in every place, I'd put some bit flags indicating the
  capabilities, and set at the initialization appropriately.
- A few easy coding-style issues; run scripts/checkpatch.pl and fix
  the errors appropriately.


thanks,

Takashi
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868
  2011-05-30 13:22 Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868 Harry Butterworth
  2011-06-03 15:44 ` Takashi Iwai
@ 2011-06-05  4:35 ` Marshall DeBerry
  1 sibling, 0 replies; 11+ messages in thread
From: Marshall DeBerry @ 2011-06-05  4:35 UTC (permalink / raw)
  To: alsa-devel

Harry Butterworth <heb1001 <at> gmail.com> writes:

> 
> Hello folks,
> 
>     I bought an X-Fi Titanium HD thinking it would work with the ctxfi
> driver but it is a new card and has a few differences from the earlier
> cards.  Creative technical support have been quite helpful in
> answering my questions.  This email is a heads-up to let you know that
> I'm doing some work on the driver.
> 
>     I'm not finished yet.  In particular the PLL initialization still
> does not work reliably, the capture source selection is a bit broken
> and one of the ADC chips is being driven out-of-spec when the card is
> run at 192kHz.
> 
>     I have attached the current state of my changes which are enough
> to get the Titanium HD card working but the patch shouldn't be applied
> because my hack at the PLL code and a couple of other bits may break
> existing cards.  I have been working against the ALSA 1.0.24 release
> so this is a patch against 1.0.24.
> 
>     I'm waiting for creative to answer my questions about the PLL
> initialization and correct setup for 196kHz operation.  Once I get the
> answers I'll try to fix the issues and submit a cleaner patch.
> 
>     Comments on the current version are welcome.
> 
> Harry
> 
> Attachment (Titanium-HD): application/octet-stream, 35 KiB

Hello,
  I just want to confirm that the patches you have submitted are working for me
under Fedora 15 64 bit.  Thank you very much for attacking this issue;  my music
sounds great so far with this driver in conjunction with the Titanium HD card. 
Please let me know if you would like me to test any additional changes you may
make with any future patches.
  Thanks again.




_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868
  2011-06-03 15:44 ` Takashi Iwai
@ 2011-06-11 10:35   ` Harry Butterworth
  2011-06-11 10:39     ` Harry Butterworth
       [not found]   ` <BANLkTinovea9fE1Hxey83W+WAiYGBv600Q@mail.gmail.com>
  1 sibling, 1 reply; 11+ messages in thread
From: Harry Butterworth @ 2011-06-11 10:35 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: Alsa-devel

[-- Attachment #1: Type: text/plain, Size: 1046 bytes --]

Hi,

   (2nd attempt at this email as the first went over alsa-devel's 60KB limit)

   I have redone the patch against today's git repositories.
Creative have not yet got back to me about the PLL initialization.
Perhaps we can fix that later.

   I have only put the PCI ID in the pci_ids_compat.h.in file.  Is it
going to be necessary to add the PCI device ID somewhere in the kernel
tree to avoid breaking the kernel build?

> A few comment about the patch:
>
> - Instead of adding have_dedicated_mic and have_output_switch
>  callbacks in every place, I'd put some bit flags indicating the
>  capabilities, and set at the initialization appropriately.

I will follow up with a second patch.

> - A few easy coding-style issues; run scripts/checkpatch.pl and fix
>  the errors appropriately.

checkpatch now reports no errors.

I've only tested these changes with my Titanium HD card.  I don't have
any of the other X-Fi cards so I couldn't do any regression testing.

If there's anything else I need to do, please let me know.

Thanks,

Harry

[-- Attachment #2: 0001-Add-PCI-device-ID-for-Creative-Titanium-HD-to-pci_id.patch --]
[-- Type: text/x-patch, Size: 746 bytes --]

From a93e31bec95a508544f9aea6aa9a635ece5d4db3 Mon Sep 17 00:00:00 2001
From: Harry Butterworth <heb1001@gmail.com>
Date: Mon, 6 Jun 2011 16:31:41 +0800
Subject: [PATCH - ALSA:ctxfi 1/1] Add PCI device ID for Creative Titanium HD to pci_ids_compat.h.

Signed-off-by: Harry Butterworth <heb1001@gmail.com>

diff --git a/include/pci_ids_compat.h.in b/include/pci_ids_compat.h.in
index c8a3a1b..67f4bec 100644
--- a/include/pci_ids_compat.h.in
+++ b/include/pci_ids_compat.h.in
@@ -314,6 +314,10 @@
 #define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX	0x6000
 #endif
 
+#ifndef PCI_SUBDEVICE_ID_CREATIVE_SB1270
+#define PCI_SUBDEVICE_ID_CREATIVE_SB1270 0x0062
+#endif
+
 /* ice1712 */
 #ifndef PCI_VENDOR_ID_ICE
 #define PCI_VENDOR_ID_ICE		0x1412
-- 
1.7.0.4


[-- Attachment #3: 0001-ALSA-ctxfi-Add-support-for-Creative-Titanium-HD.patch --]
[-- Type: text/x-patch, Size: 37519 bytes --]

From 5522eb159b18b3c77a561447898564d2ef658f4c Mon Sep 17 00:00:00 2001
From: Harry Butterworth <heb1001@gmail.com>
Date: Sat, 11 Jun 2011 16:02:06 +0800
Subject: [PATCH - ALSA:ctxfi 1/2] 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>

diff --git a/pci/ctxfi/ct20k2reg.h b/pci/ctxfi/ct20k2reg.h
index e0394e3..ca501ba 100644
--- a/pci/ctxfi/ct20k2reg.h
+++ b/pci/ctxfi/ct20k2reg.h
@@ -55,6 +55,7 @@
 /* GPIO Registers */
 #define GPIO_DATA           0x1B7020
 #define GPIO_CTRL           0x1B7024
+#define GPIO_EXT_DATA       0x1B70A0
 
 /* Virtual memory registers */
 #define VMEM_PTPAL          0x1C6300 /* 0x1C6300 + (16 * Chn) */
diff --git a/pci/ctxfi/ctatc.c b/pci/ctxfi/ctatc.c
index 13f33c0..952fd94 100644
--- a/pci/ctxfi/ctatc.c
+++ b/pci/ctxfi/ctatc.c
@@ -30,7 +30,6 @@
 #include <sound/asoundef.h>
 
 #define MONO_SUM_SCALE	0x19a8	/* 2^(-0.5) in 14-bit floating format */
-#define DAIONUM		7
 #define MAX_MULTI_CHN	8
 
 #define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \
@@ -53,6 +52,8 @@ static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = {
 static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = {
 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760,
 		      "SB0760", CTSB0760),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270,
+		      "SB1270", CTSB1270),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801,
 		      "SB0880", CTSB0880),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802,
@@ -75,6 +76,7 @@ static const char *ct_subsys_name[NUM_CTCARDS] = {
 	[CTSB0760]	= "SB076x",
 	[CTHENDRIX]	= "Hendrix",
 	[CTSB0880]	= "SB0880",
+	[CTSB1270]      = "SB1270",
 	[CT20K2_UNKNOWN] = "Unknown",
 };
 
@@ -459,12 +461,12 @@ static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm,
 				apcm->substream->runtime->rate);
 	*n_srcc = 0;
 
-	if (1 == atc->msr) {
+	if (1 == atc->msr) { /* FIXME: do we really need SRC here if pitch==1 */
 		*n_srcc = apcm->substream->runtime->channels;
 		conf[0].pitch = pitch;
 		conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1;
 		conf[0].vo = 1;
-	} else if (2 == atc->msr) {
+	} else if (2 <= atc->msr) {
 		if (0x8000000 < pitch) {
 			/* Need two-stage SRCs, SRCIMPs and
 			 * AMIXERs for converting format */
@@ -977,6 +979,55 @@ static int atc_have_digit_io_switch(struct ct_atc *atc)
 	return hw->have_digit_io_switch(hw);
 }
 
+static int atc_have_dedicated_mic(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->have_dedicated_mic(hw);
+}
+
+static int atc_have_output_switch(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->have_output_switch(hw);
+}
+
+static int atc_output_switch_get(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->output_switch_get(hw);
+}
+
+static int atc_output_switch_put(struct ct_atc *atc, int position)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->output_switch_put(hw, position);
+}
+
+static int atc_have_mic_source_switch(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->have_mic_source_switch(hw);
+}
+
+static int atc_mic_source_switch_get(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->mic_source_switch_get(hw);
+}
+
+static int atc_mic_source_switch_put(struct ct_atc *atc, int position)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->mic_source_switch_put(hw, position);
+}
+
 static int atc_select_digit_io(struct ct_atc *atc)
 {
 	struct hw *hw = atc->hw;
@@ -1045,6 +1096,11 @@ static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state)
 	return atc_daio_unmute(atc, state, LINEIM);
 }
 
+static int atc_mic_unmute(struct ct_atc *atc, unsigned char state)
+{
+	return atc_daio_unmute(atc, state, MIC);
+}
+
 static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
 {
 	return atc_daio_unmute(atc, state, SPDIFOO);
@@ -1331,17 +1387,20 @@ static int atc_get_resources(struct ct_atc *atc)
 	struct srcimp_mgr *srcimp_mgr;
 	struct sum_desc sum_dsc = {0};
 	struct sum_mgr *sum_mgr;
-	int err, i;
+	int err, i, num_srcs, num_daios;
+
+	num_daios = ((atc->model == CTSB1270) ? 8 : 7);
+	num_srcs = ((atc->model == CTSB1270) ? 6 : 4);
 
-	atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL);
+	atc->daios = kzalloc(sizeof(void *)*num_daios, GFP_KERNEL);
 	if (!atc->daios)
 		return -ENOMEM;
 
-	atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+	atc->srcs = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL);
 	if (!atc->srcs)
 		return -ENOMEM;
 
-	atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+	atc->srcimps = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL);
 	if (!atc->srcimps)
 		return -ENOMEM;
 
@@ -1351,8 +1410,9 @@ static int atc_get_resources(struct ct_atc *atc)
 
 	daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
 	da_desc.msr = atc->msr;
-	for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) {
-		da_desc.type = i;
+	for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
+		da_desc.type = (atc->model != CTSB073X) ? i :
+			     ((i == SPDIFIO) ? SPDIFI1 : i);
 		err = daio_mgr->get_daio(daio_mgr, &da_desc,
 					(struct daio **)&atc->daios[i]);
 		if (err) {
@@ -1362,23 +1422,12 @@ static int atc_get_resources(struct ct_atc *atc)
 		}
 		atc->n_daio++;
 	}
-	if (atc->model == CTSB073X)
-		da_desc.type = SPDIFI1;
-	else
-		da_desc.type = SPDIFIO;
-	err = daio_mgr->get_daio(daio_mgr, &da_desc,
-				(struct daio **)&atc->daios[i]);
-	if (err) {
-		printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n");
-		return err;
-	}
-	atc->n_daio++;
 
 	src_mgr = atc->rsc_mgrs[SRC];
 	src_dsc.multi = 1;
 	src_dsc.msr = atc->msr;
 	src_dsc.mode = ARCRW;
-	for (i = 0, atc->n_src = 0; i < (2*2); i++) {
+	for (i = 0, atc->n_src = 0; i < num_srcs; i++) {
 		err = src_mgr->get_src(src_mgr, &src_dsc,
 					(struct src **)&atc->srcs[i]);
 		if (err)
@@ -1388,8 +1437,8 @@ static int atc_get_resources(struct ct_atc *atc)
 	}
 
 	srcimp_mgr = atc->rsc_mgrs[SRCIMP];
-	srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */
-	for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) {
+	srcimp_dsc.msr = 8;
+	for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) {
 		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
 					(struct srcimp **)&atc->srcimps[i]);
 		if (err)
@@ -1397,15 +1446,6 @@ static int atc_get_resources(struct ct_atc *atc)
 
 		atc->n_srcimp++;
 	}
-	srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */
-	for (i = 0; i < (2*1); i++) {
-		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
-				(struct srcimp **)&atc->srcimps[2*1+i]);
-		if (err)
-			return err;
-
-		atc->n_srcimp++;
-	}
 
 	sum_mgr = atc->rsc_mgrs[SUM];
 	sum_dsc.msr = atc->msr;
@@ -1488,6 +1528,18 @@ static void atc_connect_resources(struct ct_atc *atc)
 	src = atc->srcs[3];
 	mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
 
+	if (atc->model == CTSB1270) {
+		/* Titanium HD has a dedicated ADC for the Mic. */
+		dai = container_of(atc->daios[MIC], struct dai, daio);
+		atc_connect_dai(atc->rsc_mgrs[SRC], dai,
+			(struct src **)&atc->srcs[4],
+			(struct srcimp **)&atc->srcimps[4]);
+		src = atc->srcs[4];
+		mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc);
+		src = atc->srcs[5];
+		mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc);
+	}
+
 	dai = container_of(atc->daios[SPDIFIO], struct dai, daio);
 	atc_connect_dai(atc->rsc_mgrs[SRC], dai,
 			(struct src **)&atc->srcs[0],
@@ -1606,12 +1658,20 @@ static struct ct_atc atc_preset __devinitdata = {
 	.line_clfe_unmute = atc_line_clfe_unmute,
 	.line_rear_unmute = atc_line_rear_unmute,
 	.line_in_unmute = atc_line_in_unmute,
+	.mic_unmute = atc_mic_unmute,
 	.spdif_out_unmute = atc_spdif_out_unmute,
 	.spdif_in_unmute = atc_spdif_in_unmute,
 	.spdif_out_get_status = atc_spdif_out_get_status,
 	.spdif_out_set_status = atc_spdif_out_set_status,
 	.spdif_out_passthru = atc_spdif_out_passthru,
 	.have_digit_io_switch = atc_have_digit_io_switch,
+	.have_dedicated_mic = atc_have_dedicated_mic,
+	.have_output_switch = atc_have_output_switch,
+	.output_switch_get = atc_output_switch_get,
+	.output_switch_put = atc_output_switch_put,
+	.have_mic_source_switch = atc_have_mic_source_switch,
+	.mic_source_switch_get = atc_mic_source_switch_get,
+	.mic_source_switch_put = atc_mic_source_switch_put,
 #ifdef CONFIG_PM
 	.suspend = atc_suspend,
 	.resume = atc_resume,
diff --git a/pci/ctxfi/ctatc.h b/pci/ctxfi/ctatc.h
index 7167c01..6bad27e 100644
--- a/pci/ctxfi/ctatc.h
+++ b/pci/ctxfi/ctatc.h
@@ -115,12 +115,20 @@ struct ct_atc {
 	int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
+	int (*mic_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
 	int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
 	int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
 	int (*have_digit_io_switch)(struct ct_atc *atc);
+	int (*have_dedicated_mic)(struct ct_atc *atc);
+	int (*have_output_switch)(struct ct_atc *atc);
+	int (*output_switch_get)(struct ct_atc *atc);
+	int (*output_switch_put)(struct ct_atc *atc, int position);
+	int (*have_mic_source_switch)(struct ct_atc *atc);
+	int (*mic_source_switch_get)(struct ct_atc *atc);
+	int (*mic_source_switch_put)(struct ct_atc *atc, int position);
 
 	/* Don't touch! Used for internal object. */
 	void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */
diff --git a/pci/ctxfi/ctdaio.c b/pci/ctxfi/ctdaio.c
index 47d9ea9..0c00eb4 100644
--- a/pci/ctxfi/ctdaio.c
+++ b/pci/ctxfi/ctdaio.c
@@ -22,20 +22,9 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 
-#define DAIO_RESOURCE_NUM	NUM_DAIOTYP
 #define DAIO_OUT_MAX		SPDIFOO
 
-union daio_usage {
-	struct {
-		unsigned short lineo1:1;
-		unsigned short lineo2:1;
-		unsigned short lineo3:1;
-		unsigned short lineo4:1;
-		unsigned short spdifoo:1;
-		unsigned short lineim:1;
-		unsigned short spdifio:1;
-		unsigned short spdifi1:1;
-	} bf;
+struct daio_usage {
 	unsigned short data;
 };
 
@@ -61,6 +50,7 @@ struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
 	[LINEO3] = {.left = 0x50, .right = 0x51},
 	[LINEO4] = {.left = 0x70, .right = 0x71},
 	[LINEIM] = {.left = 0x45, .right = 0xc5},
+	[MIC]	 = {.left = 0x55, .right = 0xd5},
 	[SPDIFOO] = {.left = 0x00, .right = 0x01},
 	[SPDIFIO] = {.left = 0x05, .right = 0x85},
 };
@@ -138,6 +128,7 @@ static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
 		case LINEO3:	return 5;
 		case LINEO4:	return 6;
 		case LINEIM:	return 4;
+		case MIC:	return 5;
 		default:	return -EINVAL;
 		}
 	default:
@@ -519,17 +510,17 @@ static int dai_rsc_uninit(struct dai *dai)
 
 static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
 {
-	if (((union daio_usage *)mgr->rscs)->data & (0x1 << type))
+	if (((struct daio_usage *)mgr->rscs)->data & (0x1 << type))
 		return -ENOENT;
 
-	((union daio_usage *)mgr->rscs)->data |= (0x1 << type);
+	((struct daio_usage *)mgr->rscs)->data |= (0x1 << type);
 
 	return 0;
 }
 
 static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
 {
-	((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
+	((struct daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
 
 	return 0;
 }
@@ -712,7 +703,7 @@ int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr)
 	if (!daio_mgr)
 		return -ENOMEM;
 
-	err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw);
+	err = rsc_mgr_init(&daio_mgr->mgr, DAIO, NUM_DAIOTYP, hw);
 	if (err)
 		goto error1;
 
diff --git a/pci/ctxfi/ctdaio.h b/pci/ctxfi/ctdaio.h
index 0f52ce5..85ccb6e 100644
--- a/pci/ctxfi/ctdaio.h
+++ b/pci/ctxfi/ctdaio.h
@@ -33,6 +33,7 @@ enum DAIOTYP {
 	SPDIFOO,	/* S/PDIF Out (Flexijack/Optical) */
 	LINEIM,
 	SPDIFIO,	/* S/PDIF In (Flexijack/Optical) on the card */
+	MIC,		/* Dedicated mic on Titanium HD */
 	SPDIFI1,	/* S/PDIF In on internal Drive Bay */
 	NUM_DAIOTYP
 };
diff --git a/pci/ctxfi/cthardware.h b/pci/ctxfi/cthardware.h
index af55405..de59bbf 100644
--- a/pci/ctxfi/cthardware.h
+++ b/pci/ctxfi/cthardware.h
@@ -39,6 +39,7 @@ enum CTCARDS {
 	CT20K2_MODEL_FIRST = CTSB0760,
 	CTHENDRIX,
 	CTSB0880,
+	CTSB1270,
 	CT20K2_UNKNOWN,
 	NUM_CTCARDS		/* This should always be the last */
 };
@@ -71,6 +72,13 @@ struct hw {
 	int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
 	int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
 	int (*have_digit_io_switch)(struct hw *hw);
+	int (*have_dedicated_mic)(struct hw *hw);
+	int (*have_output_switch)(struct hw *hw);
+	int (*output_switch_get)(struct hw *hw);
+	int (*output_switch_put)(struct hw *hw, int position);
+	int (*have_mic_source_switch)(struct hw *hw);
+	int (*mic_source_switch_get)(struct hw *hw);
+	int (*mic_source_switch_put)(struct hw *hw, int position);
 
 	/* SRC operations */
 	int (*src_rsc_get_ctrl_blk)(void **rblk);
diff --git a/pci/ctxfi/cthw20k1.c b/pci/ctxfi/cthw20k1.c
index a5c957d..9a85a84 100644
--- a/pci/ctxfi/cthw20k1.c
+++ b/pci/ctxfi/cthw20k1.c
@@ -1783,6 +1783,21 @@ static int hw_have_digit_io_switch(struct hw *hw)
 	return !(hw->model == CTSB073X || hw->model == CTUAA);
 }
 
+static int hw_have_dedicated_mic(struct hw *hw)
+{
+	return 0;
+}
+
+static int hw_have_output_switch(struct hw *hw)
+{
+	return 0;
+}
+
+static int hw_have_mic_source_switch(struct hw *hw)
+{
+	return 0;
+}
+
 #define CTLBITS(a, b, c, d)	(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
 
 #define UAA_CFG_PWRSTATUS	0x44
@@ -2173,6 +2188,9 @@ static struct hw ct20k1_preset __devinitdata = {
 	.is_adc_source_selected = hw_is_adc_input_selected,
 	.select_adc_source = hw_adc_input_select,
 	.have_digit_io_switch = hw_have_digit_io_switch,
+	.have_dedicated_mic = hw_have_dedicated_mic,
+	.have_output_switch = hw_have_output_switch,
+	.have_mic_source_switch = hw_have_mic_source_switch,
 #ifdef CONFIG_PM
 	.suspend = hw_suspend,
 	.resume = hw_resume,
diff --git a/pci/ctxfi/cthw20k2.c b/pci/ctxfi/cthw20k2.c
index 5364164..8bc6e41 100644
--- a/pci/ctxfi/cthw20k2.c
+++ b/pci/ctxfi/cthw20k2.c
@@ -8,7 +8,7 @@
  * @File	cthw20k2.c
  *
  * @Brief
- * This file contains the implementation of hardware access methord for 20k2.
+ * This file contains the implementation of hardware access method for 20k2.
  *
  * @Author	Liu Chun
  * @Date 	May 14 2008
@@ -38,6 +38,8 @@ struct hw20k2 {
 	unsigned char dev_id;
 	unsigned char addr_size;
 	unsigned char data_size;
+
+	int mic_source;
 };
 
 static u32 hw_read_20kx(struct hw *hw, u32 reg);
@@ -1163,7 +1165,12 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
 		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101);
 		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
 	} else if (2 == info->msr) {
-		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
+		if (hw->model != CTSB1270) {
+			hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
+		} else {
+			/* PCM4220 on Titanium HD is different. */
+			hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11011111);
+		}
 		/* Specify all playing 96khz
 		 * EA [0]	- Enabled
 		 * RTA [4:5]	- 96kHz
@@ -1175,6 +1182,10 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
 		 * RTD [28:29]	- 96kHz */
 		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
 		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+	} else if ((4 == info->msr) && (hw->model == CTSB1270)) {
+		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111);
+		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
+		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
 	} else {
 		printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n");
 		return -EINVAL;
@@ -1182,6 +1193,8 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
 
 	for (i = 0; i < 8; i++) {
 		if (i <= 3) {
+			/* This comment looks wrong since loop is over 4  */
+			/* channels and emu20k2 supports 4 spdif IOs.     */
 			/* 1st 3 channels are SPDIFs (SB0960) */
 			if (i == 3)
 				data = 0x1001001;
@@ -1206,12 +1219,16 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
 
 			hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B);
 		} else {
+			/* Again, loop is over 4 channels not 5. */
 			/* Next 5 channels are I2S (SB0960) */
 			data = 0x11;
 			hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data);
 			if (2 == info->msr) {
 				/* Four channels per sample period */
 				data |= 0x1000;
+			} else if (4 == info->msr) {
+				/* FIXME: check this against the chip spec */
+				data |= 0x2000;
 			}
 			hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data);
 		}
@@ -1557,7 +1574,7 @@ static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data)
 
 	hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
 	hw20k2_i2c_wait_data_ready(hw);
-	/* Dummy write to trigger the write oprtation */
+	/* Dummy write to trigger the write operation */
 	hw_write_20kx(hw, I2C_IF_WDATA, 0);
 	hw20k2_i2c_wait_data_ready(hw);
 
@@ -1568,6 +1585,30 @@ static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data)
 	return 0;
 }
 
+static void hw_dac_stop(struct hw *hw)
+{
+	u32 data;
+	data = hw_read_20kx(hw, GPIO_DATA);
+	data &= 0xFFFFFFFD;
+	hw_write_20kx(hw, GPIO_DATA, data);
+	mdelay(10);
+}
+
+static void hw_dac_start(struct hw *hw)
+{
+	u32 data;
+	data = hw_read_20kx(hw, GPIO_DATA);
+	data |= 0x2;
+	hw_write_20kx(hw, GPIO_DATA, data);
+	mdelay(50);
+}
+
+static void hw_dac_reset(struct hw *hw)
+{
+	hw_dac_stop(hw);
+	hw_dac_start(hw);
+}
+
 static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
 {
 	int err;
@@ -1594,6 +1635,21 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
 				   0x00000000   /* Vol Control B4 */
 				 };
 
+	if (hw->model == CTSB1270) {
+		hw_dac_stop(hw);
+		data = hw_read_20kx(hw, GPIO_DATA);
+		data &= ~0x0600;
+		if (1 == info->msr)
+			data |= 0x0000; /* Single Speed Mode 0-50kHz */
+		else if (2 == info->msr)
+			data |= 0x0200; /* Double Speed Mode 50-100kHz */
+		else
+			data |= 0x0600; /* Quad Speed Mode 100-200kHz */
+		hw_write_20kx(hw, GPIO_DATA, data);
+		hw_dac_start(hw);
+		return 0;
+	}
+
 	/* Set DAC reset bit as output */
 	data = hw_read_20kx(hw, GPIO_CTRL);
 	data |= 0x02;
@@ -1606,22 +1662,8 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
 	for (i = 0; i < 2; i++) {
 		/* Reset DAC twice just in-case the chip
 		 * didn't initialized properly */
-		data = hw_read_20kx(hw, GPIO_DATA);
-		/* GPIO data bit 1 */
-		data &= 0xFFFFFFFD;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(10);
-		data |= 0x2;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(50);
-
-		/* Reset the 2nd time */
-		data &= 0xFFFFFFFD;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(10);
-		data |= 0x2;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(50);
+		hw_dac_reset(hw);
+		hw_dac_reset(hw);
 
 		if (hw20k2_i2c_read(hw, CS4382_MC1,  &cs_read.mode_control_1))
 			continue;
@@ -1725,7 +1767,11 @@ End:
 static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
 {
 	u32 data;
-
+	if (hw->model == CTSB1270) {
+		/* Titanium HD has two ADC chips, one for line in and one */
+		/* for MIC. We don't need to switch the ADC input. */
+		return 1;
+	}
 	data = hw_read_20kx(hw, GPIO_DATA);
 	switch (type) {
 	case ADC_MICIN:
@@ -1742,35 +1788,47 @@ static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
 
 #define MIC_BOOST_0DB 0xCF
 #define MIC_BOOST_STEPS_PER_DB 2
-#define MIC_BOOST_20DB (MIC_BOOST_0DB + 20 * MIC_BOOST_STEPS_PER_DB)
+
+static void hw_wm8775_input_select(struct hw *hw, u8 input, s8 gain_in_db)
+{
+	u32 adcmc, gain;
+
+	if (input > 3)
+		input = 3;
+
+	adcmc = ((u32)1 << input) | 0x100; /* Link L+R gain... */
+
+	hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, adcmc),
+				MAKE_WM8775_DATA(adcmc));
+
+	if (gain_in_db < -103)
+		gain_in_db = -103;
+	if (gain_in_db > 24)
+		gain_in_db = 24;
+
+	gain = gain_in_db * MIC_BOOST_STEPS_PER_DB + MIC_BOOST_0DB;
+
+	hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, gain),
+				MAKE_WM8775_DATA(gain));
+	/* ...so there should be no need for the following. */
+	hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, gain),
+				MAKE_WM8775_DATA(gain));
+}
 
 static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
 {
 	u32 data;
-
 	data = hw_read_20kx(hw, GPIO_DATA);
 	switch (type) {
 	case ADC_MICIN:
 		data |= (0x1 << 14);
 		hw_write_20kx(hw, GPIO_DATA, data);
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
-				MAKE_WM8775_DATA(0x101)); /* Mic-in */
-		hw20k2_i2c_write(hw,
-				MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB),
-				MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
-		hw20k2_i2c_write(hw,
-				MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB),
-				MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
+		hw_wm8775_input_select(hw, 0, 20); /* Mic, 20dB */
 		break;
 	case ADC_LINEIN:
 		data &= ~(0x1 << 14);
 		hw_write_20kx(hw, GPIO_DATA, data);
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
-				MAKE_WM8775_DATA(0x102)); /* Line-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
+		hw_wm8775_input_select(hw, 1, 0); /* Line-in, 0dB */
 		break;
 	default:
 		break;
@@ -1782,7 +1840,7 @@ static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
 static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
 {
 	int err;
-	u32 mux = 2, data, ctl;
+	u32 data, ctl;
 
 	/*  Set ADC reset bit as output */
 	data = hw_read_20kx(hw, GPIO_CTRL);
@@ -1796,19 +1854,42 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
 		goto error;
 	}
 
-	/* Make ADC in normal operation */
+	/* Reset the ADC (reset is active low). */
 	data = hw_read_20kx(hw, GPIO_DATA);
 	data &= ~(0x1 << 15);
+	hw_write_20kx(hw, GPIO_DATA, data);
+
+	if (hw->model == CTSB1270) {
+		/* Set up the PCM4220 ADC on Titanium HD */
+		data &= ~0x0C;
+		if (1 == info->msr)
+			data |= 0x00; /* Single Speed Mode 32-50kHz */
+		else if (2 == info->msr)
+			data |= 0x08; /* Double Speed Mode 50-108kHz */
+		else
+			data |= 0x04; /* Quad Speed Mode 108kHz-216kHz */
+		hw_write_20kx(hw, GPIO_DATA, data);
+	}
+
 	mdelay(10);
+	/* Return the ADC to normal operation. */
 	data |= (0x1 << 15);
 	hw_write_20kx(hw, GPIO_DATA, data);
 	mdelay(50);
 
+	/* I2C write to register offset 0x0B to set ADC LRCLK polarity */
+	/* invert bit, interface format to I2S, word length to 24-bit, */
+	/* enable ADC high pass filter. Fixes bug 5323?		*/
+	hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_IC, 0x26),
+			 MAKE_WM8775_DATA(0x26));
+
 	/* Set the master mode (256fs) */
 	if (1 == info->msr) {
+		/* slave mode, 128x oversampling 256fs */
 		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02),
 						MAKE_WM8775_DATA(0x02));
-	} else if (2 == info->msr) {
+	} else if ((2 == info->msr) || (4 == info->msr)) {
+		/* slave mode, 64x oversampling, 256fs */
 		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A),
 						MAKE_WM8775_DATA(0x0A));
 	} else {
@@ -1818,47 +1899,17 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
 		goto error;
 	}
 
-	/* Configure GPIO bit 14 change to line-in/mic-in */
-	ctl = hw_read_20kx(hw, GPIO_CTRL);
-	ctl |= 0x1 << 14;
-	hw_write_20kx(hw, GPIO_CTRL, ctl);
-
-	/* Check using Mic-in or Line-in */
-	data = hw_read_20kx(hw, GPIO_DATA);
-
-	if (mux == 1) {
-		/* Configures GPIO data to select Mic-in */
-		data |= 0x1 << 14;
-		hw_write_20kx(hw, GPIO_DATA, data);
-
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
-				MAKE_WM8775_DATA(0x101)); /* Mic-in */
-		hw20k2_i2c_write(hw,
-				MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB),
-				MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
-		hw20k2_i2c_write(hw,
-				MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB),
-				MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
-	} else if (mux == 2) {
-		/* Configures GPIO data to select Line-in */
-		data &= ~(0x1 << 14);
-		hw_write_20kx(hw, GPIO_DATA, data);
-
-		/* Setup ADC */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
-				MAKE_WM8775_DATA(0x102)); /* Line-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
+	if (hw->model != CTSB1270) {
+		/* Configure GPIO bit 14 change to line-in/mic-in */
+		ctl = hw_read_20kx(hw, GPIO_CTRL);
+		ctl |= 0x1 << 14;
+		hw_write_20kx(hw, GPIO_CTRL, ctl);
+		hw_adc_input_select(hw, ADC_LINEIN);
 	} else {
-		printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n");
-		err = -EINVAL;
-		goto error;
+		hw_wm8775_input_select(hw, 0, 0);
 	}
 
 	return 0;
-
 error:
 	hw20k2_i2c_uninit(hw);
 	return err;
@@ -1869,6 +1920,102 @@ static int hw_have_digit_io_switch(struct hw *hw)
 	return 0;
 }
 
+static int hw_have_dedicated_mic(struct hw *hw)
+{
+	return hw->model == CTSB1270;
+}
+
+static int hw_have_output_switch(struct hw *hw)
+{
+	return hw->model == CTSB1270;
+}
+
+static int hw_output_switch_get(struct hw *hw)
+{
+	u32 data = hw_read_20kx(hw, GPIO_EXT_DATA);
+
+	switch (data & 0x30) {
+	case 0x00:
+	     return 0;
+	case 0x10:
+	     return 1;
+	case 0x20:
+	     return 2;
+	default:
+	     return 3;
+	}
+}
+
+static int hw_output_switch_put(struct hw *hw, int position)
+{
+	u32 data;
+
+	if (position == hw_output_switch_get(hw))
+		return 0;
+
+	/* Mute line and headphones (intended for anti-pop). */
+	data = hw_read_20kx(hw, GPIO_DATA);
+	data |= (0x03 << 11);
+	hw_write_20kx(hw, GPIO_DATA, data);
+
+	data = hw_read_20kx(hw, GPIO_EXT_DATA) & ~0x30;
+	switch (position) {
+	case 0:
+		break;
+	case 1:
+		data |= 0x10;
+		break;
+	default:
+		data |= 0x20;
+	}
+	hw_write_20kx(hw, GPIO_EXT_DATA, data);
+
+	/* Unmute line and headphones. */
+	data = hw_read_20kx(hw, GPIO_DATA);
+	data &= ~(0x03 << 11);
+	hw_write_20kx(hw, GPIO_DATA, data);
+
+	return 1;
+}
+
+static int hw_have_mic_source_switch(struct hw *hw)
+{
+	return hw->model == CTSB1270;
+}
+
+static int hw_mic_source_switch_get(struct hw *hw)
+{
+	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+
+	return hw20k2->mic_source;
+}
+
+static int hw_mic_source_switch_put(struct hw *hw, int position)
+{
+	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+
+	if (position == hw20k2->mic_source)
+		return 0;
+
+	switch (position) {
+	case 0:
+		hw_wm8775_input_select(hw, 0, 0); /* Mic, 0dB */
+		break;
+	case 1:
+		hw_wm8775_input_select(hw, 1, 0); /* FP Mic, 0dB */
+		break;
+	case 2:
+		hw_wm8775_input_select(hw, 3, 0); /* Aux Ext, 0dB */
+		break;
+	default:
+		return 0;
+	}
+
+	hw20k2->mic_source = position;
+
+	return 1;
+}
+
 static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id)
 {
 	struct hw *hw = dev_id;
@@ -2023,13 +2170,16 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
 	/* Reset all SRC pending interrupts */
 	hw_write_20kx(hw, SRC_IP, 0);
 
-	/* TODO: detect the card ID and configure GPIO accordingly. */
-	/* Configures GPIO (0xD802 0x98028) */
-	/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
-	/* Configures GPIO (SB0880) */
-	/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
-	hw_write_20kx(hw, GPIO_CTRL, 0xD802);
-
+	if (hw->model != CTSB1270) {
+		/* TODO: detect the card ID and configure GPIO accordingly. */
+		/* Configures GPIO (0xD802 0x98028) */
+		/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
+		/* Configures GPIO (SB0880) */
+		/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
+		hw_write_20kx(hw, GPIO_CTRL, 0xD802);
+	} else {
+		hw_write_20kx(hw, GPIO_CTRL, 0x9E5F);
+	}
 	/* Enable audio ring */
 	hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01);
 
@@ -2107,6 +2257,13 @@ static struct hw ct20k2_preset __devinitdata = {
 	.is_adc_source_selected = hw_is_adc_input_selected,
 	.select_adc_source = hw_adc_input_select,
 	.have_digit_io_switch = hw_have_digit_io_switch,
+	.have_dedicated_mic = hw_have_dedicated_mic,
+	.have_output_switch = hw_have_output_switch,
+	.output_switch_get = hw_output_switch_get,
+	.output_switch_put = hw_output_switch_put,
+	.have_mic_source_switch = hw_have_mic_source_switch,
+	.mic_source_switch_get = hw_mic_source_switch_get,
+	.mic_source_switch_put = hw_mic_source_switch_put,
 #ifdef CONFIG_PM
 	.suspend = hw_suspend,
 	.resume = hw_resume,
diff --git a/pci/ctxfi/ctmixer.c b/pci/ctxfi/ctmixer.c
index c3519ff..388235c 100644
--- a/pci/ctxfi/ctmixer.c
+++ b/pci/ctxfi/ctmixer.c
@@ -86,9 +86,7 @@ enum CTALSA_MIXER_CTL {
 	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 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
 	},
 	[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 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
 	},
 	[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 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
 		.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 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
 	},
 	[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 @@ ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
 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 @@ static struct snd_kcontrol_new vol_ctl = {
 	.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 @@ do_digit_io_switch(struct ct_atc *atc, int state)
 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 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
 		}
 	}
 	/* 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 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
 		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 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
 
 	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 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
 	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 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
 	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;
 }
diff --git a/pci/ctxfi/xfi.c b/pci/ctxfi/xfi.c
index f42e7e1..7afa765 100644
--- a/pci/ctxfi/xfi.c
+++ b/pci/ctxfi/xfi.c
@@ -80,11 +80,11 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 		       "are 48000 and 44100, Value 48000 is assumed.\n");
 		reference_rate = 48000;
 	}
-	if ((multiple != 1) && (multiple != 2)) {
+	if ((multiple != 1) && (multiple != 2) && (multiple != 4)) {
 		printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n",
 		       multiple);
 		printk(KERN_ERR "ctxfi: The valid values for multiple are "
-		       "1 and 2, Value 2 is assumed.\n");
+		       "1, 2 and 4, Value 2 is assumed.\n");
 		multiple = 2;
 	}
 	err = ct_atc_create(card, pci, reference_rate, multiple,
-- 
1.7.0.4


[-- Attachment #4: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868
  2011-06-11 10:35   ` Harry Butterworth
@ 2011-06-11 10:39     ` Harry Butterworth
  0 siblings, 0 replies; 11+ messages in thread
From: Harry Butterworth @ 2011-06-11 10:39 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: Alsa-devel

[-- Attachment #1: Type: text/plain, Size: 308 bytes --]

>> A few comment about the patch:
>>
>> - Instead of adding have_dedicated_mic and have_output_switch
>>  callbacks in every place, I'd put some bit flags indicating the
>>  capabilities, and set at the initialization appropriately.
>
> I will follow up with a second patch.

Here's the second patch.

Harry

[-- Attachment #2: 0002-ALSA-ctxfi-Implement-a-combined-capabilities-query.patch --]
[-- Type: text/x-patch, Size: 10469 bytes --]

From efd33778d7183bb7a2d7630c6e57c30af8c27dd0 Mon Sep 17 00:00:00 2001
From: Harry Butterworth <heb1001@gmail.com>
Date: Sat, 11 Jun 2011 17:41:13 +0800
Subject: [PATCH - ALSA:ctxfi 2/2] ALSA: ctxfi: Implement a combined capabilities query
 method to replace multiple have_x query methods.

Signed-off-by: Harry Butterworth <heb1001@gmail.com>

diff --git a/pci/ctxfi/ctatc.c b/pci/ctxfi/ctatc.c
index 952fd94..d8a4423 100644
--- a/pci/ctxfi/ctatc.c
+++ b/pci/ctxfi/ctatc.c
@@ -18,7 +18,6 @@
 #include "ctatc.h"
 #include "ctpcm.h"
 #include "ctmixer.h"
-#include "cthardware.h"
 #include "ctsrc.h"
 #include "ctamixer.h"
 #include "ctdaio.h"
@@ -972,25 +971,11 @@ static int atc_select_mic_in(struct ct_atc *atc)
 	return 0;
 }
 
-static int atc_have_digit_io_switch(struct ct_atc *atc)
+static struct capabilities atc_capabilities(struct ct_atc *atc)
 {
 	struct hw *hw = atc->hw;
 
-	return hw->have_digit_io_switch(hw);
-}
-
-static int atc_have_dedicated_mic(struct ct_atc *atc)
-{
-	struct hw *hw = atc->hw;
-
-	return hw->have_dedicated_mic(hw);
-}
-
-static int atc_have_output_switch(struct ct_atc *atc)
-{
-	struct hw *hw = atc->hw;
-
-	return hw->have_output_switch(hw);
+	return hw->capabilities(hw);
 }
 
 static int atc_output_switch_get(struct ct_atc *atc)
@@ -1007,13 +992,6 @@ static int atc_output_switch_put(struct ct_atc *atc, int position)
 	return hw->output_switch_put(hw, position);
 }
 
-static int atc_have_mic_source_switch(struct ct_atc *atc)
-{
-	struct hw *hw = atc->hw;
-
-	return hw->have_mic_source_switch(hw);
-}
-
 static int atc_mic_source_switch_get(struct ct_atc *atc)
 {
 	struct hw *hw = atc->hw;
@@ -1664,12 +1642,9 @@ static struct ct_atc atc_preset __devinitdata = {
 	.spdif_out_get_status = atc_spdif_out_get_status,
 	.spdif_out_set_status = atc_spdif_out_set_status,
 	.spdif_out_passthru = atc_spdif_out_passthru,
-	.have_digit_io_switch = atc_have_digit_io_switch,
-	.have_dedicated_mic = atc_have_dedicated_mic,
-	.have_output_switch = atc_have_output_switch,
+	.capabilities = atc_capabilities,
 	.output_switch_get = atc_output_switch_get,
 	.output_switch_put = atc_output_switch_put,
-	.have_mic_source_switch = atc_have_mic_source_switch,
 	.mic_source_switch_get = atc_mic_source_switch_get,
 	.mic_source_switch_put = atc_mic_source_switch_put,
 #ifdef CONFIG_PM
diff --git a/pci/ctxfi/ctatc.h b/pci/ctxfi/ctatc.h
index 6bad27e..3a0def6 100644
--- a/pci/ctxfi/ctatc.h
+++ b/pci/ctxfi/ctatc.h
@@ -25,6 +25,7 @@
 #include <sound/core.h>
 
 #include "ctvmem.h"
+#include "cthardware.h"
 #include "ctresource.h"
 
 enum CTALSADEVS {		/* Types of alsa devices */
@@ -121,12 +122,9 @@ struct ct_atc {
 	int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
 	int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
 	int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
-	int (*have_digit_io_switch)(struct ct_atc *atc);
-	int (*have_dedicated_mic)(struct ct_atc *atc);
-	int (*have_output_switch)(struct ct_atc *atc);
+	struct capabilities (*capabilities)(struct ct_atc *atc);
 	int (*output_switch_get)(struct ct_atc *atc);
 	int (*output_switch_put)(struct ct_atc *atc, int position);
-	int (*have_mic_source_switch)(struct ct_atc *atc);
 	int (*mic_source_switch_get)(struct ct_atc *atc);
 	int (*mic_source_switch_put)(struct ct_atc *atc, int position);
 
diff --git a/pci/ctxfi/cthardware.h b/pci/ctxfi/cthardware.h
index de59bbf..9d7d2fb 100644
--- a/pci/ctxfi/cthardware.h
+++ b/pci/ctxfi/cthardware.h
@@ -61,6 +61,13 @@ struct card_conf {
 	unsigned int msr;	/* master sample rate in rsrs */
 };
 
+struct capabilities {
+       unsigned int digit_io_switch:1;
+       unsigned int dedicated_mic:1;
+       unsigned int output_switch:1;
+       unsigned int mic_source_switch:1;
+};
+
 struct hw {
 	int (*card_init)(struct hw *hw, struct card_conf *info);
 	int (*card_stop)(struct hw *hw);
@@ -71,12 +78,9 @@ struct hw {
 #endif
 	int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
 	int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
-	int (*have_digit_io_switch)(struct hw *hw);
-	int (*have_dedicated_mic)(struct hw *hw);
-	int (*have_output_switch)(struct hw *hw);
+	struct capabilities (*capabilities)(struct hw *hw);
 	int (*output_switch_get)(struct hw *hw);
 	int (*output_switch_put)(struct hw *hw, int position);
-	int (*have_mic_source_switch)(struct hw *hw);
 	int (*mic_source_switch_get)(struct hw *hw);
 	int (*mic_source_switch_put)(struct hw *hw, int position);
 
diff --git a/pci/ctxfi/cthw20k1.c b/pci/ctxfi/cthw20k1.c
index 9a85a84..1ff692a 100644
--- a/pci/ctxfi/cthw20k1.c
+++ b/pci/ctxfi/cthw20k1.c
@@ -1777,25 +1777,17 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
 		return adc_init_SBx(hw, info->input, info->mic20db);
 }
 
-static int hw_have_digit_io_switch(struct hw *hw)
+static struct capabilities hw_capabilities(struct hw *hw)
 {
-	/* SB073x and Vista compatible cards have no digit IO switch */
-	return !(hw->model == CTSB073X || hw->model == CTUAA);
-}
-
-static int hw_have_dedicated_mic(struct hw *hw)
-{
-	return 0;
-}
+	struct capabilities cap;
 
-static int hw_have_output_switch(struct hw *hw)
-{
-	return 0;
-}
+	/* SB073x and Vista compatible cards have no digit IO switch */
+	cap.digit_io_switch = !(hw->model == CTSB073X || hw->model == CTUAA);
+	cap.dedicated_mic = 0;
+	cap.output_switch = 0;
+	cap.mic_source_switch = 0;
 
-static int hw_have_mic_source_switch(struct hw *hw)
-{
-	return 0;
+	return cap;
 }
 
 #define CTLBITS(a, b, c, d)	(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
@@ -2187,10 +2179,7 @@ static struct hw ct20k1_preset __devinitdata = {
 	.pll_init = hw_pll_init,
 	.is_adc_source_selected = hw_is_adc_input_selected,
 	.select_adc_source = hw_adc_input_select,
-	.have_digit_io_switch = hw_have_digit_io_switch,
-	.have_dedicated_mic = hw_have_dedicated_mic,
-	.have_output_switch = hw_have_output_switch,
-	.have_mic_source_switch = hw_have_mic_source_switch,
+	.capabilities = hw_capabilities,
 #ifdef CONFIG_PM
 	.suspend = hw_suspend,
 	.resume = hw_resume,
diff --git a/pci/ctxfi/cthw20k2.c b/pci/ctxfi/cthw20k2.c
index 8bc6e41..ea559a9 100644
--- a/pci/ctxfi/cthw20k2.c
+++ b/pci/ctxfi/cthw20k2.c
@@ -1915,19 +1915,16 @@ error:
 	return err;
 }
 
-static int hw_have_digit_io_switch(struct hw *hw)
+static struct capabilities hw_capabilities(struct hw *hw)
 {
-	return 0;
-}
+	struct capabilities cap;
 
-static int hw_have_dedicated_mic(struct hw *hw)
-{
-	return hw->model == CTSB1270;
-}
+	cap.digit_io_switch = 0;
+	cap.dedicated_mic = hw->model == CTSB1270;
+	cap.output_switch = hw->model == CTSB1270;
+	cap.mic_source_switch = hw->model == CTSB1270;
 
-static int hw_have_output_switch(struct hw *hw)
-{
-	return hw->model == CTSB1270;
+	return cap;
 }
 
 static int hw_output_switch_get(struct hw *hw)
@@ -1978,11 +1975,6 @@ static int hw_output_switch_put(struct hw *hw, int position)
 	return 1;
 }
 
-static int hw_have_mic_source_switch(struct hw *hw)
-{
-	return hw->model == CTSB1270;
-}
-
 static int hw_mic_source_switch_get(struct hw *hw)
 {
 	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
@@ -2256,12 +2248,9 @@ static struct hw ct20k2_preset __devinitdata = {
 	.pll_init = hw_pll_init,
 	.is_adc_source_selected = hw_is_adc_input_selected,
 	.select_adc_source = hw_adc_input_select,
-	.have_digit_io_switch = hw_have_digit_io_switch,
-	.have_dedicated_mic = hw_have_dedicated_mic,
-	.have_output_switch = hw_have_output_switch,
+	.capabilities = hw_capabilities,
 	.output_switch_get = hw_output_switch_get,
 	.output_switch_put = hw_output_switch_put,
-	.have_mic_source_switch = hw_have_mic_source_switch,
 	.mic_source_switch_get = hw_mic_source_switch_get,
 	.mic_source_switch_put = hw_mic_source_switch_put,
 #ifdef CONFIG_PM
diff --git a/pci/ctxfi/ctmixer.c b/pci/ctxfi/ctmixer.c
index 388235c..0cc13ee 100644
--- a/pci/ctxfi/ctmixer.c
+++ b/pci/ctxfi/ctmixer.c
@@ -527,7 +527,7 @@ do_digit_io_switch(struct ct_atc *atc, int state)
 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);
+	struct capabilities cap = atc->capabilities(atc);
 
 	/* Do changes in mixer. */
 	if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
@@ -540,14 +540,14 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
 		}
 	}
 	/* Do changes out of mixer. */
-	if (!have_dedicated_mic &&
+	if (!cap.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))
+	} else if (cap.dedicated_mic && (MIXER_LINEIN_C_S == type))
 		atc->line_in_unmute(atc, state);
-	else if (have_dedicated_mic && (MIXER_MIC_C_S == type))
+	else if (cap.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);
@@ -739,6 +739,7 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
 {
 	enum CTALSA_MIXER_CTL type;
 	struct ct_atc *atc = mixer->atc;
+	struct capabilities cap = atc->capabilities(atc);
 	int err;
 
 	/* Create snd kcontrol instances on demand */
@@ -752,8 +753,7 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
 		}
 	}
 
-	ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl =
-					atc->have_digit_io_switch(atc);
+	ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = cap.digit_io_switch;
 
 	for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) {
 		if (ct_kcontrol_init_table[type].ctl) {
@@ -777,13 +777,13 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
 	if (err)
 		return err;
 
-	if (atc->have_output_switch(atc)) {
+	if (cap.output_switch) {
 		err = ct_mixer_kcontrol_new(mixer, &output_ctl);
 		if (err)
 			return err;
 	}
 
-	if (atc->have_mic_source_switch(atc)) {
+	if (cap.mic_source_switch) {
 		err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl);
 		if (err)
 			return err;
@@ -799,7 +799,7 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
 	atc->spdif_out_unmute(atc, 0);
 	set_switch_state(mixer, MIXER_SPDIFO_P_S, 0);
 	atc->line_in_unmute(atc, 0);
-	if (atc->have_dedicated_mic(atc))
+	if (cap.dedicated_mic)
 		atc->mic_unmute(atc, 0);
 	atc->spdif_in_unmute(atc, 0);
 	set_switch_state(mixer, MIXER_PCM_C_S, 0);
-- 
1.7.0.4


[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868
       [not found]   ` <BANLkTinovea9fE1Hxey83W+WAiYGBv600Q@mail.gmail.com>
@ 2011-06-12 16:48     ` Takashi Iwai
  2011-06-14  5:38       ` Takashi Iwai
  0 siblings, 1 reply; 11+ messages in thread
From: Takashi Iwai @ 2011-06-12 16:48 UTC (permalink / raw)
  To: Harry Butterworth; +Cc: Alsa-devel

At Sat, 11 Jun 2011 18:25:36 +0800,
Harry Butterworth wrote:
> 
> Hi,
> 
>     I have redone the patch against today's git repositories.
> Creative have not yet got back to me about the PLL initialization.
> Perhaps we can fix that later.
> 
>     I have only put the PCI ID in the pci_ids_compat.h.in file.  Is it
> going to be necessary to add the PCI device ID somewhere in the kernel
> tree to avoid breaking the kernel build?

Yes, include/linux/pci_ids.h is the place to change.
But I can fix it by myself, too.

> 
> > A few comment about the patch:
> >
> > - Instead of adding have_dedicated_mic and have_output_switch
> >  callbacks in every place, I'd put some bit flags indicating the
> >  capabilities, and set at the initialization appropriately.
> 
> I had a go at this in the patch 0002-ALSA...
> 
> > - A few easy coding-style issues; run scripts/checkpatch.pl and fix
> >  the errors appropriately.
> 
> checkpatch now reports no errors.
> 
> I've only tested these changes with my Titanium HD card.  I don't have
> any of the other X-Fi cards so I couldn't do any regression testing.
> 
> If there's anything else I need to do, please let me know.

I'm going to check patches in a more detail tomorrow.

Thanks!


Takashi
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868
  2011-06-12 16:48     ` Takashi Iwai
@ 2011-06-14  5:38       ` Takashi Iwai
  2011-06-14  8:23         ` Harry Butterworth
  0 siblings, 1 reply; 11+ messages in thread
From: Takashi Iwai @ 2011-06-14  5:38 UTC (permalink / raw)
  To: Harry Butterworth; +Cc: Alsa-devel

At Sun, 12 Jun 2011 18:48:27 +0200,
Takashi Iwai wrote:
> 
> At Sat, 11 Jun 2011 18:25:36 +0800,
> Harry Butterworth wrote:
> > 
> > Hi,
> > 
> >     I have redone the patch against today's git repositories.
> > Creative have not yet got back to me about the PLL initialization.
> > Perhaps we can fix that later.
> > 
> >     I have only put the PCI ID in the pci_ids_compat.h.in file.  Is it
> > going to be necessary to add the PCI device ID somewhere in the kernel
> > tree to avoid breaking the kernel build?
> 
> Yes, include/linux/pci_ids.h is the place to change.
> But I can fix it by myself, too.
> 
> > 
> > > A few comment about the patch:
> > >
> > > - Instead of adding have_dedicated_mic and have_output_switch
> > >  callbacks in every place, I'd put some bit flags indicating the
> > >  capabilities, and set at the initialization appropriately.
> > 
> > I had a go at this in the patch 0002-ALSA...
> > 
> > > - A few easy coding-style issues; run scripts/checkpatch.pl and fix
> > >  the errors appropriately.
> > 
> > checkpatch now reports no errors.
> > 
> > I've only tested these changes with my Titanium HD card.  I don't have
> > any of the other X-Fi cards so I couldn't do any regression testing.
> > 
> > If there's anything else I need to do, please let me know.
> 
> I'm going to check patches in a more detail tomorrow.

Now both patches were applied to sound git tree.
Just minor fixes were applied in addition (coding-style issues in the
second patch and added the definition in include/linux/pci_ids.h in
the first patch).


thanks,

Takashi
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868
  2011-06-14  5:38       ` Takashi Iwai
@ 2011-06-14  8:23         ` Harry Butterworth
  2011-06-16  0:32           ` Harry Butterworth
  0 siblings, 1 reply; 11+ messages in thread
From: Harry Butterworth @ 2011-06-14  8:23 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: Alsa-devel

Great.  Creative got back to me today with a proposed solution for the
PLL initialization.  I'll follow up with another patch in the next
week probably.

Harry

On 14 June 2011 13:38, Takashi Iwai <tiwai@suse.de> wrote:
> At Sun, 12 Jun 2011 18:48:27 +0200,
> Takashi Iwai wrote:
>>
>> At Sat, 11 Jun 2011 18:25:36 +0800,
>> Harry Butterworth wrote:
>> >
>> > Hi,
>> >
>> >     I have redone the patch against today's git repositories.
>> > Creative have not yet got back to me about the PLL initialization.
>> > Perhaps we can fix that later.
>> >
>> >     I have only put the PCI ID in the pci_ids_compat.h.in file.  Is it
>> > going to be necessary to add the PCI device ID somewhere in the kernel
>> > tree to avoid breaking the kernel build?
>>
>> Yes, include/linux/pci_ids.h is the place to change.
>> But I can fix it by myself, too.
>>
>> >
>> > > A few comment about the patch:
>> > >
>> > > - Instead of adding have_dedicated_mic and have_output_switch
>> > >  callbacks in every place, I'd put some bit flags indicating the
>> > >  capabilities, and set at the initialization appropriately.
>> >
>> > I had a go at this in the patch 0002-ALSA...
>> >
>> > > - A few easy coding-style issues; run scripts/checkpatch.pl and fix
>> > >  the errors appropriately.
>> >
>> > checkpatch now reports no errors.
>> >
>> > I've only tested these changes with my Titanium HD card.  I don't have
>> > any of the other X-Fi cards so I couldn't do any regression testing.
>> >
>> > If there's anything else I need to do, please let me know.
>>
>> I'm going to check patches in a more detail tomorrow.
>
> Now both patches were applied to sound git tree.
> Just minor fixes were applied in addition (coding-style issues in the
> second patch and added the definition in include/linux/pci_ids.h in
> the first patch).
>
>
> thanks,
>
> Takashi
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868
  2011-06-14  8:23         ` Harry Butterworth
@ 2011-06-16  0:32           ` Harry Butterworth
  2011-06-16  5:30             ` Takashi Iwai
  0 siblings, 1 reply; 11+ messages in thread
From: Harry Butterworth @ 2011-06-16  0:32 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: Alsa-devel

[-- Attachment #1: Type: text/plain, Size: 446 bytes --]

On 14 June 2011 16:23, Harry Butterworth <heb1001@gmail.com> wrote:
> Great.  Creative got back to me today with a proposed solution for the
> PLL initialization.  I'll follow up with another patch in the next
> week probably.

Here's the change from Creative for the PLL initialization.  It works
for me and hasn't failed yet but it didn't fail that often before and
I don't have the chip spec so I can't vouch for the new magic numbers.

Harry

[-- Attachment #2: 0003-ALSA-ctxfi-Change-PLL-initialization-code.patch --]
[-- Type: text/x-patch, Size: 1562 bytes --]

From 27b2ddf7343d569764da750d39dd403d1648cf06 Mon Sep 17 00:00:00 2001
From: Harry Butterworth <heb1001@gmail.com>
Date: Tue, 14 Jun 2011 23:09:12 +0800
Subject: [PATCH - ALSA:ctxfi 3/3] ALSA: ctxfi: Change PLL initialization code

This is a reworked patch from Creative to change the PLL code to address
unreliable 44100Hz initialization.

Signed-off-by: Harry Butterworth <heb1001@gmail.com>

diff --git a/pci/ctxfi/cthw20k2.c b/pci/ctxfi/cthw20k2.c
index ea559a9..4101a8e 100644
--- a/pci/ctxfi/cthw20k2.c
+++ b/pci/ctxfi/cthw20k2.c
@@ -1316,21 +1316,18 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr)
 
 	pllenb = 0xB;
 	hw_write_20kx(hw, PLL_ENB, pllenb);
-	pllctl = 0x20D00000;
-	set_field(&pllctl, PLLCTL_FD, 16 - 4);
+	pllctl = 0x20C00000;
+	set_field(&pllctl, PLLCTL_B, 0);
+	set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 4 : 147 - 4);
+	set_field(&pllctl, PLLCTL_RD, 48000 == rsr ? 1 - 1 : 10 - 1);
 	hw_write_20kx(hw, PLL_CTL, pllctl);
 	mdelay(40);
+
 	pllctl = hw_read_20kx(hw, PLL_CTL);
-	set_field(&pllctl, PLLCTL_B, 0);
-	if (48000 == rsr) {
-		set_field(&pllctl, PLLCTL_FD, 16 - 2);
-		set_field(&pllctl, PLLCTL_RD, 1 - 1); /* 3000*16/1 = 48000 */
-	} else { /* 44100 */
-		set_field(&pllctl, PLLCTL_FD, 147 - 2);
-		set_field(&pllctl, PLLCTL_RD, 10 - 1); /* 3000*147/10 = 44100 */
-	}
+	set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 2 : 147 - 2);
 	hw_write_20kx(hw, PLL_CTL, pllctl);
 	mdelay(40);
+
 	for (i = 0; i < 1000; i++) {
 		pllstat = hw_read_20kx(hw, PLL_STAT);
 		if (get_field(pllstat, PLLSTAT_PD))
-- 
1.7.0.4


[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868
  2011-06-16  0:32           ` Harry Butterworth
@ 2011-06-16  5:30             ` Takashi Iwai
  0 siblings, 0 replies; 11+ messages in thread
From: Takashi Iwai @ 2011-06-16  5:30 UTC (permalink / raw)
  To: Harry Butterworth; +Cc: Alsa-devel

At Thu, 16 Jun 2011 08:32:15 +0800,
Harry Butterworth wrote:
> 
> On 14 June 2011 16:23, Harry Butterworth <heb1001@gmail.com> wrote:
> > Great.  Creative got back to me today with a proposed solution for the
> > PLL initialization.  I'll follow up with another patch in the next
> > week probably.
> 
> Here's the change from Creative for the PLL initialization.  It works
> for me and hasn't failed yet but it didn't fail that often before and
> I don't have the chip spec so I can't vouch for the new magic numbers.

Thanks, I applied it now.  Let's see whether this breaks others.


Takashi

> 
> Harry
> [2 0003-ALSA-ctxfi-Change-PLL-initialization-code.patch <text/x-patch; US-ASCII (base64)>]
> From 27b2ddf7343d569764da750d39dd403d1648cf06 Mon Sep 17 00:00:00 2001
> From: Harry Butterworth <heb1001@gmail.com>
> Date: Tue, 14 Jun 2011 23:09:12 +0800
> Subject: [PATCH - ALSA:ctxfi 3/3] ALSA: ctxfi: Change PLL initialization code
> 
> This is a reworked patch from Creative to change the PLL code to address
> unreliable 44100Hz initialization.
> 
> Signed-off-by: Harry Butterworth <heb1001@gmail.com>
> 
> diff --git a/pci/ctxfi/cthw20k2.c b/pci/ctxfi/cthw20k2.c
> index ea559a9..4101a8e 100644
> --- a/pci/ctxfi/cthw20k2.c
> +++ b/pci/ctxfi/cthw20k2.c
> @@ -1316,21 +1316,18 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr)
>  
>  	pllenb = 0xB;
>  	hw_write_20kx(hw, PLL_ENB, pllenb);
> -	pllctl = 0x20D00000;
> -	set_field(&pllctl, PLLCTL_FD, 16 - 4);
> +	pllctl = 0x20C00000;
> +	set_field(&pllctl, PLLCTL_B, 0);
> +	set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 4 : 147 - 4);
> +	set_field(&pllctl, PLLCTL_RD, 48000 == rsr ? 1 - 1 : 10 - 1);
>  	hw_write_20kx(hw, PLL_CTL, pllctl);
>  	mdelay(40);
> +
>  	pllctl = hw_read_20kx(hw, PLL_CTL);
> -	set_field(&pllctl, PLLCTL_B, 0);
> -	if (48000 == rsr) {
> -		set_field(&pllctl, PLLCTL_FD, 16 - 2);
> -		set_field(&pllctl, PLLCTL_RD, 1 - 1); /* 3000*16/1 = 48000 */
> -	} else { /* 44100 */
> -		set_field(&pllctl, PLLCTL_FD, 147 - 2);
> -		set_field(&pllctl, PLLCTL_RD, 10 - 1); /* 3000*147/10 = 44100 */
> -	}
> +	set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 2 : 147 - 2);
>  	hw_write_20kx(hw, PLL_CTL, pllctl);
>  	mdelay(40);
> +
>  	for (i = 0; i < 1000; i++) {
>  		pllstat = hw_read_20kx(hw, PLL_STAT);
>  		if (get_field(pllstat, PLLSTAT_PD))
> -- 
> 1.7.0.4
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2011-06-16  5:30 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-30 13:22 Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868 Harry Butterworth
2011-06-03 15:44 ` Takashi Iwai
2011-06-11 10:35   ` Harry Butterworth
2011-06-11 10:39     ` Harry Butterworth
     [not found]   ` <BANLkTinovea9fE1Hxey83W+WAiYGBv600Q@mail.gmail.com>
2011-06-12 16:48     ` Takashi Iwai
2011-06-14  5:38       ` Takashi Iwai
2011-06-14  8:23         ` Harry Butterworth
2011-06-16  0:32           ` Harry Butterworth
2011-06-16  5:30             ` Takashi Iwai
2011-06-05  4:35 ` Marshall DeBerry
     [not found] <BANLkTikkMNPZ02ZmPtrJSmSEWi8nkfXsag@mail.gmail.com>
2011-06-03 12:26 ` Harry Butterworth

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox