Merge branch 'fix/hda' into topic/hda
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index 0f5d26b..8f40999 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -56,6 +56,7 @@
sony-assamd Sony ASSAMD
toshiba-s06 Toshiba S06
toshiba-rx1 Toshiba RX1
+ tyan Tyan Thunder n6650W (S2915-E)
ultra Samsung Q1 Ultra Vista model
lenovo-3000 Lenovo 3000 y410
nec NEC Versa S9100
@@ -285,6 +286,7 @@
dell-m42 Dell (unknown)
dell-m43 Dell Precision
dell-m44 Dell Inspiron
+ eapd Keep EAPD on (e.g. Gateway T1616)
STAC9220/9221
=============
@@ -353,5 +355,4 @@
STAC9872
========
- vaio Setup for VAIO FE550G/SZ110
- vaio-ar Setup for VAIO AR
+ N/A
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index d543365..6b33976 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2106,6 +2106,8 @@
#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274
+#define PCI_VENDOR_ID_DFI 0x15bd
+
#define PCI_VENDOR_ID_QUICKNET 0x15e2
#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
index b9679f0..51bf6a5 100644
--- a/sound/pci/hda/hda_beep.h
+++ b/sound/pci/hda/hda_beep.h
@@ -39,7 +39,7 @@
int snd_hda_attach_beep_device(struct hda_codec *codec, int nid);
void snd_hda_detach_beep_device(struct hda_codec *codec);
#else
-#define snd_hda_attach_beep_device(...)
+#define snd_hda_attach_beep_device(...) 0
#define snd_hda_detach_beep_device(...)
#endif
#endif
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 0b70813..c915879 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1120,6 +1120,7 @@
u16 nid = get_amp_nid(kcontrol);
u8 chs = get_amp_channels(kcontrol);
int dir = get_amp_direction(kcontrol);
+ unsigned int ofs = get_amp_offset(kcontrol);
u32 caps;
caps = query_amp_caps(codec, nid, dir);
@@ -1131,6 +1132,8 @@
kcontrol->id.name);
return -EINVAL;
}
+ if (ofs < caps)
+ caps -= ofs;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = chs == 3 ? 2 : 1;
uinfo->value.integer.min = 0;
@@ -1139,6 +1142,32 @@
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
+
+static inline unsigned int
+read_amp_value(struct hda_codec *codec, hda_nid_t nid,
+ int ch, int dir, int idx, unsigned int ofs)
+{
+ unsigned int val;
+ val = snd_hda_codec_amp_read(codec, nid, ch, dir, idx);
+ val &= HDA_AMP_VOLMASK;
+ if (val >= ofs)
+ val -= ofs;
+ else
+ val = 0;
+ return val;
+}
+
+static inline int
+update_amp_value(struct hda_codec *codec, hda_nid_t nid,
+ int ch, int dir, int idx, unsigned int ofs,
+ unsigned int val)
+{
+ if (val > 0)
+ val += ofs;
+ return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
+ HDA_AMP_VOLMASK, val);
+}
+
int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1147,14 +1176,13 @@
int chs = get_amp_channels(kcontrol);
int dir = get_amp_direction(kcontrol);
int idx = get_amp_index(kcontrol);
+ unsigned int ofs = get_amp_offset(kcontrol);
long *valp = ucontrol->value.integer.value;
if (chs & 1)
- *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx)
- & HDA_AMP_VOLMASK;
+ *valp++ = read_amp_value(codec, nid, 0, dir, idx, ofs);
if (chs & 2)
- *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx)
- & HDA_AMP_VOLMASK;
+ *valp = read_amp_value(codec, nid, 1, dir, idx, ofs);
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get);
@@ -1167,18 +1195,17 @@
int chs = get_amp_channels(kcontrol);
int dir = get_amp_direction(kcontrol);
int idx = get_amp_index(kcontrol);
+ unsigned int ofs = get_amp_offset(kcontrol);
long *valp = ucontrol->value.integer.value;
int change = 0;
snd_hda_power_up(codec);
if (chs & 1) {
- change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
- 0x7f, *valp);
+ change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp);
valp++;
}
if (chs & 2)
- change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
- 0x7f, *valp);
+ change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp);
snd_hda_power_down(codec);
return change;
}
@@ -1190,6 +1217,7 @@
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
hda_nid_t nid = get_amp_nid(kcontrol);
int dir = get_amp_direction(kcontrol);
+ unsigned int ofs = get_amp_offset(kcontrol);
u32 caps, val1, val2;
if (size < 4 * sizeof(unsigned int))
@@ -1198,6 +1226,7 @@
val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT;
val2 = (val2 + 1) * 25;
val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
+ val1 += ofs;
val1 = ((int)val1) * ((int)val2);
if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
return -EFAULT;
@@ -2614,7 +2643,7 @@
int dev;
if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
- return 0; /* no substreams assigned */
+ continue; /* no substreams assigned */
if (!cpcm->pcm) {
dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type);
@@ -3391,10 +3420,20 @@
cfg->input_pins[AUTO_PIN_AUX] = nid;
break;
case AC_JACK_SPDIF_OUT:
+ case AC_JACK_DIG_OTHER_OUT:
cfg->dig_out_pin = nid;
+ if (loc == AC_JACK_LOC_HDMI)
+ cfg->dig_out_type = HDA_PCM_TYPE_HDMI;
+ else
+ cfg->dig_out_type = HDA_PCM_TYPE_SPDIF;
break;
case AC_JACK_SPDIF_IN:
+ case AC_JACK_DIG_OTHER_IN:
cfg->dig_in_pin = nid;
+ if (loc == AC_JACK_LOC_HDMI)
+ cfg->dig_in_type = HDA_PCM_TYPE_HDMI;
+ else
+ cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
break;
}
}
@@ -3500,6 +3539,8 @@
cfg->hp_pins[1], cfg->hp_pins[2],
cfg->hp_pins[3], cfg->hp_pins[4]);
snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin);
+ if (cfg->dig_out_pin)
+ snd_printd(" dig-out=0x%x\n", cfg->dig_out_pin);
snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
" cd=0x%x, aux=0x%x\n",
cfg->input_pins[AUTO_PIN_MIC],
@@ -3508,6 +3549,8 @@
cfg->input_pins[AUTO_PIN_FRONT_LINE],
cfg->input_pins[AUTO_PIN_CD],
cfg->input_pins[AUTO_PIN_AUX]);
+ if (cfg->dig_out_pin)
+ snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin);
return 0;
}
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 1dd8716..ec687b2 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -26,8 +26,10 @@
/*
* for mixer controls
*/
+#define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \
+ ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
- ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19))
+ HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
/* mono volume with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
@@ -355,6 +357,8 @@
hda_nid_t dig_out_pin;
hda_nid_t dig_in_pin;
hda_nid_t mono_out_pin;
+ int dig_out_type; /* HDA_PCM_TYPE_XXX */
+ int dig_in_type; /* HDA_PCM_TYPE_XXX */
};
#define get_defcfg_connect(cfg) \
@@ -456,6 +460,7 @@
#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3)
#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1)
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
+#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f)
/*
* CEA Short Audio Descriptor data
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 2e7371e..e934e2c 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -1407,8 +1407,8 @@
{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
/* Mic boost: 0dB */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
/* Record selector: Front mic */
{0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
@@ -2288,10 +2288,6 @@
{0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
{0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
- /* ADCs; muted */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
{ }
};
@@ -2399,10 +2395,6 @@
{0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
{0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
- /* ADCs; muted */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* Analog Mix output amp */
{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
{ }
@@ -2474,10 +2466,6 @@
{0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
{0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
- /* ADCs; muted */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* Analog Mix output amp */
{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
{ }
@@ -3195,10 +3183,10 @@
{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
/* Port-B (front mic) pin */
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
/* Port-C (rear mic) pin */
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
/* 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)},
@@ -3349,7 +3337,7 @@
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* docking mic boost */
- {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
/* Analog mixer - docking mic; mute as default */
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
/* enable EAPD bit */
@@ -3613,10 +3601,10 @@
{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* Port-B (front mic) pin */
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
/* Port-C (rear line-in) pin */
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
/* Port-E (rear mic) pin */
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index a3baa33..5218118 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -30,6 +30,7 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
+#include "hda_beep.h"
#define ALC880_FRONT_EVENT 0x01
#define ALC880_DCVOL_EVENT 0x02
@@ -103,6 +104,7 @@
ALC262_NEC,
ALC262_TOSHIBA_S06,
ALC262_TOSHIBA_RX1,
+ ALC262_TYAN,
ALC262_AUTO,
ALC262_MODEL_LAST /* last tag */
};
@@ -238,6 +240,13 @@
ALC883_MODEL_LAST,
};
+/* styles of capture selection */
+enum {
+ CAPT_MUX = 0, /* only mux based */
+ CAPT_MIX, /* only mixer based */
+ CAPT_1MUX_MIX, /* first mux and other mixers */
+};
+
/* for GPIO Poll */
#define GPIO_MASK 0x03
@@ -269,13 +278,14 @@
* dig_out_nid and hp_nid are optional
*/
hda_nid_t alt_dac_nid;
+ int dig_out_type;
/* capture */
unsigned int num_adc_nids;
hda_nid_t *adc_nids;
hda_nid_t *capsrc_nids;
hda_nid_t dig_in_nid; /* digital-in NID; optional */
- unsigned char is_mix_capture; /* matrix-style capture (non-mux) */
+ int capture_style; /* capture style (CAPT_*) */
/* capture source */
unsigned int num_mux_defs;
@@ -293,7 +303,7 @@
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
struct snd_array kctls;
- struct hda_input_mux private_imux;
+ struct hda_input_mux private_imux[3];
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
/* hooks */
@@ -305,6 +315,9 @@
unsigned int jack_present: 1;
unsigned int master_sw: 1;
+ /* other flags */
+ unsigned int no_analog :1; /* digital I/O only */
+
/* for virtual master */
hda_nid_t vmaster_nid;
#ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -392,7 +405,8 @@
mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
imux = &spec->input_mux[mux_idx];
- if (spec->is_mix_capture) {
+ if (spec->capture_style &&
+ !(spec->capture_style == CAPT_1MUX_MIX && !adc_idx)) {
/* Matrix-mixer style (e.g. ALC882) */
unsigned int *cur_val = &spec->cur_mux[adc_idx];
unsigned int i, idx;
@@ -2018,11 +2032,13 @@
spec->multiout.dig_out_nid);
if (err < 0)
return err;
- err = snd_hda_create_spdif_share_sw(codec,
- &spec->multiout);
- if (err < 0)
- return err;
- spec->multiout.share_spdif = 1;
+ if (!spec->no_analog) {
+ err = snd_hda_create_spdif_share_sw(codec,
+ &spec->multiout);
+ if (err < 0)
+ return err;
+ spec->multiout.share_spdif = 1;
+ }
}
if (spec->dig_in_nid) {
err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -2031,7 +2047,8 @@
}
/* if we have no master control, let's create it */
- if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+ if (!spec->no_analog &&
+ !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
unsigned int vmaster_tlv[4];
snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
HDA_OUTPUT, vmaster_tlv);
@@ -2040,7 +2057,8 @@
if (err < 0)
return err;
}
- if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
+ if (!spec->no_analog &&
+ !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
err = snd_hda_add_vmaster(codec, "Master Playback Switch",
NULL, alc_slave_sws);
if (err < 0)
@@ -3059,6 +3077,9 @@
codec->num_pcms = 1;
codec->pcm_info = info;
+ if (spec->no_analog)
+ goto skip_analog;
+
info->name = spec->stream_name_analog;
if (spec->stream_analog_playback) {
if (snd_BUG_ON(!spec->multiout.dac_nids))
@@ -3082,12 +3103,16 @@
}
}
+ skip_analog:
/* SPDIF for stream index #1 */
if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
codec->num_pcms = 2;
info = spec->pcm_rec + 1;
info->name = spec->stream_name_digital;
- info->pcm_type = HDA_PCM_TYPE_SPDIF;
+ if (spec->dig_out_type)
+ info->pcm_type = spec->dig_out_type;
+ else
+ info->pcm_type = HDA_PCM_TYPE_SPDIF;
if (spec->multiout.dig_out_nid &&
spec->stream_digital_playback) {
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
@@ -3102,6 +3127,9 @@
codec->spdif_status_reset = 1;
}
+ if (spec->no_analog)
+ return 0;
+
/* If the use of more than one ADC is requested for the current
* model, configure a second analog capture-only PCM.
*/
@@ -3160,6 +3188,7 @@
alc_free_kctls(codec);
kfree(spec);
+ snd_hda_detach_beep_device(codec);
codec->spec = NULL; /* to be sure */
}
@@ -4112,7 +4141,7 @@
static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
const struct auto_pin_cfg *cfg)
{
- struct hda_input_mux *imux = &spec->private_imux;
+ struct hda_input_mux *imux = &spec->private_imux[0];
int i, err, idx;
for (i = 0; i < AUTO_PIN_LAST; i++) {
@@ -4261,7 +4290,7 @@
add_verb(spec, alc880_volume_init_verbs);
spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux;
+ spec->input_mux = &spec->private_imux[0];
store_pin_configs(codec);
return 1;
@@ -4328,6 +4357,12 @@
}
}
+ err = snd_hda_attach_beep_device(codec, 0x1);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ }
+
if (board_config != ALC880_AUTO)
setup_preset(spec, &alc880_presets[board_config]);
@@ -5469,7 +5504,7 @@
static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
const struct auto_pin_cfg *cfg)
{
- struct hda_input_mux *imux = &spec->private_imux;
+ struct hda_input_mux *imux = &spec->private_imux[0];
int i, err, idx;
for (i = 0; i < AUTO_PIN_LAST; i++) {
@@ -5629,7 +5664,7 @@
add_verb(spec, alc260_volume_init_verbs);
spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux;
+ spec->input_mux = &spec->private_imux[0];
store_pin_configs(codec);
return 1;
@@ -5855,6 +5890,12 @@
}
}
+ err = snd_hda_attach_beep_device(codec, 0x1);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ }
+
if (board_config != ALC260_AUTO)
setup_preset(spec, &alc260_presets[board_config]);
@@ -6898,18 +6939,21 @@
static void alc882_auto_init_input_src(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- const struct hda_input_mux *imux = spec->input_mux;
int c;
for (c = 0; c < spec->num_adc_nids; c++) {
hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
hda_nid_t nid = spec->capsrc_nids[c];
+ unsigned int mux_idx;
+ const struct hda_input_mux *imux;
int conns, mute, idx, item;
conns = snd_hda_get_connections(codec, nid, conn_list,
ARRAY_SIZE(conn_list));
if (conns < 0)
continue;
+ mux_idx = c >= spec->num_mux_defs ? 0 : c;
+ imux = &spec->input_mux[mux_idx];
for (idx = 0; idx < conns; idx++) {
/* if the current connection is the selected one,
* unmute it as default - otherwise mute it
@@ -6922,8 +6966,20 @@
break;
}
}
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, mute);
+ /* check if we have a selector or mixer
+ * we could check for the widget type instead, but
+ * just check for Amp-In presence (in case of mixer
+ * without amp-in there is something wrong, this
+ * function shouldn't be used or capsrc nid is wrong)
+ */
+ if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ mute);
+ else if (mute != AMP_IN_MUTE(idx))
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ idx);
}
}
}
@@ -7051,6 +7107,12 @@
}
}
+ err = snd_hda_attach_beep_device(codec, 0x1);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ }
+
if (board_config != ALC882_AUTO)
setup_preset(spec, &alc882_presets[board_config]);
@@ -7071,7 +7133,7 @@
spec->stream_digital_playback = &alc882_pcm_digital_playback;
spec->stream_digital_capture = &alc882_pcm_digital_capture;
- spec->is_mix_capture = 1; /* matrix-style capture */
+ spec->capture_style = CAPT_MIX; /* matrix-style capture */
if (!spec->adc_nids && spec->input_mux) {
/* check whether NID 0x07 is valid */
unsigned int wcap = get_wcaps(codec, 0x07);
@@ -7139,10 +7201,14 @@
0x09, 0x08
};
+#define alc889_adc_nids alc880_adc_nids
+
static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
+#define alc889_capsrc_nids alc882_capsrc_nids
+
/* input MUX */
/* FIXME: should be a matrix-type input source selection */
@@ -8963,6 +9029,8 @@
{
struct alc_spec *spec = codec->spec;
int err = alc880_parse_auto_config(codec);
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i;
if (err < 0)
return err;
@@ -8976,6 +9044,26 @@
/* hack - override the init verbs */
spec->init_verbs[0] = alc883_auto_init_verbs;
+ /* setup input_mux for ALC889 */
+ if (codec->vendor_id == 0x10ec0889) {
+ /* digital-mic input pin is excluded in alc880_auto_create..()
+ * because it's under 0x18
+ */
+ if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
+ cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
+ struct hda_input_mux *imux = &spec->private_imux[0];
+ for (i = 1; i < 3; i++)
+ memcpy(&spec->private_imux[i],
+ &spec->private_imux[0],
+ sizeof(spec->private_imux[0]));
+ imux->items[imux->num_items].label = "Int DMic";
+ imux->items[imux->num_items].index = 0x0b;
+ imux->num_items++;
+ spec->num_mux_defs = 3;
+ spec->input_mux = spec->private_imux;
+ }
+ }
+
return 1; /* config found */
}
@@ -9027,6 +9115,12 @@
}
}
+ err = snd_hda_attach_beep_device(codec, 0x1);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ }
+
if (board_config != ALC883_AUTO)
setup_preset(spec, &alc883_presets[board_config]);
@@ -9039,14 +9133,36 @@
spec->stream_name_analog = "ALC888 Analog";
spec->stream_name_digital = "ALC888 Digital";
}
+ if (!spec->num_adc_nids) {
+ spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+ spec->adc_nids = alc883_adc_nids;
+ }
+ if (!spec->capsrc_nids)
+ spec->capsrc_nids = alc883_capsrc_nids;
+ spec->capture_style = CAPT_MIX; /* matrix-style capture */
break;
case 0x10ec0889:
spec->stream_name_analog = "ALC889 Analog";
spec->stream_name_digital = "ALC889 Digital";
+ if (!spec->num_adc_nids) {
+ spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids);
+ spec->adc_nids = alc889_adc_nids;
+ }
+ if (!spec->capsrc_nids)
+ spec->capsrc_nids = alc889_capsrc_nids;
+ spec->capture_style = CAPT_1MUX_MIX; /* 1mux/Nmix-style
+ capture */
break;
default:
spec->stream_name_analog = "ALC883 Analog";
spec->stream_name_digital = "ALC883 Digital";
+ if (!spec->num_adc_nids) {
+ spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+ spec->adc_nids = alc883_adc_nids;
+ }
+ if (!spec->capsrc_nids)
+ spec->capsrc_nids = alc883_capsrc_nids;
+ spec->capture_style = CAPT_MIX; /* matrix-style capture */
break;
}
@@ -9057,13 +9173,6 @@
spec->stream_digital_playback = &alc883_pcm_digital_playback;
spec->stream_digital_capture = &alc883_pcm_digital_capture;
- if (!spec->num_adc_nids) {
- spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
- spec->adc_nids = alc883_adc_nids;
- }
- if (!spec->capsrc_nids)
- spec->capsrc_nids = alc883_capsrc_nids;
- spec->is_mix_capture = 1; /* matrix-style capture */
if (!spec->cap_mixer)
set_capture_mixer(spec);
@@ -9429,6 +9538,67 @@
{ } /* end */
};
+static struct snd_kcontrol_new alc262_tyan_mixer[] = {
+ HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
+ HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ { } /* end */
+};
+
+static struct hda_verb alc262_tyan_verbs[] = {
+ /* Headphone automute */
+ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ /* P11 AUX_IN, white 4-pin connector */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
+ {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
+ {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
+
+ {}
+};
+
+/* unsolicited event for HP jack sensing */
+static void alc262_tyan_automute(struct hda_codec *codec)
+{
+ unsigned int mute;
+ unsigned int present;
+
+ snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
+ present = snd_hda_codec_read(codec, 0x1b, 0,
+ AC_VERB_GET_PIN_SENSE, 0);
+ present = (present & 0x80000000) != 0;
+ if (present) {
+ /* mute line output on ATX panel */
+ snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, HDA_AMP_MUTE);
+ } else {
+ /* unmute line output if necessary */
+ mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
+ snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, mute);
+ }
+}
+
+static void alc262_tyan_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ if ((res >> 26) != ALC880_HP_EVENT)
+ return;
+ alc262_tyan_automute(codec);
+}
+
#define alc262_capture_mixer alc882_capture_mixer
#define alc262_capture_alt_mixer alc882_capture_alt_mixer
@@ -10468,8 +10638,14 @@
alc262_ignore);
if (err < 0)
return err;
- if (!spec->autocfg.line_outs)
+ if (!spec->autocfg.line_outs) {
+ if (spec->autocfg.dig_out_pin || spec->autocfg.dig_in_pin) {
+ spec->multiout.max_channels = 2;
+ spec->no_analog = 1;
+ goto dig_only;
+ }
return 0; /* can't find valid BIOS pin config */
+ }
err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
if (err < 0)
return err;
@@ -10479,8 +10655,11 @@
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
- if (spec->autocfg.dig_out_pin)
+ dig_only:
+ if (spec->autocfg.dig_out_pin) {
spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
+ spec->dig_out_type = spec->autocfg.dig_out_type;
+ }
if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = ALC262_DIGIN_NID;
@@ -10489,7 +10668,7 @@
add_verb(spec, alc262_volume_init_verbs);
spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux;
+ spec->input_mux = &spec->private_imux[0];
err = alc_auto_add_mic_boost(codec);
if (err < 0)
@@ -10537,6 +10716,7 @@
[ALC262_ULTRA] = "ultra",
[ALC262_LENOVO_3000] = "lenovo-3000",
[ALC262_NEC] = "nec",
+ [ALC262_TYAN] = "tyan",
[ALC262_AUTO] = "auto",
};
@@ -10577,6 +10757,7 @@
SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
+ SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
@@ -10795,6 +10976,19 @@
.unsol_event = alc262_hippo_unsol_event,
.init_hook = alc262_hippo_automute,
},
+ [ALC262_TYAN] = {
+ .mixers = { alc262_tyan_mixer },
+ .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
+ .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+ .dac_nids = alc262_dac_nids,
+ .hp_nid = 0x02,
+ .dig_out_nid = ALC262_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc262_modes),
+ .channel_mode = alc262_modes,
+ .input_mux = &alc262_capture_source,
+ .unsol_event = alc262_tyan_unsol_event,
+ .init_hook = alc262_tyan_automute,
+ },
};
static int patch_alc262(struct hda_codec *codec)
@@ -10847,6 +11041,12 @@
}
}
+ err = snd_hda_attach_beep_device(codec, 0x1);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ }
+
if (board_config != ALC262_AUTO)
setup_preset(spec, &alc262_presets[board_config]);
@@ -10858,7 +11058,7 @@
spec->stream_digital_playback = &alc262_pcm_digital_playback;
spec->stream_digital_capture = &alc262_pcm_digital_capture;
- spec->is_mix_capture = 1;
+ spec->capture_style = CAPT_MIX;
if (!spec->adc_nids && spec->input_mux) {
/* check whether NID 0x07 is valid */
unsigned int wcap = get_wcaps(codec, 0x07);
@@ -10875,7 +11075,7 @@
spec->capsrc_nids = alc262_capsrc_nids;
}
}
- if (!spec->cap_mixer)
+ if (!spec->cap_mixer && !spec->no_analog)
set_capture_mixer(spec);
spec->vmaster_nid = 0x0c;
@@ -11256,19 +11456,13 @@
static struct hda_verb alc268_base_init_verbs[] = {
/* Unmute DAC0-1 and set vol = 0 */
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
/*
* Set up output mixers (0x0c - 0x0e)
*/
/* set vol=0 to output mixers */
{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
{0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -11287,9 +11481,7 @@
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* set PCBEEP vol = 0, mute connections */
{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -11311,10 +11503,8 @@
*/
static struct hda_verb alc268_volume_init_verbs[] = {
/* set output DAC */
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
@@ -11322,16 +11512,12 @@
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* set PCBEEP vol = 0, mute connections */
{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -11530,7 +11716,7 @@
static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
const struct auto_pin_cfg *cfg)
{
- struct hda_input_mux *imux = &spec->private_imux;
+ struct hda_input_mux *imux = &spec->private_imux[0];
int i, idx1;
for (i = 0; i < AUTO_PIN_LAST; i++) {
@@ -11648,7 +11834,7 @@
add_verb(spec, alc268_volume_init_verbs);
spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux;
+ spec->input_mux = &spec->private_imux[0];
err = alc_auto_add_mic_boost(codec);
if (err < 0)
@@ -11899,6 +12085,12 @@
}
}
+ err = snd_hda_attach_beep_device(codec, 0x1);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ }
+
if (board_config != ALC268_AUTO)
setup_preset(spec, &alc268_presets[board_config]);
@@ -12502,7 +12694,7 @@
*/
if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
- struct hda_input_mux *imux = &spec->private_imux;
+ struct hda_input_mux *imux = &spec->private_imux[0];
imux->items[imux->num_items].label = "Int Mic";
imux->items[imux->num_items].index = 0x05;
imux->num_items++;
@@ -12558,7 +12750,7 @@
add_verb(spec, alc269_init_verbs);
spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux;
+ spec->input_mux = &spec->private_imux[0];
/* set default input source */
snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
0, AC_VERB_SET_CONNECT_SEL,
@@ -12733,6 +12925,12 @@
}
}
+ err = snd_hda_attach_beep_device(codec, 0x1);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ }
+
if (board_config != ALC269_AUTO)
setup_preset(spec, &alc269_presets[board_config]);
@@ -13474,7 +13672,7 @@
static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
const struct auto_pin_cfg *cfg)
{
- struct hda_input_mux *imux = &spec->private_imux;
+ struct hda_input_mux *imux = &spec->private_imux[0];
int i, err, idx, idx1;
for (i = 0; i < AUTO_PIN_LAST; i++) {
@@ -13611,7 +13809,7 @@
add_verb(spec, alc861_auto_init_verbs);
spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux;
+ spec->input_mux = &spec->private_imux[0];
spec->adc_nids = alc861_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
@@ -13826,6 +14024,12 @@
}
}
+ err = snd_hda_attach_beep_device(codec, 0x23);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ }
+
if (board_config != ALC861_AUTO)
setup_preset(spec, &alc861_presets[board_config]);
@@ -14715,7 +14919,7 @@
add_verb(spec, alc861vd_volume_init_verbs);
spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux;
+ spec->input_mux = &spec->private_imux[0];
err = alc_auto_add_mic_boost(codec);
if (err < 0)
@@ -14772,6 +14976,12 @@
}
}
+ err = snd_hda_attach_beep_device(codec, 0x23);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ }
+
if (board_config != ALC861VD_AUTO)
setup_preset(spec, &alc861vd_presets[board_config]);
@@ -14794,7 +15004,7 @@
spec->adc_nids = alc861vd_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
spec->capsrc_nids = alc861vd_capsrc_nids;
- spec->is_mix_capture = 1;
+ spec->capture_style = CAPT_MIX;
set_capture_mixer(spec);
@@ -16388,7 +16598,7 @@
static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
const struct auto_pin_cfg *cfg)
{
- struct hda_input_mux *imux = &spec->private_imux;
+ struct hda_input_mux *imux = &spec->private_imux[0];
int i, err, idx;
for (i = 0; i < AUTO_PIN_LAST; i++) {
@@ -16519,7 +16729,7 @@
add_mixer(spec, spec->kctls.list);
spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux;
+ spec->input_mux = &spec->private_imux[0];
add_verb(spec, alc662_auto_init_verbs);
if (codec->vendor_id == 0x10ec0663)
@@ -16581,6 +16791,12 @@
}
}
+ err = snd_hda_attach_beep_device(codec, 0x1);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ }
+
if (board_config != ALC662_AUTO)
setup_preset(spec, &alc662_presets[board_config]);
@@ -16604,7 +16820,7 @@
spec->adc_nids = alc662_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
spec->capsrc_nids = alc662_capsrc_nids;
- spec->is_mix_capture = 1;
+ spec->capture_style = CAPT_MIX;
if (!spec->cap_mixer)
set_capture_mixer(spec);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 38428e2..a7df81e 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -66,6 +66,7 @@
STAC_9205_DELL_M42,
STAC_9205_DELL_M43,
STAC_9205_DELL_M44,
+ STAC_9205_EAPD,
STAC_9205_MODELS
};
@@ -167,6 +168,7 @@
unsigned int alt_switch: 1;
unsigned int hp_detect: 1;
unsigned int spdif_mute: 1;
+ unsigned int check_volume_offset:1;
/* gpio lines */
unsigned int eapd_mask;
@@ -203,6 +205,8 @@
hda_nid_t hp_dacs[5];
hda_nid_t speaker_dacs[5];
+ int volume_offset;
+
/* capture */
hda_nid_t *adc_nids;
unsigned int num_adcs;
@@ -854,26 +858,25 @@
static struct hda_verb stac92hd71bxx_core_init[] = {
/* set master volume and direct control */
{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
- { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{}
};
-#define HD_DISABLE_PORTF 2
+#define HD_DISABLE_PORTF 1
static struct hda_verb stac92hd71bxx_analog_core_init[] = {
/* start of config #1 */
/* connect port 0f to audio mixer */
{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
- /* unmute right and left channels for node 0x0f */
- { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
/* start of config #2 */
/* set master volume and direct control */
{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- /* unmute right and left channels for nodes 0x0a, 0xd */
+ {}
+};
+
+static struct hda_verb stac92hd71bxx_unmute_core_init[] = {
+ /* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
+ { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{}
@@ -954,16 +957,6 @@
.private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \
}
-#define STAC_INPUT_SOURCE(cnt) \
- { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = "Input Source", \
- .count = cnt, \
- .info = stac92xx_mux_enum_info, \
- .get = stac92xx_mux_enum_get, \
- .put = stac92xx_mux_enum_put, \
- }
-
#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
{ \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -978,7 +971,6 @@
static struct snd_kcontrol_new stac9200_mixer[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
- STAC_INPUT_SOURCE(1),
HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
{ } /* end */
@@ -1094,7 +1086,6 @@
};
static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
- STAC_INPUT_SOURCE(2),
STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -1123,7 +1114,6 @@
};
static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
- STAC_INPUT_SOURCE(2),
STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -1137,14 +1127,12 @@
static struct snd_kcontrol_new stac925x_mixer[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
- STAC_INPUT_SOURCE(1),
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
{ } /* end */
};
static struct snd_kcontrol_new stac9205_mixer[] = {
- STAC_INPUT_SOURCE(2),
STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
@@ -1157,7 +1145,6 @@
/* This needs to be generated dynamically based on sequence */
static struct snd_kcontrol_new stac922x_mixer[] = {
- STAC_INPUT_SOURCE(2),
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
@@ -1168,7 +1155,6 @@
static struct snd_kcontrol_new stac927x_mixer[] = {
- STAC_INPUT_SOURCE(3),
STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
@@ -1294,6 +1280,8 @@
unsigned int vmaster_tlv[4];
snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
HDA_OUTPUT, vmaster_tlv);
+ /* correct volume offset */
+ vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
vmaster_tlv, slave_vols);
if (err < 0)
@@ -1511,6 +1499,8 @@
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+ "DFI LanParty", STAC_REF),
/* Dell laptops have BIOS problem */
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
"unknown Dell", STAC_9200_DELL_D21),
@@ -1660,6 +1650,7 @@
static struct snd_pci_quirk stac925x_cfg_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF),
SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
/* Default table for unknown ID */
@@ -1703,6 +1694,8 @@
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_92HD73XX_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+ "DFI LanParty", STAC_92HD73XX_REF),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
"Dell Studio 1535", STAC_DELL_M6_DMIC),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
@@ -1747,6 +1740,8 @@
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_92HD83XXX_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+ "DFI LanParty", STAC_92HD83XXX_REF),
{} /* terminator */
};
@@ -1796,6 +1791,8 @@
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_92HD71BXX_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+ "DFI LanParty", STAC_92HD71BXX_REF),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2,
"HP dv5", STAC_HP_M4),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4,
@@ -1988,6 +1985,8 @@
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_D945_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+ "DFI LanParty", STAC_D945_REF),
/* Intel 945G based systems */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
"Intel D945G", STAC_D945GTP3),
@@ -2041,6 +2040,9 @@
"Intel D945P", STAC_D945GTP3),
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
"Intel D945P", STAC_D945GTP5),
+ /* other intel */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0204,
+ "Intel D945", STAC_D945_REF),
/* other systems */
/* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
SND_PCI_QUIRK(0x8384, 0x7680,
@@ -2144,6 +2146,8 @@
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_D965_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+ "DFI LanParty", STAC_D965_REF),
/* Intel 946 based systems */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
@@ -2240,6 +2244,7 @@
[STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
[STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
[STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
+ [STAC_9205_EAPD] = NULL,
};
static const char *stac9205_models[STAC_9205_MODELS] = {
@@ -2247,12 +2252,16 @@
[STAC_9205_DELL_M42] = "dell-m42",
[STAC_9205_DELL_M43] = "dell-m43",
[STAC_9205_DELL_M44] = "dell-m44",
+ [STAC_9205_EAPD] = "eapd",
};
static struct snd_pci_quirk stac9205_cfg_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_9205_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+ "DFI LanParty", STAC_9205_REF),
+ /* Dell */
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
"unknown Dell", STAC_9205_DELL_M42),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
@@ -2283,6 +2292,8 @@
"Dell Inspiron", STAC_9205_DELL_M44),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
"Dell Vostro 1500", STAC_9205_DELL_M42),
+ /* Gateway */
+ SND_PCI_QUIRK(0x107b, 0x0565, "Gateway T1616", STAC_9205_EAPD),
{} /* terminator */
};
@@ -2558,7 +2569,7 @@
codec->num_pcms++;
info++;
info->name = "STAC92xx Digital";
- info->pcm_type = HDA_PCM_TYPE_SPDIF;
+ info->pcm_type = spec->autocfg.dig_out_type;
if (spec->multiout.dig_out_nid) {
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
@@ -2750,22 +2761,37 @@
};
/* add dynamic controls */
-static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
- struct snd_kcontrol_new *ktemp,
- int idx, const char *name,
- unsigned long val)
+static struct snd_kcontrol_new *
+stac_control_new(struct sigmatel_spec *spec,
+ struct snd_kcontrol_new *ktemp,
+ const char *name)
{
struct snd_kcontrol_new *knew;
snd_array_init(&spec->kctls, sizeof(*knew), 32);
knew = snd_array_new(&spec->kctls);
if (!knew)
- return -ENOMEM;
+ return NULL;
*knew = *ktemp;
- knew->index = idx;
knew->name = kstrdup(name, GFP_KERNEL);
- if (!knew->name)
+ if (!knew->name) {
+ /* roolback */
+ memset(knew, 0, sizeof(*knew));
+ spec->kctls.alloced--;
+ return NULL;
+ }
+ return knew;
+}
+
+static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
+ struct snd_kcontrol_new *ktemp,
+ int idx, const char *name,
+ unsigned long val)
+{
+ struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name);
+ if (!knew)
return -ENOMEM;
+ knew->index = idx;
knew->private_value = val;
return 0;
}
@@ -2787,6 +2813,29 @@
return stac92xx_add_control_idx(spec, type, 0, name, val);
}
+static struct snd_kcontrol_new stac_input_src_temp = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Source",
+ .info = stac92xx_mux_enum_info,
+ .get = stac92xx_mux_enum_get,
+ .put = stac92xx_mux_enum_put,
+};
+
+static int stac92xx_add_input_source(struct sigmatel_spec *spec)
+{
+ struct snd_kcontrol_new *knew;
+ struct hda_input_mux *imux = &spec->private_imux;
+
+ if (!spec->num_adcs || imux->num_items <= 1)
+ return 0; /* no need for input source control */
+ knew = stac_control_new(spec, &stac_input_src_temp,
+ stac_input_src_temp.name);
+ if (!knew)
+ return -ENOMEM;
+ knew->count = spec->num_adcs;
+ return 0;
+}
+
/* check whether the line-input can be used as line-out */
static hda_nid_t check_line_out_switch(struct hda_codec *codec)
{
@@ -2985,14 +3034,34 @@
}
/* create volume control/switch for the given prefx type */
-static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
+static int create_controls(struct hda_codec *codec, const char *pfx,
+ hda_nid_t nid, int chs)
{
+ struct sigmatel_spec *spec = codec->spec;
char name[32];
int err;
+ if (!spec->check_volume_offset) {
+ unsigned int caps, step, nums, db_scale;
+ caps = query_amp_caps(codec, nid, HDA_OUTPUT);
+ step = (caps & AC_AMPCAP_STEP_SIZE) >>
+ AC_AMPCAP_STEP_SIZE_SHIFT;
+ step = (step + 1) * 25; /* in .01dB unit */
+ nums = (caps & AC_AMPCAP_NUM_STEPS) >>
+ AC_AMPCAP_NUM_STEPS_SHIFT;
+ db_scale = nums * step;
+ /* if dB scale is over -64dB, and finer enough,
+ * let's reduce it to half
+ */
+ if (db_scale > 6400 && nums >= 0x1f)
+ spec->volume_offset = nums / 2;
+ spec->check_volume_offset = 1;
+ }
+
sprintf(name, "%s Playback Volume", pfx);
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+ HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT,
+ spec->volume_offset));
if (err < 0)
return err;
sprintf(name, "%s Playback Switch", pfx);
@@ -3058,10 +3127,10 @@
nid = spec->multiout.dac_nids[i];
if (i == 2) {
/* Center/LFE */
- err = create_controls(spec, "Center", nid, 1);
+ err = create_controls(codec, "Center", nid, 1);
if (err < 0)
return err;
- err = create_controls(spec, "LFE", nid, 2);
+ err = create_controls(codec, "LFE", nid, 2);
if (err < 0)
return err;
@@ -3089,7 +3158,7 @@
break;
}
}
- err = create_controls(spec, name, nid, 3);
+ err = create_controls(codec, name, nid, 3);
if (err < 0)
return err;
}
@@ -3144,7 +3213,7 @@
nid = spec->hp_dacs[i];
if (!nid)
continue;
- err = create_controls(spec, pfxs[nums++], nid, 3);
+ err = create_controls(codec, pfxs[nums++], nid, 3);
if (err < 0)
return err;
}
@@ -3158,7 +3227,7 @@
nid = spec->speaker_dacs[i];
if (!nid)
continue;
- err = create_controls(spec, pfxs[nums++], nid, 3);
+ err = create_controls(codec, pfxs[nums++], nid, 3);
if (err < 0)
return err;
}
@@ -3652,6 +3721,10 @@
return err;
}
+ err = stac92xx_add_input_source(spec);
+ if (err < 0)
+ return err;
+
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
if (spec->multiout.max_channels > 2)
spec->surr_switch = 1;
@@ -3734,7 +3807,7 @@
}
if (lfe_pin) {
- err = create_controls(spec, "LFE", lfe_pin, 1);
+ err = create_controls(codec, "LFE", lfe_pin, 1);
if (err < 0)
return err;
}
@@ -3765,6 +3838,10 @@
return err;
}
+ err = stac92xx_add_input_source(spec);
+ if (err < 0)
+ return err;
+
if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = 0x05;
if (spec->autocfg.dig_in_pin)
@@ -4110,7 +4187,9 @@
static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
unsigned int flag)
{
- unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
+ unsigned int old_ctl, pin_ctl;
+
+ pin_ctl = snd_hda_codec_read(codec, nid,
0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
if (pin_ctl & AC_PINCTL_IN_EN) {
@@ -4124,14 +4203,17 @@
return;
}
+ old_ctl = pin_ctl;
/* if setting pin direction bits, clear the current
direction bits first */
if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- pin_ctl | flag);
+ pin_ctl |= flag;
+ if (old_ctl != pin_ctl)
+ snd_hda_codec_write_cache(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pin_ctl);
}
static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
@@ -4139,9 +4221,10 @@
{
unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- pin_ctl & ~flag);
+ if (pin_ctl & flag)
+ snd_hda_codec_write_cache(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pin_ctl & ~flag);
}
static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
@@ -4860,6 +4943,7 @@
static int patch_stac92hd71bxx(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
+ struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init;
int err = 0;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
@@ -4933,6 +5017,7 @@
/* disable VSW */
spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
+ unmute_init++;
stac_change_pin_config(codec, 0xf, 0x40f000f0);
break;
case 0x111d7603: /* 6 Port with Analog Mixer */
@@ -4949,6 +5034,9 @@
codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
}
+ if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
+ snd_hda_sequence_write_cache(codec, unmute_init);
+
spec->aloopback_mask = 0x50;
spec->aloopback_shift = 0;
@@ -5298,7 +5386,9 @@
spec->aloopback_mask = 0x40;
spec->aloopback_shift = 0;
- spec->eapd_switch = 1;
+ /* Turn on/off EAPD per HP plugging */
+ if (spec->board_config != STAC_9205_EAPD)
+ spec->eapd_switch = 1;
spec->multiout.dac_nids = spec->dac_nids;
switch (spec->board_config){
@@ -5362,223 +5452,64 @@
* STAC9872 hack
*/
-/* static config for Sony VAIO FE550G and Sony VAIO AR */
-static hda_nid_t vaio_dacs[] = { 0x2 };
-#define VAIO_HP_DAC 0x5
-static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
-static hda_nid_t vaio_mux_nids[] = { 0x15 };
-
-static struct hda_input_mux vaio_mux = {
- .num_items = 3,
- .items = {
- /* { "HP", 0x0 }, */
- { "Mic Jack", 0x1 },
- { "Internal Mic", 0x2 },
- { "PCM", 0x3 },
- }
-};
-
-static struct hda_verb vaio_init[] = {
- {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
- {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
- {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
- {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
- {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
+static struct hda_verb stac9872_core_init[] = {
{0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
{}
};
-static struct hda_verb vaio_ar_init[] = {
- {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
- {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
- {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
- {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
-/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
-/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
- {}
-};
-
-static struct snd_kcontrol_new vaio_mixer[] = {
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
- /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
+static struct snd_kcontrol_new stac9872_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .count = 1,
- .info = stac92xx_mux_enum_info,
- .get = stac92xx_mux_enum_get,
- .put = stac92xx_mux_enum_put,
- },
- {}
+ { } /* end */
};
-static struct snd_kcontrol_new vaio_ar_mixer[] = {
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
- /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
- HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
- /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .count = 1,
- .info = stac92xx_mux_enum_info,
- .get = stac92xx_mux_enum_get,
- .put = stac92xx_mux_enum_put,
- },
- {}
+static hda_nid_t stac9872_pin_nids[] = {
+ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x11, 0x13, 0x14,
};
-static struct hda_codec_ops stac9872_patch_ops = {
- .build_controls = stac92xx_build_controls,
- .build_pcms = stac92xx_build_pcms,
- .init = stac92xx_init,
- .free = stac92xx_free,
-#ifdef SND_HDA_NEEDS_RESUME
- .resume = stac92xx_resume,
-#endif
+static hda_nid_t stac9872_adc_nids[] = {
+ 0x8 /*,0x6*/
};
-static int stac9872_vaio_init(struct hda_codec *codec)
-{
- int err;
-
- err = stac92xx_init(codec);
- if (err < 0)
- return err;
- if (codec->patch_ops.unsol_event)
- codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
- return 0;
-}
-
-static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
-{
- if (get_pin_presence(codec, 0x0a)) {
- stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
- stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
- } else {
- stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
- stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
- }
-}
-
-static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
-{
- switch (res >> 26) {
- case STAC_HP_EVENT:
- stac9872_vaio_hp_detect(codec, res);
- break;
- }
-}
-
-static struct hda_codec_ops stac9872_vaio_patch_ops = {
- .build_controls = stac92xx_build_controls,
- .build_pcms = stac92xx_build_pcms,
- .init = stac9872_vaio_init,
- .free = stac92xx_free,
- .unsol_event = stac9872_vaio_unsol_event,
-#ifdef CONFIG_PM
- .resume = stac92xx_resume,
-#endif
-};
-
-enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
- CXD9872RD_VAIO,
- /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
- STAC9872AK_VAIO,
- /* Unknown. id=0x83847661 and subsys=0x104D1200. */
- STAC9872K_VAIO,
- /* AR Series. id=0x83847664 and subsys=104D1300 */
- CXD9872AKD_VAIO,
- STAC_9872_MODELS,
-};
-
-static const char *stac9872_models[STAC_9872_MODELS] = {
- [CXD9872RD_VAIO] = "vaio",
- [CXD9872AKD_VAIO] = "vaio-ar",
-};
-
-static struct snd_pci_quirk stac9872_cfg_tbl[] = {
- SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
- SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
- SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
- SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
- {}
+static hda_nid_t stac9872_mux_nids[] = {
+ 0x15
};
static int patch_stac9872(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
- int board_config;
+ int err;
- board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
- stac9872_models,
- stac9872_cfg_tbl);
- if (board_config < 0)
- /* unknown config, let generic-parser do its job... */
- return snd_hda_parse_generic_codec(codec);
-
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
return -ENOMEM;
-
codec->spec = spec;
- switch (board_config) {
- case CXD9872RD_VAIO:
- case STAC9872AK_VAIO:
- case STAC9872K_VAIO:
- spec->mixer = vaio_mixer;
- spec->init = vaio_init;
- spec->multiout.max_channels = 2;
- spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
- spec->multiout.dac_nids = vaio_dacs;
- spec->multiout.hp_nid = VAIO_HP_DAC;
- spec->num_adcs = ARRAY_SIZE(vaio_adcs);
- spec->adc_nids = vaio_adcs;
- spec->num_pwrs = 0;
- spec->input_mux = &vaio_mux;
- spec->mux_nids = vaio_mux_nids;
- codec->patch_ops = stac9872_vaio_patch_ops;
- break;
-
- case CXD9872AKD_VAIO:
- spec->mixer = vaio_ar_mixer;
- spec->init = vaio_ar_init;
- spec->multiout.max_channels = 2;
- spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
- spec->multiout.dac_nids = vaio_dacs;
- spec->multiout.hp_nid = VAIO_HP_DAC;
- spec->num_adcs = ARRAY_SIZE(vaio_adcs);
- spec->num_pwrs = 0;
- spec->adc_nids = vaio_adcs;
- spec->input_mux = &vaio_mux;
- spec->mux_nids = vaio_mux_nids;
- codec->patch_ops = stac9872_patch_ops;
- break;
- }
+#if 0 /* no model right now */
+ spec->board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
+ stac9872_models,
+ stac9872_cfg_tbl);
+#endif
+
+ spec->num_pins = ARRAY_SIZE(stac9872_pin_nids);
+ spec->pin_nids = stac9872_pin_nids;
+ spec->multiout.dac_nids = spec->dac_nids;
+ spec->num_adcs = ARRAY_SIZE(stac9872_adc_nids);
+ spec->adc_nids = stac9872_adc_nids;
+ spec->num_muxes = ARRAY_SIZE(stac9872_mux_nids);
+ spec->mux_nids = stac9872_mux_nids;
+ spec->mixer = stac9872_mixer;
+ spec->init = stac9872_core_init;
+
+ err = stac92xx_parse_auto_config(codec, 0x10, 0x12);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return -EINVAL;
+ }
+ spec->input_mux = &spec->private_imux;
+ codec->patch_ops = stac92xx_patch_ops;
return 0;
}