Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55309216 authored by Harry Butterworth's avatar Harry Butterworth Committed by Takashi Iwai
Browse files

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: default avatarHarry Butterworth <heb1001@gmail.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 37f7ec38
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1308,6 +1308,7 @@
#define PCI_SUBDEVICE_ID_CREATIVE_SB08801	0x0041
#define PCI_SUBDEVICE_ID_CREATIVE_SB08802	0x0042
#define PCI_SUBDEVICE_ID_CREATIVE_SB08803	0x0043
#define PCI_SUBDEVICE_ID_CREATIVE_SB1270	0x0062
#define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX	0x6000

#define PCI_VENDOR_ID_ECTIVA		0x1102 /* duplicate: CREATIVE */
+1 −0
Original line number Diff line number Diff line
@@ -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) */
+92 −32
Original line number Diff line number Diff line
@@ -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;

	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 @@ 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,
+8 −0
Original line number Diff line number Diff line
@@ -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 */
+7 −16
Original line number Diff line number Diff line
@@ -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;

Loading