]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Merge branch 'for-linus' into for-next
authorTakashi Iwai <tiwai@suse.de>
Mon, 14 Jul 2025 12:29:49 +0000 (14:29 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 14 Jul 2025 12:29:49 +0000 (14:29 +0200)
Signed-off-by: Takashi Iwai <tiwai@suse.de>
1  2 
sound/hda/codecs/realtek/alc269.c
sound/hda/codecs/side-codecs/cs35l56_hda.c

index 03daa58a88de6fe3f24acb09f4a06c05afce10de,47ceb6f32291210b4f73be0f0fea7b2240f529b9..5b899e13715950444d4e71bdba28c306b142620f
@@@ -2826,376 -4195,402 +2826,379 @@@ static void alc287_fixup_legion_15imhg0
  {
        struct alc_spec *spec = codec->spec;
  
 -      if (action == HDA_FIXUP_ACT_PRE_PROBE)
 -              spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
 +      switch (action) {
 +      case HDA_FIXUP_ACT_PRE_PROBE:
 +              spec->gen.suppress_auto_mute = 1;
 +              break;
 +      }
  }
  
 -static void alc271_fixup_dmic(struct hda_codec *codec,
 -                            const struct hda_fixup *fix, int action)
 +static void comp_acpi_device_notify(acpi_handle handle, u32 event, void *data)
  {
 -      static const struct hda_verb verbs[] = {
 -              {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
 -              {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
 -              {}
 -      };
 -      unsigned int cfg;
 +      struct hda_codec *cdc = data;
 +      struct alc_spec *spec = cdc->spec;
  
 -      if (strcmp(codec->core.chip_name, "ALC271X") &&
 -          strcmp(codec->core.chip_name, "ALC269VB"))
 -              return;
 -      cfg = snd_hda_codec_get_pincfg(codec, 0x12);
 -      if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
 -              snd_hda_sequence_write(codec, verbs);
 -}
 +      codec_info(cdc, "ACPI Notification %d\n", event);
  
 -/* Fix the speaker amp after resume, etc */
 -static void alc269vb_fixup_aspire_e1_coef(struct hda_codec *codec,
 -                                        const struct hda_fixup *fix,
 -                                        int action)
 -{
 -      if (action == HDA_FIXUP_ACT_INIT)
 -              alc_update_coef_idx(codec, 0x0d, 0x6000, 0x6000);
 +      hda_component_acpi_device_notify(&spec->comps, handle, event, data);
  }
  
 -static void alc269_fixup_pcm_44k(struct hda_codec *codec,
 -                               const struct hda_fixup *fix, int action)
 +static int comp_bind(struct device *dev)
  {
 -      struct alc_spec *spec = codec->spec;
 +      struct hda_codec *cdc = dev_to_hda_codec(dev);
 +      struct alc_spec *spec = cdc->spec;
 +      int ret;
  
 -      if (action != HDA_FIXUP_ACT_PROBE)
 -              return;
 +      ret = hda_component_manager_bind(cdc, &spec->comps);
 +      if (ret)
 +              return ret;
  
 -      /* Due to a hardware problem on Lenovo Ideadpad, we need to
 -       * fix the sample rate of analog I/O to 44.1kHz
 -       */
 -      spec->gen.stream_analog_playback = &alc269_44k_pcm_analog_playback;
 -      spec->gen.stream_analog_capture = &alc269_44k_pcm_analog_capture;
 +      return hda_component_manager_bind_acpi_notifications(cdc,
 +                                                           &spec->comps,
 +                                                           comp_acpi_device_notify, cdc);
  }
  
 -static void alc269_fixup_stereo_dmic(struct hda_codec *codec,
 -                                   const struct hda_fixup *fix, int action)
 +static void comp_unbind(struct device *dev)
  {
 -      /* The digital-mic unit sends PDM (differential signal) instead of
 -       * the standard PCM, thus you can't record a valid mono stream as is.
 -       * Below is a workaround specific to ALC269 to control the dmic
 -       * signal source as mono.
 -       */
 -      if (action == HDA_FIXUP_ACT_INIT)
 -              alc_update_coef_idx(codec, 0x07, 0, 0x80);
 +      struct hda_codec *cdc = dev_to_hda_codec(dev);
 +      struct alc_spec *spec = cdc->spec;
 +
 +      hda_component_manager_unbind_acpi_notifications(cdc, &spec->comps, comp_acpi_device_notify);
 +      hda_component_manager_unbind(cdc, &spec->comps);
  }
  
 -static void alc269_quanta_automute(struct hda_codec *codec)
 +static const struct component_master_ops comp_master_ops = {
 +      .bind = comp_bind,
 +      .unbind = comp_unbind,
 +};
 +
 +static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_codec *cdc,
 +                                     struct snd_pcm_substream *sub, int action)
  {
 -      snd_hda_gen_update_outputs(codec);
 +      struct alc_spec *spec = cdc->spec;
  
 -      alc_write_coef_idx(codec, 0x0c, 0x680);
 -      alc_write_coef_idx(codec, 0x0c, 0x480);
 +      hda_component_manager_playback_hook(&spec->comps, action);
  }
  
 -static void alc269_fixup_quanta_mute(struct hda_codec *codec,
 -                                   const struct hda_fixup *fix, int action)
 +static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
 +                             const char *hid, const char *match_str, int count)
  {
 -      struct alc_spec *spec = codec->spec;
 -      if (action != HDA_FIXUP_ACT_PROBE)
 -              return;
 -      spec->gen.automute_hook = alc269_quanta_automute;
 +      struct alc_spec *spec = cdc->spec;
 +      int ret;
 +
 +      switch (action) {
 +      case HDA_FIXUP_ACT_PRE_PROBE:
 +              ret = hda_component_manager_init(cdc, &spec->comps, count, bus, hid,
 +                                               match_str, &comp_master_ops);
 +              if (ret)
 +                      return;
 +
 +              spec->gen.pcm_playback_hook = comp_generic_playback_hook;
 +              break;
 +      case HDA_FIXUP_ACT_FREE:
 +              hda_component_manager_free(&spec->comps, &comp_master_ops);
 +              break;
 +      }
  }
  
 -static void alc269_x101_hp_automute_hook(struct hda_codec *codec,
 -                                       struct hda_jack_callback *jack)
 +static void find_cirrus_companion_amps(struct hda_codec *cdc)
  {
 -      struct alc_spec *spec = codec->spec;
 -      int vref;
 -      msleep(200);
 -      snd_hda_gen_hp_automute(codec, jack);
 +      struct device *dev = hda_codec_dev(cdc);
 +      struct acpi_device *adev;
 +      struct fwnode_handle *fwnode __free(fwnode_handle) = NULL;
 +      const char *bus = NULL;
 +      static const struct {
 +              const char *hid;
 +              const char *name;
 +      } acpi_ids[] = {{ "CSC3554", "cs35l54-hda" },
 +                      { "CSC3556", "cs35l56-hda" },
 +                      { "CSC3557", "cs35l57-hda" }};
 +      char *match;
 +      int i, count = 0, count_devindex = 0;
  
 -      vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
 -      msleep(100);
 -      snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 -                          vref);
 -      msleep(500);
 -      snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 -                          vref);
 -}
 +      for (i = 0; i < ARRAY_SIZE(acpi_ids); ++i) {
 +              adev = acpi_dev_get_first_match_dev(acpi_ids[i].hid, NULL, -1);
 +              if (adev)
 +                      break;
 +      }
 +      if (!adev) {
 +              codec_dbg(cdc, "Did not find ACPI entry for a Cirrus Amp\n");
 +              return;
 +      }
  
 -/*
 - * Magic sequence to make Huawei Matebook X right speaker working (bko#197801)
 - */
 -struct hda_alc298_mbxinit {
 -      unsigned char value_0x23;
 -      unsigned char value_0x25;
 -};
 +      count = i2c_acpi_client_count(adev);
 +      if (count > 0) {
 +              bus = "i2c";
 +      } else {
 +              count = acpi_spi_count_resources(adev);
 +              if (count > 0)
 +                      bus = "spi";
 +      }
  
 -static void alc298_huawei_mbx_stereo_seq(struct hda_codec *codec,
 -                                       const struct hda_alc298_mbxinit *initval,
 -                                       bool first)
 -{
 -      snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x0);
 -      alc_write_coef_idx(codec, 0x26, 0xb000);
 +      fwnode = fwnode_handle_get(acpi_fwnode_handle(adev));
 +      acpi_dev_put(adev);
  
 -      if (first)
 -              snd_hda_codec_write(codec, 0x21, 0, AC_VERB_GET_PIN_SENSE, 0x0);
 +      if (!bus) {
 +              codec_err(cdc, "Did not find any buses for %s\n", acpi_ids[i].hid);
 +              return;
 +      }
  
 -      snd_hda_codec_write(codec, 0x6, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x80);
 -      alc_write_coef_idx(codec, 0x26, 0xf000);
 -      alc_write_coef_idx(codec, 0x23, initval->value_0x23);
 +      if (!fwnode) {
 +              codec_err(cdc, "Could not get fwnode for %s\n", acpi_ids[i].hid);
 +              return;
 +      }
  
 -      if (initval->value_0x23 != 0x1e)
 -              alc_write_coef_idx(codec, 0x25, initval->value_0x25);
 +      /*
 +       * When available the cirrus,dev-index property is an accurate
 +       * count of the amps in a system and is used in preference to
 +       * the count of bus devices that can contain additional address
 +       * alias entries.
 +       */
 +      count_devindex = fwnode_property_count_u32(fwnode, "cirrus,dev-index");
 +      if (count_devindex > 0)
 +              count = count_devindex;
  
 -      snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x26);
 -      snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0xb010);
 +      match = devm_kasprintf(dev, GFP_KERNEL, "-%%s:00-%s.%%d", acpi_ids[i].name);
 +      if (!match)
 +              return;
 +      codec_info(cdc, "Found %d %s on %s (%s)\n", count, acpi_ids[i].hid, bus, match);
 +      comp_generic_fixup(cdc, HDA_FIXUP_ACT_PRE_PROBE, bus, acpi_ids[i].hid, match, count);
  }
  
 -static void alc298_fixup_huawei_mbx_stereo(struct hda_codec *codec,
 -                                         const struct hda_fixup *fix,
 -                                         int action)
 +static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
  {
 -      /* Initialization magic */
 -      static const struct hda_alc298_mbxinit dac_init[] = {
 -              {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
 -              {0x10, 0x00}, {0x1a, 0x40}, {0x1b, 0x82}, {0x1c, 0x00},
 -              {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
 -              {0x20, 0xc2}, {0x21, 0xc8}, {0x22, 0x26}, {0x23, 0x24},
 -              {0x27, 0xff}, {0x28, 0xff}, {0x29, 0xff}, {0x2a, 0x8f},
 -              {0x2b, 0x02}, {0x2c, 0x48}, {0x2d, 0x34}, {0x2e, 0x00},
 -              {0x2f, 0x00},
 -              {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
 -              {0x34, 0x00}, {0x35, 0x01}, {0x36, 0x93}, {0x37, 0x0c},
 -              {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0xf8}, {0x38, 0x80},
 -              {}
 -      };
 -      const struct hda_alc298_mbxinit *seq;
 +      comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
 +}
  
 -      if (action != HDA_FIXUP_ACT_INIT)
 -              return;
 +static void cs35l41_fixup_i2c_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
 +{
 +      comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
 +}
  
 -      /* Start */
 -      snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x00);
 -      snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x80);
 -      alc_write_coef_idx(codec, 0x26, 0xf000);
 -      alc_write_coef_idx(codec, 0x22, 0x31);
 -      alc_write_coef_idx(codec, 0x23, 0x0b);
 -      alc_write_coef_idx(codec, 0x25, 0x00);
 -      snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x26);
 -      snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0xb010);
 +static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixup *fix, int action)
 +{
 +      comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
 +}
  
 -      for (seq = dac_init; seq->value_0x23; seq++)
 -              alc298_huawei_mbx_stereo_seq(codec, seq, seq == dac_init);
 +static void cs35l41_fixup_spi_one(struct hda_codec *codec, const struct hda_fixup *fix, int action)
 +{
 +      comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 1);
  }
  
 -static void alc269_fixup_x101_headset_mic(struct hda_codec *codec,
 -                                   const struct hda_fixup *fix, int action)
 +static void cs35l41_fixup_spi_four(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->parse_flags |= HDA_PINCFG_HEADSET_MIC;
 -              spec->gen.hp_automute_hook = alc269_x101_hp_automute_hook;
 -      }
 +      comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
  }
  
 -static void alc_update_vref_led(struct hda_codec *codec, hda_nid_t pin,
 -                              bool polarity, bool on)
 +static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
 +                                               int action)
  {
 -      unsigned int pinval;
 +      comp_generic_fixup(cdc, action, "i2c", "CLSA0100", "-%s:00-cs35l41-hda.%d", 2);
 +}
  
 -      if (!pin)
 -              return;
 -      if (polarity)
 -              on = !on;
 -      pinval = snd_hda_codec_get_pin_target(codec, pin);
 -      pinval &= ~AC_PINCTL_VREFEN;
 -      pinval |= on ? AC_PINCTL_VREF_80 : AC_PINCTL_VREF_HIZ;
 -      /* temporarily power up/down for setting VREF */
 -      snd_hda_power_up_pm(codec);
 -      snd_hda_set_pin_ctl_cache(codec, pin, pinval);
 -      snd_hda_power_down_pm(codec);
 -}
 -
 -/* update mute-LED according to the speaker mute state via mic VREF pin */
 -static int vref_mute_led_set(struct led_classdev *led_cdev,
 -                           enum led_brightness brightness)
 -{
 -      struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
 -      struct alc_spec *spec = codec->spec;
 -
 -      alc_update_vref_led(codec, spec->mute_led_nid,
 -                          spec->mute_led_polarity, brightness);
 -      return 0;
 -}
 -
 -/* Make sure the led works even in runtime suspend */
 -static unsigned int led_power_filter(struct hda_codec *codec,
 -                                                hda_nid_t nid,
 -                                                unsigned int power_state)
 +static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
 +                                               int action)
  {
 -      struct alc_spec *spec = codec->spec;
 -
 -      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 */
 -      snd_hda_set_pin_ctl(codec, nid,
 -                          snd_hda_codec_get_pin_target(codec, nid));
 -
 -      return snd_hda_gen_path_power_filter(codec, nid, power_state);
 +      comp_generic_fixup(cdc, action, "i2c", "CLSA0101", "-%s:00-cs35l41-hda.%d", 2);
  }
  
 -static void alc269_fixup_hp_mute_led(struct hda_codec *codec,
 -                                   const struct hda_fixup *fix, int action)
 +static void alc285_fixup_asus_ga403u(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
  {
 -      struct alc_spec *spec = codec->spec;
 -      const struct dmi_device *dev = NULL;
 -
 -      if (action != HDA_FIXUP_ACT_PRE_PROBE)
 -              return;
 -
 -      while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
 -              int pol, pin;
 -              if (sscanf(dev->name, "HP_Mute_LED_%d_%x", &pol, &pin) != 2)
 -                      continue;
 -              if (pin < 0x0a || pin >= 0x10)
 -                      break;
 -              spec->mute_led_polarity = pol;
 -              spec->mute_led_nid = pin - 0x0a + 0x18;
 -              snd_hda_gen_add_mute_led_cdev(codec, vref_mute_led_set);
 -              codec->power_filter = led_power_filter;
 -              codec_dbg(codec,
 -                        "Detected mute LED for %x:%d\n", spec->mute_led_nid,
 -                         spec->mute_led_polarity);
 -              break;
 -      }
 +      /*
 +       * The same SSID has been re-used in different hardware, they have
 +       * different codecs and the newer GA403U has a ALC285.
 +       */
 +      if (cdc->core.vendor_id != 0x10ec0285)
 +              alc_fixup_inv_dmic(cdc, fix, action);
  }
  
 -static void alc269_fixup_hp_mute_led_micx(struct hda_codec *codec,
 -                                        const struct hda_fixup *fix,
 -                                        int action, hda_nid_t pin)
 +static void tas2781_fixup_tias_i2c(struct hda_codec *cdc,
 +      const struct hda_fixup *fix, int action)
  {
 -      struct alc_spec *spec = codec->spec;
 -
 -      if (action == HDA_FIXUP_ACT_PRE_PROBE) {
 -              spec->mute_led_polarity = 0;
 -              spec->mute_led_nid = pin;
 -              snd_hda_gen_add_mute_led_cdev(codec, vref_mute_led_set);
 -              codec->power_filter = led_power_filter;
 -      }
 +      comp_generic_fixup(cdc, action, "i2c", "TIAS2781", "-%s:00", 1);
  }
  
 -static void alc269_fixup_hp_mute_led_mic1(struct hda_codec *codec,
 -                              const struct hda_fixup *fix, int action)
 +static void tas2781_fixup_spi(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
  {
 -      alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x18);
 +      comp_generic_fixup(cdc, action, "spi", "TXNW2781", "-%s:00-tas2781-hda.%d", 2);
  }
  
 -static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec,
 -                              const struct hda_fixup *fix, int action)
 +static void tas2781_fixup_txnw_i2c(struct hda_codec *cdc,
 +      const struct hda_fixup *fix, int action)
  {
 -      alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x19);
 +      comp_generic_fixup(cdc, action, "i2c", "TXNW2781", "-%s:00-tas2781-hda.%d", 1);
  }
  
 -static void alc269_fixup_hp_mute_led_mic3(struct hda_codec *codec,
 -                              const struct hda_fixup *fix, int action)
 +static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc,
 +      const struct hda_fixup *fix, int action)
  {
 -      alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1b);
 +      comp_generic_fixup(cdc, action, "i2c", "INT8866", "-%s:00", 1);
  }
  
 -/* update LED status via GPIO */
 -static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
 -                              int polarity, bool enabled)
 +static void alc256_fixup_acer_sfg16_micmute_led(struct hda_codec *codec,
 +      const struct hda_fixup *fix, int action)
  {
 -      if (polarity)
 -              enabled = !enabled;
 -      alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */
 +      alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
  }
  
 -/* turn on/off mute LED via GPIO per vmaster hook */
 -static int gpio_mute_led_set(struct led_classdev *led_cdev,
 -                           enum led_brightness brightness)
 -{
 -      struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
 -      struct alc_spec *spec = codec->spec;
  
 -      alc_update_gpio_led(codec, spec->gpio_mute_led_mask,
 -                          spec->mute_led_polarity, !brightness);
 -      return 0;
 -}
 +/* for alc295_fixup_hp_top_speakers */
 +#include "../helpers/hp_x360.c"
  
 -/* turn on/off mic-mute LED via GPIO per capture hook */
 -static int micmute_led_set(struct led_classdev *led_cdev,
 -                         enum led_brightness brightness)
 -{
 -      struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
 -      struct alc_spec *spec = codec->spec;
 +/* for alc285_fixup_ideapad_s740_coef() */
 +#include "../helpers/ideapad_s740.c"
  
 -      alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
 -                          spec->micmute_led_polarity, !brightness);
 -      return 0;
 -}
 +static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = {
 +      WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000),
 +      WRITE_COEF(0x26, 0x0000), WRITE_COEF(0x29, 0x3000),
 +      WRITE_COEF(0x37, 0xfe05), WRITE_COEF(0x45, 0x5089),
 +      {}
 +};
  
 -/* setup mute and mic-mute GPIO bits, add hooks appropriately */
 -static void alc_fixup_hp_gpio_led(struct hda_codec *codec,
 -                                int action,
 -                                unsigned int mute_mask,
 -                                unsigned int micmute_mask)
 +static void alc256_fixup_set_coef_defaults(struct hda_codec *codec,
 +                                         const struct hda_fixup *fix,
 +                                         int action)
  {
 -      struct alc_spec *spec = codec->spec;
 -
 -      alc_fixup_gpio(codec, action, mute_mask | micmute_mask);
 -
 -      if (action != HDA_FIXUP_ACT_PRE_PROBE)
 -              return;
 -      if (mute_mask) {
 -              spec->gpio_mute_led_mask = mute_mask;
 -              snd_hda_gen_add_mute_led_cdev(codec, gpio_mute_led_set);
 -      }
 -      if (micmute_mask) {
 -              spec->gpio_mic_led_mask = micmute_mask;
 -              snd_hda_gen_add_micmute_led_cdev(codec, micmute_led_set);
 -      }
 +      /*
 +       * A certain other OS sets these coeffs to different values. On at least
 +       * one TongFang barebone these settings might survive even a cold
 +       * reboot. So to restore a clean slate the values are explicitly reset
 +       * to default here. Without this, the external microphone is always in a
 +       * plugged-in state, while the internal microphone is always in an
 +       * unplugged state, breaking the ability to use the internal microphone.
 +       */
 +      alc_process_coef_fw(codec, alc256_fixup_set_coef_defaults_coefs);
  }
  
 -static void alc236_fixup_hp_gpio_led(struct hda_codec *codec,
 -                              const struct hda_fixup *fix, int action)
 -{
 -      alc_fixup_hp_gpio_led(codec, action, 0x02, 0x01);
 -}
 +static const struct coef_fw alc233_fixup_no_audio_jack_coefs[] = {
 +      WRITE_COEF(0x1a, 0x9003), WRITE_COEF(0x1b, 0x0e2b), WRITE_COEF(0x37, 0xfe06),
 +      WRITE_COEF(0x38, 0x4981), WRITE_COEF(0x45, 0xd489), WRITE_COEF(0x46, 0x0074),
 +      WRITE_COEF(0x49, 0x0149),
 +      {}
 +};
  
 -static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
 -                              const struct hda_fixup *fix, int action)
 +static void alc233_fixup_no_audio_jack(struct hda_codec *codec,
 +                                     const struct hda_fixup *fix,
 +                                     int action)
  {
 -      alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10);
 +      /*
 +       * The audio jack input and output is not detected on the ASRock NUC Box
 +       * 1100 series when cold booting without this fix. Warm rebooting from a
 +       * certain other OS makes the audio functional, as COEF settings are
 +       * preserved in this case. This fix sets these altered COEF values as
 +       * the default.
 +       */
 +      alc_process_coef_fw(codec, alc233_fixup_no_audio_jack_coefs);
  }
  
 -static void alc285_fixup_hp_gpio_led(struct hda_codec *codec,
 -                              const struct hda_fixup *fix, int action)
 +static void alc256_fixup_mic_no_presence_and_resume(struct hda_codec *codec,
 +                                                  const struct hda_fixup *fix,
 +                                                  int action)
  {
 -      alc_fixup_hp_gpio_led(codec, action, 0x04, 0x01);
 +      /*
 +       * The Clevo NJ51CU comes either with the ALC293 or the ALC256 codec,
 +       * but uses the 0x8686 subproduct id in both cases. The ALC256 codec
 +       * needs an additional quirk for sound working after suspend and resume.
 +       */
 +      if (codec->core.vendor_id == 0x10ec0256) {
 +              alc_update_coef_idx(codec, 0x10, 1<<9, 0);
 +              snd_hda_codec_set_pincfg(codec, 0x19, 0x04a11120);
 +      } else {
 +              snd_hda_codec_set_pincfg(codec, 0x1a, 0x04a1113c);
 +      }
  }
  
 -static void alc286_fixup_hp_gpio_led(struct hda_codec *codec,
 -                              const struct hda_fixup *fix, int action)
 +static void alc256_decrease_headphone_amp_val(struct hda_codec *codec,
 +                                            const struct hda_fixup *fix, int action)
  {
 -      alc_fixup_hp_gpio_led(codec, action, 0x02, 0x20);
 -}
 +      u32 caps;
 +      u8 nsteps, offs;
  
 -static void alc287_fixup_hp_gpio_led(struct hda_codec *codec,
 -                              const struct hda_fixup *fix, int action)
 -{
 -      alc_fixup_hp_gpio_led(codec, action, 0x10, 0);
 -}
 +      if (action != HDA_FIXUP_ACT_PRE_PROBE)
 +              return;
  
 -static void alc245_fixup_hp_gpio_led(struct hda_codec *codec,
 -                              const struct hda_fixup *fix, int action)
 -{
 -      struct alc_spec *spec = codec->spec;
 +      caps = query_amp_caps(codec, 0x3, HDA_OUTPUT);
 +      nsteps = ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) - 10;
 +      offs = ((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT) - 10;
 +      caps &= ~AC_AMPCAP_NUM_STEPS & ~AC_AMPCAP_OFFSET;
 +      caps |= (nsteps << AC_AMPCAP_NUM_STEPS_SHIFT) | (offs << AC_AMPCAP_OFFSET_SHIFT);
  
 -      if (action == HDA_FIXUP_ACT_PRE_PROBE)
 -              spec->micmute_led_polarity = 1;
 -      alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
 +      if (snd_hda_override_amp_caps(codec, 0x3, HDA_OUTPUT, caps))
 +              codec_warn(codec, "failed to override amp caps for NID 0x3\n");
  }
  
 -/* turn on/off mic-mute LED per capture hook via VREF change */
 -static int vref_micmute_led_set(struct led_classdev *led_cdev,
 -                              enum led_brightness brightness)
 +static void alc_fixup_dell4_mic_no_presence_quiet(struct hda_codec *codec,
 +                                                const struct hda_fixup *fix,
 +                                                int action)
  {
 -      struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
        struct alc_spec *spec = codec->spec;
 +      struct hda_input_mux *imux = &spec->gen.input_mux;
 +      int i;
  
 -      alc_update_vref_led(codec, spec->cap_mute_led_nid,
 -                          spec->micmute_led_polarity, brightness);
 -      return 0;
 +      alc269_fixup_limit_int_mic_boost(codec, fix, action);
 +
 +      switch (action) {
 +      case HDA_FIXUP_ACT_PRE_PROBE:
 +              /**
 +               * Set the vref of pin 0x19 (Headset Mic) and pin 0x1b (Headphone Mic)
 +               * to Hi-Z to avoid pop noises at startup and when plugging and
 +               * unplugging headphones.
 +               */
 +              snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
 +              snd_hda_codec_set_pin_target(codec, 0x1b, PIN_VREFHIZ);
 +              break;
 +      case HDA_FIXUP_ACT_PROBE:
 +              /**
 +               * Make the internal mic (0x12) the default input source to
 +               * prevent pop noises on cold boot.
 +               */
 +              for (i = 0; i < imux->num_items; i++) {
 +                      if (spec->gen.imux_pins[i] == 0x12) {
 +                              spec->gen.cur_mux[0] = i;
 +                              break;
 +                      }
 +              }
 +              break;
 +      }
  }
  
 -static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec,
 -                              const struct hda_fixup *fix, int action)
 +static void alc287_fixup_yoga9_14iap7_bass_spk_pin(struct hda_codec *codec,
 +                                        const struct hda_fixup *fix, int action)
  {
 -      struct alc_spec *spec = codec->spec;
 -
 -      alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
 -      if (action == HDA_FIXUP_ACT_PRE_PROBE) {
 -              /* Like hp_gpio_mic1_led, but also needs GPIO4 low to
 -               * enable headphone amp
 -               */
 -              spec->gpio_mask |= 0x10;
 -              spec->gpio_dir |= 0x10;
 -              spec->cap_mute_led_nid = 0x18;
 -              snd_hda_gen_add_micmute_led_cdev(codec, vref_micmute_led_set);
 -              codec->power_filter = led_power_filter;
 +      /*
 +       * The Pin Complex 0x17 for the bass speakers is wrongly reported as
 +       * unconnected.
 +       */
 +      static const struct hda_pintbl pincfgs[] = {
 +              { 0x17, 0x90170121 },
 +              { }
 +      };
 +      /*
 +       * Avoid DAC 0x06 and 0x08, as they have no volume controls.
 +       * DAC 0x02 and 0x03 would be fine.
 +       */
 +      static const hda_nid_t conn[] = { 0x02, 0x03 };
 +      /*
 +       * Prefer both speakerbar (0x14) and bass speakers (0x17) connected to DAC 0x02.
 +       * Headphones (0x21) are connected to DAC 0x03.
 +       */
 +      static const hda_nid_t preferred_pairs[] = {
 +              0x14, 0x02,
 +              0x17, 0x02,
 +              0x21, 0x03,
 +              0
 +      };
 +      struct alc_spec *spec = codec->spec;
 +
++      /* Support Audio mute LED and Mic mute LED on keyboard */
++      hda_fixup_ideapad_acpi(codec, fix, action);
++
 +      switch (action) {
 +      case HDA_FIXUP_ACT_PRE_PROBE:
 +              snd_hda_apply_pincfgs(codec, pincfgs);
 +              snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
 +              spec->gen.preferred_dacs = preferred_pairs;
 +              break;
        }
  }