1 // SPDX-License-Identifier: GPL-2.0-or-later 2 // 3 // Realtek ALC260 codec 4 // 5 6 #include <linux/init.h> 7 #include <linux/module.h> 8 #include "realtek.h" 9 10 static int alc260_parse_auto_config(struct hda_codec *codec) 11 { 12 static const hda_nid_t alc260_ignore[] = { 0x17, 0 }; 13 static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 }; 14 return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids); 15 } 16 17 /* 18 * Pin config fixes 19 */ 20 enum { 21 ALC260_FIXUP_HP_DC5750, 22 ALC260_FIXUP_HP_PIN_0F, 23 ALC260_FIXUP_COEF, 24 ALC260_FIXUP_GPIO1, 25 ALC260_FIXUP_GPIO1_TOGGLE, 26 ALC260_FIXUP_REPLACER, 27 ALC260_FIXUP_HP_B1900, 28 ALC260_FIXUP_KN1, 29 ALC260_FIXUP_FSC_S7020, 30 ALC260_FIXUP_FSC_S7020_JWSE, 31 ALC260_FIXUP_VAIO_PINS, 32 }; 33 34 static void alc260_gpio1_automute(struct hda_codec *codec) 35 { 36 struct alc_spec *spec = codec->spec; 37 38 alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present); 39 } 40 41 static void alc260_fixup_gpio1_toggle(struct hda_codec *codec, 42 const struct hda_fixup *fix, int action) 43 { 44 struct alc_spec *spec = codec->spec; 45 if (action == HDA_FIXUP_ACT_PROBE) { 46 /* although the machine has only one output pin, we need to 47 * toggle GPIO1 according to the jack state 48 */ 49 spec->gen.automute_hook = alc260_gpio1_automute; 50 spec->gen.detect_hp = 1; 51 spec->gen.automute_speaker = 1; 52 spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */ 53 snd_hda_jack_detect_enable_callback(codec, 0x0f, 54 snd_hda_gen_hp_automute); 55 alc_setup_gpio(codec, 0x01); 56 } 57 } 58 59 static void alc260_fixup_kn1(struct hda_codec *codec, 60 const struct hda_fixup *fix, int action) 61 { 62 struct alc_spec *spec = codec->spec; 63 static const struct hda_pintbl pincfgs[] = { 64 { 0x0f, 0x02214000 }, /* HP/speaker */ 65 { 0x12, 0x90a60160 }, /* int mic */ 66 { 0x13, 0x02a19000 }, /* ext mic */ 67 { 0x18, 0x01446000 }, /* SPDIF out */ 68 /* disable bogus I/O pins */ 69 { 0x10, 0x411111f0 }, 70 { 0x11, 0x411111f0 }, 71 { 0x14, 0x411111f0 }, 72 { 0x15, 0x411111f0 }, 73 { 0x16, 0x411111f0 }, 74 { 0x17, 0x411111f0 }, 75 { 0x19, 0x411111f0 }, 76 { } 77 }; 78 79 switch (action) { 80 case HDA_FIXUP_ACT_PRE_PROBE: 81 snd_hda_apply_pincfgs(codec, pincfgs); 82 spec->init_amp = ALC_INIT_NONE; 83 break; 84 } 85 } 86 87 static void alc260_fixup_fsc_s7020(struct hda_codec *codec, 88 const struct hda_fixup *fix, int action) 89 { 90 struct alc_spec *spec = codec->spec; 91 if (action == HDA_FIXUP_ACT_PRE_PROBE) 92 spec->init_amp = ALC_INIT_NONE; 93 } 94 95 static void alc260_fixup_fsc_s7020_jwse(struct hda_codec *codec, 96 const struct hda_fixup *fix, int action) 97 { 98 struct alc_spec *spec = codec->spec; 99 if (action == HDA_FIXUP_ACT_PRE_PROBE) { 100 spec->gen.add_jack_modes = 1; 101 spec->gen.hp_mic = 1; 102 } 103 } 104 105 static const struct hda_fixup alc260_fixups[] = { 106 [ALC260_FIXUP_HP_DC5750] = { 107 .type = HDA_FIXUP_PINS, 108 .v.pins = (const struct hda_pintbl[]) { 109 { 0x11, 0x90130110 }, /* speaker */ 110 { } 111 } 112 }, 113 [ALC260_FIXUP_HP_PIN_0F] = { 114 .type = HDA_FIXUP_PINS, 115 .v.pins = (const struct hda_pintbl[]) { 116 { 0x0f, 0x01214000 }, /* HP */ 117 { } 118 } 119 }, 120 [ALC260_FIXUP_COEF] = { 121 .type = HDA_FIXUP_VERBS, 122 .v.verbs = (const struct hda_verb[]) { 123 { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 }, 124 { 0x1a, AC_VERB_SET_PROC_COEF, 0x3040 }, 125 { } 126 }, 127 }, 128 [ALC260_FIXUP_GPIO1] = { 129 .type = HDA_FIXUP_FUNC, 130 .v.func = alc_fixup_gpio1, 131 }, 132 [ALC260_FIXUP_GPIO1_TOGGLE] = { 133 .type = HDA_FIXUP_FUNC, 134 .v.func = alc260_fixup_gpio1_toggle, 135 .chained = true, 136 .chain_id = ALC260_FIXUP_HP_PIN_0F, 137 }, 138 [ALC260_FIXUP_REPLACER] = { 139 .type = HDA_FIXUP_VERBS, 140 .v.verbs = (const struct hda_verb[]) { 141 { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 }, 142 { 0x1a, AC_VERB_SET_PROC_COEF, 0x3050 }, 143 { } 144 }, 145 .chained = true, 146 .chain_id = ALC260_FIXUP_GPIO1_TOGGLE, 147 }, 148 [ALC260_FIXUP_HP_B1900] = { 149 .type = HDA_FIXUP_FUNC, 150 .v.func = alc260_fixup_gpio1_toggle, 151 .chained = true, 152 .chain_id = ALC260_FIXUP_COEF, 153 }, 154 [ALC260_FIXUP_KN1] = { 155 .type = HDA_FIXUP_FUNC, 156 .v.func = alc260_fixup_kn1, 157 }, 158 [ALC260_FIXUP_FSC_S7020] = { 159 .type = HDA_FIXUP_FUNC, 160 .v.func = alc260_fixup_fsc_s7020, 161 }, 162 [ALC260_FIXUP_FSC_S7020_JWSE] = { 163 .type = HDA_FIXUP_FUNC, 164 .v.func = alc260_fixup_fsc_s7020_jwse, 165 .chained = true, 166 .chain_id = ALC260_FIXUP_FSC_S7020, 167 }, 168 [ALC260_FIXUP_VAIO_PINS] = { 169 .type = HDA_FIXUP_PINS, 170 .v.pins = (const struct hda_pintbl[]) { 171 /* Pin configs are missing completely on some VAIOs */ 172 { 0x0f, 0x01211020 }, 173 { 0x10, 0x0001003f }, 174 { 0x11, 0x411111f0 }, 175 { 0x12, 0x01a15930 }, 176 { 0x13, 0x411111f0 }, 177 { 0x14, 0x411111f0 }, 178 { 0x15, 0x411111f0 }, 179 { 0x16, 0x411111f0 }, 180 { 0x17, 0x411111f0 }, 181 { 0x18, 0x411111f0 }, 182 { 0x19, 0x411111f0 }, 183 { } 184 } 185 }, 186 }; 187 188 static const struct hda_quirk alc260_fixup_tbl[] = { 189 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1), 190 SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF), 191 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1), 192 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750), 193 SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900), 194 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_FIXUP_VAIO_PINS), 195 SND_PCI_QUIRK(0x104d, 0x81e2, "Sony VAIO TX", ALC260_FIXUP_HP_PIN_0F), 196 SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020), 197 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1), 198 SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1), 199 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER), 200 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF), 201 {} 202 }; 203 204 static const struct hda_model_fixup alc260_fixup_models[] = { 205 {.id = ALC260_FIXUP_GPIO1, .name = "gpio1"}, 206 {.id = ALC260_FIXUP_COEF, .name = "coef"}, 207 {.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"}, 208 {.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"}, 209 {} 210 }; 211 212 /* 213 */ 214 static int alc260_probe(struct hda_codec *codec, const struct hda_device_id *id) 215 { 216 struct alc_spec *spec; 217 int err; 218 219 err = alc_alloc_spec(codec, 0x07); 220 if (err < 0) 221 return err; 222 223 spec = codec->spec; 224 /* as quite a few machines require HP amp for speaker outputs, 225 * it's easier to enable it unconditionally; even if it's unneeded, 226 * it's almost harmless. 227 */ 228 spec->gen.prefer_hp_amp = 1; 229 spec->gen.beep_nid = 0x01; 230 231 spec->shutup = alc_eapd_shutup; 232 233 alc_pre_init(codec); 234 235 snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl, 236 alc260_fixups); 237 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); 238 239 /* automatic parse from the BIOS config */ 240 err = alc260_parse_auto_config(codec); 241 if (err < 0) 242 goto error; 243 244 if (!spec->gen.no_analog) { 245 err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); 246 if (err < 0) 247 goto error; 248 } 249 250 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); 251 252 return 0; 253 254 error: 255 snd_hda_gen_remove(codec); 256 return err; 257 } 258 259 static const struct hda_codec_ops alc260_codec_ops = { 260 .probe = alc260_probe, 261 .remove = snd_hda_gen_remove, 262 .build_controls = alc_build_controls, 263 .build_pcms = snd_hda_gen_build_pcms, 264 .init = alc_init, 265 .unsol_event = snd_hda_jack_unsol_event, 266 .resume = alc_resume, 267 .suspend = alc_suspend, 268 .check_power_status = snd_hda_gen_check_power_status, 269 .stream_pm = snd_hda_gen_stream_pm, 270 }; 271 272 /* 273 * driver entries 274 */ 275 static const struct hda_device_id snd_hda_id_alc260[] = { 276 HDA_CODEC_ID(0x10ec0260, "ALC260"), 277 {} /* terminator */ 278 }; 279 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc260); 280 281 MODULE_LICENSE("GPL"); 282 MODULE_DESCRIPTION("Realtek ALC260 HD-audio codec"); 283 MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); 284 285 static struct hda_codec_driver alc260_driver = { 286 .id = snd_hda_id_alc260, 287 .ops = &alc260_codec_ops, 288 }; 289 290 module_hda_codec_driver(alc260_driver); 291