Skip to content

Commit

Permalink
ALSA: ctxfi: Add support for Creative Titanium HD
Browse files Browse the repository at this point in the history
Initialise model-specific DAC and ADC parts.
Add controls for output and mic source selection.
Rename some mixer controls according to ControlNames.txt.
Remove Playback switches for Line-in and IEC958-in - these
were controlling the input mute/unmute which affected
capture too.  Use the capture switches to control the
input mute/unmute instead - it's less confusing.
Initialise the WM8775 to invert the left-right clock
to swap the left and right channels of the mic and aux
input.

Signed-off-by: Harry Butterworth <heb1001@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Harry Butterworth authored and Takashi Iwai committed Jun 14, 2011
1 parent 37f7ec3 commit 5530921
Show file tree
Hide file tree
Showing 11 changed files with 488 additions and 164 deletions.
1 change: 1 addition & 0 deletions include/linux/pci_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
1 change: 1 addition & 0 deletions sound/pci/ctxfi/ct20k2reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) */
Expand Down
124 changes: 92 additions & 32 deletions sound/pci/ctxfi/ctatc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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,
Expand All @@ -75,6 +76,7 @@ static const char *ct_subsys_name[NUM_CTCARDS] = {
[CTSB0760] = "SB076x",
[CTHENDRIX] = "Hendrix",
[CTSB0880] = "SB0880",
[CTSB1270] = "SB1270",
[CT20K2_UNKNOWN] = "Unknown",
};

Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand All @@ -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) {
Expand All @@ -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)
Expand All @@ -1388,24 +1437,15 @@ 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)
return err;

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;
Expand Down Expand Up @@ -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],
Expand Down Expand Up @@ -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,
Expand Down
8 changes: 8 additions & 0 deletions sound/pci/ctxfi/ctatc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
23 changes: 7 additions & 16 deletions sound/pci/ctxfi/ctdaio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand All @@ -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},
};
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions sound/pci/ctxfi/ctdaio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand Down
8 changes: 8 additions & 0 deletions sound/pci/ctxfi/cthardware.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ enum CTCARDS {
CT20K2_MODEL_FIRST = CTSB0760,
CTHENDRIX,
CTSB0880,
CTSB1270,
CT20K2_UNKNOWN,
NUM_CTCARDS /* This should always be the last */
};
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 5530921

Please sign in to comment.