hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/sound/pci/hda/patch_conexant.c
....@@ -1,23 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * HD audio interface patch for Conexant HDA audio codec
34 *
45 * Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com>
56 * Takashi Iwai <tiwai@suse.de>
67 * Tobin Davis <tdavis@dsl-only.net>
7
- *
8
- * This driver is free software; you can redistribute it and/or modify
9
- * it under the terms of the GNU General Public License as published by
10
- * the Free Software Foundation; either version 2 of the License, or
11
- * (at your option) any later version.
12
- *
13
- * This driver is distributed in the hope that it will be useful,
14
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- * GNU General Public License for more details.
17
- *
18
- * You should have received a copy of the GNU General Public License
19
- * along with this program; if not, write to the Free Software
20
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
218 */
229
2310 #include <linux/init.h>
....@@ -27,7 +14,7 @@
2714 #include <sound/core.h>
2815 #include <sound/jack.h>
2916
30
-#include "hda_codec.h"
17
+#include <sound/hda_codec.h>
3118 #include "hda_local.h"
3219 #include "hda_auto_parser.h"
3320 #include "hda_beep.h"
....@@ -129,7 +116,7 @@
129116 }
130117
131118 static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
132
- hda_nid_t *pins, bool on)
119
+ const hda_nid_t *pins, bool on)
133120 {
134121 int i;
135122 for (i = 0; i < num_pins; i++) {
....@@ -150,14 +137,31 @@
150137 }
151138
152139 /* turn on/off EAPD according to Master switch (inversely!) for mute LED */
153
-static void cx_auto_vmaster_hook_mute_led(void *private_data, int enabled)
140
+static int cx_auto_vmaster_mute_led(struct led_classdev *led_cdev,
141
+ enum led_brightness brightness)
154142 {
155
- struct hda_codec *codec = private_data;
143
+ struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
156144 struct conexant_spec *spec = codec->spec;
157145
158146 snd_hda_codec_write(codec, spec->mute_led_eapd, 0,
159147 AC_VERB_SET_EAPD_BTLENABLE,
160
- enabled ? 0x00 : 0x02);
148
+ brightness ? 0x02 : 0x00);
149
+ return 0;
150
+}
151
+
152
+static void cxt_init_gpio_led(struct hda_codec *codec)
153
+{
154
+ struct conexant_spec *spec = codec->spec;
155
+ unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
156
+
157
+ if (mask) {
158
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
159
+ mask);
160
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
161
+ mask);
162
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
163
+ spec->gpio_led);
164
+ }
161165 }
162166
163167 static int cx_auto_init(struct hda_codec *codec)
....@@ -167,6 +171,7 @@
167171 if (!spec->dynamic_eapd)
168172 cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
169173
174
+ cxt_init_gpio_led(codec);
170175 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
171176
172177 return 0;
....@@ -210,6 +215,7 @@
210215 CXT_PINCFG_LEMOTE_A1205,
211216 CXT_PINCFG_COMPAQ_CQ60,
212217 CXT_FIXUP_STEREO_DMIC,
218
+ CXT_PINCFG_LENOVO_NOTEBOOK,
213219 CXT_FIXUP_INC_MIC_BOOST,
214220 CXT_FIXUP_HEADPHONE_MIC_PIN,
215221 CXT_FIXUP_HEADPHONE_MIC,
....@@ -226,6 +232,7 @@
226232 CXT_FIXUP_HP_SPECTRE,
227233 CXT_FIXUP_HP_GATE_MIC,
228234 CXT_FIXUP_MUTE_LED_GPIO,
235
+ CXT_FIXUP_HP_ZBOOK_MUTE_LED,
229236 CXT_FIXUP_HEADSET_MIC,
230237 CXT_FIXUP_HP_MIC_NO_PRESENCE,
231238 };
....@@ -579,7 +586,7 @@
579586 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
580587 spec->mute_led_eapd = 0x1b;
581588 spec->dynamic_eapd = 1;
582
- spec->gen.vmaster_mute.hook = cx_auto_vmaster_hook_mute_led;
589
+ snd_hda_gen_add_mute_led_cdev(codec, cx_auto_vmaster_mute_led);
583590 }
584591 }
585592
....@@ -644,48 +651,57 @@
644651 }
645652
646653 /* turn on/off mute LED via GPIO per vmaster hook */
647
-static void cxt_fixup_gpio_mute_hook(void *private_data, int enabled)
654
+static int cxt_gpio_mute_update(struct led_classdev *led_cdev,
655
+ enum led_brightness brightness)
648656 {
649
- struct hda_codec *codec = private_data;
657
+ struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
650658 struct conexant_spec *spec = codec->spec;
651
- /* muted -> LED on */
652
- cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, !enabled);
659
+
660
+ cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, brightness);
661
+ return 0;
653662 }
654663
655664 /* turn on/off mic-mute LED via GPIO per capture hook */
656
-static void cxt_gpio_micmute_update(struct hda_codec *codec)
665
+static int cxt_gpio_micmute_update(struct led_classdev *led_cdev,
666
+ enum led_brightness brightness)
667
+{
668
+ struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
669
+ struct conexant_spec *spec = codec->spec;
670
+
671
+ cxt_update_gpio_led(codec, spec->gpio_mic_led_mask, brightness);
672
+ return 0;
673
+}
674
+
675
+static void cxt_setup_mute_led(struct hda_codec *codec,
676
+ unsigned int mute, unsigned int mic_mute)
657677 {
658678 struct conexant_spec *spec = codec->spec;
659679
660
- cxt_update_gpio_led(codec, spec->gpio_mic_led_mask,
661
- spec->gen.micmute_led.led_value);
680
+ spec->gpio_led = 0;
681
+ spec->mute_led_polarity = 0;
682
+ if (mute) {
683
+ snd_hda_gen_add_mute_led_cdev(codec, cxt_gpio_mute_update);
684
+ spec->gpio_mute_led_mask = mute;
685
+ }
686
+ if (mic_mute) {
687
+ snd_hda_gen_add_micmute_led_cdev(codec, cxt_gpio_micmute_update);
688
+ spec->gpio_mic_led_mask = mic_mute;
689
+ }
662690 }
663
-
664691
665692 static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
666693 const struct hda_fixup *fix, int action)
667694 {
668
- struct conexant_spec *spec = codec->spec;
669
- static const struct hda_verb gpio_init[] = {
670
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x03 },
671
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03 },
672
- {}
673
- };
674
-
675
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
676
- spec->gen.vmaster_mute.hook = cxt_fixup_gpio_mute_hook;
677
- spec->gpio_led = 0;
678
- spec->mute_led_polarity = 0;
679
- spec->gpio_mute_led_mask = 0x01;
680
- spec->gpio_mic_led_mask = 0x02;
681
- snd_hda_gen_add_micmute_led(codec, cxt_gpio_micmute_update);
682
- }
683
- snd_hda_add_verbs(codec, gpio_init);
684
- if (spec->gpio_led)
685
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
686
- spec->gpio_led);
695
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
696
+ cxt_setup_mute_led(codec, 0x01, 0x02);
687697 }
688698
699
+static void cxt_fixup_hp_zbook_mute_led(struct hda_codec *codec,
700
+ const struct hda_fixup *fix, int action)
701
+{
702
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
703
+ cxt_setup_mute_led(codec, 0x10, 0x20);
704
+}
689705
690706 /* ThinkPad X200 & co with cxt5051 */
691707 static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
....@@ -749,6 +765,14 @@
749765 [CXT_FIXUP_STEREO_DMIC] = {
750766 .type = HDA_FIXUP_FUNC,
751767 .v.func = cxt_fixup_stereo_dmic,
768
+ },
769
+ [CXT_PINCFG_LENOVO_NOTEBOOK] = {
770
+ .type = HDA_FIXUP_PINS,
771
+ .v.pins = (const struct hda_pintbl[]) {
772
+ { 0x1a, 0x05d71030 },
773
+ { }
774
+ },
775
+ .chain_id = CXT_FIXUP_STEREO_DMIC,
752776 },
753777 [CXT_FIXUP_INC_MIC_BOOST] = {
754778 .type = HDA_FIXUP_FUNC,
....@@ -846,6 +870,10 @@
846870 .type = HDA_FIXUP_FUNC,
847871 .v.func = cxt_fixup_mute_led_gpio,
848872 },
873
+ [CXT_FIXUP_HP_ZBOOK_MUTE_LED] = {
874
+ .type = HDA_FIXUP_FUNC,
875
+ .v.func = cxt_fixup_hp_zbook_mute_led,
876
+ },
849877 [CXT_FIXUP_HEADSET_MIC] = {
850878 .type = HDA_FIXUP_FUNC,
851879 .v.func = cxt_fixup_headset_mic,
....@@ -918,12 +946,15 @@
918946 SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
919947 SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
920948 SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
949
+ SND_PCI_QUIRK(0x103c, 0x82b4, "HP ProDesk 600 G3", CXT_FIXUP_HP_MIC_NO_PRESENCE),
921950 SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO),
922951 SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO),
923952 SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK),
924953 SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK),
925954 SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK),
926955 SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO),
956
+ SND_PCI_QUIRK(0x103c, 0x8427, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED),
957
+ SND_PCI_QUIRK(0x103c, 0x844f, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED),
927958 SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE),
928959 SND_PCI_QUIRK(0x103c, 0x8456, "HP Z2 G4 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
929960 SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE),
....@@ -942,6 +973,9 @@
942973 SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC),
943974 SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
944975 SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
976
+ /* NOTE: we'd need to extend the quirk for 17aa:3977 as the same
977
+ * PCI SSID is used on multiple Lenovo models
978
+ */
945979 SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
946980 SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC),
947981 SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
....@@ -963,7 +997,9 @@
963997 { .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" },
964998 { .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" },
965999 { .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" },
1000
+ { .id = CXT_FIXUP_HP_ZBOOK_MUTE_LED, .name = "hp-zbook-mute-led" },
9661001 { .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" },
1002
+ { .id = CXT_PINCFG_LENOVO_NOTEBOOK, .name = "lenovo-20149" },
9671003 {}
9681004 };
9691005
....@@ -973,10 +1009,10 @@
9731009 static void add_cx5051_fake_mutes(struct hda_codec *codec)
9741010 {
9751011 struct conexant_spec *spec = codec->spec;
976
- static hda_nid_t out_nids[] = {
1012
+ static const hda_nid_t out_nids[] = {
9771013 0x10, 0x11, 0
9781014 };
979
- hda_nid_t *p;
1015
+ const hda_nid_t *p;
9801016
9811017 for (p = out_nids; *p; p++)
9821018 snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT,
....@@ -1001,8 +1037,6 @@
10011037
10021038 cx_auto_parse_eapd(codec);
10031039 spec->gen.own_eapd_ctl = 1;
1004
- if (spec->dynamic_eapd)
1005
- spec->gen.vmaster_mute.hook = cx_auto_vmaster_hook;
10061040
10071041 switch (codec->core.vendor_id) {
10081042 case 0x14f15045:
....@@ -1025,9 +1059,16 @@
10251059 snd_hda_pick_fixup(codec, cxt5051_fixup_models,
10261060 cxt5051_fixups, cxt_fixups);
10271061 break;
1062
+ case 0x14f15098:
1063
+ codec->pin_amp_workaround = 1;
1064
+ spec->gen.mixer_nid = 0x22;
1065
+ spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
1066
+ snd_hda_pick_fixup(codec, cxt5066_fixup_models,
1067
+ cxt5066_fixups, cxt_fixups);
1068
+ break;
10281069 case 0x14f150f2:
10291070 codec->power_save_node = 1;
1030
- /* Fall through */
1071
+ fallthrough;
10311072 default:
10321073 codec->pin_amp_workaround = 1;
10331074 snd_hda_pick_fixup(codec, cxt5066_fixup_models,
....@@ -1035,17 +1076,8 @@
10351076 break;
10361077 }
10371078
1038
- /* Show mute-led control only on HP laptops
1039
- * This is a sort of white-list: on HP laptops, EAPD corresponds
1040
- * only to the mute-LED without actualy amp function. Meanwhile,
1041
- * others may use EAPD really as an amp switch, so it might be
1042
- * not good to expose it blindly.
1043
- */
1044
- switch (codec->core.subsystem_id >> 16) {
1045
- case 0x103c:
1046
- spec->gen.vmaster_mute_enum = 1;
1047
- break;
1048
- }
1079
+ if (!spec->gen.vmaster_mute.hook && spec->dynamic_eapd)
1080
+ spec->gen.vmaster_mute.hook = cx_auto_vmaster_hook;
10491081
10501082 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
10511083
....@@ -1054,11 +1086,11 @@
10541086 if (err < 0)
10551087 goto error;
10561088
1057
- err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
1089
+ err = cx_auto_parse_beep(codec);
10581090 if (err < 0)
10591091 goto error;
10601092
1061
- err = cx_auto_parse_beep(codec);
1093
+ err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
10621094 if (err < 0)
10631095 goto error;
10641096
....@@ -1089,6 +1121,7 @@
10891121 HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto),
10901122 HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
10911123 HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto),
1124
+ HDA_CODEC_ENTRY(0x14f120d1, "SN6180", patch_conexant_auto),
10921125 HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
10931126 HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
10941127 HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto),