forked from Minki/linux
[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:
parent
dfedc5f47c
commit
a9430dd8fc
@ -57,6 +57,7 @@ enum {
|
|||||||
enum {
|
enum {
|
||||||
ALC260_BASIC,
|
ALC260_BASIC,
|
||||||
ALC260_HP,
|
ALC260_HP,
|
||||||
|
ALC260_FUJITSU_S702x,
|
||||||
ALC260_MODEL_LAST /* last tag */
|
ALC260_MODEL_LAST /* last tag */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -72,6 +73,7 @@ enum {
|
|||||||
#define PIN_VREF50 0x21
|
#define PIN_VREF50 0x21
|
||||||
#define PIN_OUT 0x40
|
#define PIN_OUT 0x40
|
||||||
#define PIN_HP 0xc0
|
#define PIN_HP 0xc0
|
||||||
|
#define PIN_HP_AMP 0x80
|
||||||
|
|
||||||
struct alc_spec {
|
struct alc_spec {
|
||||||
/* codec parameterization */
|
/* 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)
|
#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
|
* 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
|
* 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
|
* 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 */
|
{ } /* 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[] = {
|
static struct hda_verb alc260_init_verbs[] = {
|
||||||
/* Line In pin widget for input */
|
/* Line In pin widget for input */
|
||||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
{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 = {
|
static struct hda_pcm_stream alc260_pcm_analog_playback = {
|
||||||
.substreams = 1,
|
.substreams = 1,
|
||||||
.channels_min = 2,
|
.channels_min = 2,
|
||||||
@ -2347,6 +2486,8 @@ static struct hda_pcm_stream alc260_pcm_analog_capture = {
|
|||||||
static struct hda_board_config alc260_cfg_tbl[] = {
|
static struct hda_board_config alc260_cfg_tbl[] = {
|
||||||
{ .modelname = "hp", .config = ALC260_HP },
|
{ .modelname = "hp", .config = ALC260_HP },
|
||||||
{ .pci_subvendor = 0x103c, .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->mixers[spec->num_mixers] = alc260_hp_mixer;
|
||||||
spec->num_mixers++;
|
spec->num_mixers++;
|
||||||
break;
|
break;
|
||||||
|
case ALC260_FUJITSU_S702x:
|
||||||
|
spec->mixers[spec->num_mixers] = alc260_fujitsu_mixer;
|
||||||
|
spec->num_mixers++;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
spec->mixers[spec->num_mixers] = alc260_base_mixer;
|
spec->mixers[spec->num_mixers] = alc260_base_mixer;
|
||||||
spec->num_mixers++;
|
spec->num_mixers++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
spec->init_verbs[0] = alc260_init_verbs;
|
if (board_config != ALC260_FUJITSU_S702x) {
|
||||||
spec->num_init_verbs = 1;
|
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->channel_mode = alc260_modes;
|
||||||
spec->num_channel_mode = ARRAY_SIZE(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.num_dacs = ARRAY_SIZE(alc260_dac_nids);
|
||||||
spec->multiout.dac_nids = 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) {
|
switch (board_config) {
|
||||||
case ALC260_HP:
|
case ALC260_HP:
|
||||||
spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids);
|
spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids);
|
||||||
|
Loading…
Reference in New Issue
Block a user