diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-03-16 17:38:46 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-03-16 17:38:46 +0100 |
commit | 433e8327caf9f7c0432b2f2f6684a5b79cfe18e9 (patch) | |
tree | 515e7bb9b0169fc4f8c1422ef6c926d4bd63e808 /sound | |
parent | 27b92d4ff2be2359a21ff4acde5b63563ff720e2 (diff) | |
parent | cc90fd725e14020607c5a6ba3ea02a0ddec5655f (diff) |
Merge branch 'topic/hda' into for-linus
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 105 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 5 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 7 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 24 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 117 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 124 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 22 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 204 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 318 |
9 files changed, 417 insertions, 509 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ae5c5d5e4b7c..2c79e96d0324 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -29,6 +29,7 @@ #include <sound/asoundef.h> #include <sound/tlv.h> #include <sound/initval.h> +#include <sound/jack.h> #include "hda_local.h" #include "hda_beep.h" #include <sound/hda_hwdep.h> @@ -4959,5 +4960,109 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen) } EXPORT_SYMBOL_HDA(snd_print_pcm_bits); +#ifdef CONFIG_SND_HDA_INPUT_JACK +/* + * Input-jack notification support + */ +struct hda_jack_item { + hda_nid_t nid; + int type; + struct snd_jack *jack; +}; + +static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid, + int type) +{ + switch (type) { + case SND_JACK_HEADPHONE: + return "Headphone"; + case SND_JACK_MICROPHONE: + return "Mic"; + case SND_JACK_LINEOUT: + return "Line-out"; + case SND_JACK_HEADSET: + return "Headset"; + default: + return "Misc"; + } +} + +static void hda_free_jack_priv(struct snd_jack *jack) +{ + struct hda_jack_item *jacks = jack->private_data; + jacks->nid = 0; + jacks->jack = NULL; +} + +int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type, + const char *name) +{ + struct hda_jack_item *jack; + int err; + + snd_array_init(&codec->jacks, sizeof(*jack), 32); + jack = snd_array_new(&codec->jacks); + if (!jack) + return -ENOMEM; + + jack->nid = nid; + jack->type = type; + if (!name) + name = get_jack_default_name(codec, nid, type); + err = snd_jack_new(codec->bus->card, name, type, &jack->jack); + if (err < 0) { + jack->nid = 0; + return err; + } + jack->jack->private_data = jack; + jack->jack->private_free = hda_free_jack_priv; + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_input_jack_add); + +void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_jack_item *jacks = codec->jacks.list; + int i; + + if (!jacks) + return; + + for (i = 0; i < codec->jacks.used; i++, jacks++) { + unsigned int pin_ctl; + unsigned int present; + int type; + + if (jacks->nid != nid) + continue; + present = snd_hda_jack_detect(codec, nid); + type = jacks->type; + if (type == (SND_JACK_HEADPHONE | SND_JACK_LINEOUT)) { + pin_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + type = (pin_ctl & AC_PINCTL_HP_EN) ? + SND_JACK_HEADPHONE : SND_JACK_LINEOUT; + } + snd_jack_report(jacks->jack, present ? type : 0); + } +} +EXPORT_SYMBOL_HDA(snd_hda_input_jack_report); + +/* free jack instances manually when clearing/reconfiguring */ +void snd_hda_input_jack_free(struct hda_codec *codec) +{ + if (!codec->bus->shutdown && codec->jacks.list) { + struct hda_jack_item *jacks = codec->jacks.list; + int i; + for (i = 0; i < codec->jacks.used; i++, jacks++) { + if (jacks->jack) + snd_device_free(codec->bus->card, jacks->jack); + } + } + snd_array_free(&codec->jacks); +} +EXPORT_SYMBOL_HDA(snd_hda_input_jack_free); +#endif /* CONFIG_SND_HDA_INPUT_JACK */ + MODULE_DESCRIPTION("HDA codec core"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index fdf8d44f8b6b..e46d5420a9f2 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -866,6 +866,11 @@ struct hda_codec { /* codec-specific additional proc output */ void (*proc_widget_hook)(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid); + +#ifdef CONFIG_SND_HDA_INPUT_JACK + /* jack detection */ + struct snd_array jacks; +#endif }; /* direction */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index fcedad9a5fef..70a9d32f0e96 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1052,9 +1052,12 @@ static void azx_init_pci(struct azx *chip) /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) * TCSEL == Traffic Class Select Register, which sets PCI express QOS * Ensuring these bits are 0 clears playback static on some HD Audio - * codecs + * codecs. + * The PCI register TCSEL is defined in the Intel manuals. */ - update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); + if (chip->driver_type != AZX_DRIVER_ATI && + chip->driver_type != AZX_DRIVER_ATIHDMI) + update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); switch (chip->driver_type) { case AZX_DRIVER_ATI: diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 3ab5e7a303db..ff5e2ac2239a 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -656,4 +656,28 @@ static inline void snd_hda_eld_proc_free(struct hda_codec *codec, #define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); +/* + * Input-jack notification support + */ +#ifdef CONFIG_SND_HDA_INPUT_JACK +int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type, + const char *name); +void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid); +void snd_hda_input_jack_free(struct hda_codec *codec); +#else /* CONFIG_SND_HDA_INPUT_JACK */ +static inline int snd_hda_input_jack_add(struct hda_codec *codec, + hda_nid_t nid, int type, + const char *name) +{ + return 0; +} +static inline void snd_hda_input_jack_report(struct hda_codec *codec, + hda_nid_t nid) +{ +} +static inline void snd_hda_input_jack_free(struct hda_codec *codec) +{ +} +#endif /* CONFIG_SND_HDA_INPUT_JACK */ + #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 8dabab798689..734c6ee55d8a 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -30,10 +30,10 @@ #include "hda_beep.h" struct ad198x_spec { - struct snd_kcontrol_new *mixers[5]; + struct snd_kcontrol_new *mixers[6]; int num_mixers; unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ - const struct hda_verb *init_verbs[5]; /* initialization verbs + const struct hda_verb *init_verbs[6]; /* initialization verbs * don't forget NULL termination! */ unsigned int num_init_verbs; @@ -331,36 +331,11 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); } -static int ad198x_alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->alt_dac_nid[0], stream_tag, - 0, format); - return 0; -} - -static int ad198x_alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->alt_dac_nid[0]); - return 0; -} - static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, /* NID is set in ad198x_build_pcms */ - .ops = { - .prepare = ad198x_alt_playback_pcm_prepare, - .cleanup = ad198x_alt_playback_pcm_cleanup - }, }; /* @@ -2239,29 +2214,6 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = { static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), - HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), - - HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), - { } /* end */ }; @@ -2545,11 +2497,6 @@ static struct hda_verb ad1988_6stack_init_verbs[] = { }; static struct hda_verb ad1988_6stack_fp_init_verbs[] = { - /* Front, Surround, CLFE, side DAC; unmute as default */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Headphone; unmute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Port-A front headphon path */ @@ -2558,50 +2505,6 @@ static struct hda_verb ad1988_6stack_fp_init_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Port-D line-out path */ - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-F surround path */ - {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-G CLFE path */ - {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-H side path */ - {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Mono out path */ - {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ - /* Port-B front mic-in path */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-C line-in path */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Port-E mic-in path */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Analog CD Input */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ { } }; @@ -3316,20 +3219,20 @@ static int patch_ad1988(struct hda_codec *codec) spec->mixers[0] = ad1988_6stack_mixers1_rev2; else spec->mixers[0] = ad1988_6stack_mixers1; + spec->mixers[1] = ad1988_6stack_mixers2; + spec->num_init_verbs = 1; + spec->init_verbs[0] = ad1988_6stack_init_verbs; if (board_config == AD1988_6STACK_DIG_FP) { - spec->mixers[1] = ad1988_6stack_fp_mixers; + spec->num_mixers++; + spec->mixers[2] = ad1988_6stack_fp_mixers; + spec->num_init_verbs++; + spec->init_verbs[1] = ad1988_6stack_fp_init_verbs; spec->slave_vols = ad1988_6stack_fp_slave_vols; spec->slave_sws = ad1988_6stack_fp_slave_sws; spec->alt_dac_nid = ad1988_alt_dac_nid; spec->stream_analog_alt_playback = &ad198x_pcm_analog_alt_playback; - } else - spec->mixers[1] = ad1988_6stack_mixers2; - spec->num_init_verbs = 1; - if (board_config == AD1988_6STACK_DIG_FP) - spec->init_verbs[0] = ad1988_6stack_fp_init_verbs; - else - spec->init_verbs[0] = ad1988_6stack_init_verbs; + } if ((board_config == AD1988_6STACK_DIG) || (board_config == AD1988_6STACK_DIG_FP)) { spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 4d5004e693f0..d08cf31596f3 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -49,14 +49,6 @@ #define AUTO_MIC_PORTB (1 << 1) #define AUTO_MIC_PORTC (1 << 2) -struct conexant_jack { - - hda_nid_t nid; - int type; - struct snd_jack *jack; - -}; - struct pin_dac_pair { hda_nid_t pin; hda_nid_t dac; @@ -111,9 +103,6 @@ struct conexant_spec { unsigned int spdif_route; - /* jack detection */ - struct snd_array jacks; - /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; struct hda_input_mux private_imux; @@ -393,71 +382,9 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, &spec->cur_mux[adc_idx]); } -#ifdef CONFIG_SND_HDA_INPUT_JACK -static void conexant_free_jack_priv(struct snd_jack *jack) -{ - struct conexant_jack *jacks = jack->private_data; - jacks->nid = 0; - jacks->jack = NULL; -} - -static int conexant_add_jack(struct hda_codec *codec, - hda_nid_t nid, int type) -{ - struct conexant_spec *spec; - struct conexant_jack *jack; - const char *name; - int i, err; - - spec = codec->spec; - snd_array_init(&spec->jacks, sizeof(*jack), 32); - - jack = spec->jacks.list; - for (i = 0; i < spec->jacks.used; i++, jack++) - if (jack->nid == nid) - return 0 ; /* already present */ - - jack = snd_array_new(&spec->jacks); - name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ; - - if (!jack) - return -ENOMEM; - - jack->nid = nid; - jack->type = type; - - err = snd_jack_new(codec->bus->card, name, type, &jack->jack); - if (err < 0) - return err; - jack->jack->private_data = jack; - jack->jack->private_free = conexant_free_jack_priv; - return 0; -} - -static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) -{ - struct conexant_spec *spec = codec->spec; - struct conexant_jack *jacks = spec->jacks.list; - - if (jacks) { - int i; - for (i = 0; i < spec->jacks.used; i++) { - if (jacks->nid == nid) { - unsigned int present; - present = snd_hda_jack_detect(codec, nid); - - present = (present) ? jacks->type : 0 ; - - snd_jack_report(jacks->jack, - present); - } - jacks++; - } - } -} - static int conexant_init_jacks(struct hda_codec *codec) { +#ifdef CONFIG_SND_HDA_INPUT_JACK struct conexant_spec *spec = codec->spec; int i; @@ -469,15 +396,15 @@ static int conexant_init_jacks(struct hda_codec *codec) int err = 0; switch (hv->param ^ AC_USRSP_EN) { case CONEXANT_HP_EVENT: - err = conexant_add_jack(codec, hv->nid, - SND_JACK_HEADPHONE); - conexant_report_jack(codec, hv->nid); + err = snd_hda_input_jack_add(codec, hv->nid, + SND_JACK_HEADPHONE, NULL); + snd_hda_input_jack_report(codec, hv->nid); break; case CXT5051_PORTC_EVENT: case CONEXANT_MIC_EVENT: - err = conexant_add_jack(codec, hv->nid, - SND_JACK_MICROPHONE); - conexant_report_jack(codec, hv->nid); + err = snd_hda_input_jack_add(codec, hv->nid, + SND_JACK_MICROPHONE, NULL); + snd_hda_input_jack_report(codec, hv->nid); break; } if (err < 0) @@ -485,19 +412,9 @@ static int conexant_init_jacks(struct hda_codec *codec) ++hv; } } - return 0; - -} -#else -static inline void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) -{ -} - -static inline int conexant_init_jacks(struct hda_codec *codec) -{ +#endif /* CONFIG_SND_HDA_INPUT_JACK */ return 0; } -#endif static int conexant_init(struct hda_codec *codec) { @@ -511,18 +428,7 @@ static int conexant_init(struct hda_codec *codec) static void conexant_free(struct hda_codec *codec) { -#ifdef CONFIG_SND_HDA_INPUT_JACK - struct conexant_spec *spec = codec->spec; - if (spec->jacks.list) { - struct conexant_jack *jacks = spec->jacks.list; - int i; - for (i = 0; i < spec->jacks.used; i++, jacks++) { - if (jacks->jack) - snd_device_free(codec->bus->card, jacks->jack); - } - snd_array_free(&spec->jacks); - } -#endif + snd_hda_input_jack_free(codec); snd_hda_detach_beep_device(codec); kfree(codec->spec); } @@ -1787,7 +1693,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec, cxt5051_portc_automic(codec); break; } - conexant_report_jack(codec, nid); + snd_hda_input_jack_report(codec, nid); } static struct snd_kcontrol_new cxt5051_playback_mixers[] = { @@ -1959,10 +1865,8 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | event); -#ifdef CONFIG_SND_HDA_INPUT_JACK - conexant_add_jack(codec, nid, SND_JACK_MICROPHONE); - conexant_report_jack(codec, nid); -#endif + snd_hda_input_jack_add(codec, nid, SND_JACK_MICROPHONE, NULL); + snd_hda_input_jack_report(codec, nid); } static struct hda_verb cxt5051_ideapad_init_verbs[] = { @@ -3477,11 +3381,11 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) switch (res >> 26) { case CONEXANT_HP_EVENT: cx_auto_hp_automute(codec); - conexant_report_jack(codec, nid); + snd_hda_input_jack_report(codec, nid); break; case CONEXANT_MIC_EVENT: cx_auto_automic(codec); - conexant_report_jack(codec, nid); + snd_hda_input_jack_report(codec, nid); break; } } diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index ec0fa2dd0a27..251773e45f61 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -110,6 +110,12 @@ struct dp_audio_infoframe { u8 LFEPBL01_LSV36_DM_INH7; }; +union audio_infoframe { + struct hdmi_audio_infoframe hdmi; + struct dp_audio_infoframe dp; + u8 bytes[0]; +}; + /* * CEA speaker placement: * @@ -620,8 +626,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, int channels = substream->runtime->channels; int ca; int i; - u8 ai[max(sizeof(struct hdmi_audio_infoframe), - sizeof(struct dp_audio_infoframe))]; + union audio_infoframe ai; ca = hdmi_channel_allocation(codec, nid, channels); @@ -633,11 +638,10 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, pin_nid = spec->pin[i]; - memset(ai, 0, sizeof(ai)); + memset(&ai, 0, sizeof(ai)); if (spec->sink_eld[i].conn_type == 0) { /* HDMI */ - struct hdmi_audio_infoframe *hdmi_ai; + struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi; - hdmi_ai = (struct hdmi_audio_infoframe *)ai; hdmi_ai->type = 0x84; hdmi_ai->ver = 0x01; hdmi_ai->len = 0x0a; @@ -645,9 +649,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, hdmi_ai->CA = ca; hdmi_checksum_audio_infoframe(hdmi_ai); } else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */ - struct dp_audio_infoframe *dp_ai; + struct dp_audio_infoframe *dp_ai = &ai.dp; - dp_ai = (struct dp_audio_infoframe *)ai; dp_ai->type = 0x84; dp_ai->len = 0x1b; dp_ai->ver = 0x11 << 2; @@ -664,7 +667,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, * sizeof(*dp_ai) to avoid partial match/update problems when * the user switches between HDMI/DP monitors. */ - if (!hdmi_infoframe_uptodate(codec, pin_nid, ai, sizeof(ai))) { + if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes, + sizeof(ai))) { snd_printdd("hdmi_setup_audio_infoframe: " "cvt=%d pin=%d channels=%d\n", nid, pin_nid, @@ -672,7 +676,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, hdmi_setup_channel_mapping(codec, pin_nid, ca); hdmi_stop_infoframe_trans(codec, pin_nid); hdmi_fill_audio_infoframe(codec, pin_nid, - ai, sizeof(ai)); + ai.bytes, sizeof(ai)); hdmi_start_infoframe_trans(codec, pin_nid); } } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4261bb8eec1d..639d2746713f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -282,12 +282,6 @@ struct alc_mic_route { unsigned char amix_idx; }; -struct alc_jack { - hda_nid_t nid; - int type; - struct snd_jack *jack; -}; - #define MUX_IDX_UNDEF ((unsigned char)-1) struct alc_customize_define { @@ -366,9 +360,6 @@ struct alc_spec { /* PCM information */ struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ - /* jack detection */ - struct snd_array jacks; - /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; struct alc_customize_define cdefine; @@ -394,6 +385,7 @@ struct alc_spec { /* other flags */ unsigned int no_analog :1; /* digital I/O only */ unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */ + unsigned int single_input_src:1; int init_amp; int codec_variant; /* flag for other variants */ @@ -1032,94 +1024,32 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, alc_fix_pll(codec); } -#ifdef CONFIG_SND_HDA_INPUT_JACK -static void alc_free_jack_priv(struct snd_jack *jack) -{ - struct alc_jack *jacks = jack->private_data; - jacks->nid = 0; - jacks->jack = NULL; -} - -static int alc_add_jack(struct hda_codec *codec, - hda_nid_t nid, int type) -{ - struct alc_spec *spec; - struct alc_jack *jack; - const char *name; - int err; - - spec = codec->spec; - snd_array_init(&spec->jacks, sizeof(*jack), 32); - jack = snd_array_new(&spec->jacks); - if (!jack) - return -ENOMEM; - - jack->nid = nid; - jack->type = type; - name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ; - - err = snd_jack_new(codec->bus->card, name, type, &jack->jack); - if (err < 0) - return err; - jack->jack->private_data = jack; - jack->jack->private_free = alc_free_jack_priv; - return 0; -} - -static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid) -{ - struct alc_spec *spec = codec->spec; - struct alc_jack *jacks = spec->jacks.list; - - if (jacks) { - int i; - for (i = 0; i < spec->jacks.used; i++) { - if (jacks->nid == nid) { - unsigned int present; - present = snd_hda_jack_detect(codec, nid); - - present = (present) ? jacks->type : 0; - - snd_jack_report(jacks->jack, present); - } - jacks++; - } - } -} - static int alc_init_jacks(struct hda_codec *codec) { +#ifdef CONFIG_SND_HDA_INPUT_JACK struct alc_spec *spec = codec->spec; int err; unsigned int hp_nid = spec->autocfg.hp_pins[0]; unsigned int mic_nid = spec->ext_mic.pin; if (hp_nid) { - err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE); + err = snd_hda_input_jack_add(codec, hp_nid, + SND_JACK_HEADPHONE, NULL); if (err < 0) return err; - alc_report_jack(codec, hp_nid); + snd_hda_input_jack_report(codec, hp_nid); } if (mic_nid) { - err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE); + err = snd_hda_input_jack_add(codec, mic_nid, + SND_JACK_MICROPHONE, NULL); if (err < 0) return err; - alc_report_jack(codec, mic_nid); + snd_hda_input_jack_report(codec, mic_nid); } - - return 0; -} -#else -static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid) -{ -} - -static inline int alc_init_jacks(struct hda_codec *codec) -{ +#endif /* CONFIG_SND_HDA_INPUT_JACK */ return 0; } -#endif static void alc_automute_speaker(struct hda_codec *codec, int pinctl) { @@ -1133,7 +1063,7 @@ static void alc_automute_speaker(struct hda_codec *codec, int pinctl) nid = spec->autocfg.hp_pins[i]; if (!nid) break; - alc_report_jack(codec, nid); + snd_hda_input_jack_report(codec, nid); spec->jack_present |= snd_hda_jack_detect(codec, nid); } @@ -1240,7 +1170,7 @@ static void alc_mic_automute(struct hda_codec *codec) AC_VERB_SET_CONNECT_SEL, alive->mux_idx); } - alc_report_jack(codec, spec->ext_mic.pin); + snd_hda_input_jack_report(codec, spec->ext_mic.pin); /* FIXME: analog mixer */ } @@ -2292,13 +2222,13 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0f, 2, 0x0, + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0f, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0e, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0e, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -2309,7 +2239,6 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { { } /* end */ }; - static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -3919,6 +3848,8 @@ static struct hda_amp_list alc880_lg_loopbacks[] = { * Common callbacks */ +static void alc_init_special_input_src(struct hda_codec *codec); + static int alc_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -3929,6 +3860,7 @@ static int alc_init(struct hda_codec *codec) for (i = 0; i < spec->num_init_verbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); + alc_init_special_input_src(codec); if (spec->init_hook) spec->init_hook(codec); @@ -4284,6 +4216,7 @@ static void alc_free(struct hda_codec *codec) return; alc_shutup(codec); + snd_hda_input_jack_free(codec); alc_free_kctls(codec); kfree(spec); snd_hda_detach_beep_device(codec); @@ -5151,7 +5084,9 @@ static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg, switch (cfg->line_out_type) { case AUTO_PIN_SPEAKER_OUT: - return "Speaker"; + if (cfg->line_outs == 1) + return "Speaker"; + break; case AUTO_PIN_HP_OUT: return "Headphone"; default: @@ -5205,16 +5140,19 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, return err; } else { const char *name = pfx; - if (!name) + int index = i; + if (!name) { name = chname[i]; + index = 0; + } err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, - name, i, + name, index, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); if (err < 0) return err; err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, - name, i, + name, index, HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); if (err < 0) @@ -5585,6 +5523,7 @@ static void fixup_single_adc(struct hda_codec *codec) spec->capsrc_nids += i; spec->adc_nids += i; spec->num_adc_nids = 1; + spec->single_input_src = 1; } } @@ -5596,6 +5535,16 @@ static void fixup_dual_adc_switch(struct hda_codec *codec) init_capsrc_for_pin(codec, spec->int_mic.pin); } +/* initialize some special cases for input sources */ +static void alc_init_special_input_src(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + if (spec->dual_adc_switch) + fixup_dual_adc_switch(codec); + else if (spec->single_input_src) + init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin); +} + static void set_capture_mixer(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -5611,7 +5560,7 @@ static void set_capture_mixer(struct hda_codec *codec) int mux = 0; int num_adcs = spec->num_adc_nids; if (spec->dual_adc_switch) - fixup_dual_adc_switch(codec); + num_adcs = 1; else if (spec->auto_mic) fixup_automic_adc(codec); else if (spec->input_mux) { @@ -5620,8 +5569,6 @@ static void set_capture_mixer(struct hda_codec *codec) else if (spec->input_mux->num_items == 1) fixup_single_adc(codec); } - if (spec->dual_adc_switch) - num_adcs = 1; spec->cap_mixer = caps[mux][num_adcs - 1]; } } @@ -10748,6 +10695,7 @@ static struct alc_config_preset alc882_presets[] = { */ enum { PINFIX_ABIT_AW9D_MAX, + PINFIX_LENOVO_Y530, PINFIX_PB_M5210, PINFIX_ACER_ASPIRE_7736, }; @@ -10762,6 +10710,14 @@ static const struct alc_fixup alc882_fixups[] = { { } } }, + [PINFIX_LENOVO_Y530] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x15, 0x99130112 }, /* rear int speakers */ + { 0x16, 0x99130111 }, /* subwoofer */ + { } + } + }, [PINFIX_PB_M5210] = { .type = ALC_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -10777,6 +10733,7 @@ static const struct alc_fixup alc882_fixups[] = { static struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210), + SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736), {} @@ -10829,23 +10786,28 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec) hda_nid_t pin, dac; int i; - for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { - pin = spec->autocfg.hp_pins[i]; - if (!pin) - break; - dac = spec->multiout.hp_nid; - if (!dac) - dac = spec->multiout.dac_nids[0]; /* to front */ - alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac); + if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) { + for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { + pin = spec->autocfg.hp_pins[i]; + if (!pin) + break; + dac = spec->multiout.hp_nid; + if (!dac) + dac = spec->multiout.dac_nids[0]; /* to front */ + alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac); + } } - for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { - pin = spec->autocfg.speaker_pins[i]; - if (!pin) - break; - dac = spec->multiout.extra_out_nid[0]; - if (!dac) - dac = spec->multiout.dac_nids[0]; /* to front */ - alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac); + + if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) { + for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { + pin = spec->autocfg.speaker_pins[i]; + if (!pin) + break; + dac = spec->multiout.extra_out_nid[0]; + if (!dac) + dac = spec->multiout.dac_nids[0]; /* to front */ + alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac); + } } } @@ -13796,6 +13758,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) } #define alc268_auto_init_analog_input alc882_auto_init_analog_input +#define alc268_auto_init_input_src alc882_auto_init_input_src /* init callback for auto-configuration model -- overriding the default init */ static void alc268_auto_init(struct hda_codec *codec) @@ -13805,6 +13768,7 @@ static void alc268_auto_init(struct hda_codec *codec) alc268_auto_init_hp_out(codec); alc268_auto_init_mono_speaker_out(codec); alc268_auto_init_analog_input(codec); + alc268_auto_init_input_src(codec); alc_auto_init_digital(codec); if (spec->unsol_event) alc_inithook(codec); @@ -14092,7 +14056,6 @@ static int patch_alc268(struct hda_codec *codec) if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, 0x07); - int i; spec->capsrc_nids = alc268_capsrc_nids; /* get type */ @@ -14112,13 +14075,6 @@ static int patch_alc268(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids); add_mixer(spec, alc268_capture_mixer); } - /* set default input source */ - for (i = 0; i < spec->num_adc_nids; i++) - snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i], - 0, AC_VERB_SET_CONNECT_SEL, - i < spec->num_mux_defs ? - spec->input_mux[i].items[0].index : - spec->input_mux->items[0].index); } spec->vmaster_nid = 0x02; @@ -14495,7 +14451,7 @@ static void alc269_speaker_automute(struct hda_codec *codec) HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, HDA_AMP_MUTE, bits); - alc_report_jack(codec, nid); + snd_hda_input_jack_report(codec, nid); } /* unsolicited event for HP jack sensing */ @@ -14807,11 +14763,6 @@ static int alc269_parse_auto_config(struct hda_codec *codec) fillup_priv_adc_nids(codec, alc269_adc_candidates, sizeof(alc269_adc_candidates)); - /* set default input source */ - if (!spec->dual_adc_switch) - select_or_unmute_capsrc(codec, spec->capsrc_nids[0], - spec->input_mux->items[0].index); - err = alc_auto_add_mic_boost(codec); if (err < 0) return err; @@ -14825,6 +14776,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) #define alc269_auto_init_multi_out alc268_auto_init_multi_out #define alc269_auto_init_hp_out alc268_auto_init_hp_out #define alc269_auto_init_analog_input alc882_auto_init_analog_input +#define alc269_auto_init_input_src alc882_auto_init_input_src /* init callback for auto-configuration model -- overriding the default init */ @@ -14834,6 +14786,8 @@ static void alc269_auto_init(struct hda_codec *codec) alc269_auto_init_multi_out(codec); alc269_auto_init_hp_out(codec); alc269_auto_init_analog_input(codec); + if (!spec->dual_adc_switch) + alc269_auto_init_input_src(codec); alc_auto_init_digital(codec); if (spec->unsol_event) alc_inithook(codec); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index bd7b123f6440..05fcd60cc46f 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -180,18 +180,16 @@ struct sigmatel_event { int data; }; -struct sigmatel_jack { - hda_nid_t nid; - int type; - struct snd_jack *jack; -}; - struct sigmatel_mic_route { hda_nid_t pin; signed char mux_idx; signed char dmux_idx; }; +#define MAX_PINS_NUM 16 +#define MAX_ADCS_NUM 4 +#define MAX_DMICS_NUM 4 + struct sigmatel_spec { struct snd_kcontrol_new *mixers[4]; unsigned int num_mixers; @@ -229,9 +227,6 @@ struct sigmatel_spec { hda_nid_t *pwr_nids; hda_nid_t *dac_list; - /* jack detection */ - struct snd_array jacks; - /* events */ struct snd_array events; @@ -309,6 +304,17 @@ struct sigmatel_spec { struct hda_input_mux private_imux; struct hda_input_mux private_smux; struct hda_input_mux private_mono_mux; + + /* auto spec */ + unsigned auto_pin_cnt; + hda_nid_t auto_pin_nids[MAX_PINS_NUM]; + unsigned auto_adc_cnt; + hda_nid_t auto_adc_nids[MAX_ADCS_NUM]; + hda_nid_t auto_mux_nids[MAX_ADCS_NUM]; + hda_nid_t auto_dmux_nids[MAX_ADCS_NUM]; + unsigned long auto_capvols[MAX_ADCS_NUM]; + unsigned auto_dmic_cnt; + hda_nid_t auto_dmic_nids[MAX_DMICS_NUM]; }; static hda_nid_t stac9200_adc_nids[1] = { @@ -364,14 +370,6 @@ static unsigned long stac92hd73xx_capvols[] = { #define STAC92HD83_DAC_COUNT 3 -static hda_nid_t stac92hd83xxx_mux_nids[2] = { - 0x17, 0x18, -}; - -static hda_nid_t stac92hd83xxx_adc_nids[2] = { - 0x15, 0x16, -}; - static hda_nid_t stac92hd83xxx_pwr_nids[4] = { 0xa, 0xb, 0xd, 0xe, }; @@ -384,25 +382,9 @@ static unsigned int stac92hd83xxx_pwr_mapping[4] = { 0x03, 0x0c, 0x20, 0x40, }; -#define STAC92HD83XXX_NUM_DMICS 2 -static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = { - 0x11, 0x20, 0 -}; - -#define STAC92HD88XXX_NUM_DMICS STAC92HD83XXX_NUM_DMICS -#define stac92hd88xxx_dmic_nids stac92hd83xxx_dmic_nids - -#define STAC92HD87B_NUM_DMICS 1 -static hda_nid_t stac92hd87b_dmic_nids[STAC92HD87B_NUM_DMICS + 1] = { - 0x11, 0 -}; - -#define STAC92HD83XXX_NUM_CAPS 2 -static unsigned long stac92hd83xxx_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_OUTPUT), +static hda_nid_t stac92hd83xxx_dmic_nids[] = { + 0x11, 0x20, }; -#define stac92hd83xxx_capsws stac92hd83xxx_capvols static hda_nid_t stac92hd71bxx_pwr_nids[3] = { 0x0a, 0x0d, 0x0f @@ -581,21 +563,6 @@ static hda_nid_t stac92hd73xx_pin_nids[13] = { 0x14, 0x22, 0x23 }; -static hda_nid_t stac92hd83xxx_pin_nids[10] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x1f, 0x20, -}; - -static hda_nid_t stac92hd87xxx_pin_nids[6] = { - 0x0a, 0x0b, 0x0c, 0x0d, - 0x0f, 0x11, -}; - -static hda_nid_t stac92hd88xxx_pin_nids[8] = { - 0x0a, 0x0b, 0x0c, 0x0d, - 0x0f, 0x11, 0x1f, 0x20, -}; - #define STAC92HD71BXX_NUM_PINS 13 static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x00, @@ -757,7 +724,7 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e struct sigmatel_spec *spec = codec->spec; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); const struct hda_input_mux *imux = spec->input_mux; - unsigned int idx, prev_idx; + unsigned int idx, prev_idx, didx; idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) @@ -769,7 +736,8 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0, AC_VERB_SET_CONNECT_SEL, imux->items[idx].index); - if (prev_idx >= spec->num_analog_muxes) { + if (prev_idx >= spec->num_analog_muxes && + spec->mux_nids[adc_idx] != spec->dmux_nids[adc_idx]) { imux = spec->dinput_mux; /* 0 = analog */ snd_hda_codec_write_cache(codec, @@ -779,9 +747,13 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e } } else { imux = spec->dinput_mux; + /* first dimux item is hardcoded to select analog imux, + * so lets skip it + */ + didx = idx - spec->num_analog_muxes + 1; snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0, AC_VERB_SET_CONNECT_SEL, - imux->items[idx - 1].index); + imux->items[didx].index); } spec->cur_mux[adc_idx] = idx; return 1; @@ -3419,6 +3391,17 @@ static const char * const stac92xx_dmic_labels[5] = { "Digital Mic 3", "Digital Mic 4" }; +static hda_nid_t get_connected_node(struct hda_codec *codec, hda_nid_t mux, + int idx) +{ + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int nums; + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + if (idx >= 0 && idx < nums) + return conn[idx]; + return 0; +} + static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, hda_nid_t nid) { @@ -3429,6 +3412,15 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, for (i = 0; i < nums; i++) if (conn[i] == nid) return i; + + for (i = 0; i < nums; i++) { + unsigned int wid_caps = get_wcaps(codec, conn[i]); + unsigned int wid_type = get_wcaps_type(wid_caps); + + if (wid_type != AC_WID_PIN && wid_type != AC_WID_AUD_MIX) + if (get_connection_index(codec, conn[i], nid) >= 0) + return i; + } return -1; } @@ -3501,6 +3493,16 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, type_idx, HDA_OUTPUT); if (err < 0) return err; + if (!err) { + nid = get_connected_node(codec, + spec->dmux_nids[0], index); + if (nid) + err = create_elem_capture_vol(codec, + nid, label, + type_idx, HDA_INPUT); + if (err < 0) + return err; + } } } @@ -4054,21 +4056,10 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ } -#ifdef CONFIG_SND_HDA_INPUT_JACK -static void stac92xx_free_jack_priv(struct snd_jack *jack) -{ - struct sigmatel_jack *jacks = jack->private_data; - jacks->nid = 0; - jacks->jack = NULL; -} -#endif - static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type) { #ifdef CONFIG_SND_HDA_INPUT_JACK - struct sigmatel_spec *spec = codec->spec; - struct sigmatel_jack *jack; int def_conf = snd_hda_codec_get_pincfg(codec, nid); int connectivity = get_defcfg_connect(def_conf); char name[32]; @@ -4077,26 +4068,15 @@ static int stac92xx_add_jack(struct hda_codec *codec, if (connectivity && connectivity != AC_JACK_PORT_FIXED) return 0; - snd_array_init(&spec->jacks, sizeof(*jack), 32); - jack = snd_array_new(&spec->jacks); - if (!jack) - return -ENOMEM; - jack->nid = nid; - jack->type = type; - snprintf(name, sizeof(name), "%s at %s %s Jack", snd_hda_get_jack_type(def_conf), snd_hda_get_jack_connectivity(def_conf), snd_hda_get_jack_location(def_conf)); - err = snd_jack_new(codec->bus->card, name, type, &jack->jack); - if (err < 0) { - jack->nid = 0; + err = snd_hda_input_jack_add(codec, nid, type, name); + if (err < 0) return err; - } - jack->jack->private_data = jack; - jack->jack->private_free = stac92xx_free_jack_priv; -#endif +#endif /* CONFIG_SND_HDA_INPUT_JACK */ return 0; } @@ -4399,23 +4379,6 @@ static int stac92xx_init(struct hda_codec *codec) return 0; } -static void stac92xx_free_jacks(struct hda_codec *codec) -{ -#ifdef CONFIG_SND_HDA_INPUT_JACK - /* free jack instances manually when clearing/reconfiguring */ - struct sigmatel_spec *spec = codec->spec; - if (!codec->bus->shutdown && spec->jacks.list) { - struct sigmatel_jack *jacks = spec->jacks.list; - int i; - for (i = 0; i < spec->jacks.used; i++, jacks++) { - if (jacks->jack) - snd_device_free(codec->bus->card, jacks->jack); - } - } - snd_array_free(&spec->jacks); -#endif -} - static void stac92xx_free_kctls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -4449,7 +4412,7 @@ static void stac92xx_free(struct hda_codec *codec) return; stac92xx_shutup(codec); - stac92xx_free_jacks(codec); + snd_hda_input_jack_free(codec); snd_array_free(&spec->events); kfree(spec); @@ -4667,33 +4630,6 @@ static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid) stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid)); } -static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) -{ - struct sigmatel_spec *spec = codec->spec; - struct sigmatel_jack *jacks = spec->jacks.list; - - if (jacks) { - int i; - for (i = 0; i < spec->jacks.used; i++) { - if (jacks->nid == nid) { - unsigned int pin_ctl = - snd_hda_codec_read(codec, nid, - 0, AC_VERB_GET_PIN_WIDGET_CONTROL, - 0x00); - int type = jacks->type; - if (type == (SND_JACK_LINEOUT - | SND_JACK_HEADPHONE)) - type = (pin_ctl & AC_PINCTL_HP_EN) - ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT; - snd_jack_report(jacks->jack, - get_pin_presence(codec, nid) - ? type : 0); - } - jacks++; - } - } -} - /* get the pin connection (fixed, none, etc) */ static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx) { @@ -4782,7 +4718,7 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) case STAC_PWR_EVENT: if (spec->num_pwrs > 0) stac92xx_pin_sense(codec, event->nid); - stac92xx_report_jack(codec, event->nid); + snd_hda_input_jack_report(codec, event->nid); switch (codec->subsystem_id) { case 0x103c308f: @@ -5378,6 +5314,105 @@ static int hp_bnb2011_with_dock(struct hda_codec *codec) return 0; } +static void stac92hd8x_add_pin(struct hda_codec *codec, hda_nid_t nid) +{ + struct sigmatel_spec *spec = codec->spec; + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); + int i; + + spec->auto_pin_nids[spec->auto_pin_cnt] = nid; + spec->auto_pin_cnt++; + + if (get_defcfg_device(def_conf) == AC_JACK_MIC_IN && + get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) { + for (i = 0; i < ARRAY_SIZE(stac92hd83xxx_dmic_nids); i++) { + if (nid == stac92hd83xxx_dmic_nids[i]) { + spec->auto_dmic_nids[spec->auto_dmic_cnt] = nid; + spec->auto_dmic_cnt++; + } + } + } +} + +static void stac92hd8x_add_adc(struct hda_codec *codec, hda_nid_t nid) +{ + struct sigmatel_spec *spec = codec->spec; + + spec->auto_adc_nids[spec->auto_adc_cnt] = nid; + spec->auto_adc_cnt++; +} + +static void stac92hd8x_add_mux(struct hda_codec *codec, hda_nid_t nid) +{ + int i, j; + struct sigmatel_spec *spec = codec->spec; + + for (i = 0; i < spec->auto_adc_cnt; i++) { + if (get_connection_index(codec, + spec->auto_adc_nids[i], nid) >= 0) { + /* mux and volume for adc_nids[i] */ + if (!spec->auto_mux_nids[i]) { + spec->auto_mux_nids[i] = nid; + /* 92hd codecs capture volume is in mux */ + spec->auto_capvols[i] = HDA_COMPOSE_AMP_VAL(nid, + 3, 0, HDA_OUTPUT); + } + for (j = 0; j < spec->auto_dmic_cnt; j++) { + if (get_connection_index(codec, nid, + spec->auto_dmic_nids[j]) >= 0) { + /* dmux for adc_nids[i] */ + if (!spec->auto_dmux_nids[i]) + spec->auto_dmux_nids[i] = nid; + break; + } + } + break; + } + } +} + +static void stac92hd8x_fill_auto_spec(struct hda_codec *codec) +{ + hda_nid_t nid, end_nid; + unsigned int wid_caps, wid_type; + struct sigmatel_spec *spec = codec->spec; + + end_nid = codec->start_nid + codec->num_nodes; + + for (nid = codec->start_nid; nid < end_nid; nid++) { + wid_caps = get_wcaps(codec, nid); + wid_type = get_wcaps_type(wid_caps); + + if (wid_type == AC_WID_PIN) + stac92hd8x_add_pin(codec, nid); + + if (wid_type == AC_WID_AUD_IN && !(wid_caps & AC_WCAP_DIGITAL)) + stac92hd8x_add_adc(codec, nid); + } + + for (nid = codec->start_nid; nid < end_nid; nid++) { + wid_caps = get_wcaps(codec, nid); + wid_type = get_wcaps_type(wid_caps); + + if (wid_type == AC_WID_AUD_SEL) + stac92hd8x_add_mux(codec, nid); + } + + spec->pin_nids = spec->auto_pin_nids; + spec->num_pins = spec->auto_pin_cnt; + spec->adc_nids = spec->auto_adc_nids; + spec->num_adcs = spec->auto_adc_cnt; + spec->capvols = spec->auto_capvols; + spec->capsws = spec->auto_capvols; + spec->num_caps = spec->auto_adc_cnt; + spec->mux_nids = spec->auto_mux_nids; + spec->num_muxes = spec->auto_adc_cnt; + spec->dmux_nids = spec->auto_dmux_nids; + spec->num_dmuxes = spec->auto_adc_cnt; + spec->dmic_nids = spec->auto_dmic_nids; + spec->num_dmics = spec->auto_dmic_cnt; +} + static int patch_stac92hd83xxx(struct hda_codec *codec) { struct sigmatel_spec *spec; @@ -5399,26 +5434,17 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0); codec->no_trigger_sense = 1; codec->spec = spec; + + stac92hd8x_fill_auto_spec(codec); + spec->linear_tone_beep = 0; codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; spec->digbeep_nid = 0x21; - spec->dmic_nids = stac92hd83xxx_dmic_nids; - spec->dmux_nids = stac92hd83xxx_mux_nids; - spec->mux_nids = stac92hd83xxx_mux_nids; - spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids); - spec->adc_nids = stac92hd83xxx_adc_nids; - spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids); spec->pwr_nids = stac92hd83xxx_pwr_nids; spec->pwr_mapping = stac92hd83xxx_pwr_mapping; spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); spec->multiout.dac_nids = spec->dac_nids; - spec->init = stac92hd83xxx_core_init; - spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids); - spec->pin_nids = stac92hd83xxx_pin_nids; - spec->num_caps = STAC92HD83XXX_NUM_CAPS; - spec->capvols = stac92hd83xxx_capvols; - spec->capsws = stac92hd83xxx_capsws; spec->board_config = snd_hda_check_board_config(codec, STAC_92HD83XXX_MODELS, @@ -5436,28 +5462,11 @@ again: case 0x111d76d1: case 0x111d76d9: case 0x111d76e5: - spec->dmic_nids = stac92hd87b_dmic_nids; - spec->num_dmics = stac92xx_connected_ports(codec, - stac92hd87b_dmic_nids, - STAC92HD87B_NUM_DMICS); - spec->num_pins = ARRAY_SIZE(stac92hd87xxx_pin_nids); - spec->pin_nids = stac92hd87xxx_pin_nids; - spec->mono_nid = 0; - spec->num_pwrs = 0; - break; case 0x111d7666: case 0x111d7667: case 0x111d7668: case 0x111d7669: case 0x111d76e3: - spec->num_dmics = stac92xx_connected_ports(codec, - stac92hd88xxx_dmic_nids, - STAC92HD88XXX_NUM_DMICS); - spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids); - spec->pin_nids = stac92hd88xxx_pin_nids; - spec->mono_nid = 0; - spec->num_pwrs = 0; - break; case 0x111d7604: case 0x111d76d4: case 0x111d7605: @@ -5466,9 +5475,6 @@ again: if (spec->board_config == STAC_92HD83XXX_PWR_REF) break; spec->num_pwrs = 0; - spec->num_dmics = stac92xx_connected_ports(codec, - stac92hd83xxx_dmic_nids, - STAC92HD83XXX_NUM_DMICS); break; } |