It turned out that Lenovo shipped two completely different products with the very same PCI SSID, where both require different quirks; namely, Lenovo C940 has already the fixup for its speaker (ALC298_FIXUP_LENOVO_SPK_VOLUME) with the PCI SSID 17aa:3818, while Yoga Duet 7 has also the very same PCI SSID but requires a different quirk, ALC287_FIXUP_YOGA7_14TIL_SPEAKERS. Fortunately, both are with different codecs (C940 with ALC298 and Duet 7 with ALC287), hence we can apply different fixes by checking the codec ID. This patch implements that special fixup function. For easier handling, the internal function for applying a specific fixup entry is exported as __snd_hda_apply_fixup(), so that it can be called from the codec driver. The rest is simply calling it with a different fixup ID depending on the codec ID.
Unified · Split
| @@ -819,7 +819,7 @@ static void set_pin_targets(struct hda_codec *codec, · 818 unmodified lines | |||
| 819 | snd_hda_set_pin_ctl_cache(codec, cfg->nid, cfg->val); | 819 | snd_hda_set_pin_ctl_cache(codec, cfg->nid, cfg->val); |
| 820 | } | 820 | } |
| 821 | 821 | ||
| 822 | static void apply_fixup(struct hda_codec *codec, int id, int action, int depth) | 822 | void __snd_hda_apply_fixup(struct hda_codec *codec, int id, int action, int depth) |
| 823 | { | 823 | { |
| 824 | const char *modelname = codec->fixup_name; | 824 | const char *modelname = codec->fixup_name; |
| 825 | 825 | ||
| @@ -829,7 +829,7 @@ static void apply_fixup(struct hda_codec *codec, int id, int action, int depth) · 3 unmodified lines | |||
| 829 | if (++depth > 10) | 829 | if (++depth > 10) |
| 830 | break; | 830 | break; |
| 831 | if (fix->chained_before) | 831 | if (fix->chained_before) |
| 832 | apply_fixup(codec, fix->chain_id, action, depth + 1); | 832 | __snd_hda_apply_fixup(codec, fix->chain_id, action, depth + 1); |
| 833 | 833 | ||
| 834 | switch (fix->type) { | 834 | switch (fix->type) { |
| 835 | case HDA_FIXUP_PINS: | 835 | case HDA_FIXUP_PINS: |
| @@ -870,6 +870,7 @@ static void apply_fixup(struct hda_codec *codec, int id, int action, int depth) · 34 unmodified lines | |||
| 870 | id = fix->chain_id; | 870 | id = fix->chain_id; |
| 871 | } | 871 | } |
| 872 | } | 872 | } |
| 873 | EXPORT_SYMBOL_GPL(__snd_hda_apply_fixup); | ||
| 873 | 874 | ||
| 874 | /** | 875 | /** |
| 875 | * snd_hda_apply_fixup - Apply the fixup chain with the given action | 876 | * snd_hda_apply_fixup - Apply the fixup chain with the given action |
| @@ -879,7 +880,7 @@ static void apply_fixup(struct hda_codec *codec, int id, int action, int depth) · 3 unmodified lines | |||
| 879 | void snd_hda_apply_fixup(struct hda_codec *codec, int action) | 880 | void snd_hda_apply_fixup(struct hda_codec *codec, int action) |
| 880 | { | 881 | { |
| 881 | if (codec->fixup_list) | 882 | if (codec->fixup_list) |
| 882 | apply_fixup(codec, codec->fixup_id, action, 0); | 883 | __snd_hda_apply_fixup(codec, codec->fixup_id, action, 0); |
| 883 | } | 884 | } |
| 884 | EXPORT_SYMBOL_GPL(snd_hda_apply_fixup); | 885 | EXPORT_SYMBOL_GPL(snd_hda_apply_fixup); |
| 885 | 886 | ||
| @@ -348,6 +348,7 @@ void snd_hda_apply_verbs(struct hda_codec *codec); · 347 unmodified lines | |||
| 348 | void snd_hda_apply_pincfgs(struct hda_codec *codec, | 348 | void snd_hda_apply_pincfgs(struct hda_codec *codec, |
| 349 | const struct hda_pintbl *cfg); | 349 | const struct hda_pintbl *cfg); |
| 350 | void snd_hda_apply_fixup(struct hda_codec *codec, int action); | 350 | void snd_hda_apply_fixup(struct hda_codec *codec, int action); |
| 351 | void __snd_hda_apply_fixup(struct hda_codec *codec, int id, int action, int depth); | ||
| 351 | void snd_hda_pick_fixup(struct hda_codec *codec, | 352 | void snd_hda_pick_fixup(struct hda_codec *codec, |
| 352 | const struct hda_model_fixup *models, | 353 | const struct hda_model_fixup *models, |
| 353 | const struct snd_pci_quirk *quirk, | 354 | const struct snd_pci_quirk *quirk, |
| @@ -7004,6 +7004,7 @@ enum { · 7003 unmodified lines | |||
| 7004 | ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS, | 7004 | ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS, |
| 7005 | ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE, | 7005 | ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE, |
| 7006 | ALC287_FIXUP_YOGA7_14ITL_SPEAKERS, | 7006 | ALC287_FIXUP_YOGA7_14ITL_SPEAKERS, |
| 7007 | ALC298_FIXUP_LENOVO_C940_DUET7, | ||
| 7007 | ALC287_FIXUP_13S_GEN2_SPEAKERS, | 7008 | ALC287_FIXUP_13S_GEN2_SPEAKERS, |
| 7008 | ALC256_FIXUP_SET_COEF_DEFAULTS, | 7009 | ALC256_FIXUP_SET_COEF_DEFAULTS, |
| 7009 | ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE, | 7010 | ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE, |
| @@ -7022,6 +7023,23 @@ enum { · 12 unmodified lines | |||
| 7022 | ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE, | 7023 | ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE, |
| 7023 | }; | 7024 | }; |
| 7024 | 7025 | ||
| 7026 | /* A special fixup for Lenovo C940 and Yoga Duet 7; | ||
| 7027 | * both have the very same PCI SSID, and we need to apply different fixups | ||
| 7028 | * depending on the codec ID | ||
| 7029 | */ | ||
| 7030 | static void alc298_fixup_lenovo_c940_duet7(struct hda_codec *codec, | ||
| 7031 | const struct hda_fixup *fix, | ||
| 7032 | int action) | ||
| 7033 | { | ||
| 7034 | int id; | ||
| 7035 | |||
| 7036 | if (codec->core.vendor_id == 0x10ec0298) | ||
| 7037 | id = ALC298_FIXUP_LENOVO_SPK_VOLUME; /* C940 */ | ||
| 7038 | else | ||
| 7039 | id = ALC287_FIXUP_YOGA7_14ITL_SPEAKERS; /* Duet 7 */ | ||
| 7040 | __snd_hda_apply_fixup(codec, id, action, 0); | ||
| 7041 | } | ||
| 7042 | |||
| 7025 | static const struct hda_fixup alc269_fixups[] = { | 7043 | static const struct hda_fixup alc269_fixups[] = { |
| 7026 | [ALC269_FIXUP_GPIO2] = { | 7044 | [ALC269_FIXUP_GPIO2] = { |
| 7027 | .type = HDA_FIXUP_FUNC, | 7045 | .type = HDA_FIXUP_FUNC, |
| @@ -8721,6 +8739,10 @@ static const struct hda_fixup alc269_fixups[] = { · 1693 unmodified lines | |||
| 8721 | .chained = true, | 8739 | .chained = true, |
| 8722 | .chain_id = ALC269_FIXUP_HEADSET_MODE, | 8740 | .chain_id = ALC269_FIXUP_HEADSET_MODE, |
| 8723 | }, | 8741 | }, |
| 8742 | [ALC298_FIXUP_LENOVO_C940_DUET7] = { | ||
| 8743 | .type = HDA_FIXUP_FUNC, | ||
| 8744 | .v.func = alc298_fixup_lenovo_c940_duet7, | ||
| 8745 | }, | ||
| 8724 | [ALC287_FIXUP_13S_GEN2_SPEAKERS] = { | 8746 | [ALC287_FIXUP_13S_GEN2_SPEAKERS] = { |
| 8725 | .type = HDA_FIXUP_VERBS, | 8747 | .type = HDA_FIXUP_VERBS, |
| 8726 | .v.verbs = (const struct hda_verb[]) { | 8748 | .v.verbs = (const struct hda_verb[]) { |
| @@ -9274,7 +9296,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { · 547 unmodified lines | |||
| 9274 | SND_PCI_QUIRK(0x17aa, 0x31af, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340), | 9296 | SND_PCI_QUIRK(0x17aa, 0x31af, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340), |
| 9275 | SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), | 9297 | SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), |
| 9276 | SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS), | 9298 | SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS), |
| 9277 | SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940", ALC298_FIXUP_LENOVO_SPK_VOLUME), | 9299 | SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7), |
| 9278 | SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS), | 9300 | SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS), |
| 9279 | SND_PCI_QUIRK(0x17aa, 0x3820, "Yoga Duet 7 13ITL6", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), | 9301 | SND_PCI_QUIRK(0x17aa, 0x3820, "Yoga Duet 7 13ITL6", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), |
| 9280 | SND_PCI_QUIRK(0x17aa, 0x3824, "Legion Y9000X 2020", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS), | 9302 | SND_PCI_QUIRK(0x17aa, 0x3824, "Legion Y9000X 2020", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS), |