From 9c5dc3bf121b10f1324f2bb3b9a6f7645850c40e Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Thu, 19 Jun 2014 16:11:36 +0800 Subject: ALSA: hda/realtek - Support HP mute led for output and input HP mute led support output mute led and input mute led. ALC280: GPIO3 to control output mute led. Mic1 vref to control input mute led. ALC282: Line1 vref to control output mute led. Mic1 vref to control input mute led. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 114 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index af76995fa966..4852120dd9c6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -101,6 +101,7 @@ struct alc_spec { /* mute LED for HP laptops, see alc269_fixup_mic_mute_hook() */ int mute_led_polarity; hda_nid_t mute_led_nid; + hda_nid_t cap_mute_led_nid; unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */ @@ -3520,6 +3521,67 @@ static void alc269_fixup_hp_gpio_led(struct hda_codec *codec, } } +/* turn on/off mic-mute LED per capture hook */ +static void alc269_fixup_hp_cap_mic_mute_hook(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct alc_spec *spec = codec->spec; + unsigned int pinval, enable, disable; + + pinval = snd_hda_codec_get_pin_target(codec, spec->mute_led_nid); + pinval &= ~AC_PINCTL_VREFEN; + enable = pinval | AC_PINCTL_VREF_80; + disable = pinval | AC_PINCTL_VREF_HIZ; + + if (!ucontrol) + return; + + if (ucontrol->value.integer.value[0] || + ucontrol->value.integer.value[1]) + pinval = disable; + else + pinval = enable; + + if (spec->cap_mute_led_nid) + snd_hda_set_pin_ctl_cache(codec, spec->cap_mute_led_nid, pinval); +} + +static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + static const struct hda_verb gpio_init[] = { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x08 }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x08 }, + {} + }; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook; + spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; + spec->gpio_led = 0; + spec->cap_mute_led_nid = 0x18; + snd_hda_add_verbs(codec, gpio_init); + } +} + +static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook; + spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; + spec->mute_led_polarity = 0; + spec->mute_led_nid = 0x1a; + spec->cap_mute_led_nid = 0x18; + spec->gen.vmaster_mute_enum = 1; + codec->power_filter = led_power_filter; + } +} + static void alc_headset_mode_unplugged(struct hda_codec *codec) { int val; @@ -4255,6 +4317,8 @@ enum { ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC269_FIXUP_HP_MUTE_LED_MIC2, ALC269_FIXUP_HP_GPIO_LED, + ALC269_FIXUP_HP_GPIO_MIC1_LED, + ALC269_FIXUP_HP_LINE1_MIC1_LED, ALC269_FIXUP_INV_DMIC, ALC269_FIXUP_LENOVO_DOCK, ALC269_FIXUP_NO_SHUTUP, @@ -4447,6 +4511,14 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_hp_gpio_led, }, + [ALC269_FIXUP_HP_GPIO_MIC1_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_hp_gpio_mic1_led, + }, + [ALC269_FIXUP_HP_LINE1_MIC1_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_hp_line1_mic1_led, + }, [ALC269_FIXUP_INV_DMIC] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, @@ -4790,6 +4862,20 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2212, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2213, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2234, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2235, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2237, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2238, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2239, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2247, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2248, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2249, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x224a, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x224b, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x224c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x224d, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2266, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2267, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -4814,13 +4900,41 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x22ce, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22d0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22da, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x8004, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), /* ALC290 */ + SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2220, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2222, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2223, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2224, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2247, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2248, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2249, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2256, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2257, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2258, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2259, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2261, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2262, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2277, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2278, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x227d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x227e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), -- cgit v1.2.3-59-g8ed1b From 79514d473b097da82f5bc0b4e41251c44e29d98c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 6 Jun 2014 18:04:34 +0200 Subject: ALSA: hda - Kill snd_printd*() in HDMI debug / info prints Pass codec instance to each function that still prints info and debug outputs via snd_printd*(). Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 46 ++++++++++++++++++++++------------------------ sound/pci/hda/hda_local.h | 4 ++-- sound/pci/hda/patch_hdmi.c | 11 ++++++----- 3 files changed, 30 insertions(+), 31 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 46690a7f48f6..e1cd34d9011d 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -167,7 +167,8 @@ static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid, (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ }) -static void hdmi_update_short_audio_desc(struct cea_sad *a, +static void hdmi_update_short_audio_desc(struct hda_codec *codec, + struct cea_sad *a, const unsigned char *buf) { int i; @@ -188,8 +189,7 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, a->format = GRAB_BITS(buf, 0, 3, 4); switch (a->format) { case AUDIO_CODING_TYPE_REF_STREAM_HEADER: - snd_printd(KERN_INFO - "HDMI: audio coding type 0 not expected\n"); + codec_info(codec, "HDMI: audio coding type 0 not expected\n"); break; case AUDIO_CODING_TYPE_LPCM: @@ -233,9 +233,9 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, a->format = GRAB_BITS(buf, 2, 3, 5); if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { - snd_printd(KERN_INFO - "HDMI: audio coding xtype %d not expected\n", - a->format); + codec_info(codec, + "HDMI: audio coding xtype %d not expected\n", + a->format); a->format = 0; } else a->format += AUDIO_CODING_TYPE_HE_AAC - @@ -247,7 +247,7 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, /* * Be careful, ELD buf could be totally rubbish! */ -int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, +int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, const unsigned char *buf, int size) { int mnl; @@ -256,8 +256,7 @@ int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, e->eld_ver = GRAB_BITS(buf, 0, 3, 5); if (e->eld_ver != ELD_VER_CEA_861D && e->eld_ver != ELD_VER_PARTIAL) { - snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n", - e->eld_ver); + codec_info(codec, "HDMI: Unknown ELD version %d\n", e->eld_ver); goto out_fail; } @@ -280,20 +279,20 @@ int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, e->product_id = get_unaligned_le16(buf + 18); if (mnl > ELD_MAX_MNL) { - snd_printd(KERN_INFO "HDMI: MNL is reserved value %d\n", mnl); + codec_info(codec, "HDMI: MNL is reserved value %d\n", mnl); goto out_fail; } else if (ELD_FIXED_BYTES + mnl > size) { - snd_printd(KERN_INFO "HDMI: out of range MNL %d\n", mnl); + codec_info(codec, "HDMI: out of range MNL %d\n", mnl); goto out_fail; } else strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1); for (i = 0; i < e->sad_count; i++) { if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { - snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i); + codec_info(codec, "HDMI: out of range SAD %d\n", i); goto out_fail; } - hdmi_update_short_audio_desc(e->sad + i, + hdmi_update_short_audio_desc(codec, e->sad + i, buf + ELD_FIXED_BYTES + mnl + 3 * i); } @@ -394,7 +393,8 @@ static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) #define SND_PRINT_RATES_ADVISED_BUFSIZE 80 -static void hdmi_show_short_audio_desc(struct cea_sad *a) +static void hdmi_show_short_audio_desc(struct hda_codec *codec, + struct cea_sad *a) { char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; @@ -412,12 +412,10 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) else buf2[0] = '\0'; - _snd_printd(SND_PR_VERBOSE, "HDMI: supports coding type %s:" - " channels = %d, rates =%s%s\n", - cea_audio_coding_type_names[a->format], - a->channels, - buf, - buf2); + codec_dbg(codec, + "HDMI: supports coding type %s: channels = %d, rates =%s%s\n", + cea_audio_coding_type_names[a->format], + a->channels, buf, buf2); } void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) @@ -432,22 +430,22 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } -void snd_hdmi_show_eld(struct parsed_hdmi_eld *e) +void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e) { int i; - _snd_printd(SND_PR_VERBOSE, "HDMI: detected monitor %s at connection type %s\n", + codec_dbg(codec, "HDMI: detected monitor %s at connection type %s\n", e->monitor_name, eld_connection_type_names[e->conn_type]); if (e->spk_alloc) { char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - _snd_printd(SND_PR_VERBOSE, "HDMI: available speakers:%s\n", buf); + codec_dbg(codec, "HDMI: available speakers:%s\n", buf); } for (i = 0; i < e->sad_count; i++) - hdmi_show_short_audio_desc(e->sad + i); + hdmi_show_short_audio_desc(codec, e->sad + i); } #ifdef CONFIG_PROC_FS diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index ebd1fa6f015c..08a67e4c5df3 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -752,9 +752,9 @@ struct hdmi_eld { int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid, unsigned char *buf, int *eld_size); -int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, +int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, const unsigned char *buf, int size); -void snd_hdmi_show_eld(struct parsed_hdmi_eld *e); +void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e); void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, struct hda_pcm_stream *hinfo); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 3e4417b0ddbe..eab53d7a0f18 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -648,7 +648,8 @@ static int get_channel_allocation_order(int ca) * * TODO: it could select the wrong CA from multiple candidates. */ -static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) +static int hdmi_channel_allocation(struct hda_codec *codec, + struct hdmi_eld *eld, int channels) { int i; int ca = 0; @@ -694,7 +695,7 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) } snd_print_channel_allocation(eld->info.spk_alloc, buf, sizeof(buf)); - snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n", + codec_dbg(codec, "HDMI: select CA 0x%x for %d-channel allocation: %s\n", ca, channels, buf); return ca; @@ -1131,7 +1132,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, if (!non_pcm && per_pin->chmap_set) ca = hdmi_manual_channel_allocation(channels, per_pin->chmap); else - ca = hdmi_channel_allocation(eld, channels); + ca = hdmi_channel_allocation(codec, eld, channels); if (ca < 0) ca = 0; @@ -1557,13 +1558,13 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) eld->eld_valid = false; else { memset(&eld->info, 0, sizeof(struct parsed_hdmi_eld)); - if (snd_hdmi_parse_eld(&eld->info, eld->eld_buffer, + if (snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer, eld->eld_size) < 0) eld->eld_valid = false; } if (eld->eld_valid) { - snd_hdmi_show_eld(&eld->info); + snd_hdmi_show_eld(codec, &eld->info); update_eld = true; } else if (repoll) { -- cgit v1.2.3-59-g8ed1b From 6194b99de9f52b9953b7cf2b48ce0da9276af9c3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 6 Jun 2014 18:12:16 +0200 Subject: ALSA: hda - Kill the rest of snd_print*() usages Pass the codec object so that we can replace all the rest of snd_print*() usages with the proper device-specific print helpers. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 35 +++++++++++++++++++++-------------- sound/pci/hda/hda_codec.h | 3 ++- sound/pci/hda/hda_controller.c | 3 ++- sound/pci/hda/hda_generic.c | 2 +- sound/pci/hda/hda_local.h | 3 ++- sound/pci/hda/patch_ca0132.c | 6 +++--- sound/pci/hda/patch_sigmatel.c | 2 +- 7 files changed, 32 insertions(+), 22 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 4c20277a6835..d91cb7f5961a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2727,7 +2727,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) return 0; } -typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *); +typedef int (*map_slave_func_t)(struct hda_codec *, void *, struct snd_kcontrol *); /* apply the function to all matching slave ctls in the mixer list */ static int map_slaves(struct hda_codec *codec, const char * const *slaves, @@ -2751,7 +2751,7 @@ static int map_slaves(struct hda_codec *codec, const char * const *slaves, name = tmpname; } if (!strcmp(sctl->id.name, name)) { - err = func(data, sctl); + err = func(codec, data, sctl); if (err) return err; break; @@ -2761,13 +2761,15 @@ static int map_slaves(struct hda_codec *codec, const char * const *slaves, return 0; } -static int check_slave_present(void *data, struct snd_kcontrol *sctl) +static int check_slave_present(struct hda_codec *codec, + void *data, struct snd_kcontrol *sctl) { return 1; } /* guess the value corresponding to 0dB */ -static int get_kctl_0dB_offset(struct snd_kcontrol *kctl, int *step_to_check) +static int get_kctl_0dB_offset(struct hda_codec *codec, + struct snd_kcontrol *kctl, int *step_to_check) { int _tlv[4]; const int *tlv = NULL; @@ -2788,7 +2790,7 @@ static int get_kctl_0dB_offset(struct snd_kcontrol *kctl, int *step_to_check) if (!step) return -1; if (*step_to_check && *step_to_check != step) { - snd_printk(KERN_ERR "hda_codec: Mismatching dB step for vmaster slave (%d!=%d)\n", + codec_err(codec, "Mismatching dB step for vmaster slave (%d!=%d)\n", - *step_to_check, step); return -1; } @@ -2813,16 +2815,18 @@ static int put_kctl_with_value(struct snd_kcontrol *kctl, int val) } /* initialize the slave volume with 0dB */ -static int init_slave_0dB(void *data, struct snd_kcontrol *slave) +static int init_slave_0dB(struct hda_codec *codec, + void *data, struct snd_kcontrol *slave) { - int offset = get_kctl_0dB_offset(slave, data); + int offset = get_kctl_0dB_offset(codec, slave, data); if (offset > 0) put_kctl_with_value(slave, offset); return 0; } /* unmute the slave */ -static int init_slave_unmute(void *data, struct snd_kcontrol *slave) +static int init_slave_unmute(struct hda_codec *codec, + void *data, struct snd_kcontrol *slave) { return put_kctl_with_value(slave, 1); } @@ -4280,6 +4284,7 @@ static struct hda_rate_tbl rate_bits[] = { /** * snd_hda_calc_stream_format - calculate format bitset + * @codec: HD-audio codec * @rate: the sample rate * @channels: the number of channels * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) @@ -4289,7 +4294,8 @@ static struct hda_rate_tbl rate_bits[] = { * * Return zero if invalid. */ -unsigned int snd_hda_calc_stream_format(unsigned int rate, +unsigned int snd_hda_calc_stream_format(struct hda_codec *codec, + unsigned int rate, unsigned int channels, unsigned int format, unsigned int maxbps, @@ -4304,12 +4310,12 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, break; } if (!rate_bits[i].hz) { - snd_printdd("invalid rate %d\n", rate); + codec_dbg(codec, "invalid rate %d\n", rate); return 0; } if (channels == 0 || channels > 8) { - snd_printdd("invalid channels %d\n", channels); + codec_dbg(codec, "invalid channels %d\n", channels); return 0; } val |= channels - 1; @@ -4332,7 +4338,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, val |= AC_FMT_BITS_20; break; default: - snd_printdd("invalid format width %d\n", + codec_dbg(codec, "invalid format width %d\n", snd_pcm_format_width(format)); return 0; } @@ -5670,12 +5676,13 @@ EXPORT_SYMBOL_GPL(_snd_hda_set_pin_ctl); * suffix is appended to the label. This label index number is stored * to type_idx when non-NULL pointer is given. */ -int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, +int snd_hda_add_imux_item(struct hda_codec *codec, + struct hda_input_mux *imux, const char *label, int index, int *type_idx) { int i, label_idx = 0; if (imux->num_items >= HDA_MAX_NUM_INPUTS) { - snd_printd(KERN_ERR "hda_codec: Too many imux items!\n"); + codec_err(codec, "hda_codec: Too many imux items!\n"); return -EINVAL; } for (i = 0; i < imux->num_items; i++) { diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 5825aa17d8e3..f84a40ef42af 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -538,7 +538,8 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, int do_now); #define snd_hda_codec_cleanup_stream(codec, nid) \ __snd_hda_codec_cleanup_stream(codec, nid, 0) -unsigned int snd_hda_calc_stream_format(unsigned int rate, +unsigned int snd_hda_calc_stream_format(struct hda_codec *codec, + unsigned int rate, unsigned int channels, unsigned int format, unsigned int maxbps, diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 480bbddbd801..875e0ebf56eb 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -481,7 +481,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) } azx_stream_reset(chip, azx_dev); - format_val = snd_hda_calc_stream_format(runtime->rate, + format_val = snd_hda_calc_stream_format(apcm->codec, + runtime->rate, runtime->channels, runtime->format, hinfo->maxbps, diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 589e47c5aeb3..a24c7b28b000 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -3054,7 +3054,7 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, if (spec->hp_mic_pin == pin) spec->hp_mic_mux_idx = imux->num_items; spec->imux_pins[imux->num_items] = pin; - snd_hda_add_imux_item(imux, label, cfg_idx, NULL); + snd_hda_add_imux_item(codec, imux, label, cfg_idx, NULL); imux_added = true; if (spec->dyn_adc_switch) spec->dyn_adc_idx[imux_idx] = c; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 08a67e4c5df3..d52cc3ef5135 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -268,7 +268,8 @@ int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, struct snd_ctl_elem_value *ucontrol, hda_nid_t nid, unsigned int *cur_val); -int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, +int snd_hda_add_imux_item(struct hda_codec *codec, + struct hda_input_mux *imux, const char *label, int index, int *type_index_ret); /* diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 092f2bd030bd..4f3aba78f720 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2046,14 +2046,14 @@ enum dma_state { DMA_STATE_RUN = 1 }; -static int dma_convert_to_hda_format( +static int dma_convert_to_hda_format(struct hda_codec *codec, unsigned int sample_rate, unsigned short channels, unsigned short *hda_format) { unsigned int format_val; - format_val = snd_hda_calc_stream_format( + format_val = snd_hda_calc_stream_format(codec, sample_rate, channels, SNDRV_PCM_FORMAT_S32_LE, @@ -2452,7 +2452,7 @@ static int dspxfr_image(struct hda_codec *codec, } dma_engine->codec = codec; - dma_convert_to_hda_format(sample_rate, channels, &hda_format); + dma_convert_to_hda_format(codec, sample_rate, channels, &hda_format); dma_engine->m_converter_format = hda_format; dma_engine->buf_size = (ovly ? DSP_DMA_WRITE_BUFLEN_OVLY : DSP_DMA_WRITE_BUFLEN_INIT) * 2; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7f40a150899c..5267ef2b1dcc 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1011,7 +1011,7 @@ static int stac_create_spdif_mux_ctls(struct hda_codec *codec) for (i = 0; i < num_cons; i++) { if (snd_BUG_ON(!labels[i])) return -EINVAL; - snd_hda_add_imux_item(&spec->spdif_mux, labels[i], i, NULL); + snd_hda_add_imux_item(codec, &spec->spdif_mux, labels[i], i, NULL); } kctl = snd_hda_gen_add_kctl(&spec->gen, NULL, &stac_smux_mixer); -- cgit v1.2.3-59-g8ed1b From d0ea6d270bd9f1883f716f92e7837152a4146cf7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 6 Jun 2014 18:17:31 +0200 Subject: ALSA: hda - Remove the obsoleted static quirk codes from patch_conexant.c The static quirk code has been disabled for a while and it seems working fine, so it's time to actually get rid of it. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 2715 +--------------------------------------- 1 file changed, 51 insertions(+), 2664 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 1dc7e974f3b1..7627a69ca6d7 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -34,2671 +34,65 @@ #include "hda_jack.h" #include "hda_generic.h" -#undef ENABLE_CXT_STATIC_QUIRKS - -#define CXT_PIN_DIR_IN 0x00 -#define CXT_PIN_DIR_OUT 0x01 -#define CXT_PIN_DIR_INOUT 0x02 -#define CXT_PIN_DIR_IN_NOMICBIAS 0x03 -#define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04 - -#define CONEXANT_HP_EVENT 0x37 -#define CONEXANT_MIC_EVENT 0x38 -#define CONEXANT_LINE_EVENT 0x39 - -/* Conexant 5051 specific */ - -#define CXT5051_SPDIF_OUT 0x12 -#define CXT5051_PORTB_EVENT 0x38 -#define CXT5051_PORTC_EVENT 0x39 - -#define AUTO_MIC_PORTB (1 << 1) -#define AUTO_MIC_PORTC (1 << 2) - -struct conexant_spec { - struct hda_gen_spec gen; - - unsigned int beep_amp; - - /* extra EAPD pins */ - unsigned int num_eapds; - hda_nid_t eapds[4]; - bool dynamic_eapd; - - unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ - - /* OPLC XO specific */ - bool recording; - bool dc_enable; - unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */ - struct nid_path *dc_mode_path; - -#ifdef ENABLE_CXT_STATIC_QUIRKS - const struct snd_kcontrol_new *mixers[5]; - int num_mixers; - hda_nid_t vmaster_nid; - - const struct hda_verb *init_verbs[5]; /* initialization verbs - * don't forget NULL - * termination! - */ - unsigned int num_init_verbs; - - /* playback */ - struct hda_multi_out multiout; /* playback set-up - * max_channels, dacs must be set - * dig_out_nid and hp_nid are optional - */ - unsigned int cur_eapd; - unsigned int hp_present; - unsigned int line_present; - unsigned int auto_mic; - - /* capture */ - unsigned int num_adc_nids; - const hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; /* digital-in NID; optional */ - - unsigned int cur_adc_idx; - hda_nid_t cur_adc; - unsigned int cur_adc_stream_tag; - unsigned int cur_adc_format; - - const struct hda_pcm_stream *capture_stream; - - /* capture source */ - const struct hda_input_mux *input_mux; - const hda_nid_t *capsrc_nids; - unsigned int cur_mux[3]; - - /* channel model */ - const struct hda_channel_mode *channel_mode; - int num_channel_mode; - - /* PCM information */ - struct hda_pcm pcm_rec[2]; /* used in build_pcms() */ - - unsigned int spdif_route; - - unsigned int port_d_mode; - unsigned int dell_automute:1; - unsigned int dell_vostro:1; - unsigned int ideapad:1; - unsigned int thinkpad:1; - unsigned int hp_laptop:1; - unsigned int asus:1; - - unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ -#endif /* ENABLE_CXT_STATIC_QUIRKS */ -}; - - -#ifdef CONFIG_SND_HDA_INPUT_BEEP -static inline void set_beep_amp(struct conexant_spec *spec, hda_nid_t nid, - int idx, int dir) -{ - spec->gen.beep_nid = nid; - spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir); -} -/* additional beep mixers; the actual parameters are overwritten at build */ -static const struct snd_kcontrol_new cxt_beep_mixer[] = { - HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), - HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), - { } /* end */ -}; - -/* create beep controls if needed */ -static int add_beep_ctls(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int err; - - if (spec->beep_amp) { - const struct snd_kcontrol_new *knew; - for (knew = cxt_beep_mixer; knew->name; knew++) { - struct snd_kcontrol *kctl; - kctl = snd_ctl_new1(knew, codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = spec->beep_amp; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) - return err; - } - } - return 0; -} -#else -#define set_beep_amp(spec, nid, idx, dir) /* NOP */ -#define add_beep_ctls(codec) 0 -#endif - - -#ifdef ENABLE_CXT_STATIC_QUIRKS -static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int conexant_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 conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, - format, substream); -} - -static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int conexant_dig_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 conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); - return 0; -} - - - -static const struct hda_pcm_stream conexant_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .open = conexant_playback_pcm_open, - .prepare = conexant_playback_pcm_prepare, - .cleanup = conexant_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream conexant_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = conexant_capture_pcm_prepare, - .cleanup = conexant_capture_pcm_cleanup - }, -}; - - -static const struct hda_pcm_stream conexant_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .open = conexant_dig_playback_pcm_open, - .close = conexant_dig_playback_pcm_close, - .prepare = conexant_dig_playback_pcm_prepare - }, -}; - -static const struct hda_pcm_stream conexant_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -static int cx5051_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); - return 0; -} - -static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - return 0; -} - -static const struct hda_pcm_stream cx5051_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = cx5051_capture_pcm_prepare, - .cleanup = cx5051_capture_pcm_cleanup - }, -}; - -static int conexant_build_pcms(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "CONEXANT Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dac_nids[0]; - if (spec->capture_stream) - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream; - else { - if (codec->vendor_id == 0x14f15051) - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - cx5051_pcm_analog_capture; - else { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - conexant_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = - spec->num_adc_nids; - } - } - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - - if (spec->multiout.dig_out_nid) { - info++; - codec->num_pcms++; - info->name = "Conexant Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - conexant_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dig_out_nid; - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - conexant_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->dig_in_nid; - } - } - - return 0; -} - -static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - - return snd_hda_input_mux_info(spec->input_mux, uinfo); -} - -static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_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, - spec->capsrc_nids[adc_idx], - &spec->cur_mux[adc_idx]); -} - -static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state) -{ - if (power_state == AC_PWRST_D3) - msleep(100); - snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, - power_state); - /* partial workaround for "azx_get_response timeout" */ - if (power_state == AC_PWRST_D0) - msleep(10); - snd_hda_codec_set_power_to_all(codec, fg, power_state); -} - -static int conexant_init(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_init_verbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); - return 0; -} - -static void conexant_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} - -static const struct snd_kcontrol_new cxt_capture_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put - }, - {} -}; - -static const char * const slave_pfxs[] = { - "Headphone", "Speaker", "Bass Speaker", "Front", "Surround", "CLFE", - NULL -}; - -static int conexant_build_controls(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int i; - int err; - - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - 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->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid); - if (err < 0) - return err; - } - - /* if we have no master control, let's create it */ - if (spec->vmaster_nid && - !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); - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, slave_pfxs, - "Playback Volume"); - if (err < 0) - return err; - } - if (spec->vmaster_nid && - !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, slave_pfxs, - "Playback Switch"); - if (err < 0) - return err; - } - - if (spec->input_mux) { - err = snd_hda_add_new_ctls(codec, cxt_capture_mixers); - if (err < 0) - return err; - } - - err = add_beep_ctls(codec); - if (err < 0) - return err; - - return 0; -} - -static const struct hda_codec_ops conexant_patch_ops = { - .build_controls = conexant_build_controls, - .build_pcms = conexant_build_pcms, - .init = conexant_init, - .free = conexant_free, - .set_power_state = conexant_set_power, -}; - -static int patch_conexant_auto(struct hda_codec *codec); -/* - * EAPD control - * the private value = nid | (invert << 8) - */ - -#define cxt_eapd_info snd_ctl_boolean_mono_info - -static int cxt_eapd_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int invert = (kcontrol->private_value >> 8) & 1; - if (invert) - ucontrol->value.integer.value[0] = !spec->cur_eapd; - else - ucontrol->value.integer.value[0] = spec->cur_eapd; - return 0; - -} - -static int cxt_eapd_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int invert = (kcontrol->private_value >> 8) & 1; - hda_nid_t nid = kcontrol->private_value & 0xff; - unsigned int eapd; - - eapd = !!ucontrol->value.integer.value[0]; - if (invert) - eapd = !eapd; - if (eapd == spec->cur_eapd) - return 0; - - spec->cur_eapd = eapd; - snd_hda_codec_write_cache(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); - return 1; -} - -/* controls for test mode */ -#ifdef CONFIG_SND_DEBUG - -#define CXT_EAPD_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = cxt_eapd_info, \ - .get = cxt_eapd_get, \ - .put = cxt_eapd_put, \ - .private_value = nid | (mask<<16) } - - - -static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, - spec->num_channel_mode); -} - -static int conexant_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - spec->multiout.max_channels); -} - -static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - &spec->multiout.max_channels); - return err; -} - -#define CXT_PIN_MODE(xname, nid, dir) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = conexant_ch_mode_info, \ - .get = conexant_ch_mode_get, \ - .put = conexant_ch_mode_put, \ - .private_value = nid | (dir<<16) } - -#endif /* CONFIG_SND_DEBUG */ - -/* Conexant 5045 specific */ - -static const hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; -static const hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; -static const hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; -#define CXT5045_SPDIF_OUT 0x18 - -static const struct hda_channel_mode cxt5045_modes[1] = { - { 2, NULL }, -}; - -static const struct hda_input_mux cxt5045_capture_source = { - .num_items = 2, - .items = { - { "Internal Mic", 0x1 }, - { "Mic", 0x2 }, - } -}; - -static const struct hda_input_mux cxt5045_capture_source_benq = { - .num_items = 4, - .items = { - { "Internal Mic", 0x1 }, - { "Mic", 0x2 }, - { "Line", 0x3 }, - { "Mixer", 0x0 }, - } -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - /* toggle internal speakers mute depending of presence of - * the headphone jack - */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - - bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, 0x11, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - return 1; -} - -/* bind volumes of both NID 0x10 and 0x11 */ -static const struct hda_bind_ctls cxt5045_hp_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5045_hp_automic(struct hda_codec *codec) -{ - static const struct hda_verb mic_jack_on[] = { - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - static const struct hda_verb mic_jack_off[] = { - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x12); - if (present) - snd_hda_sequence_write(codec, mic_jack_on); - else - snd_hda_sequence_write(codec, mic_jack_off); -} - - -/* mute internal speaker if HP is plugged */ -static void cxt5045_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - spec->hp_present = snd_hda_jack_detect(codec, 0x11); - - bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5045_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - res >>= 26; - switch (res) { - case CONEXANT_HP_EVENT: - cxt5045_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - cxt5045_hp_automic(codec); - break; - - } -} - -static const struct snd_kcontrol_new cxt5045_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x2, HDA_INPUT), - HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5045_hp_master_sw_put, - .private_value = 0x10, - }, - - {} -}; - -static const struct snd_kcontrol_new cxt5045_benq_mixers[] = { - HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x3, HDA_INPUT), - - {} -}; - -static const struct hda_verb cxt5045_init_verbs[] = { - /* Line in, Mic */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - /* HP, Amp */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x11, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Record selector: Internal mic */ - {0x1a, AC_VERB_SET_CONNECT_SEL,0x1}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, - /* SPDIF route: PCM */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - { 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* EAPD */ - {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2 }, /* default on */ - { } /* end */ -}; - -static const struct hda_verb cxt5045_benq_init_verbs[] = { - /* Internal Mic, Mic */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - /* Line In,HP, Amp */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x11, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Record selector: Internal mic */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, - /* SPDIF route: PCM */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - { } /* end */ -}; - -static const struct hda_verb cxt5045_hp_sense_init_verbs[] = { - /* pin sensing on HP jack */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5045_mic_sense_init_verbs[] = { - /* pin sensing on HP jack */ - {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -#ifdef CONFIG_SND_DEBUG -/* Test configuration for debugging, modelled after the ALC260 test - * configuration. - */ -static const struct hda_input_mux cxt5045_test_capture_source = { - .num_items = 5, - .items = { - { "MIXER", 0x0 }, - { "MIC1 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "HP-OUT pin", 0x3 }, - { "CD pin", 0x4 }, - }, -}; - -static const struct snd_kcontrol_new cxt5045_test_mixer[] = { - - /* Output controls */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("HP-OUT Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("HP-OUT Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("LINE1 Playback Switch", 0x12, 0x0, HDA_OUTPUT), - - /* Modes for retasking pin widgets */ - CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT), - CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT), - - /* EAPD Switch Control */ - CXT_EAPD_SWITCH("External Amplifier", 0x10, 0x0), - - /* Loopback mixer controls */ - - HDA_CODEC_VOLUME("PCM Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("PCM Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("MIC1 pin Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 pin Switch", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("LINE1 pin Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("LINE1 pin Switch", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("HP-OUT pin Volume", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("HP-OUT pin Switch", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("CD pin Volume", 0x17, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD pin Switch", 0x17, 0x4, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put, - }, - /* Audio input controls */ - HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb cxt5045_test_init_verbs[] = { - /* Set connections */ - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, - { 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 }, - { 0x12, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* Enable retasking pins as output, initially without power amp */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x01}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - - { } -}; -#endif - - -/* initialize jack-sensing, too */ -static int cxt5045_init(struct hda_codec *codec) -{ - conexant_init(codec); - cxt5045_hp_automute(codec); - return 0; -} - - -enum { - CXT5045_LAPTOP_HPSENSE, - CXT5045_LAPTOP_MICSENSE, - CXT5045_LAPTOP_HPMICSENSE, - CXT5045_BENQ, -#ifdef CONFIG_SND_DEBUG - CXT5045_TEST, -#endif - CXT5045_AUTO, - CXT5045_MODELS -}; - -static const char * const cxt5045_models[CXT5045_MODELS] = { - [CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense", - [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", - [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", - [CXT5045_BENQ] = "benq", -#ifdef CONFIG_SND_DEBUG - [CXT5045_TEST] = "test", -#endif - [CXT5045_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5045_cfg_tbl[] = { - SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), - SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), - SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", - CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK_MASK(0x1631, 0xff00, 0xc100, "Packard Bell", - CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE), - {} -}; - -static int patch_cxt5045(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, - cxt5045_models, - cxt5045_cfg_tbl); - if (board_config < 0) - board_config = CXT5045_AUTO; /* model=auto as default */ - if (board_config == CXT5045_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - codec->single_adc_amp = 1; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids); - spec->multiout.dac_nids = cxt5045_dac_nids; - spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = cxt5045_adc_nids; - spec->capsrc_nids = cxt5045_capsrc_nids; - spec->input_mux = &cxt5045_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = cxt5045_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5045_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes); - spec->channel_mode = cxt5045_modes; - - set_beep_amp(spec, 0x16, 0, 1); - - codec->patch_ops = conexant_patch_ops; - - switch (board_config) { - case CXT5045_LAPTOP_HPSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - case CXT5045_LAPTOP_MICSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - default: - case CXT5045_LAPTOP_HPMICSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 3; - spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; - spec->init_verbs[2] = cxt5045_mic_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - case CXT5045_BENQ: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source_benq; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5045_benq_init_verbs; - spec->mixers[0] = cxt5045_mixers; - spec->mixers[1] = cxt5045_benq_mixers; - spec->num_mixers = 2; - codec->patch_ops.init = cxt5045_init; - break; -#ifdef CONFIG_SND_DEBUG - case CXT5045_TEST: - spec->input_mux = &cxt5045_test_capture_source; - spec->mixers[0] = cxt5045_test_mixer; - spec->init_verbs[0] = cxt5045_test_init_verbs; - break; - -#endif - } - - switch (codec->subsystem_id >> 16) { - case 0x103c: - case 0x1631: - case 0x1734: - case 0x17aa: - /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have - * really bad sound over 0dB on NID 0x17. Fix max PCM level to - * 0 dB (originally it has 0x2b steps with 0dB offset 0x14) - */ - snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, - (0x14 << AC_AMPCAP_OFFSET_SHIFT) | - (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - } - - if (spec->beep_amp) - snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); - - return 0; -} - - -/* Conexant 5047 specific */ -#define CXT5047_SPDIF_OUT 0x11 - -static const hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */ -static const hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; -static const hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; - -static const struct hda_channel_mode cxt5047_modes[1] = { - { 2, NULL }, -}; - -static const struct hda_input_mux cxt5047_toshiba_capture_source = { - .num_items = 2, - .items = { - { "ExtMic", 0x2 }, - { "Line-In", 0x1 }, - } -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - /* toggle internal speakers mute depending of presence of - * the headphone jack - */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; - /* NOTE: Conexat codec needs the index for *OUTPUT* amp of - * pin widgets unlike other codecs. In this case, we need to - * set index 0x01 for the volume from the mixer amp 0x19. - */ - snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01, - HDA_AMP_MUTE, bits); - bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - return 1; -} - -/* mute internal speaker if HP is plugged */ -static void cxt5047_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - spec->hp_present = snd_hda_jack_detect(codec, 0x13); - - bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; - /* See the note in cxt5047_hp_master_sw_put */ - snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01, - HDA_AMP_MUTE, bits); -} - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5047_hp_automic(struct hda_codec *codec) -{ - static const struct hda_verb mic_jack_on[] = { - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {} - }; - static const struct hda_verb mic_jack_off[] = { - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {} - }; - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x15); - if (present) - snd_hda_sequence_write(codec, mic_jack_on); - else - snd_hda_sequence_write(codec, mic_jack_off); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5047_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5047_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - cxt5047_hp_automic(codec); - break; - } -} - -static const struct snd_kcontrol_new cxt5047_base_mixers[] = { - HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5047_hp_master_sw_put, - .private_value = 0x13, - }, - - {} -}; - -static const struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = { - /* See the note in cxt5047_hp_master_sw_put */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), - { } /* end */ -}; - -static const struct hda_verb cxt5047_init_verbs[] = { - /* Line in, Mic, Built-in Mic */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, - /* HP, Speaker */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, /* mixer(0x19) */ - {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mixer(0x19) */ - /* Record selector: Mic */ - {0x12, AC_VERB_SET_CONNECT_SEL,0x03}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, - {0x1A, AC_VERB_SET_CONNECT_SEL,0x02}, - {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, - {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, - /* SPDIF route: PCM */ - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* Enable unsolicited events */ - {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -/* configuration for Toshiba Laptops */ -static const struct hda_verb cxt5047_toshiba_init_verbs[] = { - {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */ - {} -}; - -/* Test configuration for debugging, modelled after the ALC260 test - * configuration. - */ -#ifdef CONFIG_SND_DEBUG -static const struct hda_input_mux cxt5047_test_capture_source = { - .num_items = 4, - .items = { - { "LINE1 pin", 0x0 }, - { "MIC1 pin", 0x1 }, - { "MIC2 pin", 0x2 }, - { "CD pin", 0x3 }, - }, -}; - -static const struct snd_kcontrol_new cxt5047_test_mixer[] = { - - /* Output only controls */ - HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line1-Out Playback Volume", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line1-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line2-Out Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line2-Out Playback Switch", 0x15, 0x0, HDA_OUTPUT), - - /* Modes for retasking pin widgets */ - CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT), - CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT), - - /* EAPD Switch Control */ - CXT_EAPD_SWITCH("External Amplifier", 0x13, 0x0), - - /* Loopback mixer controls */ - HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x12, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 Playback Switch", 0x12, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x12, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("MIC2 Playback Switch", 0x12, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LINE Playback Volume", 0x12, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("LINE Playback Switch", 0x12, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x12, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x12, 0x04, HDA_INPUT), - - HDA_CODEC_VOLUME("Capture-1 Volume", 0x19, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture-1 Switch", 0x19, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-2 Volume", 0x19, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Capture-2 Switch", 0x19, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-3 Volume", 0x19, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Capture-3 Switch", 0x19, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-4 Volume", 0x19, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Capture-4 Switch", 0x19, 0x3, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put, - }, - HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), - - { } /* end */ -}; - -static const struct hda_verb cxt5047_test_init_verbs[] = { - /* Enable retasking pins as output, initially without power amp */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure mic1, mic2, line1 pin widgets take input from the - * OUT1 sum bus when acting as an output. - */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; -#endif - - -/* initialize jack-sensing, too */ -static int cxt5047_hp_init(struct hda_codec *codec) -{ - conexant_init(codec); - cxt5047_hp_automute(codec); - return 0; -} - - -enum { - CXT5047_LAPTOP, /* Laptops w/o EAPD support */ - CXT5047_LAPTOP_HP, /* Some HP laptops */ - CXT5047_LAPTOP_EAPD, /* Laptops with EAPD support */ -#ifdef CONFIG_SND_DEBUG - CXT5047_TEST, -#endif - CXT5047_AUTO, - CXT5047_MODELS -}; - -static const char * const cxt5047_models[CXT5047_MODELS] = { - [CXT5047_LAPTOP] = "laptop", - [CXT5047_LAPTOP_HP] = "laptop-hp", - [CXT5047_LAPTOP_EAPD] = "laptop-eapd", -#ifdef CONFIG_SND_DEBUG - [CXT5047_TEST] = "test", -#endif - [CXT5047_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5047_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", - CXT5047_LAPTOP), - SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), - {} -}; - -static int patch_cxt5047(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, - cxt5047_models, - cxt5047_cfg_tbl); - if (board_config < 0) - board_config = CXT5047_AUTO; /* model=auto as default */ - if (board_config == CXT5047_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - codec->pin_amp_workaround = 1; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids); - spec->multiout.dac_nids = cxt5047_dac_nids; - spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = cxt5047_adc_nids; - spec->capsrc_nids = cxt5047_capsrc_nids; - spec->num_mixers = 1; - spec->mixers[0] = cxt5047_base_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5047_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5047_modes), - spec->channel_mode = cxt5047_modes, - - codec->patch_ops = conexant_patch_ops; - - switch (board_config) { - case CXT5047_LAPTOP: - spec->num_mixers = 2; - spec->mixers[1] = cxt5047_hp_spk_mixers; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - break; - case CXT5047_LAPTOP_HP: - spec->num_mixers = 2; - spec->mixers[1] = cxt5047_hp_only_mixers; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - codec->patch_ops.init = cxt5047_hp_init; - break; - case CXT5047_LAPTOP_EAPD: - spec->input_mux = &cxt5047_toshiba_capture_source; - spec->num_mixers = 2; - spec->mixers[1] = cxt5047_hp_spk_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5047_toshiba_init_verbs; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - break; -#ifdef CONFIG_SND_DEBUG - case CXT5047_TEST: - spec->input_mux = &cxt5047_test_capture_source; - spec->mixers[0] = cxt5047_test_mixer; - spec->init_verbs[0] = cxt5047_test_init_verbs; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; -#endif - } - spec->vmaster_nid = 0x13; - - switch (codec->subsystem_id >> 16) { - case 0x103c: - /* HP laptops have really bad sound over 0 dB on NID 0x10. - * Fix max PCM level to 0 dB (originally it has 0x1e steps - * with 0 dB offset 0x17) - */ - snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - } - - return 0; -} - -/* Conexant 5051 specific */ -static const hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; -static const hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; - -static const struct hda_channel_mode cxt5051_modes[1] = { - { 2, NULL }, -}; - -static void cxt5051_update_speaker(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int pinctl; - /* headphone pin */ - pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0; - snd_hda_set_pin_ctl(codec, 0x16, pinctl); - /* speaker pin */ - pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; - snd_hda_set_pin_ctl(codec, 0x1a, pinctl); - /* on ideapad there is an additional speaker (subwoofer) to mute */ - if (spec->ideapad) - snd_hda_set_pin_ctl(codec, 0x1b, pinctl); -} - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - cxt5051_update_speaker(codec); - return 1; -} - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5051_portb_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int present; - - if (!(spec->auto_mic & AUTO_MIC_PORTB)) - return; - present = snd_hda_jack_detect(codec, 0x17); - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_CONNECT_SEL, - present ? 0x01 : 0x00); -} - -/* switch the current ADC according to the jack state */ -static void cxt5051_portc_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int present; - hda_nid_t new_adc; - - if (!(spec->auto_mic & AUTO_MIC_PORTC)) - return; - present = snd_hda_jack_detect(codec, 0x18); - if (present) - spec->cur_adc_idx = 1; - else - spec->cur_adc_idx = 0; - new_adc = spec->adc_nids[spec->cur_adc_idx]; - if (spec->cur_adc && spec->cur_adc != new_adc) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = new_adc; - snd_hda_codec_setup_stream(codec, new_adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - } -} - -/* mute internal speaker if HP is plugged */ -static void cxt5051_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - - spec->hp_present = snd_hda_jack_detect(codec, 0x16); - cxt5051_update_speaker(codec); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5051_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5051_hp_automute(codec); - break; - case CXT5051_PORTB_EVENT: - cxt5051_portb_automic(codec); - break; - case CXT5051_PORTC_EVENT: - cxt5051_portc_automic(codec); - break; - } -} - -static const struct snd_kcontrol_new cxt5051_playback_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5051_hp_master_sw_put, - .private_value = 0x1a, - }, - {} -}; - -static const struct snd_kcontrol_new cxt5051_capture_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Dock Mic Switch", 0x15, 0x00, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_hp_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x15, 0x00, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_f700_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), - {} -}; - -static const struct hda_verb cxt5051_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - /* SPK */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Internal mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, - /* SPDIF route: PCM */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - /* SPK */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Internal mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* SPDIF route: PCM */ - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5051_f700_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - /* SPK */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Internal mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* SPDIF route: PCM */ - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, - unsigned int event) -{ - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | event); -} - -static const struct hda_verb cxt5051_ideapad_init_verbs[] = { - /* Subwoofer */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } /* end */ -}; - -/* initialize jack-sensing, too */ -static int cxt5051_init(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - - conexant_init(codec); - - if (spec->auto_mic & AUTO_MIC_PORTB) - cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT); - if (spec->auto_mic & AUTO_MIC_PORTC) - cxt5051_init_mic_port(codec, 0x18, CXT5051_PORTC_EVENT); - - if (codec->patch_ops.unsol_event) { - cxt5051_hp_automute(codec); - cxt5051_portb_automic(codec); - cxt5051_portc_automic(codec); - } - return 0; -} - - -enum { - CXT5051_LAPTOP, /* Laptops w/ EAPD support */ - CXT5051_HP, /* no docking */ - CXT5051_HP_DV6736, /* HP without mic switch */ - CXT5051_F700, /* HP Compaq Presario F700 */ - CXT5051_TOSHIBA, /* Toshiba M300 & co */ - CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ - CXT5051_AUTO, /* auto-parser */ - CXT5051_MODELS -}; - -static const char *const cxt5051_models[CXT5051_MODELS] = { - [CXT5051_LAPTOP] = "laptop", - [CXT5051_HP] = "hp", - [CXT5051_HP_DV6736] = "hp-dv6736", - [CXT5051_F700] = "hp-700", - [CXT5051_TOSHIBA] = "toshiba", - [CXT5051_IDEAPAD] = "ideapad", - [CXT5051_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5051_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), - SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), - SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), - SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba M30x", CXT5051_TOSHIBA), - SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", - CXT5051_LAPTOP), - SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), - SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD), - {} -}; - -static int patch_cxt5051(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, - cxt5051_models, - cxt5051_cfg_tbl); - if (board_config < 0) - board_config = CXT5051_AUTO; /* model=auto as default */ - if (board_config == CXT5051_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - codec->pin_amp_workaround = 1; - - codec->patch_ops = conexant_patch_ops; - codec->patch_ops.init = cxt5051_init; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5051_dac_nids); - spec->multiout.dac_nids = cxt5051_dac_nids; - spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; - spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ - spec->adc_nids = cxt5051_adc_nids; - spec->num_mixers = 2; - spec->mixers[0] = cxt5051_capture_mixers; - spec->mixers[1] = cxt5051_playback_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5051_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5051_modes); - spec->channel_mode = cxt5051_modes; - spec->cur_adc = 0; - spec->cur_adc_idx = 0; - - set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); - - codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; - - spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; - switch (board_config) { - case CXT5051_HP: - spec->mixers[0] = cxt5051_hp_mixers; - break; - case CXT5051_HP_DV6736: - spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs; - spec->mixers[0] = cxt5051_hp_dv6736_mixers; - spec->auto_mic = 0; - break; - case CXT5051_F700: - spec->init_verbs[0] = cxt5051_f700_init_verbs; - spec->mixers[0] = cxt5051_f700_mixers; - spec->auto_mic = 0; - break; - case CXT5051_TOSHIBA: - spec->mixers[0] = cxt5051_toshiba_mixers; - spec->auto_mic = AUTO_MIC_PORTB; - break; - case CXT5051_IDEAPAD: - spec->init_verbs[spec->num_init_verbs++] = - cxt5051_ideapad_init_verbs; - spec->ideapad = 1; - break; - } - - if (spec->beep_amp) - snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); - - return 0; -} - -/* Conexant 5066 specific */ - -static const hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; -static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; -static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; -static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; - -static const struct hda_channel_mode cxt5066_modes[1] = { - { 2, NULL }, -}; - -#define HP_PRESENT_PORT_A (1 << 0) -#define HP_PRESENT_PORT_D (1 << 1) -#define hp_port_a_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_A) -#define hp_port_d_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_D) - -static void cxt5066_update_speaker(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int pinctl; - - codec_dbg(codec, - "CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n", - spec->hp_present, spec->cur_eapd); - - /* Port A (HP) */ - pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0; - snd_hda_set_pin_ctl(codec, 0x19, pinctl); - - /* Port D (HP/LO) */ - pinctl = spec->cur_eapd ? spec->port_d_mode : 0; - if (spec->dell_automute || spec->thinkpad) { - /* Mute if Port A is connected */ - if (hp_port_a_present(spec)) - pinctl = 0; - } else { - /* Thinkpad/Dell doesn't give pin-D status */ - if (!hp_port_d_present(spec)) - pinctl = 0; - } - snd_hda_set_pin_ctl(codec, 0x1c, pinctl); - - /* CLASS_D AMP */ - pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; - snd_hda_set_pin_ctl(codec, 0x1f, pinctl); -} - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - cxt5066_update_speaker(codec); - return 1; -} - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_vostro_automic(struct hda_codec *codec) -{ - unsigned int present; - - struct hda_verb ext_mic_present[] = { - /* enable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - - /* switch to external mic input */ - {0x17, AC_VERB_SET_CONNECT_SEL, 0}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - - /* disable internal digital mic */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb ext_mic_absent[] = { - /* enable internal mic, port C */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* switch to internal mic input */ - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, - - /* disable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - - present = snd_hda_jack_detect(codec, 0x1a); - if (present) { - codec_dbg(codec, "CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); - } else { - codec_dbg(codec, "CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); - } -} - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_ideapad_automic(struct hda_codec *codec) -{ - unsigned int present; - - struct hda_verb ext_mic_present[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb ext_mic_absent[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - - present = snd_hda_jack_detect(codec, 0x1b); - if (present) { - codec_dbg(codec, "CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); - } else { - codec_dbg(codec, "CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); - } -} - - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_asus_automic(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x1b); - codec_dbg(codec, "CXT5066: external microphone present=%d\n", present); - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, - present ? 1 : 0); -} - - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_hp_laptop_automic(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x1b); - codec_dbg(codec, "CXT5066: external microphone present=%d\n", present); - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, - present ? 1 : 3); -} - - -/* toggle input of built-in digital mic and mic jack appropriately - order is: external mic -> dock mic -> interal mic */ -static void cxt5066_thinkpad_automic(struct hda_codec *codec) -{ - unsigned int ext_present, dock_present; - - static const struct hda_verb ext_mic_present[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - {0x17, AC_VERB_SET_CONNECT_SEL, 1}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb dock_mic_present[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb ext_mic_absent[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - - ext_present = snd_hda_jack_detect(codec, 0x1b); - dock_present = snd_hda_jack_detect(codec, 0x1a); - if (ext_present) { - codec_dbg(codec, "CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); - } else if (dock_present) { - codec_dbg(codec, "CXT5066: dock microphone detected\n"); - snd_hda_sequence_write(codec, dock_mic_present); - } else { - codec_dbg(codec, "CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); - } -} - -/* mute internal speaker if HP is plugged */ -static void cxt5066_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int portA, portD; - - /* Port A */ - portA = snd_hda_jack_detect(codec, 0x19); - - /* Port D */ - portD = snd_hda_jack_detect(codec, 0x1c); - - spec->hp_present = portA ? HP_PRESENT_PORT_A : 0; - spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0; - codec_dbg(codec, "CXT5066: hp automute portA=%x portD=%x present=%d\n", - portA, portD, spec->hp_present); - cxt5066_update_speaker(codec); -} - -/* Dispatch the right mic autoswitch function */ -static void cxt5066_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; +struct conexant_spec { + struct hda_gen_spec gen; - if (spec->dell_vostro) - cxt5066_vostro_automic(codec); - else if (spec->ideapad) - cxt5066_ideapad_automic(codec); - else if (spec->thinkpad) - cxt5066_thinkpad_automic(codec); - else if (spec->hp_laptop) - cxt5066_hp_laptop_automic(codec); - else if (spec->asus) - cxt5066_asus_automic(codec); -} + unsigned int beep_amp; -/* unsolicited event for jack sensing */ -static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) -{ - codec_dbg(codec, "CXT5066: unsol event %x (%x)\n", res, res >> 26); - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5066_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - cxt5066_automic(codec); - break; - } -} + /* extra EAPD pins */ + unsigned int num_eapds; + hda_nid_t eapds[4]; + bool dynamic_eapd; + unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ -static const struct hda_input_mux cxt5066_analog_mic_boost = { - .num_items = 5, - .items = { - { "0dB", 0 }, - { "10dB", 1 }, - { "20dB", 2 }, - { "30dB", 3 }, - { "40dB", 4 }, - }, + /* OPLC XO specific */ + bool recording; + bool dc_enable; + unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */ + struct nid_path *dc_mode_path; }; -static void cxt5066_set_mic_boost(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_write_cache(codec, 0x17, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | - cxt5066_analog_mic_boost.items[spec->mic_boost].index); - if (spec->ideapad || spec->thinkpad) { - /* adjust the internal mic as well...it is not through 0x17 */ - snd_hda_codec_write_cache(codec, 0x23, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_INPUT | - cxt5066_analog_mic_boost. - items[spec->mic_boost].index); - } -} - -static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - return snd_hda_input_mux_info(&cxt5066_analog_mic_boost, uinfo); -} - -static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->mic_boost; - return 0; -} - -static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; - unsigned int idx; - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - - spec->mic_boost = idx; - cxt5066_set_mic_boost(codec); - return 1; -} -static void conexant_check_dig_outs(struct hda_codec *codec, - const hda_nid_t *dig_pins, - int num_pins) +#ifdef CONFIG_SND_HDA_INPUT_BEEP +static inline void set_beep_amp(struct conexant_spec *spec, hda_nid_t nid, + int idx, int dir) { - struct conexant_spec *spec = codec->spec; - hda_nid_t *nid_loc = &spec->multiout.dig_out_nid; - int i; - - for (i = 0; i < num_pins; i++, dig_pins++) { - unsigned int cfg = snd_hda_codec_get_pincfg(codec, *dig_pins); - if (get_defcfg_connect(cfg) == AC_JACK_PORT_NONE) - continue; - if (snd_hda_get_connections(codec, *dig_pins, nid_loc, 1) != 1) - continue; - } + spec->gen.beep_nid = nid; + spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir); } - -static const struct hda_input_mux cxt5066_capture_source = { - .num_items = 4, - .items = { - { "Mic B", 0 }, - { "Mic C", 1 }, - { "Mic E", 2 }, - { "Mic F", 3 }, - }, -}; - -static const struct hda_bind_ctls cxt5066_bind_capture_vol_others = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), - 0 - }, -}; - -static const struct hda_bind_ctls cxt5066_bind_capture_sw_others = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new cxt5066_mixer_master[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5066_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5066_hp_master_sw_put, - .private_value = 0x1d, - }, - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Mic Boost Capture Enum", - .info = cxt5066_mic_boost_mux_enum_info, - .get = cxt5066_mic_boost_mux_enum_get, - .put = cxt5066_mic_boost_mux_enum_put, - }, - - HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), - HDA_BIND_SW("Capture Switch", &cxt5066_bind_capture_sw_others), - {} -}; - -static const struct snd_kcontrol_new cxt5066_vostro_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Internal Mic Boost Capture Enum", - .info = cxt5066_mic_boost_mux_enum_info, - .get = cxt5066_mic_boost_mux_enum_get, - .put = cxt5066_mic_boost_mux_enum_put, - .private_value = 0x23 | 0x100, - }, - {} -}; - -static const struct hda_verb cxt5066_init_verbs[] = { - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ - - /* Speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* HP, Amp */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - /* no digital microphone support yet */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Audio input selector */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, - - /* SPDIF route: PCM */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, - - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* EAPD */ - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* not handling these yet */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_vostro[] = { - /* Port A: headphones */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port B: external microphone */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port C: unused */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port D: unused */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port E: unused, but has primary EAPD */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* Port F: unused */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port G: internal speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* DAC2: unused */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - - /* Digital microphone port */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* Audio input selectors */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - - /* Disable SPDIF */ - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* enable unsolicited events for Port A and B */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_ideapad[] = { - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ - - /* Speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* HP, Amp */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */ - - /* Audio input selector */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, - {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ - - /* SPDIF route: PCM */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, - - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* internal microphone */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */ - - /* EAPD */ - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_thinkpad[] = { - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ - - /* Port G: internal speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port A: HP, Amp */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port B: Mic Dock */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port C: Mic */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port D: HP Dock, Amp */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */ - - /* Audio input selector */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, - {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ - - /* SPDIF route: PCM */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, - - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* internal microphone */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */ - - /* EAPD */ - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* enable unsolicited events for Port A, B, C and D */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_portd_lo[] = { - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - { } /* end */ -}; - - -static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, +/* additional beep mixers; the actual parameters are overwritten at build */ +static const struct snd_kcontrol_new cxt_beep_mixer[] = { + HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), + HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), { } /* end */ }; -/* initialize jack-sensing, too */ -static int cxt5066_init(struct hda_codec *codec) -{ - codec_dbg(codec, "CXT5066: init\n"); - conexant_init(codec); - if (codec->patch_ops.unsol_event) { - cxt5066_hp_automute(codec); - cxt5066_automic(codec); - } - cxt5066_set_mic_boost(codec); - return 0; -} - -enum { - CXT5066_LAPTOP, /* Laptops w/ EAPD support */ - CXT5066_DELL_LAPTOP, /* Dell Laptop */ - CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */ - CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ - CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ - CXT5066_ASUS, /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */ - CXT5066_HP_LAPTOP, /* HP Laptop */ - CXT5066_AUTO, /* BIOS auto-parser */ - CXT5066_MODELS -}; - -static const char * const cxt5066_models[CXT5066_MODELS] = { - [CXT5066_LAPTOP] = "laptop", - [CXT5066_DELL_LAPTOP] = "dell-laptop", - [CXT5066_DELL_VOSTRO] = "dell-vostro", - [CXT5066_IDEAPAD] = "ideapad", - [CXT5066_THINKPAD] = "thinkpad", - [CXT5066_ASUS] = "asus", - [CXT5066_HP_LAPTOP] = "hp-laptop", - [CXT5066_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { - SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), - SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO), - SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_ASUS), - SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS), - SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS), - SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", - CXT5066_LAPTOP), - SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), - {} -}; - -static int patch_cxt5066(struct hda_codec *codec) +/* create beep controls if needed */ +static int add_beep_ctls(struct hda_codec *codec) { - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, - cxt5066_models, cxt5066_cfg_tbl); - if (board_config < 0) - board_config = CXT5066_AUTO; /* model=auto as default */ - if (board_config == CXT5066_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - - codec->patch_ops = conexant_patch_ops; - codec->patch_ops.init = conexant_init; - - spec->dell_automute = 0; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids); - spec->multiout.dac_nids = cxt5066_dac_nids; - conexant_check_dig_outs(codec, cxt5066_digout_pin_nids, - ARRAY_SIZE(cxt5066_digout_pin_nids)); - spec->num_adc_nids = 1; - spec->adc_nids = cxt5066_adc_nids; - spec->capsrc_nids = cxt5066_capsrc_nids; - spec->input_mux = &cxt5066_capture_source; - - spec->port_d_mode = PIN_HP; - - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5066_init_verbs; - spec->num_channel_mode = ARRAY_SIZE(cxt5066_modes); - spec->channel_mode = cxt5066_modes; - spec->cur_adc = 0; - spec->cur_adc_idx = 0; - - set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); - - switch (board_config) { - default: - case CXT5066_LAPTOP: - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - break; - case CXT5066_DELL_LAPTOP: - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - - spec->port_d_mode = PIN_OUT; - spec->init_verbs[spec->num_init_verbs] = cxt5066_init_verbs_portd_lo; - spec->num_init_verbs++; - spec->dell_automute = 1; - break; - case CXT5066_ASUS: - case CXT5066_HP_LAPTOP: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->init_verbs[spec->num_init_verbs] = - cxt5066_init_verbs_hp_laptop; - spec->num_init_verbs++; - spec->hp_laptop = board_config == CXT5066_HP_LAPTOP; - spec->asus = board_config == CXT5066_ASUS; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - /* no S/PDIF out */ - if (board_config == CXT5066_HP_LAPTOP) - spec->multiout.dig_out_nid = 0; - /* input source automatically selected */ - spec->input_mux = NULL; - spec->port_d_mode = 0; - spec->mic_boost = 3; /* default 30dB gain */ - break; + struct conexant_spec *spec = codec->spec; + int err; - case CXT5066_DELL_VOSTRO: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->init_verbs[0] = cxt5066_init_verbs_vostro; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; - spec->port_d_mode = 0; - spec->dell_vostro = 1; - spec->mic_boost = 3; /* default 30dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - break; - case CXT5066_IDEAPAD: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - spec->init_verbs[0] = cxt5066_init_verbs_ideapad; - spec->port_d_mode = 0; - spec->ideapad = 1; - spec->mic_boost = 2; /* default 20dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - break; - case CXT5066_THINKPAD: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - spec->init_verbs[0] = cxt5066_init_verbs_thinkpad; - spec->thinkpad = 1; - spec->port_d_mode = PIN_OUT; - spec->mic_boost = 2; /* default 20dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - break; + if (spec->beep_amp) { + const struct snd_kcontrol_new *knew; + for (knew = cxt_beep_mixer; knew->name; knew++) { + struct snd_kcontrol *kctl; + kctl = snd_ctl_new1(knew, codec); + if (!kctl) + return -ENOMEM; + kctl->private_value = spec->beep_amp; + err = snd_hda_ctl_add(codec, 0, kctl); + if (err < 0) + return err; + } } - - if (spec->beep_amp) - snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); - return 0; } - -#endif /* ENABLE_CXT_STATIC_QUIRKS */ - +#else +#define set_beep_amp(spec, nid, idx, dir) /* NOP */ +#define add_beep_ctls(codec) 0 +#endif /* * Automatic parser for CX20641 & co @@ -3487,35 +881,28 @@ static int patch_conexant_auto(struct hda_codec *codec) return err; } -#ifndef ENABLE_CXT_STATIC_QUIRKS -#define patch_cxt5045 patch_conexant_auto -#define patch_cxt5047 patch_conexant_auto -#define patch_cxt5051 patch_conexant_auto -#define patch_cxt5066 patch_conexant_auto -#endif - /* */ static const struct hda_codec_preset snd_hda_preset_conexant[] = { { .id = 0x14f15045, .name = "CX20549 (Venice)", - .patch = patch_cxt5045 }, + .patch = patch_conexant_auto }, { .id = 0x14f15047, .name = "CX20551 (Waikiki)", - .patch = patch_cxt5047 }, + .patch = patch_conexant_auto }, { .id = 0x14f15051, .name = "CX20561 (Hermosa)", - .patch = patch_cxt5051 }, + .patch = patch_conexant_auto }, { .id = 0x14f15066, .name = "CX20582 (Pebble)", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15068, .name = "CX20584", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15069, .name = "CX20585", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f1506c, .name = "CX20588", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f1506e, .name = "CX20590", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15097, .name = "CX20631", .patch = patch_conexant_auto }, { .id = 0x14f15098, .name = "CX20632", -- cgit v1.2.3-59-g8ed1b From db8e8a9dc97224b016461e596721ebbcfed9c08d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 6 Jun 2014 18:21:38 +0200 Subject: ALSA: hda - Remove the obsoleted static quirk codes from patch_cmedia.c The static quirk code has been disabled for a while and it seems working fine, so it's time to actually get rid of it. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cmedia.c | 624 +------------------------------------------ 1 file changed, 9 insertions(+), 615 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 061ea5965dd5..ed3d133ffbb6 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -31,549 +31,10 @@ #include "hda_jack.h" #include "hda_generic.h" -#undef ENABLE_CMI_STATIC_QUIRKS - -#ifdef ENABLE_CMI_STATIC_QUIRKS -#define NUM_PINS 11 - - -/* board config type */ -enum { - CMI_MINIMAL, /* back 3-jack */ - CMI_MIN_FP, /* back 3-jack + front-panel 2-jack */ - CMI_FULL, /* back 6-jack + front-panel 2-jack */ - CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ - CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ - CMI_AUTO, /* let driver guess it */ - CMI_MODELS -}; -#endif /* ENABLE_CMI_STATIC_QUIRKS */ - struct cmi_spec { struct hda_gen_spec gen; - -#ifdef ENABLE_CMI_STATIC_QUIRKS - /* below are only for static models */ - - int board_config; - unsigned int no_line_in: 1; /* no line-in (5-jack) */ - unsigned int front_panel: 1; /* has front-panel 2-jack */ - - /* playback */ - struct hda_multi_out multiout; - hda_nid_t dac_nids[AUTO_CFG_MAX_OUTS]; /* NID for each DAC */ - int num_dacs; - - /* capture */ - const hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; - - /* capture source */ - const struct hda_input_mux *input_mux; - unsigned int cur_mux[2]; - - /* channel mode */ - int num_channel_modes; - const struct hda_channel_mode *channel_modes; - - struct hda_pcm pcm_rec[2]; /* PCM information */ - - /* pin default configuration */ - hda_nid_t pin_nid[NUM_PINS]; - unsigned int def_conf[NUM_PINS]; - unsigned int pin_def_confs; - - /* multichannel pins */ - struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ -#endif /* ENABLE_CMI_STATIC_QUIRKS */ -}; - -#ifdef ENABLE_CMI_STATIC_QUIRKS -/* - * input MUX - */ -static int cmi_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->input_mux, uinfo); -} - -static int cmi_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int cmi_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_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, - spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); -} - -/* - * shared line-in, mic for surrounds - */ - -/* 3-stack / 2 channel */ -static const struct hda_verb cmi9880_ch2_init[] = { - /* set line-in PIN for input */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* set mic PIN for input, also enable vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* route front PCM (DAC1) to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - {} -}; - -/* 3-stack / 6 channel */ -static const struct hda_verb cmi9880_ch6_init[] = { - /* set line-in PIN for output */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* set mic PIN for output */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* route front PCM (DAC1) to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - {} -}; - -/* 3-stack+front / 8 channel */ -static const struct hda_verb cmi9880_ch8_init[] = { - /* set line-in PIN for output */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* set mic PIN for output */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* route rear-surround PCM (DAC4) to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 }, - {} -}; - -static const struct hda_channel_mode cmi9880_channel_modes[3] = { - { 2, cmi9880_ch2_init }, - { 6, cmi9880_ch6_init }, - { 8, cmi9880_ch8_init }, -}; - -static int cmi_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_modes, - spec->num_channel_modes); -} - -static int cmi_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_modes, - spec->num_channel_modes, spec->multiout.max_channels); -} - -static int cmi_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_modes, - spec->num_channel_modes, &spec->multiout.max_channels); -} - -/* - */ -static const struct snd_kcontrol_new cmi9880_basic_mixer[] = { - /* CMI9880 has no playback volumes! */ - HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */ - HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x06, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = cmi_mux_enum_info, - .get = cmi_mux_enum_get, - .put = cmi_mux_enum_put, - }, - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x23, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x23, 0, HDA_OUTPUT), - { } /* end */ }; -/* - * shared I/O pins - */ -static const struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = cmi_ch_mode_info, - .get = cmi_ch_mode_get, - .put = cmi_ch_mode_put, - }, - { } /* end */ -}; - -/* AUD-in selections: - * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20 - */ -static const struct hda_input_mux cmi9880_basic_mux = { - .num_items = 4, - .items = { - { "Front Mic", 0x5 }, - { "Rear Mic", 0x2 }, - { "Line", 0x1 }, - { "CD", 0x7 }, - } -}; - -static const struct hda_input_mux cmi9880_no_line_mux = { - .num_items = 3, - .items = { - { "Front Mic", 0x5 }, - { "Rear Mic", 0x2 }, - { "CD", 0x7 }, - } -}; - -/* front, rear, clfe, rear_surr */ -static const hda_nid_t cmi9880_dac_nids[4] = { - 0x03, 0x04, 0x05, 0x06 -}; -/* ADC0, ADC1 */ -static const hda_nid_t cmi9880_adc_nids[2] = { - 0x08, 0x09 -}; - -#define CMI_DIG_OUT_NID 0x07 -#define CMI_DIG_IN_NID 0x0a - -/* - */ -static const struct hda_verb cmi9880_basic_init[] = { - /* port-D for line out (rear panel) */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* route front mic to ADC1/2 */ - { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, - { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, - {} /* terminator */ -}; - -static const struct hda_verb cmi9880_allout_init[] = { - /* port-D for line out (rear panel) */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-A for side (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, - /* port-C for surround (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* route front mic to ADC1/2 */ - { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, - { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, - {} /* terminator */ -}; - -/* - */ -static int cmi9880_build_controls(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - struct snd_kcontrol *kctl; - int i, err; - - err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer); - if (err < 0) - return err; - if (spec->channel_modes) { - err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - 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->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } - - /* assign Capture Source enums to NID */ - kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); - for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nid(codec, kctl, i, spec->adc_nids[i]); - if (err < 0) - return err; - } - return 0; -} - -static int cmi9880_init(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - if (spec->board_config == CMI_ALLOUT) - snd_hda_sequence_write(codec, cmi9880_allout_init); - else - snd_hda_sequence_write(codec, cmi9880_basic_init); - if (spec->board_config == CMI_AUTO) - snd_hda_sequence_write(codec, spec->multi_init); - return 0; -} - -/* - * Analog playback callbacks - */ -static int cmi9880_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int cmi9880_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 cmi_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -static int cmi9880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int cmi9880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int cmi9880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int cmi9880_dig_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 cmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int cmi9880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - - snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); - return 0; -} - - -/* - */ -static const struct hda_pcm_stream cmi9880_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .nid = 0x03, /* NID to query formats and rates */ - .ops = { - .open = cmi9880_playback_pcm_open, - .prepare = cmi9880_playback_pcm_prepare, - .cleanup = cmi9880_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream cmi9880_pcm_analog_capture = { - .substreams = 2, - .channels_min = 2, - .channels_max = 2, - .nid = 0x08, /* NID to query formats and rates */ - .ops = { - .prepare = cmi9880_capture_pcm_prepare, - .cleanup = cmi9880_capture_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream cmi9880_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in cmi9880_build_pcms */ - .ops = { - .open = cmi9880_dig_playback_pcm_open, - .close = cmi9880_dig_playback_pcm_close, - .prepare = cmi9880_dig_playback_pcm_prepare - }, -}; - -static const struct hda_pcm_stream cmi9880_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in cmi9880_build_pcms */ -}; - -static int cmi9880_build_pcms(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "CMI9880"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_analog_capture; - - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - codec->num_pcms++; - info++; - info->name = "CMI9880 Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->multiout.dig_out_nid) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - } - - return 0; -} - -static void cmi9880_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} - -/* - */ - -static const char * const cmi9880_models[CMI_MODELS] = { - [CMI_MINIMAL] = "minimal", - [CMI_MIN_FP] = "min_fp", - [CMI_FULL] = "full", - [CMI_FULL_DIG] = "full_dig", - [CMI_ALLOUT] = "allout", - [CMI_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cmi9880_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG), - SND_PCI_QUIRK(0x1854, 0x002b, "LG LS75", CMI_MINIMAL), - SND_PCI_QUIRK(0x1854, 0x0032, "LG", CMI_FULL_DIG), - {} /* terminator */ -}; - -static const struct hda_codec_ops cmi9880_patch_ops = { - .build_controls = cmi9880_build_controls, - .build_pcms = cmi9880_build_pcms, - .init = cmi9880_init, - .free = cmi9880_free, -}; -#endif /* ENABLE_CMI_STATIC_QUIRKS */ - /* * stuff for auto-parser */ @@ -585,12 +46,18 @@ static const struct hda_codec_ops cmi_auto_patch_ops = { .unsol_event = snd_hda_jack_unsol_event, }; -static int cmi_parse_auto_config(struct hda_codec *codec) +static int patch_cmi9880(struct hda_codec *codec) { - struct cmi_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->gen.autocfg; + struct cmi_spec *spec; + struct auto_pin_cfg *cfg; int err; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + cfg = &spec->gen.autocfg; snd_hda_gen_spec_init(&spec->gen); err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); @@ -608,79 +75,6 @@ static int cmi_parse_auto_config(struct hda_codec *codec) return err; } - -static int patch_cmi9880(struct hda_codec *codec) -{ - struct cmi_spec *spec; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; -#ifdef ENABLE_CMI_STATIC_QUIRKS - spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS, - cmi9880_models, - cmi9880_cfg_tbl); - if (spec->board_config < 0) { - codec_dbg(codec, "%s: BIOS auto-probing.\n", - codec->chip_name); - spec->board_config = CMI_AUTO; /* try everything */ - } - - if (spec->board_config == CMI_AUTO) - return cmi_parse_auto_config(codec); - - /* copy default DAC NIDs */ - memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); - spec->num_dacs = 4; - - switch (spec->board_config) { - case CMI_MINIMAL: - case CMI_MIN_FP: - spec->channel_modes = cmi9880_channel_modes; - if (spec->board_config == CMI_MINIMAL) - spec->num_channel_modes = 2; - else { - spec->front_panel = 1; - spec->num_channel_modes = 3; - } - spec->multiout.max_channels = cmi9880_channel_modes[0].channels; - spec->input_mux = &cmi9880_basic_mux; - break; - case CMI_FULL: - case CMI_FULL_DIG: - spec->front_panel = 1; - spec->multiout.max_channels = 8; - spec->input_mux = &cmi9880_basic_mux; - if (spec->board_config == CMI_FULL_DIG) { - spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; - spec->dig_in_nid = CMI_DIG_IN_NID; - } - break; - case CMI_ALLOUT: - default: - spec->front_panel = 1; - spec->multiout.max_channels = 8; - spec->no_line_in = 1; - spec->input_mux = &cmi9880_no_line_mux; - spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; - break; - } - - spec->multiout.num_dacs = spec->num_dacs; - spec->multiout.dac_nids = spec->dac_nids; - - spec->adc_nids = cmi9880_adc_nids; - - codec->patch_ops = cmi9880_patch_ops; - - return 0; -#else - return cmi_parse_auto_config(codec); -#endif -} - /* * patch entries */ -- cgit v1.2.3-59-g8ed1b From 085ec0d945cd52caba3765e4cbcfe24cc136e905 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Jun 2014 15:51:40 +0200 Subject: ALSA: hda - Remove superfluous MAX_AZX_DEV MAX_AZX_DEV is no longer referred anywhere, let's kill it. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_priv.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index 4a7cb01fa912..da12d10b778f 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -120,9 +120,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define TERA_NUM_CAPTURE 3 #define TERA_NUM_PLAYBACK 4 -/* this number is statically defined for simplicity */ -#define MAX_AZX_DEV 16 - /* max number of fragments - we may use more if allocating more pages for BDL */ #define BDL_SIZE 4096 #define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) -- cgit v1.2.3-59-g8ed1b From b6050ef664219a0bc97d0626759ef070ed77fcba Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Jun 2014 16:50:16 +0200 Subject: ALSA: hda - Make position_fix as generic callback ... and move most parts into hda_intel.c from the generic controller code. This is a clean up, and there should be no functional change by this patch. Now, struct azx obtains the generic callbacks for getting the position and the delay. As default NULL, posbuf is read. These replace the old position_fix[], and each is implemented as a callback. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 127 ++++++---------------------------- sound/pci/hda/hda_controller.h | 6 +- sound/pci/hda/hda_intel.c | 151 ++++++++++++++++++++++++++++++++++++++--- sound/pci/hda/hda_priv.h | 17 ++--- sound/pci/hda/hda_tegra.c | 2 - 5 files changed, 174 insertions(+), 129 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 875e0ebf56eb..a562d86c02fb 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -152,8 +152,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) upper_32_bits(azx_dev->bdl.addr)); /* enable the position buffer */ - if (chip->position_fix[0] != POS_FIX_LPIB || - chip->position_fix[1] != POS_FIX_LPIB) { + if (chip->get_position[0] != azx_get_pos_lpib || + chip->get_position[1] != azx_get_pos_lpib) { if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); @@ -673,125 +673,40 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } -/* get the current DMA position with correction on VIA chips */ -static unsigned int azx_via_get_position(struct azx *chip, - struct azx_dev *azx_dev) +unsigned int azx_get_pos_lpib(struct azx *chip, struct azx_dev *azx_dev) { - unsigned int link_pos, mini_pos, bound_pos; - unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos; - unsigned int fifo_size; - - link_pos = azx_sd_readl(chip, azx_dev, SD_LPIB); - if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* Playback, no problem using link position */ - return link_pos; - } - - /* Capture */ - /* For new chipset, - * use mod to get the DMA position just like old chipset - */ - mod_dma_pos = le32_to_cpu(*azx_dev->posbuf); - mod_dma_pos %= azx_dev->period_bytes; - - /* azx_dev->fifo_size can't get FIFO size of in stream. - * Get from base address + offset. - */ - fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET); - - if (azx_dev->insufficient) { - /* Link position never gather than FIFO size */ - if (link_pos <= fifo_size) - return 0; - - azx_dev->insufficient = 0; - } - - if (link_pos <= fifo_size) - mini_pos = azx_dev->bufsize + link_pos - fifo_size; - else - mini_pos = link_pos - fifo_size; - - /* Find nearest previous boudary */ - mod_mini_pos = mini_pos % azx_dev->period_bytes; - mod_link_pos = link_pos % azx_dev->period_bytes; - if (mod_link_pos >= fifo_size) - bound_pos = link_pos - mod_link_pos; - else if (mod_dma_pos >= mod_mini_pos) - bound_pos = mini_pos - mod_mini_pos; - else { - bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes; - if (bound_pos >= azx_dev->bufsize) - bound_pos = 0; - } + return azx_sd_readl(chip, azx_dev, SD_LPIB); +} +EXPORT_SYMBOL_GPL(azx_get_pos_lpib); - /* Calculate real DMA position we want */ - return bound_pos + mod_dma_pos; +unsigned int azx_get_pos_posbuf(struct azx *chip, struct azx_dev *azx_dev) +{ + return le32_to_cpu(*azx_dev->posbuf); } +EXPORT_SYMBOL_GPL(azx_get_pos_posbuf); unsigned int azx_get_position(struct azx *chip, - struct azx_dev *azx_dev, - bool with_check) + struct azx_dev *azx_dev) { struct snd_pcm_substream *substream = azx_dev->substream; - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); unsigned int pos; int stream = substream->stream; - struct hda_pcm_stream *hinfo = apcm->hinfo[stream]; int delay = 0; - switch (chip->position_fix[stream]) { - case POS_FIX_LPIB: - /* read LPIB */ - pos = azx_sd_readl(chip, azx_dev, SD_LPIB); - break; - case POS_FIX_VIACOMBO: - pos = azx_via_get_position(chip, azx_dev); - break; - default: - /* use the position buffer */ - pos = le32_to_cpu(*azx_dev->posbuf); - if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) { - if (!pos || pos == (u32)-1) { - dev_info(chip->card->dev, - "Invalid position buffer, using LPIB read method instead.\n"); - chip->position_fix[stream] = POS_FIX_LPIB; - pos = azx_sd_readl(chip, azx_dev, SD_LPIB); - } else - chip->position_fix[stream] = POS_FIX_POSBUF; - } - break; - } + if (chip->get_position[stream]) + pos = chip->get_position[stream](chip, azx_dev); + else /* use the position buffer as default */ + pos = azx_get_pos_posbuf(chip, azx_dev); if (pos >= azx_dev->bufsize) pos = 0; - /* calculate runtime delay from LPIB */ - if (substream->runtime && - chip->position_fix[stream] == POS_FIX_POSBUF && - (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { - unsigned int lpib_pos = azx_sd_readl(chip, azx_dev, SD_LPIB); - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - delay = pos - lpib_pos; - else - delay = lpib_pos - pos; - if (delay < 0) { - if (delay >= azx_dev->delay_negative_threshold) - delay = 0; - else - delay += azx_dev->bufsize; - } - if (delay >= azx_dev->period_bytes) { - dev_info(chip->card->dev, - "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n", - delay, azx_dev->period_bytes); - delay = 0; - chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; - } - delay = bytes_to_frames(substream->runtime, delay); - } - if (substream->runtime) { + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct hda_pcm_stream *hinfo = apcm->hinfo[stream]; + + if (chip->get_delay[stream]) + delay += chip->get_delay[stream](chip, azx_dev, pos); if (hinfo->ops.get_delay) delay += hinfo->ops.get_delay(hinfo, apcm->codec, substream); @@ -809,7 +724,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) struct azx *chip = apcm->chip; struct azx_dev *azx_dev = get_azx_dev(substream); return bytes_to_frames(substream->runtime, - azx_get_position(chip, azx_dev, false)); + azx_get_position(chip, azx_dev)); } static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream, diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index baf0e77330af..91f04958e2b0 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -25,9 +25,9 @@ static inline struct azx_dev *get_azx_dev(struct snd_pcm_substream *substream) { return substream->runtime->private_data; } -unsigned int azx_get_position(struct azx *chip, - struct azx_dev *azx_dev, - bool with_check); +unsigned int azx_get_position(struct azx *chip, struct azx_dev *azx_dev); +unsigned int azx_get_pos_lpib(struct azx *chip, struct azx_dev *azx_dev); +unsigned int azx_get_pos_posbuf(struct azx *chip, struct azx_dev *azx_dev); /* Stream control. */ void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 25753db97071..cb5d807bbd0c 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -66,6 +66,15 @@ #include "hda_controller.h" #include "hda_priv.h" +/* position fix mode */ +enum { + POS_FIX_AUTO, + POS_FIX_LPIB, + POS_FIX_POSBUF, + POS_FIX_VIACOMBO, + POS_FIX_COMBO, +}; + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; @@ -434,6 +443,38 @@ static void azx_init_pci(struct azx *chip) } } +/* calculate runtime delay from LPIB */ +static int azx_get_delay_from_lpib(struct azx *chip, struct azx_dev *azx_dev, + unsigned int pos) +{ + struct snd_pcm_substream *substream = azx_dev->substream; + int stream = substream->stream; + unsigned int lpib_pos = azx_get_pos_lpib(chip, azx_dev); + int delay; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + delay = pos - lpib_pos; + else + delay = lpib_pos - pos; + if (delay < 0) { + if (delay >= azx_dev->delay_negative_threshold) + delay = 0; + else + delay += azx_dev->bufsize; + } + + if (delay >= azx_dev->period_bytes) { + dev_info(chip->card->dev, + "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n", + delay, azx_dev->period_bytes); + delay = 0; + chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; + chip->get_delay[stream] = NULL; + } + + return bytes_to_frames(substream->runtime, delay); +} + static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev); /* called from IRQ */ @@ -464,6 +505,8 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) */ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) { + struct snd_pcm_substream *substream = azx_dev->substream; + int stream = substream->stream; u32 wallclk; unsigned int pos; @@ -471,7 +514,25 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) if (wallclk < (azx_dev->period_wallclk * 2) / 3) return -1; /* bogus (too early) interrupt */ - pos = azx_get_position(chip, azx_dev, true); + if (chip->get_position[stream]) + pos = chip->get_position[stream](chip, azx_dev); + else { /* use the position buffer as default */ + pos = azx_get_pos_posbuf(chip, azx_dev); + if (!pos || pos == (u32)-1) { + dev_info(chip->card->dev, + "Invalid position buffer, using LPIB read method instead.\n"); + chip->get_position[stream] = azx_get_pos_lpib; + pos = azx_get_pos_lpib(chip, azx_dev); + chip->get_delay[stream] = NULL; + } else { + chip->get_position[stream] = azx_get_pos_posbuf; + if (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY) + chip->get_delay[stream] = azx_get_delay_from_lpib; + } + } + + if (pos >= azx_dev->bufsize) + pos = 0; if (WARN_ONCE(!azx_dev->period_bytes, "hda-intel: zero azx_dev->period_bytes")) @@ -554,6 +615,62 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) return 0; } +/* get the current DMA position with correction on VIA chips */ +static unsigned int azx_via_get_position(struct azx *chip, + struct azx_dev *azx_dev) +{ + unsigned int link_pos, mini_pos, bound_pos; + unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos; + unsigned int fifo_size; + + link_pos = azx_sd_readl(chip, azx_dev, SD_LPIB); + if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* Playback, no problem using link position */ + return link_pos; + } + + /* Capture */ + /* For new chipset, + * use mod to get the DMA position just like old chipset + */ + mod_dma_pos = le32_to_cpu(*azx_dev->posbuf); + mod_dma_pos %= azx_dev->period_bytes; + + /* azx_dev->fifo_size can't get FIFO size of in stream. + * Get from base address + offset. + */ + fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET); + + if (azx_dev->insufficient) { + /* Link position never gather than FIFO size */ + if (link_pos <= fifo_size) + return 0; + + azx_dev->insufficient = 0; + } + + if (link_pos <= fifo_size) + mini_pos = azx_dev->bufsize + link_pos - fifo_size; + else + mini_pos = link_pos - fifo_size; + + /* Find nearest previous boudary */ + mod_mini_pos = mini_pos % azx_dev->period_bytes; + mod_link_pos = link_pos % azx_dev->period_bytes; + if (mod_link_pos >= fifo_size) + bound_pos = link_pos - mod_link_pos; + else if (mod_dma_pos >= mod_mini_pos) + bound_pos = mini_pos - mod_mini_pos; + else { + bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes; + if (bound_pos >= azx_dev->bufsize) + bound_pos = 0; + } + + /* Calculate real DMA position we want */ + return bound_pos + mod_dma_pos; +} + #ifdef CONFIG_PM static DEFINE_MUTEX(card_list_lock); static LIST_HEAD(card_list); @@ -1084,6 +1201,30 @@ static int check_position_fix(struct azx *chip, int fix) return POS_FIX_AUTO; } +static void assign_position_fix(struct azx *chip, int fix) +{ + static azx_get_pos_callback_t callbacks[] = { + [POS_FIX_AUTO] = NULL, + [POS_FIX_LPIB] = azx_get_pos_lpib, + [POS_FIX_POSBUF] = azx_get_pos_posbuf, + [POS_FIX_VIACOMBO] = azx_via_get_position, + [POS_FIX_COMBO] = azx_get_pos_lpib, + }; + + chip->get_position[0] = chip->get_position[1] = callbacks[fix]; + + /* combo mode uses LPIB only for playback */ + if (fix == POS_FIX_COMBO) + chip->get_position[1] = NULL; + + if (fix == POS_FIX_POSBUF && + (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { + chip->get_delay[0] = chip->get_delay[1] = + azx_get_delay_from_lpib; + } + +} + /* * black-lists for probe_mask */ @@ -1258,13 +1399,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, init_vga_switcheroo(chip); init_completion(&chip->probe_wait); - chip->position_fix[0] = chip->position_fix[1] = - check_position_fix(chip, position_fix[dev]); - /* combo mode uses LPIB for playback */ - if (chip->position_fix[0] == POS_FIX_COMBO) { - chip->position_fix[0] = POS_FIX_LPIB; - chip->position_fix[1] = POS_FIX_AUTO; - } + assign_position_fix(chip, check_position_fix(chip, position_fix[dev])); check_probe_mask(chip, dev); diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index da12d10b778f..43dd8a19cc09 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -188,15 +188,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ -/* position fix mode */ -enum { - POS_FIX_AUTO, - POS_FIX_LPIB, - POS_FIX_POSBUF, - POS_FIX_VIACOMBO, - POS_FIX_COMBO, -}; - /* Defines for ATI HD Audio support in SB450 south bridge */ #define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 #define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 @@ -321,6 +312,9 @@ struct azx_pcm { struct list_head list; }; +typedef unsigned int (*azx_get_pos_callback_t)(struct azx *, struct azx_dev *); +typedef int (*azx_get_delay_callback_t)(struct azx *, struct azx_dev *, unsigned int pos); + struct azx { struct snd_card *card; struct pci_dev *pci; @@ -339,6 +333,10 @@ struct azx { /* Register interaction. */ const struct hda_controller_ops *ops; + /* position adjustment callbacks */ + azx_get_pos_callback_t get_position[2]; + azx_get_delay_callback_t get_delay[2]; + /* pci resources */ unsigned long addr; void __iomem *remap_addr; @@ -374,7 +372,6 @@ struct azx { #endif /* flags */ - int position_fix[2]; /* for both playback/capture streams */ const int *bdl_pos_adj; int poll_count; unsigned int running:1; diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index a366ba9293a8..12920b99d238 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -480,8 +480,6 @@ static int hda_tegra_create(struct snd_card *card, INIT_LIST_HEAD(&chip->pcm_list); INIT_LIST_HEAD(&chip->list); - chip->position_fix[0] = POS_FIX_AUTO; - chip->position_fix[1] = POS_FIX_AUTO; chip->codec_probe_mask = -1; chip->single_cmd = false; -- cgit v1.2.3-59-g8ed1b From 9a34af4a33270acbd60a85f819553463866aecbb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Jun 2014 17:19:20 +0200 Subject: ALSA: hda - Move more PCI-controller-specific stuff from generic code Just move struct fields between struct azx and struct hda_intel, and move some definitions from hda_priv.h to hda_intel.c. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 117 +++++++++++++++++++++++++++++++++------------- sound/pci/hda/hda_priv.h | 38 --------------- 2 files changed, 85 insertions(+), 70 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cb5d807bbd0c..bbb446aef67a 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -75,6 +75,26 @@ enum { POS_FIX_COMBO, }; +/* Defines for ATI HD Audio support in SB450 south bridge */ +#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 +#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 + +/* Defines for Nvidia HDA support */ +#define NVIDIA_HDA_TRANSREG_ADDR 0x4e +#define NVIDIA_HDA_ENABLE_COHBITS 0x0f +#define NVIDIA_HDA_ISTRM_COH 0x4d +#define NVIDIA_HDA_OSTRM_COH 0x4c +#define NVIDIA_HDA_ENABLE_COHBIT 0x01 + +/* Defines for Intel SCH HDA snoop control */ +#define INTEL_SCH_HDA_DEVC 0x78 +#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) + +/* Define IN stream 0 FIFO size offset in VIA controller */ +#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90 +/* Define VIA HD Audio Device ID*/ +#define VIA_HDAC_DEVICE_ID 0x3288 + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; @@ -312,8 +332,28 @@ struct hda_intel { /* HSW/BDW display HDA controller to restore BCLK from CDCLK */ unsigned int bclk_m; unsigned int bclk_n; -}; + /* for pending irqs */ + struct work_struct irq_pending_work; + + /* sync probing */ + struct completion probe_wait; + struct work_struct probe_work; + + /* card list (for power_save trigger) */ + struct list_head list; + + /* extra flags */ + unsigned int irq_pending_warned:1; + + /* VGA-switcheroo setup */ + unsigned int use_vga_switcheroo:1; + unsigned int vga_switcheroo_registered:1; + unsigned int init_failed:1; /* delayed init failed */ + + /* secondary power domain for hdmi audio under vga device */ + struct dev_pm_domain hdmi_pm_domain; +}; #ifdef CONFIG_X86 static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) @@ -480,6 +520,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev); /* called from IRQ */ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); int ok; ok = azx_position_ok(chip, azx_dev); @@ -489,7 +530,7 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) } else if (ok == 0 && chip->bus && chip->bus->workq) { /* bogus IRQ, process it later */ azx_dev->irq_pending = 1; - queue_work(chip->bus->workq, &chip->irq_pending_work); + queue_work(chip->bus->workq, &hda->irq_pending_work); } return 0; } @@ -550,14 +591,15 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) */ static void azx_irq_pending_work(struct work_struct *work) { - struct azx *chip = container_of(work, struct azx, irq_pending_work); + struct hda_intel *hda = container_of(work, struct hda_intel, irq_pending_work); + struct azx *chip = &hda->chip; int i, pending, ok; - if (!chip->irq_pending_warned) { + if (!hda->irq_pending_warned) { dev_info(chip->card->dev, "IRQ timing workaround is activated for card #%d. Suggest a bigger bdl_pos_adj.\n", chip->card->number); - chip->irq_pending_warned = 1; + hda->irq_pending_warned = 1; } for (;;) { @@ -677,21 +719,24 @@ static LIST_HEAD(card_list); static void azx_add_card_list(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); mutex_lock(&card_list_lock); - list_add(&chip->list, &card_list); + list_add(&hda->list, &card_list); mutex_unlock(&card_list_lock); } static void azx_del_card_list(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); mutex_lock(&card_list_lock); - list_del_init(&chip->list); + list_del_init(&hda->list); mutex_unlock(&card_list_lock); } /* trigger power-save check at writing parameter */ static int param_set_xint(const char *val, const struct kernel_param *kp) { + struct hda_intel *hda; struct azx *chip; struct hda_codec *c; int prev = power_save; @@ -701,7 +746,8 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) return ret; mutex_lock(&card_list_lock); - list_for_each_entry(chip, &card_list, list) { + list_for_each_entry(hda, &card_list, list) { + chip = &hda->chip; if (!chip->bus || chip->disabled) continue; list_for_each_entry(c, &chip->bus->codec_list, list) @@ -939,10 +985,11 @@ static void azx_vs_set_state(struct pci_dev *pci, { struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); bool disabled; - wait_for_completion(&chip->probe_wait); - if (chip->init_failed) + wait_for_completion(&hda->probe_wait); + if (hda->init_failed) return; disabled = (state == VGA_SWITCHEROO_OFF); @@ -956,7 +1003,7 @@ static void azx_vs_set_state(struct pci_dev *pci, "Start delayed initialization\n"); if (azx_probe_continue(chip) < 0) { dev_err(chip->card->dev, "initialization error\n"); - chip->init_failed = true; + hda->init_failed = true; } } } else { @@ -986,9 +1033,10 @@ static bool azx_vs_can_switch(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - wait_for_completion(&chip->probe_wait); - if (chip->init_failed) + wait_for_completion(&hda->probe_wait); + if (hda->init_failed) return false; if (chip->disabled || !chip->bus) return true; @@ -1000,11 +1048,12 @@ static bool azx_vs_can_switch(struct pci_dev *pci) static void init_vga_switcheroo(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); struct pci_dev *p = get_bound_vga(chip->pci); if (p) { dev_info(chip->card->dev, "Handle VGA-switcheroo audio client\n"); - chip->use_vga_switcheroo = 1; + hda->use_vga_switcheroo = 1; pci_dev_put(p); } } @@ -1016,9 +1065,10 @@ static const struct vga_switcheroo_client_ops azx_vs_ops = { static int register_vga_switcheroo(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); int err; - if (!chip->use_vga_switcheroo) + if (!hda->use_vga_switcheroo) return 0; /* FIXME: currently only handling DIS controller * is there any machine with two switchable HDMI audio controllers? @@ -1028,11 +1078,11 @@ static int register_vga_switcheroo(struct azx *chip) chip->bus != NULL); if (err < 0) return err; - chip->vga_switcheroo_registered = 1; + hda->vga_switcheroo_registered = 1; /* register as an optimus hdmi audio power domain */ vga_switcheroo_init_domain_pm_optimus_hdmi_audio(chip->card->dev, - &chip->hdmi_pm_domain); + &hda->hdmi_pm_domain); return 0; } #else @@ -1048,7 +1098,6 @@ static int azx_free(struct azx *chip) { struct pci_dev *pci = chip->pci; struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - int i; if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) @@ -1059,13 +1108,13 @@ static int azx_free(struct azx *chip) azx_notifier_unregister(chip); - chip->init_failed = 1; /* to be sure */ - complete_all(&chip->probe_wait); + hda->init_failed = 1; /* to be sure */ + complete_all(&hda->probe_wait); - if (use_vga_switcheroo(chip)) { + if (use_vga_switcheroo(hda)) { if (chip->disabled && chip->bus) snd_hda_unlock_devices(chip->bus); - if (chip->vga_switcheroo_registered) + if (hda->vga_switcheroo_registered) vga_switcheroo_unregister_client(chip->pci); } @@ -1350,7 +1399,8 @@ static void azx_check_snoop_available(struct azx *chip) static void azx_probe_work(struct work_struct *work) { - azx_probe_continue(container_of(work, struct azx, probe_work)); + struct hda_intel *hda = container_of(work, struct hda_intel, probe_work); + azx_probe_continue(&hda->chip); } /* @@ -1393,11 +1443,11 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, check_msi(chip); chip->dev_index = dev; chip->jackpoll_ms = jackpoll_ms; - INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); INIT_LIST_HEAD(&chip->pcm_list); - INIT_LIST_HEAD(&chip->list); + INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work); + INIT_LIST_HEAD(&hda->list); init_vga_switcheroo(chip); - init_completion(&chip->probe_wait); + init_completion(&hda->probe_wait); assign_position_fix(chip, check_position_fix(chip, position_fix[dev])); @@ -1428,7 +1478,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, } /* continue probing in work context as may trigger request module */ - INIT_WORK(&chip->probe_work, azx_probe_work); + INIT_WORK(&hda->probe_work, azx_probe_work); *rchip = chip; @@ -1750,6 +1800,7 @@ static int azx_probe(struct pci_dev *pci, { static int dev; struct snd_card *card; + struct hda_intel *hda; struct azx *chip; bool schedule_probe; int err; @@ -1773,6 +1824,7 @@ static int azx_probe(struct pci_dev *pci, if (err < 0) goto out_free; card->private_data = chip; + hda = container_of(chip, struct hda_intel, chip); pci_set_drvdata(pci, card); @@ -1809,11 +1861,11 @@ static int azx_probe(struct pci_dev *pci, #endif if (schedule_probe) - schedule_work(&chip->probe_work); + schedule_work(&hda->probe_work); dev++; if (chip->disabled) - complete_all(&chip->probe_wait); + complete_all(&hda->probe_wait); return 0; out_free: @@ -1829,6 +1881,7 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = { static int azx_probe_continue(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); struct pci_dev *pci = chip->pci; int dev = chip->dev_index; int err; @@ -1902,13 +1955,13 @@ static int azx_probe_continue(struct azx *chip) power_down_all_codecs(chip); azx_notifier_register(chip); azx_add_card_list(chip); - if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) || chip->use_vga_switcheroo) + if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) || hda->use_vga_switcheroo) pm_runtime_put_noidle(&pci->dev); out_free: if (err < 0) - chip->init_failed = 1; - complete_all(&chip->probe_wait); + hda->init_failed = 1; + complete_all(&hda->probe_wait); return err; } diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index 43dd8a19cc09..30bbbc48d314 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -188,26 +188,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ -/* Defines for ATI HD Audio support in SB450 south bridge */ -#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 -#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 - -/* Defines for Nvidia HDA support */ -#define NVIDIA_HDA_TRANSREG_ADDR 0x4e -#define NVIDIA_HDA_ENABLE_COHBITS 0x0f -#define NVIDIA_HDA_ISTRM_COH 0x4d -#define NVIDIA_HDA_OSTRM_COH 0x4c -#define NVIDIA_HDA_ENABLE_COHBIT 0x01 - -/* Defines for Intel SCH HDA snoop control */ -#define INTEL_SCH_HDA_DEVC 0x78 -#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) - -/* Define IN stream 0 FIFO size offset in VIA controller */ -#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90 -/* Define VIA HD Audio Device ID*/ -#define VIA_HDAC_DEVICE_ID 0x3288 - /* HD Audio class code */ #define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 @@ -345,7 +325,6 @@ struct azx { /* locks */ spinlock_t reg_lock; struct mutex open_mutex; /* Prevents concurrent open/close operations */ - struct completion probe_wait; /* streams (x num_streams) */ struct azx_dev *azx_dev; @@ -379,38 +358,21 @@ struct azx { unsigned int single_cmd:1; unsigned int polling_mode:1; unsigned int msi:1; - unsigned int irq_pending_warned:1; unsigned int probing:1; /* codec probing phase */ unsigned int snoop:1; unsigned int align_buffer_size:1; unsigned int region_requested:1; - - /* VGA-switcheroo setup */ - unsigned int use_vga_switcheroo:1; - unsigned int vga_switcheroo_registered:1; - unsigned int init_failed:1; /* delayed init failed */ unsigned int disabled:1; /* disabled by VGA-switcher */ /* for debugging */ unsigned int last_cmd[AZX_MAX_CODECS]; - /* for pending irqs */ - struct work_struct irq_pending_work; - - struct work_struct probe_work; - /* reboot notifier (for mysterious hangup problem at power-down) */ struct notifier_block reboot_notifier; - /* card list (for power_save trigger) */ - struct list_head list; - #ifdef CONFIG_SND_HDA_DSP_LOADER struct azx_dev saved_azx_dev; #endif - - /* secondary power domain for hdmi audio under vga device */ - struct dev_pm_domain hdmi_pm_domain; }; #ifdef CONFIG_SND_VERBOSE_PRINTK -- cgit v1.2.3-59-g8ed1b From 703c759f38cce7950ab460552236ca1d15adb916 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Jun 2014 17:24:45 +0200 Subject: ALSA: hda - Use common reboot notifier The very same notifier code is used in both hda_intel.c and hda_tegra.c. Move it to the generic code. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 26 ++++++++++++++++++++++++++ sound/pci/hda/hda_controller.h | 3 +++ sound/pci/hda/hda_intel.c | 24 ------------------------ sound/pci/hda/hda_tegra.c | 29 ++--------------------------- 4 files changed, 31 insertions(+), 51 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index a562d86c02fb..8d9398a4c7c9 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include "hda_priv.h" @@ -1946,5 +1947,30 @@ int azx_init_stream(struct azx *chip) } EXPORT_SYMBOL_GPL(azx_init_stream); +/* + * reboot notifier for hang-up problem at power-down + */ +static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf) +{ + struct azx *chip = container_of(nb, struct azx, reboot_notifier); + snd_hda_bus_reboot_notify(chip->bus); + azx_stop_chip(chip); + return NOTIFY_OK; +} + +void azx_notifier_register(struct azx *chip) +{ + chip->reboot_notifier.notifier_call = azx_halt; + register_reboot_notifier(&chip->reboot_notifier); +} +EXPORT_SYMBOL_GPL(azx_notifier_register); + +void azx_notifier_unregister(struct azx *chip) +{ + if (chip->reboot_notifier.notifier_call) + unregister_reboot_notifier(&chip->reboot_notifier); +} +EXPORT_SYMBOL_GPL(azx_notifier_unregister); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Common HDA driver funcitons"); diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 91f04958e2b0..c90d10fd4d8f 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -50,4 +50,7 @@ int azx_codec_configure(struct azx *chip); int azx_mixer_create(struct azx *chip); int azx_init_stream(struct azx *chip); +void azx_notifier_register(struct azx *chip); +void azx_notifier_unregister(struct azx *chip); + #endif /* __SOUND_HDA_CONTROLLER_H */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index bbb446aef67a..1e971e2f1d50 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -952,29 +951,6 @@ static const struct dev_pm_ops azx_pm = { #endif /* CONFIG_PM */ -/* - * reboot notifier for hang-up problem at power-down - */ -static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf) -{ - struct azx *chip = container_of(nb, struct azx, reboot_notifier); - snd_hda_bus_reboot_notify(chip->bus); - azx_stop_chip(chip); - return NOTIFY_OK; -} - -static void azx_notifier_register(struct azx *chip) -{ - chip->reboot_notifier.notifier_call = azx_halt; - register_reboot_notifier(&chip->reboot_notifier); -} - -static void azx_notifier_unregister(struct azx *chip) -{ - if (chip->reboot_notifier.notifier_call) - unregister_reboot_notifier(&chip->reboot_notifier); -} - static int azx_probe_continue(struct azx *chip); #ifdef SUPPORT_VGA_SWITCHEROO diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 12920b99d238..cf69dafa91c0 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -294,30 +293,6 @@ static const struct dev_pm_ops hda_tegra_pm = { SET_SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume) }; -/* - * reboot notifier for hang-up problem at power-down - */ -static int hda_tegra_halt(struct notifier_block *nb, unsigned long event, - void *buf) -{ - struct azx *chip = container_of(nb, struct azx, reboot_notifier); - snd_hda_bus_reboot_notify(chip->bus); - azx_stop_chip(chip); - return NOTIFY_OK; -} - -static void hda_tegra_notifier_register(struct azx *chip) -{ - chip->reboot_notifier.notifier_call = hda_tegra_halt; - register_reboot_notifier(&chip->reboot_notifier); -} - -static void hda_tegra_notifier_unregister(struct azx *chip) -{ - if (chip->reboot_notifier.notifier_call) - unregister_reboot_notifier(&chip->reboot_notifier); -} - /* * destructor */ @@ -326,7 +301,7 @@ static int hda_tegra_dev_free(struct snd_device *device) int i; struct azx *chip = device->device_data; - hda_tegra_notifier_unregister(chip); + azx_notifier_unregister(chip); if (chip->initialized) { for (i = 0; i < chip->num_streams; i++) @@ -557,7 +532,7 @@ static int hda_tegra_probe(struct platform_device *pdev) chip->running = 1; power_down_all_codecs(chip); - hda_tegra_notifier_register(chip); + azx_notifier_register(chip); return 0; -- cgit v1.2.3-59-g8ed1b From 33124929a23c5b555c39b99b4073766d232cb31d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Jun 2014 17:28:06 +0200 Subject: ALSA: hda - Move SD nums definitions to hda_intel.c The defined numbers of SDs are specific to hda-intel, so move them to there. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 17 +++++++++++++++++ sound/pci/hda/hda_priv.h | 17 ----------------- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1e971e2f1d50..bbf01fcb6893 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -94,6 +94,23 @@ enum { /* Define VIA HD Audio Device ID*/ #define VIA_HDAC_DEVICE_ID 0x3288 +/* max number of SDs */ +/* ICH, ATI and VIA have 4 playback and 4 capture */ +#define ICH6_NUM_CAPTURE 4 +#define ICH6_NUM_PLAYBACK 4 + +/* ULI has 6 playback and 5 capture */ +#define ULI_NUM_CAPTURE 5 +#define ULI_NUM_PLAYBACK 6 + +/* ATI HDMI may have up to 8 playbacks and 0 capture */ +#define ATIHDMI_NUM_CAPTURE 0 +#define ATIHDMI_NUM_PLAYBACK 8 + +/* TERA has 4 playback and 3 capture */ +#define TERA_NUM_CAPTURE 3 +#define TERA_NUM_PLAYBACK 4 + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index 30bbbc48d314..0688aaff09f1 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -103,23 +103,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; * other constants */ -/* max number of SDs */ -/* ICH, ATI and VIA have 4 playback and 4 capture */ -#define ICH6_NUM_CAPTURE 4 -#define ICH6_NUM_PLAYBACK 4 - -/* ULI has 6 playback and 5 capture */ -#define ULI_NUM_CAPTURE 5 -#define ULI_NUM_PLAYBACK 6 - -/* ATI HDMI may have up to 8 playbacks and 0 capture */ -#define ATIHDMI_NUM_CAPTURE 0 -#define ATIHDMI_NUM_PLAYBACK 8 - -/* TERA has 4 playback and 3 capture */ -#define TERA_NUM_CAPTURE 3 -#define TERA_NUM_PLAYBACK 4 - /* max number of fragments - we may use more if allocating more pages for BDL */ #define BDL_SIZE 4096 #define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) -- cgit v1.2.3-59-g8ed1b From c6bf1d8e8c08d37d42a3a96606470fc012cc30e7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Jun 2014 17:30:12 +0200 Subject: ALSA: hda - Remove obsoleted SFX definitions It's no longer referred by anyone after standardizing with dev_*() macros. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_auto_parser.c | 2 -- sound/pci/hda/hda_priv.h | 6 ------ 2 files changed, 8 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index dabe41975a9d..a9790198aa17 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -17,8 +17,6 @@ #include "hda_local.h" #include "hda_auto_parser.h" -#define SFX "hda_codec: " - /* * Helper for automatic pin configuration */ diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index 0688aaff09f1..da2d3a41f8f3 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -358,12 +358,6 @@ struct azx { #endif }; -#ifdef CONFIG_SND_VERBOSE_PRINTK -#define SFX /* nop */ -#else -#define SFX "hda-intel " -#endif - #ifdef CONFIG_X86 #define azx_snoop(chip) ((chip)->snoop) #else -- cgit v1.2.3-59-g8ed1b From fb1d8ac29971fc48144abe5bc760f9eb3e537b9f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Jun 2014 17:54:37 +0200 Subject: ALSA: hda - Replace ICH6_ prefix ICH6_ prefix doesn't mean that it's specific to ICH6 chipset but rather its generic for all HD-audio (or "Azalia") devices. Use AZX_ prefix instead to align with other constants. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 47 ++++++----- sound/pci/hda/hda_intel.c | 12 +-- sound/pci/hda/hda_priv.h | 172 ++++++++++++++++++++--------------------- 3 files changed, 115 insertions(+), 116 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 8d9398a4c7c9..06f39c126ba4 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -155,9 +155,9 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) /* enable the position buffer */ if (chip->get_position[0] != azx_get_pos_lpib || chip->get_position[1] != azx_get_pos_lpib) { - if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) + if (!(azx_readl(chip, DPLBASE) & AZX_DPLBASE_ENABLE)) azx_writel(chip, DPLBASE, - (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); + (u32)chip->posbuf.addr | AZX_DPLBASE_ENABLE); } /* set the interrupt enable bits in the descriptor control register */ @@ -975,10 +975,10 @@ static void azx_init_cmd_io(struct azx *chip) azx_writew(chip, CORBWP, 0); /* reset the corb hw read pointer */ - azx_writew(chip, CORBRP, ICH6_CORBRP_RST); + azx_writew(chip, CORBRP, AZX_CORBRP_RST); if (!(chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)) { for (timeout = 1000; timeout > 0; timeout--) { - if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST) + if ((azx_readw(chip, CORBRP) & AZX_CORBRP_RST) == AZX_CORBRP_RST) break; udelay(1); } @@ -998,7 +998,7 @@ static void azx_init_cmd_io(struct azx *chip) } /* enable corb dma */ - azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN); + azx_writeb(chip, CORBCTL, AZX_CORBCTL_RUN); /* RIRB set up */ chip->rirb.addr = chip->rb.addr + 2048; @@ -1011,14 +1011,14 @@ static void azx_init_cmd_io(struct azx *chip) /* set the rirb size to 256 entries (ULI requires explicitly) */ azx_writeb(chip, RIRBSIZE, 0x02); /* reset the rirb hw write pointer */ - azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST); + azx_writew(chip, RIRBWP, AZX_RIRBWP_RST); /* set N=1, get RIRB response interrupt for new entry */ if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) azx_writew(chip, RINTCNT, 0xc0); else azx_writew(chip, RINTCNT, 1); /* enable rirb dma and response irq */ - azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); + azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN); spin_unlock_irq(&chip->reg_lock); } EXPORT_SYMBOL_GPL(azx_init_cmd_io); @@ -1062,7 +1062,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) return -EIO; } wp++; - wp %= ICH6_MAX_CORB_ENTRIES; + wp %= AZX_MAX_CORB_ENTRIES; rp = azx_readw(chip, CORBRP); if (wp == rp) { @@ -1080,7 +1080,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) return 0; } -#define ICH6_RIRB_EX_UNSOL_EV (1<<4) +#define AZX_RIRB_EX_UNSOL_EV (1<<4) /* retrieve RIRB entry - called from interrupt handler */ static void azx_update_rirb(struct azx *chip) @@ -1101,7 +1101,7 @@ static void azx_update_rirb(struct azx *chip) while (chip->rirb.rp != wp) { chip->rirb.rp++; - chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES; + chip->rirb.rp %= AZX_MAX_RIRB_ENTRIES; rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); @@ -1112,8 +1112,7 @@ static void azx_update_rirb(struct azx *chip) res, res_ex, chip->rirb.rp, wp); snd_BUG(); - } - else if (res_ex & ICH6_RIRB_EX_UNSOL_EV) + } else if (res_ex & AZX_RIRB_EX_UNSOL_EV) snd_hda_queue_unsol_event(chip->bus, res, res_ex); else if (chip->rirb.cmds[addr]) { chip->rirb.res[addr] = res; @@ -1221,7 +1220,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, /* release CORB/RIRB */ azx_free_cmd_io(chip); /* disable unsolicited responses */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_UNSOL); + azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_UNSOL); return -1; } @@ -1242,7 +1241,7 @@ static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) while (timeout--) { /* check IRV busy bit */ - if (azx_readw(chip, IRS) & ICH6_IRS_VALID) { + if (azx_readw(chip, IRS) & AZX_IRS_VALID) { /* reuse rirb.res as the response return value */ chip->rirb.res[addr] = azx_readl(chip, IR); return 0; @@ -1266,13 +1265,13 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) bus->rirb_error = 0; while (timeout--) { /* check ICB busy bit */ - if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { + if (!((azx_readw(chip, IRS) & AZX_IRS_BUSY))) { /* Clear IRV valid bit */ azx_writew(chip, IRS, azx_readw(chip, IRS) | - ICH6_IRS_VALID); + AZX_IRS_VALID); azx_writel(chip, IC, val); azx_writew(chip, IRS, azx_readw(chip, IRS) | - ICH6_IRS_BUSY); + AZX_IRS_BUSY); return azx_single_wait_for_response(chip, addr); } udelay(1); @@ -1501,10 +1500,10 @@ void azx_enter_link_reset(struct azx *chip) unsigned long timeout; /* reset controller */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); + azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_RESET); timeout = jiffies + msecs_to_jiffies(100); - while ((azx_readb(chip, GCTL) & ICH6_GCTL_RESET) && + while ((azx_readb(chip, GCTL) & AZX_GCTL_RESET) && time_before(jiffies, timeout)) usleep_range(500, 1000); } @@ -1515,7 +1514,7 @@ static void azx_exit_link_reset(struct azx *chip) { unsigned long timeout; - azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET); + azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | AZX_GCTL_RESET); timeout = jiffies + msecs_to_jiffies(100); while (!azx_readb(chip, GCTL) && @@ -1556,7 +1555,7 @@ static int azx_reset(struct azx *chip, bool full_reset) /* Accept unsolicited responses */ if (!chip->single_cmd) azx_writel(chip, GCTL, azx_readl(chip, GCTL) | - ICH6_GCTL_UNSOL); + AZX_GCTL_UNSOL); /* detect codecs */ if (!chip->codec_mask) { @@ -1573,7 +1572,7 @@ static void azx_int_enable(struct azx *chip) { /* enable controller CIE and GIE */ azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) | - ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN); + AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN); } /* disable interrupts */ @@ -1594,7 +1593,7 @@ static void azx_int_disable(struct azx *chip) /* disable controller CIE and GIE */ azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) & - ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN)); + ~(AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN)); } /* clear interrupts */ @@ -1615,7 +1614,7 @@ static void azx_int_clear(struct azx *chip) azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); /* clear int status */ - azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM); + azx_writel(chip, INTSTS, AZX_INT_CTRL_EN | AZX_INT_ALL_STREAM); } /* diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index bbf01fcb6893..dc0c8dac1900 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -339,8 +339,8 @@ static char *driver_short_names[] = { * Clock) to 24MHz BCLK: BCLK = CDCLK * M / N * The values will be lost when the display power well is disabled. */ -#define ICH6_REG_EM4 0x100c -#define ICH6_REG_EM5 0x1010 +#define AZX_REG_EM4 0x100c +#define AZX_REG_EM5 0x1010 struct hda_intel { struct azx chip; @@ -451,7 +451,7 @@ static void azx_init_pci(struct azx *chip) */ if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) { dev_dbg(chip->card->dev, "Clearing TCSEL\n"); - update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); + update_pci_byte(chip->pci, AZX_PCIREG_TCSEL, 0x07, 0); } /* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio, @@ -1529,7 +1529,7 @@ static int azx_first_init(struct azx *chip) NULL); if (p_smbus) { if (p_smbus->revision < 0x30) - gcap &= ~ICH6_GCAP_64OK; + gcap &= ~AZX_GCAP_64OK; pci_dev_put(p_smbus); } } @@ -1537,7 +1537,7 @@ static int azx_first_init(struct azx *chip) /* disable 64bit DMA address on some devices */ if (chip->driver_caps & AZX_DCAPS_NO_64BIT) { dev_dbg(card->dev, "Disabling 64bit DMA\n"); - gcap &= ~ICH6_GCAP_64OK; + gcap &= ~AZX_GCAP_64OK; } /* disable buffer size rounding to 128-byte multiples if supported */ @@ -1553,7 +1553,7 @@ static int azx_first_init(struct azx *chip) } /* allow 64bit DMA address if supported by H/W */ - if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) + if ((gcap & AZX_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); else { pci_set_dma_mask(pci, DMA_BIT_MASK(32)); diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index da2d3a41f8f3..33eb5d027d38 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -22,82 +22,82 @@ /* * registers */ -#define ICH6_REG_GCAP 0x00 -#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */ -#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */ -#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */ -#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */ -#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */ -#define ICH6_REG_VMIN 0x02 -#define ICH6_REG_VMAJ 0x03 -#define ICH6_REG_OUTPAY 0x04 -#define ICH6_REG_INPAY 0x06 -#define ICH6_REG_GCTL 0x08 -#define ICH6_GCTL_RESET (1 << 0) /* controller reset */ -#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */ -#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ -#define ICH6_REG_WAKEEN 0x0c -#define ICH6_REG_STATESTS 0x0e -#define ICH6_REG_GSTS 0x10 -#define ICH6_GSTS_FSTS (1 << 1) /* flush status */ -#define ICH6_REG_INTCTL 0x20 -#define ICH6_REG_INTSTS 0x24 -#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */ -#define ICH6_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ -#define ICH6_REG_SSYNC 0x38 -#define ICH6_REG_CORBLBASE 0x40 -#define ICH6_REG_CORBUBASE 0x44 -#define ICH6_REG_CORBWP 0x48 -#define ICH6_REG_CORBRP 0x4a -#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */ -#define ICH6_REG_CORBCTL 0x4c -#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */ -#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ -#define ICH6_REG_CORBSTS 0x4d -#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */ -#define ICH6_REG_CORBSIZE 0x4e - -#define ICH6_REG_RIRBLBASE 0x50 -#define ICH6_REG_RIRBUBASE 0x54 -#define ICH6_REG_RIRBWP 0x58 -#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */ -#define ICH6_REG_RINTCNT 0x5a -#define ICH6_REG_RIRBCTL 0x5c -#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ -#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */ -#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ -#define ICH6_REG_RIRBSTS 0x5d -#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */ -#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */ -#define ICH6_REG_RIRBSIZE 0x5e - -#define ICH6_REG_IC 0x60 -#define ICH6_REG_IR 0x64 -#define ICH6_REG_IRS 0x68 -#define ICH6_IRS_VALID (1<<1) -#define ICH6_IRS_BUSY (1<<0) - -#define ICH6_REG_DPLBASE 0x70 -#define ICH6_REG_DPUBASE 0x74 -#define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */ +#define AZX_REG_GCAP 0x00 +#define AZX_GCAP_64OK (1 << 0) /* 64bit address support */ +#define AZX_GCAP_NSDO (3 << 1) /* # of serial data out signals */ +#define AZX_GCAP_BSS (31 << 3) /* # of bidirectional streams */ +#define AZX_GCAP_ISS (15 << 8) /* # of input streams */ +#define AZX_GCAP_OSS (15 << 12) /* # of output streams */ +#define AZX_REG_VMIN 0x02 +#define AZX_REG_VMAJ 0x03 +#define AZX_REG_OUTPAY 0x04 +#define AZX_REG_INPAY 0x06 +#define AZX_REG_GCTL 0x08 +#define AZX_GCTL_RESET (1 << 0) /* controller reset */ +#define AZX_GCTL_FCNTRL (1 << 1) /* flush control */ +#define AZX_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ +#define AZX_REG_WAKEEN 0x0c +#define AZX_REG_STATESTS 0x0e +#define AZX_REG_GSTS 0x10 +#define AZX_GSTS_FSTS (1 << 1) /* flush status */ +#define AZX_REG_INTCTL 0x20 +#define AZX_REG_INTSTS 0x24 +#define AZX_REG_WALLCLK 0x30 /* 24Mhz source */ +#define AZX_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ +#define AZX_REG_SSYNC 0x38 +#define AZX_REG_CORBLBASE 0x40 +#define AZX_REG_CORBUBASE 0x44 +#define AZX_REG_CORBWP 0x48 +#define AZX_REG_CORBRP 0x4a +#define AZX_CORBRP_RST (1 << 15) /* read pointer reset */ +#define AZX_REG_CORBCTL 0x4c +#define AZX_CORBCTL_RUN (1 << 1) /* enable DMA */ +#define AZX_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ +#define AZX_REG_CORBSTS 0x4d +#define AZX_CORBSTS_CMEI (1 << 0) /* memory error indication */ +#define AZX_REG_CORBSIZE 0x4e + +#define AZX_REG_RIRBLBASE 0x50 +#define AZX_REG_RIRBUBASE 0x54 +#define AZX_REG_RIRBWP 0x58 +#define AZX_RIRBWP_RST (1 << 15) /* write pointer reset */ +#define AZX_REG_RINTCNT 0x5a +#define AZX_REG_RIRBCTL 0x5c +#define AZX_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ +#define AZX_RBCTL_DMA_EN (1 << 1) /* enable DMA */ +#define AZX_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ +#define AZX_REG_RIRBSTS 0x5d +#define AZX_RBSTS_IRQ (1 << 0) /* response irq */ +#define AZX_RBSTS_OVERRUN (1 << 2) /* overrun irq */ +#define AZX_REG_RIRBSIZE 0x5e + +#define AZX_REG_IC 0x60 +#define AZX_REG_IR 0x64 +#define AZX_REG_IRS 0x68 +#define AZX_IRS_VALID (1<<1) +#define AZX_IRS_BUSY (1<<0) + +#define AZX_REG_DPLBASE 0x70 +#define AZX_REG_DPUBASE 0x74 +#define AZX_DPLBASE_ENABLE 0x1 /* Enable position buffer */ /* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* stream register offsets from stream base */ -#define ICH6_REG_SD_CTL 0x00 -#define ICH6_REG_SD_STS 0x03 -#define ICH6_REG_SD_LPIB 0x04 -#define ICH6_REG_SD_CBL 0x08 -#define ICH6_REG_SD_LVI 0x0c -#define ICH6_REG_SD_FIFOW 0x0e -#define ICH6_REG_SD_FIFOSIZE 0x10 -#define ICH6_REG_SD_FORMAT 0x12 -#define ICH6_REG_SD_BDLPL 0x18 -#define ICH6_REG_SD_BDLPU 0x1c +#define AZX_REG_SD_CTL 0x00 +#define AZX_REG_SD_STS 0x03 +#define AZX_REG_SD_LPIB 0x04 +#define AZX_REG_SD_CBL 0x08 +#define AZX_REG_SD_LVI 0x0c +#define AZX_REG_SD_FIFOW 0x0e +#define AZX_REG_SD_FIFOSIZE 0x10 +#define AZX_REG_SD_FORMAT 0x12 +#define AZX_REG_SD_BDLPL 0x18 +#define AZX_REG_SD_BDLPU 0x1c /* PCI space */ -#define ICH6_PCIREG_TCSEL 0x44 +#define AZX_PCIREG_TCSEL 0x44 /* * other constants @@ -140,13 +140,13 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define SD_STS_FIFO_READY 0x20 /* FIFO ready */ /* INTCTL and INTSTS */ -#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ -#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ -#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ +#define AZX_INT_ALL_STREAM 0xff /* all stream interrupts */ +#define AZX_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ +#define AZX_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ /* below are so far hardcoded - should read registers in future */ -#define ICH6_MAX_CORB_ENTRIES 256 -#define ICH6_MAX_RIRB_ENTRIES 256 +#define AZX_MAX_CORB_ENTRIES 256 +#define AZX_MAX_RIRB_ENTRIES 256 /* driver quirks (capabilities) */ /* bits 0-7 are used for indicating driver type */ @@ -369,29 +369,29 @@ struct azx { */ #define azx_writel(chip, reg, value) \ - ((chip)->ops->reg_writel(value, (chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writel(value, (chip)->remap_addr + AZX_REG_##reg)) #define azx_readl(chip, reg) \ - ((chip)->ops->reg_readl((chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readl((chip)->remap_addr + AZX_REG_##reg)) #define azx_writew(chip, reg, value) \ - ((chip)->ops->reg_writew(value, (chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writew(value, (chip)->remap_addr + AZX_REG_##reg)) #define azx_readw(chip, reg) \ - ((chip)->ops->reg_readw((chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readw((chip)->remap_addr + AZX_REG_##reg)) #define azx_writeb(chip, reg, value) \ - ((chip)->ops->reg_writeb(value, (chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writeb(value, (chip)->remap_addr + AZX_REG_##reg)) #define azx_readb(chip, reg) \ - ((chip)->ops->reg_readb((chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readb((chip)->remap_addr + AZX_REG_##reg)) #define azx_sd_writel(chip, dev, reg, value) \ - ((chip)->ops->reg_writel(value, (dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writel(value, (dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_readl(chip, dev, reg) \ - ((chip)->ops->reg_readl((dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readl((dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_writew(chip, dev, reg, value) \ - ((chip)->ops->reg_writew(value, (dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writew(value, (dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_readw(chip, dev, reg) \ - ((chip)->ops->reg_readw((dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readw((dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_writeb(chip, dev, reg, value) \ - ((chip)->ops->reg_writeb(value, (dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writeb(value, (dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_readb(chip, dev, reg) \ - ((chip)->ops->reg_readb((dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readb((dev)->sd_addr + AZX_REG_##reg)) #endif /* __SOUND_HDA_PRIV_H */ -- cgit v1.2.3-59-g8ed1b From e8750940ce345bf15fa0756810ae9ac491e9e352 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jun 2014 14:02:39 +0200 Subject: ALSA: hda - Fix invalid function call in snd_hda_add_vmaster() The recent commit [6194b99d: ALSA: hda - Kill the rest of snd_print*() usages] changed the callback map_slaves(), but one call was forgotten to be replaced due to the cast, which leads to kernel Oops due to invalid function. This patch replaces it with a proper function. Fixes: 6194b99de9f5 ('ALSA: hda - Kill the rest of snd_print*() usages') Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d91cb7f5961a..47a617786fca 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2831,6 +2831,12 @@ static int init_slave_unmute(struct hda_codec *codec, return put_kctl_with_value(slave, 1); } +static int add_slave(struct hda_codec *codec, + void *data, struct snd_kcontrol *slave) +{ + return snd_ctl_add_slave(data, slave); +} + /** * snd_hda_add_vmaster - create a virtual master control and add slaves * @codec: HD-audio codec @@ -2873,8 +2879,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, if (err < 0) return err; - err = map_slaves(codec, slaves, suffix, - (map_slave_func_t)snd_ctl_add_slave, kctl); + err = map_slaves(codec, slaves, suffix, add_slave, kctl); if (err < 0) return err; -- cgit v1.2.3-59-g8ed1b From 8d9048643f32d795fd6dbf71d9dd5469611151cd Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 1 Jul 2014 10:10:29 +0530 Subject: ALSA: trident: Remove unused variable in trident_main.c 'private_data' is not used in the function. Remove it. Signed-off-by: Sachin Kamat Signed-off-by: Takashi Iwai --- sound/pci/trident/trident_main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 1272c18a2544..da875dced2ef 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -3880,14 +3880,12 @@ void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voi { unsigned long flags; void (*private_free)(struct snd_trident_voice *); - void *private_data; if (voice == NULL || !voice->use) return; snd_trident_clear_voices(trident, voice->number, voice->number); spin_lock_irqsave(&trident->voice_alloc, flags); private_free = voice->private_free; - private_data = voice->private_data; voice->private_free = NULL; voice->private_data = NULL; if (voice->pcm) -- cgit v1.2.3-59-g8ed1b From e2ff8406ade81f5f431a3cac6ef96720c37906cd Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 1 Jul 2014 10:10:30 +0530 Subject: ALSA: trident: Remove unused variable in trident_memory.c 'prev' is not used in the function. Remove it. Signed-off-by: Sachin Kamat Signed-off-by: Takashi Iwai --- sound/pci/trident/trident_memory.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index 3102a579660b..04c474658e3c 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c @@ -139,12 +139,11 @@ static inline void *offset_ptr(struct snd_trident *trident, int offset) static struct snd_util_memblk * search_empty(struct snd_util_memhdr *hdr, int size) { - struct snd_util_memblk *blk, *prev; + struct snd_util_memblk *blk; int page, psize; struct list_head *p; psize = get_aligned_page(size + ALIGN_PAGE_SIZE -1); - prev = NULL; page = 0; list_for_each(p, &hdr->block) { blk = list_entry(p, struct snd_util_memblk, list); -- cgit v1.2.3-59-g8ed1b From 178942b69f4eb695bfb92742b6082052d6730ca0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 1 Jul 2014 13:59:40 +0200 Subject: ALSA: hda - Fix build error in hda_tegra.c The "list" field has been omitted from struct azx, but its initialization remained mistakenly in hda_tegra.c, which leads to a compile error: sound/pci/hda/hda_tegra.c: In function 'hda_tegra_create': sound/pci/hda/hda_tegra.c:481:22: error: 'struct azx' has no member named 'list' Reported-by: kbuild test robot Fixes: 9a34af4a3327 ('ALSA: hda - Move more PCI-controller-specific stuff from generic code') Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_tegra.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index cf69dafa91c0..cc4a923f68e3 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -453,7 +453,6 @@ static int hda_tegra_create(struct snd_card *card, chip->driver_type = driver_caps & 0xff; chip->dev_index = 0; INIT_LIST_HEAD(&chip->pcm_list); - INIT_LIST_HEAD(&chip->list); chip->codec_probe_mask = -1; -- cgit v1.2.3-59-g8ed1b From 427f42e4cf3a681d181fd1f0492731b167807877 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 1 Jul 2014 17:02:57 +0530 Subject: ALSA: echoaudio: Remove unused variable 'chip' is not used in the function. Remove it. Signed-off-by: Sachin Kamat Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/echoaudio.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 9f10c9e0df5e..631aaa4046ad 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1754,9 +1754,6 @@ static struct snd_kcontrol_new snd_echo_vumeters_switch = { static int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct echoaudio *chip; - - chip = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 96; uinfo->value.integer.min = ECHOGAIN_MINOUT; @@ -1798,9 +1795,6 @@ static struct snd_kcontrol_new snd_echo_vumeters = { static int snd_echo_channels_info_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct echoaudio *chip; - - chip = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 6; uinfo->value.integer.min = 0; -- cgit v1.2.3-59-g8ed1b From 330fb10df832b0008892964601d9d142c14a906f Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 1 Jul 2014 17:02:58 +0530 Subject: ALSA: mixart: Remove unused variable 'err' is not used in the function. Remove it. Signed-off-by: Sachin Kamat Signed-off-by: Takashi Iwai --- sound/pci/mixart/mixart_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index 71f4bdcc4055..84f67450924e 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c @@ -151,13 +151,11 @@ static int send_msg( struct mixart_mgr *mgr, { u32 headptr, tailptr; u32 msg_frame_address; - int err, i; + int i; if (snd_BUG_ON(msg->size % 4)) return -EINVAL; - err = 0; - /* get message frame address */ tailptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL)); headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_HEAD)); -- cgit v1.2.3-59-g8ed1b From d5471e67229adb31a1e5f026955d006f06315f3d Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 1 Jul 2014 17:02:54 +0530 Subject: ALSA: hda: Remove unused variable 'status' is not used in the function. Remove it. Signed-off-by: Sachin Kamat Tested-by: Dylan Reid Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_tegra.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index cc4a923f68e3..dc4bb21ed17b 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -271,13 +271,9 @@ static int hda_tegra_resume(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); - int status; hda_tegra_enable_clocks(hda); - /* Read STATESTS before controller reset */ - status = azx_readw(chip, STATESTS); - hda_tegra_init(hda); azx_init_chip(chip, 1); -- cgit v1.2.3-59-g8ed1b From 2f6ba2b31ba9442d2a16aa2a7e1b4116de2de14f Mon Sep 17 00:00:00 2001 From: Konstantinos Tsimpoukas Date: Wed, 2 Jul 2014 23:25:27 -0500 Subject: ALSA: ice1712: Correcting/completing #defines for REGS This small patch completes #defines for Control/Status Register, adds comments for the missing ones there and on the Interrupt Mask Register and additionally corrects "#define ICE1712_SERR_LEVEL 0x04 -> 0x08", according to documentation. Signed-off-by: Konstantinos Tsimpoukas Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1712.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index b209fc30b334..58f8f2ae758d 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -41,14 +41,17 @@ #define ICEREG(ice, x) ((ice)->port + ICE1712_REG_##x) #define ICE1712_REG_CONTROL 0x00 /* byte */ -#define ICE1712_RESET 0x80 /* reset whole chip */ -#define ICE1712_SERR_LEVEL 0x04 /* SERR# level otherwise edge */ +#define ICE1712_RESET 0x80 /* soft reset whole chip */ +#define ICE1712_SERR_ASSERT_DS_DMA 0x40 /* disabled SERR# assertion for the DS DMA Ch-C irq otherwise enabled */ +#define ICE1712_DOS_VOL 0x10 /* DOS WT/FM volume control */ +#define ICE1712_SERR_LEVEL 0x08 /* SERR# level otherwise edge */ +#define ICE1712_SERR_ASSERT_SB 0x02 /* disabled SERR# assertion for SB irq otherwise enabled */ #define ICE1712_NATIVE 0x01 /* native mode otherwise SB */ #define ICE1712_REG_IRQMASK 0x01 /* byte */ -#define ICE1712_IRQ_MPU1 0x80 -#define ICE1712_IRQ_TIMER 0x40 -#define ICE1712_IRQ_MPU2 0x20 -#define ICE1712_IRQ_PROPCM 0x10 +#define ICE1712_IRQ_MPU1 0x80 /* MIDI irq mask */ +#define ICE1712_IRQ_TIMER 0x40 /* Timer mask */ +#define ICE1712_IRQ_MPU2 0x20 /* Secondary MIDI irq mask */ +#define ICE1712_IRQ_PROPCM 0x10 /* professional multi-track */ #define ICE1712_IRQ_FM 0x08 /* FM/MIDI - legacy */ #define ICE1712_IRQ_PBKDS 0x04 /* playback DS channels */ #define ICE1712_IRQ_CONCAP 0x02 /* consumer capture */ -- cgit v1.2.3-59-g8ed1b From d82353e534847732c4665a21e2ea699713a0e5b0 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 5 Jul 2014 13:02:02 -0700 Subject: ALSA: hda - Fix and neaten print_nid_path/debug_badness print_nid_path has a possible buffer overflow if struct nid_path.path values are > 256. Avoid this and neaten the output to remove the leading ':' Neaten debug_badness to always verify arguments. Signed-off-by: Joe Perches Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index a24c7b28b000..b956449ddada 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -350,16 +350,16 @@ static void print_nid_path(struct hda_codec *codec, const char *pfx, struct nid_path *path) { char buf[40]; + char *pos = buf; int i; + *pos = 0; + for (i = 0; i < path->depth; i++) + pos += scnprintf(pos, sizeof(buf) - (pos - buf), "%s%02x", + pos != buf ? ":" : "", + path->path[i]); - buf[0] = 0; - for (i = 0; i < path->depth; i++) { - char tmp[4]; - sprintf(tmp, ":%02x", path->path[i]); - strlcat(buf, tmp, sizeof(buf)); - } - codec_dbg(codec, "%s path: depth=%d %s\n", pfx, path->depth, buf); + codec_dbg(codec, "%s path: depth=%d '%s'\n", pfx, path->depth, buf); } /* called recursively */ @@ -1700,9 +1700,11 @@ static int fill_and_eval_dacs(struct hda_codec *codec, #define DEBUG_BADNESS #ifdef DEBUG_BADNESS -#define debug_badness(fmt, args...) codec_dbg(codec, fmt, ##args) +#define debug_badness(fmt, ...) \ + codec_dbg(codec, fmt, ##__VA_ARGS__) #else -#define debug_badness(...) +#define debug_badness(fmt, ...) \ + do { if (0) codec_dbg(codec, fmt, ##__VA_ARGS__); } while (0) #endif #ifdef DEBUG_BADNESS -- cgit v1.2.3-59-g8ed1b From 549d87823564e6edbd2077c2e6c979d17841f691 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Mon, 7 Jul 2014 17:07:43 +0800 Subject: ALSA: hda - Add several entries for enabling HP mute led BugLink: https://bugs.launchpad.net/bugs/1329580 Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 832c2255a620..327413ee72fb 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4854,6 +4854,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), /* ALC282 */ + SND_PCI_QUIRK(0x103c, 0x21f8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x220d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x220e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x220f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -4907,6 +4909,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8004, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), /* ALC290 */ SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x221c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x221d, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2220, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2222, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), -- cgit v1.2.3-59-g8ed1b From fc1fad93c95bed53f701a1169c556113341b43f0 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Tue, 8 Jul 2014 17:56:14 +0800 Subject: ALSA: hda - fix a typo by changing mute_led_nid to cap_mute_led_nid BugLink: https://bugs.launchpad.net/bugs/1329580 Cc: David Henningsson Cc: Kailang Yang Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 327413ee72fb..73b175944a07 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3529,7 +3529,7 @@ static void alc269_fixup_hp_cap_mic_mute_hook(struct hda_codec *codec, struct alc_spec *spec = codec->spec; unsigned int pinval, enable, disable; - pinval = snd_hda_codec_get_pin_target(codec, spec->mute_led_nid); + pinval = snd_hda_codec_get_pin_target(codec, spec->cap_mute_led_nid); pinval &= ~AC_PINCTL_VREFEN; enable = pinval | AC_PINCTL_VREF_80; disable = pinval | AC_PINCTL_VREF_HIZ; -- cgit v1.2.3-59-g8ed1b From 50dd9050e45ce11c575eabcaee8a914caf78fb74 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Tue, 8 Jul 2014 17:56:15 +0800 Subject: ALSA: hda - add capture mute led support in led_power_filter Now the led_power_filter() needs to handle 3 situations: - only mute_led_nid is set - only cap_mute_led_nid is set - both mute_led_ind and cap_mute_led_nid are set BugLink: https://bugs.launchpad.net/bugs/1329580 Cc: David Henningsson Cc: Kailang Yang Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 73b175944a07..512582b1f10a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3403,7 +3403,8 @@ static unsigned int led_power_filter(struct hda_codec *codec, { struct alc_spec *spec = codec->spec; - if (power_state != AC_PWRST_D3 || nid != spec->mute_led_nid) + if (power_state != AC_PWRST_D3 || nid == 0 || + (nid != spec->mute_led_nid && nid != spec->cap_mute_led_nid)) return power_state; /* Set pin ctl again, it might have just been set to 0 */ @@ -3563,6 +3564,7 @@ static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec, spec->gpio_led = 0; spec->cap_mute_led_nid = 0x18; snd_hda_add_verbs(codec, gpio_init); + codec->power_filter = led_power_filter; } } -- cgit v1.2.3-59-g8ed1b From 8695a003a5f4f5bc88b915e1c4a56d954f810f6e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Jul 2014 16:52:40 +0200 Subject: ALSA: hda - Add the pin fixup for HP Envy TS bass speaker NID 0x10 seems corresponding to the bass speaker. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 52bdbdc7786e..946ae4094aa3 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -103,6 +103,7 @@ enum { STAC_92HD83XXX_HP, STAC_HP_ENVY_BASS, STAC_HP_BNB13_EQ, + STAC_HP_ENVY_TS_BASS, STAC_92HD83XXX_MODELS }; @@ -2668,6 +2669,13 @@ static const struct hda_fixup stac92hd83xxx_fixups[] = { .chained = true, .chain_id = STAC_92HD83XXX_HP_MIC_LED, }, + [STAC_HP_ENVY_TS_BASS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x10, 0x92170111 }, + {} + }, + }, }; static const struct hda_model_fixup stac92hd83xxx_models[] = { @@ -2684,6 +2692,7 @@ static const struct hda_model_fixup stac92hd83xxx_models[] = { { .id = STAC_92HD83XXX_HEADSET_JACK, .name = "headset-jack" }, { .id = STAC_HP_ENVY_BASS, .name = "hp-envy-bass" }, { .id = STAC_HP_BNB13_EQ, .name = "hp-bnb13-eq" }, + { .id = STAC_HP_ENVY_TS_BASS, .name = "hp-envy-ts-bass" }, {} }; @@ -2739,6 +2748,8 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = { "HP bNB13", STAC_HP_BNB13_EQ), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x190A, "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x190e, + "HP ENVY TS", STAC_HP_ENVY_TS_BASS), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1940, "HP bNB13", STAC_HP_BNB13_EQ), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1941, -- cgit v1.2.3-59-g8ed1b From 2d9772ef653ccf2d5213603e371bbdfe7573df93 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Jul 2014 16:31:04 +0200 Subject: ALSA: hda - Add NULL check to all PM ops in hda_intel.c Since devptr can be NULL due to asynchronous probe, all PM ops should have NULL checks at the beginning. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 8edcee5f034d..387fc73a5c89 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -772,10 +772,15 @@ static int azx_suspend(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct azx *chip; + struct hda_intel *hda; struct azx_pcm *p; + if (!card) + return 0; + + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); if (chip->disabled || hda->init_failed) return 0; @@ -806,9 +811,14 @@ static int azx_resume(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct azx *chip; + struct hda_intel *hda; + if (!card) + return 0; + + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); if (chip->disabled || hda->init_failed) return 0; @@ -844,9 +854,14 @@ static int azx_resume(struct device *dev) static int azx_runtime_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct azx *chip; + struct hda_intel *hda; + if (!card) + return 0; + + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); if (chip->disabled || hda->init_failed) return 0; @@ -869,12 +884,17 @@ static int azx_runtime_suspend(struct device *dev) static int azx_runtime_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct azx *chip; + struct hda_intel *hda; struct hda_bus *bus; struct hda_codec *codec; int status; + if (!card) + return 0; + + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); if (chip->disabled || hda->init_failed) return 0; @@ -910,9 +930,14 @@ static int azx_runtime_resume(struct device *dev) static int azx_runtime_idle(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct azx *chip; + struct hda_intel *hda; + + if (!card) + return 0; + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); if (chip->disabled || hda->init_failed) return 0; -- cgit v1.2.3-59-g8ed1b From 423044744aa4c250058e976474856a7a41972182 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 22 Jul 2014 11:42:17 +0200 Subject: ALSA: hda - Add mute LED pin quirk for HP 15 touchsmart This makes the mute LED work on a HP 15 touchsmart machine. BugLink: https://bugs.launchpad.net/bugs/1334950 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 512582b1f10a..6f204ba02f62 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5160,6 +5160,17 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1d, 0x40700001}, {0x1e, 0x411111f0}, {0x21, 0x02211040}), + SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP 15 Touchsmart", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x14, 0x90170110}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x03a11020}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40f41905}, + {0x1e, 0x411111f0}, + {0x21, 0x0321101f}), SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60130}, {0x14, 0x90170110}, -- cgit v1.2.3-59-g8ed1b From 9dc12862da9d56ef4da646ba540c4f58b78738fc Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 22 Jul 2014 10:58:29 +0100 Subject: ALSA: hda - Add mic fixup for Gigabyte BXBT-2807 The Gigabyte BRIX BXBT-2707 is a mini-PC with Realtek ALC283 HDA, exposing a single headset jack. However, the default pin config information only suggests that one pin is connected: a HP out jack (pin 0x21, default config 0x04211010). The microphone input is behind pin 0x19, which has default config 0x411111f0 (i.e. unused), so it does not show up in userspace, and no microphone input is possible via the headset. Override the pin config so that the headset mic can be used. [rearranged the fixup entry position by tiwai] Signed-off-by: Daniel Drake Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6f204ba02f62..124272bc935b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4358,6 +4358,7 @@ enum { ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC, ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, ALC292_FIXUP_TPT440_DOCK, + ALC283_FIXUP_BXBT2807_MIC, }; static const struct hda_fixup alc269_fixups[] = { @@ -4792,6 +4793,13 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST }, + [ALC283_FIXUP_BXBT2807_MIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x04a110f0 }, + { }, + }, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -4987,6 +4995,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), + SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), -- cgit v1.2.3-59-g8ed1b From f5662e1cbf3f0939a6e033a00c542be4a0c2edee Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 22 Jul 2014 14:09:34 +0200 Subject: ALSA: hda - Refactor quirk picking and change quirk priority Previously, calling one quirk function first and another later would make the latter one take priority, this is now changed to make the former take priority. By adding two special values for fixup_id we can also get rid of the fixup_forced flag. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_auto_parser.c | 15 ++++++++------- sound/pci/hda/hda_codec.c | 1 + sound/pci/hda/hda_codec.h | 1 - sound/pci/hda/hda_local.h | 2 ++ sound/pci/hda/patch_cirrus.c | 4 +++- sound/pci/hda/patch_sigmatel.c | 4 +++- 6 files changed, 17 insertions(+), 10 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index a9790198aa17..51dea49aadd4 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -854,7 +854,7 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, { const struct snd_hda_pin_quirk *pq; - if (codec->fixup_forced) + if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) return; for (pq = pin_quirk; pq->subvendor; pq++) { @@ -880,14 +880,17 @@ void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_fixup *fixlist) { const struct snd_pci_quirk *q; - int id = -1; + int id = HDA_FIXUP_ID_NOT_SET; const char *name = NULL; + if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) + return; + /* when model=nofixup is given, don't pick up any fixups */ if (codec->modelname && !strcmp(codec->modelname, "nofixup")) { codec->fixup_list = NULL; - codec->fixup_id = -1; - codec->fixup_forced = 1; + codec->fixup_name = NULL; + codec->fixup_id = HDA_FIXUP_ID_NO_FIXUP; return; } @@ -897,13 +900,12 @@ void snd_hda_pick_fixup(struct hda_codec *codec, codec->fixup_id = models->id; codec->fixup_name = models->name; codec->fixup_list = fixlist; - codec->fixup_forced = 1; return; } models++; } } - if (id < 0 && quirk) { + if (quirk) { q = snd_pci_quirk_lookup(codec->bus->pci, quirk); if (q) { id = q->value; @@ -927,7 +929,6 @@ void snd_hda_pick_fixup(struct hda_codec *codec, } } - codec->fixup_forced = 0; codec->fixup_id = id; if (id >= 0) { codec->fixup_list = fixlist; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 47a617786fca..ec6a7d0d1886 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1476,6 +1476,7 @@ int snd_hda_codec_new(struct hda_bus *bus, INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work); codec->depop_delay = -1; + codec->fixup_id = HDA_FIXUP_ID_NOT_SET; #ifdef CONFIG_PM spin_lock_init(&codec->power_lock); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index f84a40ef42af..bbc5a1392c75 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -402,7 +402,6 @@ struct hda_codec { /* fix-up list */ int fixup_id; - unsigned int fixup_forced:1; /* fixup explicitly set by user */ const struct hda_fixup *fixup_list; const char *fixup_name; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index aa374ad4b5d0..364bb413e02a 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -438,6 +438,8 @@ struct snd_hda_pin_quirk { #endif +#define HDA_FIXUP_ID_NOT_SET -1 +#define HDA_FIXUP_ID_NO_FIXUP -2 /* fixup types */ enum { diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 387f0b551889..3db724eaa53c 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -657,8 +657,10 @@ static void cs4208_fixup_mac(struct hda_codec *codec, { if (action != HDA_FIXUP_ACT_PRE_PROBE) return; + + codec->fixup_id = HDA_FIXUP_ID_NOT_SET; snd_hda_pick_fixup(codec, NULL, cs4208_mac_fixup_tbl, cs4208_fixups); - if (codec->fixup_id < 0 || codec->fixup_id == CS4208_MAC_AUTO) + if (codec->fixup_id == HDA_FIXUP_ID_NOT_SET) codec->fixup_id = CS4208_GPIO0; /* default fixup */ snd_hda_apply_fixup(codec, action); } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 946ae4094aa3..8dc681593920 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3449,9 +3449,11 @@ static void stac922x_fixup_intel_mac_auto(struct hda_codec *codec, { if (action != HDA_FIXUP_ACT_PRE_PROBE) return; + + codec->fixup_id = HDA_FIXUP_ID_NOT_SET; snd_hda_pick_fixup(codec, NULL, stac922x_intel_mac_fixup_tbl, stac922x_fixups); - if (codec->fixup_id != STAC_INTEL_MAC_AUTO) + if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) snd_hda_apply_fixup(codec, action); } -- cgit v1.2.3-59-g8ed1b From 214eef76eb86ef66ddbd7a2b0f734b820843bf35 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 22 Jul 2014 14:09:35 +0200 Subject: ALSA: hda - Make vendor quirks lowest prio for ALC2xx Add a new quirk table to make sure that pin quirks have a higher priority than quirks that apply to an entire vendor. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 124272bc935b..86a8186b7661 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4809,7 +4809,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), - SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), @@ -4971,7 +4970,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -4992,7 +4990,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX), - SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC), @@ -5020,7 +5017,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), - SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", ALC269_FIXUP_THINKPAD_ACPI), SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ #if 0 @@ -5074,6 +5070,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { {} }; +static const struct snd_pci_quirk alc269_fixup_vendor_tbl[] = { + SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), + SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), + SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", ALC269_FIXUP_THINKPAD_ACPI), + {} +}; + static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"}, {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"}, @@ -5302,6 +5306,8 @@ static int patch_alc269(struct hda_codec *codec) snd_hda_pick_fixup(codec, alc269_fixup_models, alc269_fixup_tbl, alc269_fixups); snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups); + snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl, + alc269_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); -- cgit v1.2.3-59-g8ed1b From c5d019c395f9f81887e6995951986c18e6411b93 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 22 Jul 2014 17:33:32 +0200 Subject: ALSA: hda - Fix loopback noise on Dell XPS 15 Dell XPS 15 (1028:05fe) gives the bad feedback noise from analog loopback line even if the channels are muted. The similar problem has been seen on XPS 13, and it was fixed by simply disabling loopback. The same fixup was confirmed to be applicable and fix the problem on XPS 15, too. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=80821 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 86a8186b7661..2f755adfbe7c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6004,6 +6004,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13), SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13), SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), -- cgit v1.2.3-59-g8ed1b From 00ef99408b6cc8d86ca614ada8025aa3606860db Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Thu, 31 Jul 2014 11:52:38 +0800 Subject: ALSA: hda - add mic mute led hook for dell machines The mic mute led on dell laptops is controlled by the wmi driver. Followed this part being merged to the kernel, we add the mic mute led hook in the hda driver. Signed-off-by: David Henningsson Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/dell_wmi_helper.c | 76 +++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/patch_realtek.c | 13 +++++++ 2 files changed, 89 insertions(+) create mode 100644 sound/pci/hda/dell_wmi_helper.c (limited to 'sound/pci') diff --git a/sound/pci/hda/dell_wmi_helper.c b/sound/pci/hda/dell_wmi_helper.c new file mode 100644 index 000000000000..9c22f95838ef --- /dev/null +++ b/sound/pci/hda/dell_wmi_helper.c @@ -0,0 +1,76 @@ +/* Helper functions for Dell Mic Mute LED control; + * to be included from codec driver + */ + +#if IS_ENABLED(CONFIG_LEDS_DELL_NETBOOKS) +#include + +static int dell_led_value; +static int (*dell_led_set_func)(int, int); +static void (*dell_old_cap_hook)(struct hda_codec *, + struct snd_kcontrol *, + struct snd_ctl_elem_value *); + +static void update_dell_wmi_micmute_led(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + if (dell_old_cap_hook) + dell_old_cap_hook(codec, kcontrol, ucontrol); + + if (!ucontrol || !dell_led_set_func) + return; + if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) { + /* TODO: How do I verify if it's a mono or stereo here? */ + int val = (ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1]) ? 0 : 1; + if (val == dell_led_value) + return; + dell_led_value = val; + if (dell_led_set_func) + dell_led_set_func(DELL_LED_MICMUTE, dell_led_value); + } +} + + +static void alc_fixup_dell_wmi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + bool removefunc = false; + + if (action == HDA_FIXUP_ACT_PROBE) { + if (!dell_led_set_func) + dell_led_set_func = symbol_request(dell_app_wmi_led_set); + if (!dell_led_set_func) { + codec_warn(codec, "Failed to find dell wmi symbol dell_app_wmi_led_set\n"); + return; + } + + removefunc = true; + if (dell_led_set_func(DELL_LED_MICMUTE, false) >= 0) { + dell_led_value = 0; + if (spec->gen.num_adc_nids > 1) + codec_dbg(codec, "Skipping micmute LED control due to several ADCs"); + else { + dell_old_cap_hook = spec->gen.cap_sync_hook; + spec->gen.cap_sync_hook = update_dell_wmi_micmute_led; + removefunc = false; + } + } + + } + + if (dell_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) { + symbol_put(dell_app_wmi_led_set); + dell_led_set_func = NULL; + dell_old_cap_hook = NULL; + } +} + +#else /* CONFIG_LEDS_DELL_NETBOOKS */ +static void alc_fixup_dell_wmi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ +} + +#endif /* CONFIG_LEDS_DELL_NETBOOKS */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2f755adfbe7c..654c8f16d150 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4295,6 +4295,9 @@ static void alc290_fixup_mono_speakers(struct hda_codec *codec, /* for hda_fixup_thinkpad_acpi() */ #include "thinkpad_helper.c" +/* for dell wmi mic mute led */ +#include "dell_wmi_helper.c" + enum { ALC269_FIXUP_SONY_VAIO, ALC275_FIXUP_SONY_VAIO_GPIO2, @@ -4359,6 +4362,7 @@ enum { ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, ALC292_FIXUP_TPT440_DOCK, ALC283_FIXUP_BXBT2807_MIC, + ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, }; static const struct hda_fixup alc269_fixups[] = { @@ -4800,6 +4804,13 @@ static const struct hda_fixup alc269_fixups[] = { { }, }, }, + [ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_dell_wmi, + .chained_before = true, + .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE + }, + }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -4842,10 +4853,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0606, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED), SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0614, "Dell Inspiron 3135", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), + SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED), SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), -- cgit v1.2.3-59-g8ed1b