aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-04-02 13:08:49 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-04-02 13:08:49 -0700
commitf27f0a045b79de5729d064497e21a70871f1d6fe (patch)
tree078416852de43b76e297224b57a9c5b9f67dfb56 /sound/pci/hda
parent[PATCH] sysfs: zero terminate sysfs write buffers (diff)
parent[ALSA] Kconfig SND_SEQUENCER_OSS help text fix (diff)
downloadlinux-dev-f27f0a045b79de5729d064497e21a70871f1d6fe.tar.xz
linux-dev-f27f0a045b79de5729d064497e21a70871f1d6fe.zip
Merge master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
* master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa: (28 commits) [ALSA] Kconfig SND_SEQUENCER_OSS help text fix [ALSA] Add Aux input switch control for Aureon Universe [ALSA] pcxhr - Fix the crash with REV01 board [ALSA] sound/pci/hda: use create_singlethread_workqueue() [ALSA] hda-intel - Add support of ATI SB600 [ALSA] cs4281 - Fix the check of timeout in probe [ALSA] cs4281 - Fix the check of right channel [ALSA] Test volume resolution of usb audio at initialization [ALSA] maestro3.c: fix BUG, optimization [ALSA] HDA/Realtek: multiple input mux definitions and pin mode additions [ALSA] AdLib FM card driver [ALSA] Fix / clean up PCM-OSS setup hooks [ALSA] Clean up PCM codes (take 2) [ALSA] Tiny clean up of PCM codes [ALSA] ISA drivers bailing on first !enable[i] [ALSA] Remove obsolete kfree_nocheck call [ALSA] Remove obsolete kfree_nocheck call [ALSA] Add snd-als300 driver for Avance Logic ALS300/ALS300+ soundcards [ALSA] Add snd-riptide driver for Conexant Riptide chip [ALSA] hda-codec - Fix noisy output wtih AD1986A 3stack model ...
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_codec.c2
-rw-r--r--sound/pci/hda/hda_intel.c2
-rw-r--r--sound/pci/hda/patch_analog.c9
-rw-r--r--sound/pci/hda/patch_realtek.c298
-rw-r--r--sound/pci/hda/patch_sigmatel.c53
5 files changed, 288 insertions, 76 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index b42dff7ceed0..5bee3b536478 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -295,7 +295,7 @@ static int init_unsol_queue(struct hda_bus *bus)
snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n");
return -ENOMEM;
}
- unsol->workq = create_workqueue("hda_codec");
+ unsol->workq = create_singlethread_workqueue("hda_codec");
if (! unsol->workq) {
snd_printk(KERN_ERR "hda_codec: can't create workqueue\n");
kfree(unsol);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c096606970ff..0ad60ae29011 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -81,6 +81,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{Intel, ESB2},"
"{Intel, ICH8},"
"{ATI, SB450},"
+ "{ATI, SB600},"
"{VIA, VT8251},"
"{VIA, VT8237A},"
"{SiS, SIS966},"
@@ -1619,6 +1620,7 @@ static struct pci_device_id azx_ids[] = {
{ 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */
{ 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
{ 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
+ { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
{ 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
{ 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
{ 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 32401bd8c229..2bfe37e8543c 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -44,6 +44,7 @@ struct ad198x_spec {
* dig_out_nid and hp_nid are optional
*/
unsigned int cur_eapd;
+ unsigned int need_dac_fix;
/* capture */
unsigned int num_adc_nids;
@@ -836,10 +837,14 @@ static int patch_ad1986a(struct hda_codec *codec)
case AD1986A_3STACK:
spec->num_mixers = 2;
spec->mixers[1] = ad1986a_3st_mixers;
- spec->num_init_verbs = 2;
+ spec->num_init_verbs = 3;
spec->init_verbs[1] = ad1986a_3st_init_verbs;
+ spec->init_verbs[2] = ad1986a_ch2_init;
spec->channel_mode = ad1986a_modes;
spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
+ spec->need_dac_fix = 1;
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = 1;
break;
case AD1986A_LAPTOP:
spec->mixers[0] = ad1986a_laptop_mixers;
@@ -1555,6 +1560,8 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct ad198x_spec *spec = codec->spec;
+ if (spec->need_dac_fix)
+ spec->multiout.num_dacs = spec->multiout.max_channels / 2;
return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
spec->num_channel_mode, &spec->multiout.max_channels);
}
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4c6c9ec8ea5b..66bbdb60f50b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -52,6 +52,7 @@ enum {
ALC880_CLEVO,
ALC880_TCL_S700,
ALC880_LG,
+ ALC880_LG_LW,
#ifdef CONFIG_SND_DEBUG
ALC880_TEST,
#endif
@@ -131,6 +132,7 @@ struct alc_spec {
hda_nid_t dig_in_nid; /* digital-in NID; optional */
/* capture source */
+ unsigned int num_mux_defs;
const struct hda_input_mux *input_mux;
unsigned int cur_mux[3];
@@ -172,6 +174,7 @@ struct alc_config_preset {
hda_nid_t dig_in_nid;
unsigned int num_channel_mode;
const struct hda_channel_mode *channel_mode;
+ unsigned int num_mux_defs;
const struct hda_input_mux *input_mux;
void (*unsol_event)(struct hda_codec *, unsigned int);
void (*init_hook)(struct hda_codec *);
@@ -185,7 +188,10 @@ static int alc_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
- return snd_hda_input_mux_info(spec->input_mux, uinfo);
+ unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
+ if (mux_idx >= spec->num_mux_defs)
+ mux_idx = 0;
+ return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
}
static int alc_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -203,7 +209,8 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+ unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
+ return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
}
@@ -245,7 +252,8 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
* states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
* are requested. Therefore order this list so that this behaviour will not
* cause problems when mixer clients move through the enum sequentially.
- * NIDs 0x0f and 0x10 have been observed to have this behaviour.
+ * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
+ * March 2006.
*/
static char *alc_pin_mode_names[] = {
"Mic 50pc bias", "Mic 80pc bias",
@@ -255,19 +263,27 @@ static unsigned char alc_pin_mode_values[] = {
PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
};
/* The control can present all 5 options, or it can limit the options based
- * in the pin being assumed to be exclusively an input or an output pin.
+ * in the pin being assumed to be exclusively an input or an output pin. In
+ * addition, "input" pins may or may not process the mic bias option
+ * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
+ * accept requests for bias as of chip versions up to March 2006) and/or
+ * wiring in the computer.
*/
-#define ALC_PIN_DIR_IN 0x00
-#define ALC_PIN_DIR_OUT 0x01
-#define ALC_PIN_DIR_INOUT 0x02
+#define ALC_PIN_DIR_IN 0x00
+#define ALC_PIN_DIR_OUT 0x01
+#define ALC_PIN_DIR_INOUT 0x02
+#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
+#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
-/* Info about the pin modes supported by the three different pin directions.
+/* Info about the pin modes supported by the different pin direction modes.
* For each direction the minimum and maximum values are given.
*/
-static signed char alc_pin_mode_dir_info[3][2] = {
+static signed char alc_pin_mode_dir_info[5][2] = {
{ 0, 2 }, /* ALC_PIN_DIR_IN */
{ 3, 4 }, /* ALC_PIN_DIR_OUT */
{ 0, 4 }, /* ALC_PIN_DIR_INOUT */
+ { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
+ { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
};
#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
@@ -329,9 +345,10 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
* input modes.
*
* Dynamically switching the input/output buffers probably
- * reduces noise slightly, particularly on input. However,
- * havingboth input and output buffers enabled
- * simultaneously doesn't seem to be problematic.
+ * reduces noise slightly (particularly on input) so we'll
+ * do it. However, having both input and output buffers
+ * enabled simultaneously doesn't seem to be problematic if
+ * this turns out to be necessary in the future.
*/
if (val <= 2) {
snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
@@ -483,6 +500,9 @@ static void setup_preset(struct alc_spec *spec, const struct alc_config_preset *
spec->multiout.dig_out_nid = preset->dig_out_nid;
spec->multiout.hp_nid = preset->hp_nid;
+ spec->num_mux_defs = preset->num_mux_defs;
+ if (! spec->num_mux_defs)
+ spec->num_mux_defs = 1;
spec->input_mux = preset->input_mux;
spec->num_adc_nids = preset->num_adc_nids;
@@ -1427,6 +1447,82 @@ static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
}
/*
+ * LG LW20
+ *
+ * Pin assignment:
+ * Speaker-out: 0x14
+ * Mic-In: 0x18
+ * Built-in Mic-In: 0x19 (?)
+ * HP-Out: 0x1b
+ * SPDIF-Out: 0x1e
+ */
+
+/* seems analog CD is not working */
+static struct hda_input_mux alc880_lg_lw_capture_source = {
+ .num_items = 2,
+ .items = {
+ { "Mic", 0x0 },
+ { "Internal Mic", 0x1 },
+ },
+};
+
+static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
+ HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, 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("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+ { } /* end */
+};
+
+static struct hda_verb alc880_lg_lw_init_verbs[] = {
+ /* set capture source to mic-in */
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)},
+ /* speaker-out */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* HP-out */
+ {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* mic-in to input */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* built-in mic */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* jack sense */
+ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
+ { }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc880_lg_lw_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x1b, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+}
+
+static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ /* Looks like the unsol event is incompatible with the standard
+ * definition. 4bit tag is placed at 28 bit!
+ */
+ if ((res >> 28) == 0x01)
+ alc880_lg_lw_automute(codec);
+}
+
+/*
* Common callbacks
*/
@@ -2078,6 +2174,9 @@ static struct hda_board_config alc880_cfg_tbl[] = {
{ .modelname = "lg", .config = ALC880_LG },
{ .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG },
+ { .modelname = "lg-lw", .config = ALC880_LG_LW },
+ { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW },
+
#ifdef CONFIG_SND_DEBUG
{ .modelname = "test", .config = ALC880_TEST },
#endif
@@ -2268,6 +2367,19 @@ static struct alc_config_preset alc880_presets[] = {
.unsol_event = alc880_lg_unsol_event,
.init_hook = alc880_lg_automute,
},
+ [ALC880_LG_LW] = {
+ .mixers = { alc880_lg_lw_mixer },
+ .init_verbs = { alc880_volume_init_verbs,
+ alc880_lg_lw_init_verbs },
+ .num_dacs = 1,
+ .dac_nids = alc880_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
+ .channel_mode = alc880_2_jack_modes,
+ .input_mux = &alc880_lg_lw_capture_source,
+ .unsol_event = alc880_lg_lw_unsol_event,
+ .init_hook = alc880_lg_lw_automute,
+ },
#ifdef CONFIG_SND_DEBUG
[ALC880_TEST] = {
.mixers = { alc880_test_mixer },
@@ -2593,6 +2705,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
+ spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
return 1;
@@ -2722,30 +2835,56 @@ static struct hda_input_mux alc260_capture_source = {
};
/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
- * headphone jack and the internal CD lines.
+ * headphone jack and the internal CD lines since these are the only pins at
+ * which audio can appear. For flexibility, also allow the option of
+ * recording the mixer output on the second ADC (ADC0 doesn't have a
+ * connection to the mixer output).
*/
-static struct hda_input_mux alc260_fujitsu_capture_source = {
- .num_items = 3,
- .items = {
- { "Mic/Line", 0x0 },
- { "CD", 0x4 },
- { "Headphone", 0x2 },
+static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
+ {
+ .num_items = 3,
+ .items = {
+ { "Mic/Line", 0x0 },
+ { "CD", 0x4 },
+ { "Headphone", 0x2 },
+ },
},
+ {
+ .num_items = 4,
+ .items = {
+ { "Mic/Line", 0x0 },
+ { "CD", 0x4 },
+ { "Headphone", 0x2 },
+ { "Mixer", 0x5 },
+ },
+ },
+
};
-/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configutation to
- * the Fujitsu S702x, but jacks are marked differently. We won't allow
- * retasking the Headphone jack, so it won't be available here.
+/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
+ * the Fujitsu S702x, but jacks are marked differently.
*/
-static struct hda_input_mux alc260_acer_capture_source = {
- .num_items = 3,
- .items = {
- { "Mic", 0x0 },
- { "Line", 0x2 },
- { "CD", 0x4 },
+static struct hda_input_mux alc260_acer_capture_sources[2] = {
+ {
+ .num_items = 4,
+ .items = {
+ { "Mic", 0x0 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ { "Headphone", 0x5 },
+ },
+ },
+ {
+ .num_items = 5,
+ .items = {
+ { "Mic", 0x0 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ { "Headphone", 0x6 },
+ { "Mixer", 0x5 },
+ },
},
};
-
/*
* 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
@@ -2806,6 +2945,9 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
{ } /* end */
};
+/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
+ * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
+ */
static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
@@ -2822,9 +2964,28 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
{ } /* end */
};
+/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
+ * versions of the ALC260 don't act on requests to enable mic bias from NID
+ * 0x0f (used to drive the headphone jack in these laptops). The ALC260
+ * datasheet doesn't mention this restriction. At this stage it's not clear
+ * whether this behaviour is intentional or is a hardware bug in chip
+ * revisions available in early 2006. Therefore for now allow the
+ * "Headphone Jack Mode" control to span all choices, but if it turns out
+ * that the lack of mic bias for this NID is intentional we could change the
+ * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
+ *
+ * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
+ * don't appear to make the mic bias available from the "line" jack, even
+ * though the NID used for this jack (0x14) can supply it. The theory is
+ * that perhaps Acer have included blocking capacitors between the ALC260
+ * and the output jack. If this turns out to be the case for all such
+ * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
+ * to ALC_PIN_DIR_INOUT_NOMICBIAS.
+ */
static struct snd_kcontrol_new alc260_acer_mixer[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
+ ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
@@ -3038,7 +3199,8 @@ static struct hda_verb alc260_hp_3013_init_verbs[] = {
};
/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
- * laptops.
+ * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
+ * audio = 0x16, internal speaker = 0x10.
*/
static struct hda_verb alc260_fujitsu_init_verbs[] = {
/* Disable all GPIOs */
@@ -3185,10 +3347,10 @@ static struct hda_verb alc260_acer_init_verbs[] = {
{0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
/* Do similar with the second ADC: mute capture input amp and
- * set ADC connection to line (on line1 pin)
+ * set ADC connection to mic to match ALSA's default state.
*/
{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
+ {0x05, 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 */
@@ -3213,26 +3375,35 @@ static hda_nid_t alc260_test_dac_nids[1] = {
static hda_nid_t alc260_test_adc_nids[2] = {
0x04, 0x05,
};
-/* This is a bit messy since the two input muxes in the ALC260 have slight
- * variations in their signal assignments. The ideal way to deal with this
- * is to extend alc_spec.input_mux to allow a different input MUX for each
- * ADC. For the purposes of the test model it's sufficient to just list
- * both options for affected signal indices. The separate input mux
- * functionality only needs to be considered if a model comes along which
- * actually uses signals 0x5, 0x6 and 0x7 for something which makes sense to
- * record.
+/* For testing the ALC260, each input MUX needs its own definition since
+ * the signal assignments are different. This assumes that the first ADC
+ * is NID 0x04.
*/
-static struct hda_input_mux alc260_test_capture_source = {
- .num_items = 8,
- .items = {
- { "MIC1 pin", 0x0 },
- { "MIC2 pin", 0x1 },
- { "LINE1 pin", 0x2 },
- { "LINE2 pin", 0x3 },
- { "CD pin", 0x4 },
- { "LINE-OUT pin (cap1), Mixer (cap2)", 0x5 },
- { "HP-OUT pin (cap1), LINE-OUT pin (cap2)", 0x6 },
- { "HP-OUT pin (cap2 only)", 0x7 },
+static struct hda_input_mux alc260_test_capture_sources[2] = {
+ {
+ .num_items = 7,
+ .items = {
+ { "MIC1 pin", 0x0 },
+ { "MIC2 pin", 0x1 },
+ { "LINE1 pin", 0x2 },
+ { "LINE2 pin", 0x3 },
+ { "CD pin", 0x4 },
+ { "LINE-OUT pin", 0x5 },
+ { "HP-OUT pin", 0x6 },
+ },
+ },
+ {
+ .num_items = 8,
+ .items = {
+ { "MIC1 pin", 0x0 },
+ { "MIC2 pin", 0x1 },
+ { "LINE1 pin", 0x2 },
+ { "LINE2 pin", 0x3 },
+ { "CD pin", 0x4 },
+ { "Mixer", 0x5 },
+ { "LINE-OUT pin", 0x6 },
+ { "HP-OUT pin", 0x7 },
+ },
},
};
static struct snd_kcontrol_new alc260_test_mixer[] = {
@@ -3244,7 +3415,17 @@ static struct snd_kcontrol_new alc260_test_mixer[] = {
HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
- /* Modes for retasking pin widgets */
+ /* Modes for retasking pin widgets
+ * Note: the ALC260 doesn't seem to act on requests to enable mic
+ * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
+ * mention this restriction. At this stage it's not clear whether
+ * this behaviour is intentional or is a hardware bug in chip
+ * revisions available at least up until early 2006. Therefore for
+ * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
+ * choices, but if it turns out that the lack of mic bias for these
+ * NIDs is intentional we could change their modes from
+ * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
+ */
ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
@@ -3606,6 +3787,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
+ spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
/* check whether NID 0x04 is valid */
@@ -3711,7 +3893,8 @@ static struct alc_config_preset alc260_presets[] = {
.adc_nids = alc260_dual_adc_nids,
.num_channel_mode = ARRAY_SIZE(alc260_modes),
.channel_mode = alc260_modes,
- .input_mux = &alc260_fujitsu_capture_source,
+ .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
+ .input_mux = alc260_fujitsu_capture_sources,
},
[ALC260_ACER] = {
.mixers = { alc260_acer_mixer,
@@ -3723,7 +3906,8 @@ static struct alc_config_preset alc260_presets[] = {
.adc_nids = alc260_dual_adc_nids,
.num_channel_mode = ARRAY_SIZE(alc260_modes),
.channel_mode = alc260_modes,
- .input_mux = &alc260_acer_capture_source,
+ .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
+ .input_mux = alc260_acer_capture_sources,
},
#ifdef CONFIG_SND_DEBUG
[ALC260_TEST] = {
@@ -3736,7 +3920,8 @@ static struct alc_config_preset alc260_presets[] = {
.adc_nids = alc260_test_adc_nids,
.num_channel_mode = ARRAY_SIZE(alc260_modes),
.channel_mode = alc260_modes,
- .input_mux = &alc260_test_capture_source,
+ .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
+ .input_mux = alc260_test_capture_sources,
},
#endif
};
@@ -3828,7 +4013,6 @@ static struct hda_input_mux alc882_capture_source = {
{ "CD", 0x4 },
},
};
-
#define alc882_mux_enum_info alc_mux_enum_info
#define alc882_mux_enum_get alc_mux_enum_get
@@ -4730,6 +4914,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
+ spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
return 1;
@@ -5406,6 +5591,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
+ spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
spec->adc_nids = alc861_adc_nids;
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index b56ca4019392..abe9493f0a2c 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -534,6 +534,22 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
return 0;
}
+static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
+{
+ unsigned int pincap = snd_hda_param_read(codec, nid,
+ AC_PAR_PIN_CAP);
+ pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
+ if (pincap & AC_PINCAP_VREF_100)
+ return AC_PINCTL_VREF_100;
+ if (pincap & AC_PINCAP_VREF_80)
+ return AC_PINCTL_VREF_80;
+ if (pincap & AC_PINCAP_VREF_50)
+ return AC_PINCTL_VREF_50;
+ if (pincap & AC_PINCAP_VREF_GRD)
+ return AC_PINCTL_VREF_GRD;
+ return 0;
+}
+
static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
{
@@ -571,9 +587,12 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
if (val)
stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
- else
- stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
-
+ else {
+ unsigned int pinctl = AC_PINCTL_IN_EN;
+ if (io_idx) /* set VREF for mic */
+ pinctl |= stac92xx_get_vref(codec, nid);
+ stac92xx_auto_set_pinctl(codec, nid, pinctl);
+ }
return 1;
}
@@ -767,13 +786,8 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin
return 0;
wid_caps = get_wcaps(codec, pin);
- if (wid_caps & AC_WCAP_UNSOL_CAP) {
- /* Enable unsolicited responses on the HP widget */
- snd_hda_codec_write(codec, pin, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- STAC_UNSOL_ENABLE);
+ if (wid_caps & AC_WCAP_UNSOL_CAP)
spec->hp_detect = 1;
- }
nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
for (i = 0; i < cfg->line_outs; i++) {
@@ -896,13 +910,8 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
return 0;
wid_caps = get_wcaps(codec, pin);
- if (wid_caps & AC_WCAP_UNSOL_CAP) {
- /* Enable unsolicited responses on the HP widget */
- snd_hda_codec_write(codec, pin, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- STAC_UNSOL_ENABLE);
+ if (wid_caps & AC_WCAP_UNSOL_CAP)
spec->hp_detect = 1;
- }
return 0;
}
@@ -944,6 +953,10 @@ static int stac92xx_init(struct hda_codec *codec)
/* set up pins */
if (spec->hp_detect) {
+ /* Enable unsolicited responses on the HP widget */
+ snd_hda_codec_write(codec, cfg->hp_pin, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ STAC_UNSOL_ENABLE);
/* fake event to set up pins */
codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
} else {
@@ -951,9 +964,13 @@ static int stac92xx_init(struct hda_codec *codec)
stac92xx_auto_init_hp_out(codec);
}
for (i = 0; i < AUTO_PIN_LAST; i++) {
- if (cfg->input_pins[i])
- stac92xx_auto_set_pinctl(codec, cfg->input_pins[i],
- AC_PINCTL_IN_EN);
+ hda_nid_t nid = cfg->input_pins[i];
+ if (nid) {
+ unsigned int pinctl = AC_PINCTL_IN_EN;
+ if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
+ pinctl |= stac92xx_get_vref(codec, nid);
+ stac92xx_auto_set_pinctl(codec, nid, pinctl);
+ }
}
if (cfg->dig_out_pin)
stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,