mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
ALSA: ctxfi: Add support for Creative Titanium HD
Initialise model-specific DAC and ADC parts. Add controls for output and mic source selection. Rename some mixer controls according to ControlNames.txt. Remove Playback switches for Line-in and IEC958-in - these were controlling the input mute/unmute which affected capture too. Use the capture switches to control the input mute/unmute instead - it's less confusing. Initialise the WM8775 to invert the left-right clock to swap the left and right channels of the mic and aux input. Signed-off-by: Harry Butterworth <heb1001@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
37f7ec38ea
commit
55309216ba
@ -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 */
|
||||
|
@ -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) */
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user