Commit 7fa9742b authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'fix/hda' into for-linus

parents a1cb9cd6 7085ec12
...@@ -209,6 +209,7 @@ AD1884A / AD1883 / AD1984A / AD1984B ...@@ -209,6 +209,7 @@ AD1884A / AD1883 / AD1984A / AD1984B
laptop laptop with HP jack sensing laptop laptop with HP jack sensing
mobile mobile devices with HP jack sensing mobile mobile devices with HP jack sensing
thinkpad Lenovo Thinkpad X300 thinkpad Lenovo Thinkpad X300
touchsmart HP Touchsmart
AD1884 AD1884
====== ======
......
...@@ -2303,6 +2303,7 @@ static void __devinit check_probe_mask(struct azx *chip, int dev) ...@@ -2303,6 +2303,7 @@ static void __devinit check_probe_mask(struct azx *chip, int dev)
* white-list for enable_msi * white-list for enable_msi
*/ */
static struct snd_pci_quirk msi_white_list[] __devinitdata = { static struct snd_pci_quirk msi_white_list[] __devinitdata = {
SND_PCI_QUIRK(0x103c, 0x30f7, "HP Pavilion dv4t-1300", 1),
SND_PCI_QUIRK(0x103c, 0x3607, "HP Compa CQ40", 1), SND_PCI_QUIRK(0x103c, 0x3607, "HP Compa CQ40", 1),
{} {}
}; };
......
...@@ -4031,6 +4031,127 @@ static int ad1984a_thinkpad_init(struct hda_codec *codec) ...@@ -4031,6 +4031,127 @@ static int ad1984a_thinkpad_init(struct hda_codec *codec)
return 0; return 0;
} }
/*
* HP Touchsmart
* port-A (0x11) - front hp-out
* port-B (0x14) - unused
* port-C (0x15) - unused
* port-D (0x12) - rear line out
* port-E (0x1c) - front mic-in
* port-F (0x16) - Internal speakers
* digital-mic (0x17) - Internal mic
*/
static struct hda_verb ad1984a_touchsmart_verbs[] = {
/* DACs; unmute as default */
{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
/* Port-A (HP) mixer - route only from analog mixer */
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
/* Port-A pin */
{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
/* Port-A (HP) pin - always unmuted */
{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Port-E (int speaker) mixer - route only from analog mixer */
{0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
/* Port-E pin */
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
/* Port-F (int speaker) mixer - route only from analog mixer */
{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
/* Port-F pin */
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* Analog mixer; mute as default */
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
/* Analog Mix output amp */
{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* capture sources */
/* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
{0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* unsolicited event for pin-sense */
{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
/* allow to touch GPIO1 (for mute control) */
{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
{0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
/* internal mic - dmic */
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
/* set magic COEFs for dmic */
{0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
{0x01, AC_VERB_SET_PROC_COEF, 0x08},
{ } /* end */
};
static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
/* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = ad1884a_mobile_master_sw_put,
.private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
},
HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
{ } /* end */
};
/* switch to external mic if plugged */
static void ad1984a_touchsmart_automic(struct hda_codec *codec)
{
if (snd_hda_codec_read(codec, 0x1c, 0,
AC_VERB_GET_PIN_SENSE, 0) & 0x80000000) {
snd_hda_codec_write(codec, 0x0c, 0,
AC_VERB_SET_CONNECT_SEL, 0x4);
} else {
snd_hda_codec_write(codec, 0x0c, 0,
AC_VERB_SET_CONNECT_SEL, 0x5);
}
}
/* unsolicited event for HP jack sensing */
static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
unsigned int res)
{
switch (res >> 26) {
case AD1884A_HP_EVENT:
ad1884a_hp_automute(codec);
break;
case AD1884A_MIC_EVENT:
ad1984a_touchsmart_automic(codec);
break;
}
}
/* initialize jack-sensing, too */
static int ad1984a_touchsmart_init(struct hda_codec *codec)
{
ad198x_init(codec);
ad1884a_hp_automute(codec);
ad1984a_touchsmart_automic(codec);
return 0;
}
/* /*
*/ */
...@@ -4039,6 +4160,7 @@ enum { ...@@ -4039,6 +4160,7 @@ enum {
AD1884A_LAPTOP, AD1884A_LAPTOP,
AD1884A_MOBILE, AD1884A_MOBILE,
AD1884A_THINKPAD, AD1884A_THINKPAD,
AD1984A_TOUCHSMART,
AD1884A_MODELS AD1884A_MODELS
}; };
...@@ -4047,6 +4169,7 @@ static const char *ad1884a_models[AD1884A_MODELS] = { ...@@ -4047,6 +4169,7 @@ static const char *ad1884a_models[AD1884A_MODELS] = {
[AD1884A_LAPTOP] = "laptop", [AD1884A_LAPTOP] = "laptop",
[AD1884A_MOBILE] = "mobile", [AD1884A_MOBILE] = "mobile",
[AD1884A_THINKPAD] = "thinkpad", [AD1884A_THINKPAD] = "thinkpad",
[AD1984A_TOUCHSMART] = "touchsmart",
}; };
static struct snd_pci_quirk ad1884a_cfg_tbl[] = { static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
...@@ -4059,6 +4182,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = { ...@@ -4059,6 +4182,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP), SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE), SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
{} {}
}; };
...@@ -4142,6 +4266,21 @@ static int patch_ad1884a(struct hda_codec *codec) ...@@ -4142,6 +4266,21 @@ static int patch_ad1884a(struct hda_codec *codec)
codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event; codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
codec->patch_ops.init = ad1984a_thinkpad_init; codec->patch_ops.init = ad1984a_thinkpad_init;
break; break;
case AD1984A_TOUCHSMART:
spec->mixers[0] = ad1984a_touchsmart_mixers;
spec->init_verbs[0] = ad1984a_touchsmart_verbs;
spec->multiout.dig_out_nid = 0;
codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
codec->patch_ops.init = ad1984a_touchsmart_init;
/* set the upper-limit for mixer amp to 0dB for avoiding the
* possible damage by overloading
*/
snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
(0x17 << AC_AMPCAP_OFFSET_SHIFT) |
(0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
(0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
(1 << AC_AMPCAP_MUTE_SHIFT));
break;
} }
return 0; return 0;
......
...@@ -682,11 +682,13 @@ static struct hda_input_mux cxt5045_capture_source = { ...@@ -682,11 +682,13 @@ static struct hda_input_mux cxt5045_capture_source = {
}; };
static struct hda_input_mux cxt5045_capture_source_benq = { static struct hda_input_mux cxt5045_capture_source_benq = {
.num_items = 3, .num_items = 5,
.items = { .items = {
{ "IntMic", 0x1 }, { "IntMic", 0x1 },
{ "ExtMic", 0x2 }, { "ExtMic", 0x2 },
{ "LineIn", 0x3 }, { "LineIn", 0x3 },
{ "CD", 0x4 },
{ "Mixer", 0x0 },
} }
}; };
...@@ -811,11 +813,19 @@ static struct snd_kcontrol_new cxt5045_mixers[] = { ...@@ -811,11 +813,19 @@ static struct snd_kcontrol_new cxt5045_mixers[] = {
}; };
static struct snd_kcontrol_new cxt5045_benq_mixers[] = { static struct snd_kcontrol_new cxt5045_benq_mixers[] = {
HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x4, HDA_INPUT),
HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT),
HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT), HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT),
HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT), HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT),
HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT), HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT),
HDA_CODEC_VOLUME("Mixer Capture Volume", 0x1a, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mixer Capture Switch", 0x1a, 0x0, HDA_INPUT),
{} {}
}; };
......
...@@ -12660,7 +12660,7 @@ static struct alc_config_preset alc268_presets[] = { ...@@ -12660,7 +12660,7 @@ static struct alc_config_preset alc268_presets[] = {
.init_hook = alc268_toshiba_automute, .init_hook = alc268_toshiba_automute,
}, },
[ALC268_ACER] = { [ALC268_ACER] = {
.mixers = { alc268_acer_mixer, alc268_capture_nosrc_mixer, .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
alc268_beep_mixer }, alc268_beep_mixer },
.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
alc268_acer_verbs }, alc268_acer_verbs },
...@@ -16852,6 +16852,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { ...@@ -16852,6 +16852,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
ALC662_3ST_6ch_DIG), ALC662_3ST_6ch_DIG),
SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB200", ALC663_ASUS_MODE4),
SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
ALC662_3ST_6ch_DIG), ALC662_3ST_6ch_DIG),
...@@ -17145,70 +17146,145 @@ static struct alc_config_preset alc662_presets[] = { ...@@ -17145,70 +17146,145 @@ static struct alc_config_preset alc662_presets[] = {
* BIOS auto configuration * BIOS auto configuration
*/ */
/* convert from MIX nid to DAC */
static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
{
if (nid == 0x0f)
return 0x02;
else if (nid >= 0x0c && nid <= 0x0e)
return nid - 0x0c + 0x02;
else
return 0;
}
/* get MIX nid connected to the given pin targeted to DAC */
static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
hda_nid_t dac)
{
hda_nid_t mix[4];
int i, num;
num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
for (i = 0; i < num; i++) {
if (alc662_mix_to_dac(mix[i]) == dac)
return mix[i];
}
return 0;
}
/* look for an empty DAC slot */
static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
{
struct alc_spec *spec = codec->spec;
hda_nid_t srcs[5];
int i, j, num;
num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
if (num < 0)
return 0;
for (i = 0; i < num; i++) {
hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
if (!nid)
continue;
for (j = 0; j < spec->multiout.num_dacs; j++)
if (spec->multiout.dac_nids[j] == nid)
break;
if (j >= spec->multiout.num_dacs)
return nid;
}
return 0;
}
/* fill in the dac_nids table from the parsed pin configuration */
static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
struct alc_spec *spec = codec->spec;
int i;
hda_nid_t dac;
spec->multiout.dac_nids = spec->private_dac_nids;
for (i = 0; i < cfg->line_outs; i++) {
dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
if (!dac)
continue;
spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
}
return 0;
}
static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
hda_nid_t nid, unsigned int chs)
{
char name[32];
sprintf(name, "%s Playback Volume", pfx);
return add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
}
static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
hda_nid_t nid, unsigned int chs)
{
char name[32];
sprintf(name, "%s Playback Switch", pfx);
return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
}
#define alc662_add_stereo_vol(spec, pfx, nid) \
alc662_add_vol_ctl(spec, pfx, nid, 3)
#define alc662_add_stereo_sw(spec, pfx, nid) \
alc662_add_sw_ctl(spec, pfx, nid, 3)
/* add playback controls from the parsed DAC table */ /* add playback controls from the parsed DAC table */
static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg) const struct auto_pin_cfg *cfg)
{ {
char name[32]; struct alc_spec *spec = codec->spec;
static const char *chname[4] = { static const char *chname[4] = {
"Front", "Surround", NULL /*CLFE*/, "Side" "Front", "Surround", NULL /*CLFE*/, "Side"
}; };
hda_nid_t nid; hda_nid_t nid, mix;
int i, err; int i, err;
for (i = 0; i < cfg->line_outs; i++) { for (i = 0; i < cfg->line_outs; i++) {
if (!spec->multiout.dac_nids[i]) nid = spec->multiout.dac_nids[i];
if (!nid)
continue;
mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
if (!mix)
continue; continue;
nid = alc880_idx_to_dac(i);
if (i == 2) { if (i == 2) {
/* Center/LFE */ /* Center/LFE */
err = add_control(spec, ALC_CTL_WIDGET_VOL, err = alc662_add_vol_ctl(spec, "Center", nid, 1);
"Center Playback Volume",
HDA_COMPOSE_AMP_VAL(nid, 1, 0,
HDA_OUTPUT));
if (err < 0) if (err < 0)
return err; return err;
err = add_control(spec, ALC_CTL_WIDGET_VOL, err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
"LFE Playback Volume",
HDA_COMPOSE_AMP_VAL(nid, 2, 0,
HDA_OUTPUT));
if (err < 0) if (err < 0)
return err; return err;
err = add_control(spec, ALC_CTL_WIDGET_MUTE, err = alc662_add_sw_ctl(spec, "Center", mix, 1);
"Center Playback Switch",
HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
HDA_INPUT));
if (err < 0) if (err < 0)
return err; return err;
err = add_control(spec, ALC_CTL_WIDGET_MUTE, err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
"LFE Playback Switch",
HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
HDA_INPUT));
if (err < 0) if (err < 0)
return err; return err;
} else { } else {
const char *pfx; const char *pfx;
if (cfg->line_outs == 1 && if (cfg->line_outs == 1 &&
cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
if (!cfg->hp_pins) if (cfg->hp_outs)
pfx = "Speaker"; pfx = "Speaker";
else else
pfx = "PCM"; pfx = "PCM";
} else } else
pfx = chname[i]; pfx = chname[i];
sprintf(name, "%s Playback Volume", pfx); err = alc662_add_vol_ctl(spec, pfx, nid, 3);
err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 0,
HDA_OUTPUT));
if (err < 0) if (err < 0)
return err; return err;
if (cfg->line_outs == 1 && if (cfg->line_outs == 1 &&
cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
pfx = "Speaker"; pfx = "Speaker";
sprintf(name, "%s Playback Switch", pfx); err = alc662_add_sw_ctl(spec, pfx, mix, 3);
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
3, 0, HDA_INPUT));
if (err < 0) if (err < 0)
return err; return err;
} }
...@@ -17217,54 +17293,38 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, ...@@ -17217,54 +17293,38 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
} }
/* add playback controls for speaker and HP outputs */ /* add playback controls for speaker and HP outputs */
static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, /* return DAC nid if any new DAC is assigned */
static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
const char *pfx) const char *pfx)
{ {
hda_nid_t nid; struct alc_spec *spec = codec->spec;
hda_nid_t nid, mix;
int err; int err;
char name[32];
if (!pin) if (!pin)
return 0; return 0;
nid = alc662_look_for_dac(codec, pin);
if (pin == 0x17) { if (!nid) {
/* ALC663 has a mono output pin on 0x17 */ char name[32];
/* the corresponding DAC is already occupied */
if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
return 0; /* no way */
/* create a switch only */
sprintf(name, "%s Playback Switch", pfx); sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT)); HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
return err;
} }
if (alc880_is_fixed_pin(pin)) { mix = alc662_dac_to_mix(codec, pin, nid);
nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); if (!mix)
/* printk(KERN_DEBUG "DAC nid=%x\n",nid); */ return 0;
/* specify the DAC as the extra output */ err = alc662_add_vol_ctl(spec, pfx, nid, 3);
if (!spec->multiout.hp_nid) if (err < 0)
spec->multiout.hp_nid = nid; return err;
else err = alc662_add_sw_ctl(spec, pfx, mix, 3);
spec->multiout.extra_out_nid[0] = nid; if (err < 0)
/* control HP volume/switch on the output mixer amp */ return err;
nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); return nid;
sprintf(name, "%s Playback Volume", pfx);
err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_BIND_MUTE, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
if (err < 0)
return err;
} else if (alc880_is_multi_pin(pin)) {
/* set manual connection */
/* we have only a switch on HP-out PIN */
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
}
return 0;
} }
/* create playback/capture controls for input pins */ /* create playback/capture controls for input pins */
...@@ -17273,30 +17333,35 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, ...@@ -17273,30 +17333,35 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
hda_nid_t nid, int pin_type, hda_nid_t nid, int pin_type,
int dac_idx) hda_nid_t dac)
{ {
int i, num;
hda_nid_t srcs[4];
alc_set_pin_output(codec, nid, pin_type); alc_set_pin_output(codec, nid, pin_type);
/* need the manual connection? */ /* need the manual connection? */
if (alc880_is_multi_pin(nid)) { num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
struct alc_spec *spec = codec->spec; if (num <= 1)
int idx = alc880_multi_pin_idx(nid); return;
snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0, for (i = 0; i < num; i++) {
AC_VERB_SET_CONNECT_SEL, if (alc662_mix_to_dac(srcs[i]) != dac)
alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx])); continue;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
return;
} }
} }
static void alc662_auto_init_multi_out(struct hda_codec *codec) static void alc662_auto_init_multi_out(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
int pin_type = get_pin_type(spec->autocfg.line_out_type);
int i; int i;
for (i = 0; i <= HDA_SIDE; i++) { for (i = 0; i <= HDA_SIDE; i++) {
hda_nid_t nid = spec->autocfg.line_out_pins[i]; hda_nid_t nid = spec->autocfg.line_out_pins[i];
int pin_type = get_pin_type(spec->autocfg.line_out_type);
if (nid) if (nid)
alc662_auto_set_output_and_unmute(codec, nid, pin_type, alc662_auto_set_output_and_unmute(codec, nid, pin_type,
i); spec->multiout.dac_nids[i]);
} }
} }
...@@ -17306,12 +17371,13 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec) ...@@ -17306,12 +17371,13 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec)
hda_nid_t pin; hda_nid_t pin;
pin = spec->autocfg.hp_pins[0]; pin = spec->autocfg.hp_pins[0];
if (pin) /* connect to front */ if (pin)
/* use dac 0 */ alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); spec->multiout.hp_nid);
pin = spec->autocfg.speaker_pins[0]; pin = spec->autocfg.speaker_pins[0];
if (pin) if (pin)
alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
spec->multiout.extra_out_nid[0]);
} }
#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID #define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
...@@ -17349,21 +17415,25 @@ static int alc662_parse_auto_config(struct hda_codec *codec) ...@@ -17349,21 +17415,25 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
if (!spec->autocfg.line_outs) if (!spec->autocfg.line_outs)
return 0; /* can't find valid BIOS pin config */ return 0; /* can't find valid BIOS pin config */
err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
if (err < 0) if (err < 0)
return err; return err;
err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg); err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
if (err < 0) if (err < 0)
return err; return err;
err = alc662_auto_create_extra_out(spec, err = alc662_auto_create_extra_out(codec,
spec->autocfg.speaker_pins[0], spec->autocfg.speaker_pins[0],
"Speaker"); "Speaker");
if (err < 0) if (err < 0)
return err; return err;
err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], if (err)
spec->multiout.extra_out_nid[0] = err;
err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
"Headphone"); "Headphone");
if (err < 0) if (err < 0)
return err; return err;
if (err)
spec->multiout.hp_nid = err;
err = alc662_auto_create_input_ctls(codec, &spec->autocfg); err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
if (err < 0) if (err < 0)
return err; return err;
......
...@@ -182,8 +182,8 @@ struct sigmatel_jack { ...@@ -182,8 +182,8 @@ struct sigmatel_jack {
struct sigmatel_mic_route { struct sigmatel_mic_route {
hda_nid_t pin; hda_nid_t pin;
unsigned char mux_idx; signed char mux_idx;
unsigned char dmux_idx; signed char dmux_idx;
}; };
struct sigmatel_spec { struct sigmatel_spec {
...@@ -3469,18 +3469,26 @@ static int set_mic_route(struct hda_codec *codec, ...@@ -3469,18 +3469,26 @@ static int set_mic_route(struct hda_codec *codec,
break; break;
if (i <= AUTO_PIN_FRONT_MIC) { if (i <= AUTO_PIN_FRONT_MIC) {
/* analog pin */ /* analog pin */
mic->dmux_idx = 0;
i = get_connection_index(codec, spec->mux_nids[0], pin); i = get_connection_index(codec, spec->mux_nids[0], pin);
if (i < 0) if (i < 0)
return -1; return -1;
mic->mux_idx = i; mic->mux_idx = i;
mic->dmux_idx = -1;
if (spec->dmux_nids)
mic->dmux_idx = get_connection_index(codec,
spec->dmux_nids[0],
spec->mux_nids[0]);
} else if (spec->dmux_nids) { } else if (spec->dmux_nids) {
/* digital pin */ /* digital pin */
mic->mux_idx = 0;
i = get_connection_index(codec, spec->dmux_nids[0], pin); i = get_connection_index(codec, spec->dmux_nids[0], pin);
if (i < 0) if (i < 0)
return -1; return -1;
mic->dmux_idx = i; mic->dmux_idx = i;
mic->mux_idx = -1;
if (spec->mux_nids)
mic->mux_idx = get_connection_index(codec,
spec->mux_nids[0],
spec->dmux_nids[0]);
} }
return 0; return 0;
} }
...@@ -4557,11 +4565,11 @@ static void stac92xx_mic_detect(struct hda_codec *codec) ...@@ -4557,11 +4565,11 @@ static void stac92xx_mic_detect(struct hda_codec *codec)
mic = &spec->ext_mic; mic = &spec->ext_mic;
else else
mic = &spec->int_mic; mic = &spec->int_mic;
if (mic->dmux_idx) if (mic->dmux_idx >= 0)
snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0,
AC_VERB_SET_CONNECT_SEL, AC_VERB_SET_CONNECT_SEL,
mic->dmux_idx); mic->dmux_idx);
else if (mic->mux_idx >= 0)
snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0, snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0,
AC_VERB_SET_CONNECT_SEL, AC_VERB_SET_CONNECT_SEL,
mic->mux_idx); mic->mux_idx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment