[ALSA] hda-codec - A new model for Fujitsu S7020

Modules: HDA Codec driver

Added a new model 'fujitsu' to ALC260 config for Fujitsu S7020.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Jonathan Woithe 2005-09-16 19:12:48 +02:00 committed by Jaroslav Kysela
parent dfedc5f47c
commit a9430dd8fc
1 changed files with 157 additions and 3 deletions

View File

@ -57,6 +57,7 @@ enum {
enum {
ALC260_BASIC,
ALC260_HP,
ALC260_FUJITSU_S702x,
ALC260_MODEL_LAST /* last tag */
};
@ -72,6 +73,7 @@ enum {
#define PIN_VREF50 0x21
#define PIN_OUT 0x40
#define PIN_HP 0xc0
#define PIN_HP_AMP 0x80
struct alc_spec {
/* codec parameterization */
@ -284,6 +286,54 @@ static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u
#define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir)
/*
* Control of pin widget settings via the mixer. Only boolean settings are
* supported, so VrefEn can't be controlled using these functions as they
* stand.
*/
static int alc_pinctl_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
static int alc_pinctl_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
hda_nid_t nid = kcontrol->private_value & 0xffff;
long mask = (kcontrol->private_value >> 16) & 0xff;
long *valp = ucontrol->value.integer.value;
*valp = 0;
if (snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00) & mask)
*valp = 1;
return 0;
}
static int alc_pinctl_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
hda_nid_t nid = kcontrol->private_value & 0xffff;
long mask = (kcontrol->private_value >> 16) & 0xff;
long *valp = ucontrol->value.integer.value;
unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00);
int change = ((pinctl & mask)!=0) != *valp;
if (change)
snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL,
*valp?(pinctl|mask):(pinctl&~mask));
return change;
}
#define ALC_PINCTL_SWITCH(xname, nid, mask) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
.info = alc_pinctl_switch_info, \
.get = alc_pinctl_switch_get, \
.put = alc_pinctl_switch_put, \
.private_value = (nid) | (mask<<16) }
/*
* ALC880 3-stack model
@ -2205,6 +2255,17 @@ static struct hda_input_mux alc260_capture_source = {
},
};
/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack
* and the internal CD lines.
*/
static struct hda_input_mux alc260_fujitsu_capture_source = {
.num_items = 2,
.items = {
{ "Mic/Line", 0x0 },
{ "CD", 0x4 },
},
};
/*
* This is just place-holder, so there's something for alc_build_pcms to look
* at when it calculates the maximum number of channels. ALC260 has no mixer
@ -2271,6 +2332,30 @@ static snd_kcontrol_new_t alc260_hp_mixer[] = {
{ } /* end */
};
static snd_kcontrol_new_t alc260_fujitsu_mixer[] = {
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
ALC_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
ALC_PINCTL_SWITCH("Headphone Amp Switch", 0x14, PIN_HP_AMP),
HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Source",
.info = alc_mux_enum_info,
.get = alc_mux_enum_get,
.put = alc_mux_enum_put,
},
{ } /* end */
};
static struct hda_verb alc260_init_verbs[] = {
/* Line In pin widget for input */
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@ -2332,6 +2417,60 @@ static struct hda_verb alc260_init_verbs[] = {
{ }
};
/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
* laptops.
*/
static struct hda_verb alc260_fujitsu_init_verbs[] = {
/* Disable all GPIOs */
{0x01, AC_VERB_SET_GPIO_MASK, 0},
/* Internal speaker is connected to headphone pin */
{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
/* Headphone/Line-out jack connects to Line1 pin; make it an output */
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
/* Mic/Line-in jack is connected to mic1 pin, so make it an input */
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
/* Ensure all other unused pins are disabled and muted.
* Note: trying to set widget 0x15 to anything blocks all audio
* output for some reason, so just leave that at the default.
*/
{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
/* Disable digital (SPDIF) pins */
{0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
{0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
/* Start with mixer outputs muted */
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Unmute Line1 pin widget amp left and right (no equiv mixer ctrl) */
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Unmute pin widget used for Line-in (no equiv mixer ctrl) */
{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
/* Mute capture amp left and right */
{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
/* Set ADC connection select to line in (on mic1 pin) */
{0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
/* Mute all inputs to mixer widget (even unconnected ones) */
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
};
static struct hda_pcm_stream alc260_pcm_analog_playback = {
.substreams = 1,
.channels_min = 2,
@ -2347,6 +2486,8 @@ static struct hda_pcm_stream alc260_pcm_analog_capture = {
static struct hda_board_config alc260_cfg_tbl[] = {
{ .modelname = "hp", .config = ALC260_HP },
{ .pci_subvendor = 0x103c, .config = ALC260_HP },
{ .modelname = "fujitsu", .config = ALC260_FUJITSU_S702x },
{ .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702x },
{}
};
@ -2373,14 +2514,23 @@ static int patch_alc260(struct hda_codec *codec)
spec->mixers[spec->num_mixers] = alc260_hp_mixer;
spec->num_mixers++;
break;
case ALC260_FUJITSU_S702x:
spec->mixers[spec->num_mixers] = alc260_fujitsu_mixer;
spec->num_mixers++;
break;
default:
spec->mixers[spec->num_mixers] = alc260_base_mixer;
spec->num_mixers++;
break;
}
spec->init_verbs[0] = alc260_init_verbs;
spec->num_init_verbs = 1;
if (board_config != ALC260_FUJITSU_S702x) {
spec->init_verbs[0] = alc260_init_verbs;
spec->num_init_verbs = 1;
} else {
spec->init_verbs[0] = alc260_fujitsu_init_verbs;
spec->num_init_verbs = 1;
}
spec->channel_mode = alc260_modes;
spec->num_channel_mode = ARRAY_SIZE(alc260_modes);
@ -2393,7 +2543,11 @@ static int patch_alc260(struct hda_codec *codec)
spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids);
spec->multiout.dac_nids = alc260_dac_nids;
spec->input_mux = &alc260_capture_source;
if (board_config != ALC260_FUJITSU_S702x) {
spec->input_mux = &alc260_capture_source;
} else {
spec->input_mux = &alc260_fujitsu_capture_source;
}
switch (board_config) {
case ALC260_HP:
spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids);