Merge branch 'for-next' into for-linus
authorTakashi Iwai <tiwai@suse.de>
Mon, 11 Mar 2024 08:12:58 +0000 (09:12 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 11 Mar 2024 08:12:58 +0000 (09:12 +0100)
Prep for 6.9 merge.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
1  2 
sound/core/pcm_native.c
sound/pci/hda/cs35l41_hda_property.c
sound/pci/hda/hda_controller.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/cs35l56-shared.c
sound/soc/codecs/cs35l56.c

diff --combined sound/core/pcm_native.c
@@@ -236,7 -236,7 +236,7 @@@ int snd_pcm_info(struct snd_pcm_substre
  int snd_pcm_info_user(struct snd_pcm_substream *substream,
                      struct snd_pcm_info __user * _info)
  {
-       struct snd_pcm_info *info;
+       struct snd_pcm_info *info __free(kfree) = NULL;
        int err;
  
        info = kmalloc(sizeof(*info), GFP_KERNEL);
                if (copy_to_user(_info, info, sizeof(*info)))
                        err = -EFAULT;
        }
-       kfree(info);
        return err;
  }
  
@@@ -359,7 -358,7 +358,7 @@@ static int constrain_params_by_rules(st
        struct snd_pcm_hw_constraints *constrs =
                                        &substream->runtime->hw_constraints;
        unsigned int k;
-       unsigned int *rstamps;
+       unsigned int *rstamps __free(kfree) = NULL;
        unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
        unsigned int stamp;
        struct snd_pcm_hw_rule *r;
@@@ -435,10 -434,8 +434,8 @@@ retry
                }
  
                changed = r->func(params, r);
-               if (changed < 0) {
-                       err = changed;
-                       goto out;
-               }
+               if (changed < 0)
+                       return changed;
  
                /*
                 * When the parameter is changed, notify it to the caller
        if (again)
                goto retry;
  
-  out:
-       kfree(rstamps);
        return err;
  }
  
@@@ -486,11 -481,6 +481,11 @@@ static int fixup_unreferenced_params(st
                i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
                if (snd_interval_single(i))
                        params->msbits = snd_interval_value(i);
 +              m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
 +              if (snd_mask_single(m)) {
 +                      snd_pcm_format_t format = (__force snd_pcm_format_t)snd_mask_min(m);
 +                      params->msbits = snd_pcm_format_width(format);
 +              }
        }
  
        if (params->msbits) {
@@@ -576,26 -566,24 +571,24 @@@ EXPORT_SYMBOL(snd_pcm_hw_refine)
  static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params __user * _params)
  {
-       struct snd_pcm_hw_params *params;
+       struct snd_pcm_hw_params *params __free(kfree) = NULL;
        int err;
  
        params = memdup_user(_params, sizeof(*params));
        if (IS_ERR(params))
-               return PTR_ERR(params);
+               return PTR_ERR(no_free_ptr(params));
  
        err = snd_pcm_hw_refine(substream, params);
        if (err < 0)
-               goto end;
+               return err;
  
        err = fixup_unreferenced_params(substream, params);
        if (err < 0)
-               goto end;
+               return err;
  
        if (copy_to_user(_params, params, sizeof(*params)))
-               err = -EFAULT;
- end:
-       kfree(params);
-       return err;
+               return -EFAULT;
+       return 0;
  }
  
  static int period_to_usecs(struct snd_pcm_runtime *runtime)
  static void snd_pcm_set_state(struct snd_pcm_substream *substream,
                              snd_pcm_state_t state)
  {
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
        if (substream->runtime->state != SNDRV_PCM_STATE_DISCONNECTED)
                __snd_pcm_set_state(substream->runtime, state);
-       snd_pcm_stream_unlock_irq(substream);
  }
  
  static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
@@@ -745,20 -732,20 +737,20 @@@ static int snd_pcm_hw_params(struct snd
        err = snd_pcm_buffer_access_lock(runtime);
        if (err < 0)
                return err;
-       snd_pcm_stream_lock_irq(substream);
-       switch (runtime->state) {
-       case SNDRV_PCM_STATE_OPEN:
-       case SNDRV_PCM_STATE_SETUP:
-       case SNDRV_PCM_STATE_PREPARED:
-               if (!is_oss_stream(substream) &&
-                   atomic_read(&substream->mmap_count))
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               switch (runtime->state) {
+               case SNDRV_PCM_STATE_OPEN:
+               case SNDRV_PCM_STATE_SETUP:
+               case SNDRV_PCM_STATE_PREPARED:
+                       if (!is_oss_stream(substream) &&
+                           atomic_read(&substream->mmap_count))
+                               err = -EBADFD;
+                       break;
+               default:
                        err = -EBADFD;
-               break;
-       default:
-               err = -EBADFD;
-               break;
+                       break;
+               }
        }
-       snd_pcm_stream_unlock_irq(substream);
        if (err)
                goto unlock;
  
  static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params __user * _params)
  {
-       struct snd_pcm_hw_params *params;
+       struct snd_pcm_hw_params *params __free(kfree) = NULL;
        int err;
  
        params = memdup_user(_params, sizeof(*params));
        if (IS_ERR(params))
-               return PTR_ERR(params);
+               return PTR_ERR(no_free_ptr(params));
  
        err = snd_pcm_hw_params(substream, params);
        if (err < 0)
-               goto end;
+               return err;
  
        if (copy_to_user(_params, params, sizeof(*params)))
-               err = -EFAULT;
- end:
-       kfree(params);
+               return -EFAULT;
        return err;
  }
  
@@@ -910,18 -895,18 +900,18 @@@ static int snd_pcm_hw_free(struct snd_p
        result = snd_pcm_buffer_access_lock(runtime);
        if (result < 0)
                return result;
-       snd_pcm_stream_lock_irq(substream);
-       switch (runtime->state) {
-       case SNDRV_PCM_STATE_SETUP:
-       case SNDRV_PCM_STATE_PREPARED:
-               if (atomic_read(&substream->mmap_count))
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               switch (runtime->state) {
+               case SNDRV_PCM_STATE_SETUP:
+               case SNDRV_PCM_STATE_PREPARED:
+                       if (atomic_read(&substream->mmap_count))
+                               result = -EBADFD;
+                       break;
+               default:
                        result = -EBADFD;
-               break;
-       default:
-               result = -EBADFD;
-               break;
+                       break;
+               }
        }
-       snd_pcm_stream_unlock_irq(substream);
        if (result)
                goto unlock;
        result = do_hw_free(substream);
@@@ -941,12 -926,10 +931,10 @@@ static int snd_pcm_sw_params(struct snd
        if (PCM_RUNTIME_CHECK(substream))
                return -ENXIO;
        runtime = substream->runtime;
-       snd_pcm_stream_lock_irq(substream);
-       if (runtime->state == SNDRV_PCM_STATE_OPEN) {
-               snd_pcm_stream_unlock_irq(substream);
-               return -EBADFD;
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               if (runtime->state == SNDRV_PCM_STATE_OPEN)
+                       return -EBADFD;
        }
-       snd_pcm_stream_unlock_irq(substream);
  
        if (params->tstamp_mode < 0 ||
            params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
                        return -EINVAL;
        }
        err = 0;
-       snd_pcm_stream_lock_irq(substream);
-       runtime->tstamp_mode = params->tstamp_mode;
-       if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
-               runtime->tstamp_type = params->tstamp_type;
-       runtime->period_step = params->period_step;
-       runtime->control->avail_min = params->avail_min;
-       runtime->start_threshold = params->start_threshold;
-       runtime->stop_threshold = params->stop_threshold;
-       runtime->silence_threshold = params->silence_threshold;
-       runtime->silence_size = params->silence_size;
-         params->boundary = runtime->boundary;
-       if (snd_pcm_running(substream)) {
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
-                   runtime->silence_size > 0)
-                       snd_pcm_playback_silence(substream, ULONG_MAX);
-               err = snd_pcm_update_state(substream, runtime);
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               runtime->tstamp_mode = params->tstamp_mode;
+               if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
+                       runtime->tstamp_type = params->tstamp_type;
+               runtime->period_step = params->period_step;
+               runtime->control->avail_min = params->avail_min;
+               runtime->start_threshold = params->start_threshold;
+               runtime->stop_threshold = params->stop_threshold;
+               runtime->silence_threshold = params->silence_threshold;
+               runtime->silence_size = params->silence_size;
+               params->boundary = runtime->boundary;
+               if (snd_pcm_running(substream)) {
+                       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+                           runtime->silence_size > 0)
+                               snd_pcm_playback_silence(substream, ULONG_MAX);
+                       err = snd_pcm_update_state(substream, runtime);
+               }
        }
-       snd_pcm_stream_unlock_irq(substream);
        return err;
  }
  
@@@ -1017,7 -1000,7 +1005,7 @@@ int snd_pcm_status64(struct snd_pcm_sub
  {
        struct snd_pcm_runtime *runtime = substream->runtime;
  
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
  
        snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data,
                                        &runtime->audio_tstamp_config);
        status->state = runtime->state;
        status->suspended_state = runtime->suspended_state;
        if (status->state == SNDRV_PCM_STATE_OPEN)
-               goto _end;
+               return 0;
        status->trigger_tstamp_sec = runtime->trigger_tstamp.tv_sec;
        status->trigger_tstamp_nsec = runtime->trigger_tstamp.tv_nsec;
        if (snd_pcm_running(substream)) {
        status->overrange = runtime->overrange;
        runtime->avail_max = 0;
        runtime->overrange = 0;
-  _end:
-       snd_pcm_stream_unlock_irq(substream);
        return 0;
  }
  
@@@ -1169,12 -1150,10 +1155,10 @@@ static int snd_pcm_channel_info(struct 
        
        channel = info->channel;
        runtime = substream->runtime;
-       snd_pcm_stream_lock_irq(substream);
-       if (runtime->state == SNDRV_PCM_STATE_OPEN) {
-               snd_pcm_stream_unlock_irq(substream);
-               return -EBADFD;
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               if (runtime->state == SNDRV_PCM_STATE_OPEN)
+                       return -EBADFD;
        }
-       snd_pcm_stream_unlock_irq(substream);
        if (channel >= runtime->channels)
                return -EINVAL;
        memset(info, 0, sizeof(*info));
@@@ -1395,12 -1374,8 +1379,8 @@@ static int snd_pcm_action_lock_irq(cons
                                   struct snd_pcm_substream *substream,
                                   snd_pcm_state_t state)
  {
-       int res;
-       snd_pcm_stream_lock_irq(substream);
-       res = snd_pcm_action(ops, substream, state);
-       snd_pcm_stream_unlock_irq(substream);
-       return res;
+       guard(pcm_stream_lock_irq)(substream);
+       return snd_pcm_action(ops, substream, state);
  }
  
  /*
@@@ -1412,17 -1387,15 +1392,15 @@@ static int snd_pcm_action_nonatomic(con
        int res;
  
        /* Guarantee the group members won't change during non-atomic action */
-       down_read(&snd_pcm_link_rwsem);
+       guard(rwsem_read)(&snd_pcm_link_rwsem);
        res = snd_pcm_buffer_access_lock(substream->runtime);
        if (res < 0)
-               goto unlock;
+               return res;
        if (snd_pcm_stream_linked(substream))
                res = snd_pcm_action_group(ops, substream, state, false);
        else
                res = snd_pcm_action_single(ops, substream, state);
        snd_pcm_buffer_access_unlock(substream->runtime);
-  unlock:
-       up_read(&snd_pcm_link_rwsem);
        return res;
  }
  
@@@ -1592,12 -1565,9 +1570,9 @@@ int snd_pcm_drain_done(struct snd_pcm_s
   */
  int snd_pcm_stop_xrun(struct snd_pcm_substream *substream)
  {
-       unsigned long flags;
-       snd_pcm_stream_lock_irqsave(substream, flags);
+       guard(pcm_stream_lock_irqsave)(substream);
        if (substream->runtime && snd_pcm_running(substream))
                __snd_pcm_xrun(substream);
-       snd_pcm_stream_unlock_irqrestore(substream, flags);
        return 0;
  }
  EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);
@@@ -1749,14 -1719,9 +1724,9 @@@ static const struct action_ops snd_pcm_
   */
  static int snd_pcm_suspend(struct snd_pcm_substream *substream)
  {
-       int err;
-       unsigned long flags;
-       snd_pcm_stream_lock_irqsave(substream, flags);
-       err = snd_pcm_action(&snd_pcm_action_suspend, substream,
-                            ACTION_ARG_IGNORE);
-       snd_pcm_stream_unlock_irqrestore(substream, flags);
-       return err;
+       guard(pcm_stream_lock_irqsave)(substream);
+       return snd_pcm_action(&snd_pcm_action_suspend, substream,
+                             ACTION_ARG_IGNORE);
  }
  
  /**
@@@ -1872,22 -1837,17 +1842,17 @@@ static int snd_pcm_resume(struct snd_pc
  static int snd_pcm_xrun(struct snd_pcm_substream *substream)
  {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       int result;
  
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
        switch (runtime->state) {
        case SNDRV_PCM_STATE_XRUN:
-               result = 0;     /* already there */
-               break;
+               return 0;       /* already there */
        case SNDRV_PCM_STATE_RUNNING:
                __snd_pcm_xrun(substream);
-               result = 0;
-               break;
+               return 0;
        default:
-               result = -EBADFD;
+               return -EBADFD;
        }
-       snd_pcm_stream_unlock_irq(substream);
-       return result;
  }
  
  /*
@@@ -1916,13 -1876,12 +1881,12 @@@ static int snd_pcm_do_reset(struct snd_
        int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
        if (err < 0)
                return err;
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
        runtime->hw_ptr_base = 0;
        runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
                runtime->status->hw_ptr % runtime->period_size;
        runtime->silence_start = runtime->status->hw_ptr;
        runtime->silence_filled = 0;
-       snd_pcm_stream_unlock_irq(substream);
        return 0;
  }
  
@@@ -1930,12 -1889,11 +1894,11 @@@ static void snd_pcm_post_reset(struct s
                               snd_pcm_state_t state)
  {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
        runtime->control->appl_ptr = runtime->status->hw_ptr;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
                snd_pcm_playback_silence(substream, ULONG_MAX);
-       snd_pcm_stream_unlock_irq(substream);
  }
  
  static const struct action_ops snd_pcm_action_reset = {
@@@ -2011,16 -1969,16 +1974,16 @@@ static int snd_pcm_prepare(struct snd_p
        else
                f_flags = substream->f_flags;
  
-       snd_pcm_stream_lock_irq(substream);
-       switch (substream->runtime->state) {
-       case SNDRV_PCM_STATE_PAUSED:
-               snd_pcm_pause(substream, false);
-               fallthrough;
-       case SNDRV_PCM_STATE_SUSPENDED:
-               snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
-               break;
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               switch (substream->runtime->state) {
+               case SNDRV_PCM_STATE_PAUSED:
+                       snd_pcm_pause(substream, false);
+                       fallthrough;
+               case SNDRV_PCM_STATE_SUSPENDED:
+                       snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
+                       break;
+               }
        }
-       snd_pcm_stream_unlock_irq(substream);
  
        return snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
                                        substream,
@@@ -2237,14 -2195,13 +2200,13 @@@ static int snd_pcm_drop(struct snd_pcm_
            runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
                return -EBADFD;
  
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
        /* resume pause */
        if (runtime->state == SNDRV_PCM_STATE_PAUSED)
                snd_pcm_pause(substream, false);
  
        snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
        /* runtime->control->appl_ptr = runtime->status->hw_ptr; */
-       snd_pcm_stream_unlock_irq(substream);
  
        return result;
  }
@@@ -2273,53 -2230,44 +2235,44 @@@ static bool is_pcm_file(struct file *fi
   */
  static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
  {
-       int res = 0;
        struct snd_pcm_file *pcm_file;
        struct snd_pcm_substream *substream1;
-       struct snd_pcm_group *group, *target_group;
+       struct snd_pcm_group *group __free(kfree) = NULL;
+       struct snd_pcm_group *target_group;
        bool nonatomic = substream->pcm->nonatomic;
-       struct fd f = fdget(fd);
+       CLASS(fd, f)(fd);
  
        if (!f.file)
                return -EBADFD;
-       if (!is_pcm_file(f.file)) {
-               res = -EBADFD;
-               goto _badf;
-       }
+       if (!is_pcm_file(f.file))
+               return -EBADFD;
        pcm_file = f.file->private_data;
        substream1 = pcm_file->substream;
  
-       if (substream == substream1) {
-               res = -EINVAL;
-               goto _badf;
-       }
+       if (substream == substream1)
+               return -EINVAL;
  
        group = kzalloc(sizeof(*group), GFP_KERNEL);
-       if (!group) {
-               res = -ENOMEM;
-               goto _nolock;
-       }
+       if (!group)
+               return -ENOMEM;
        snd_pcm_group_init(group);
  
-       down_write(&snd_pcm_link_rwsem);
+       guard(rwsem_write)(&snd_pcm_link_rwsem);
        if (substream->runtime->state == SNDRV_PCM_STATE_OPEN ||
            substream->runtime->state != substream1->runtime->state ||
-           substream->pcm->nonatomic != substream1->pcm->nonatomic) {
-               res = -EBADFD;
-               goto _end;
-       }
-       if (snd_pcm_stream_linked(substream1)) {
-               res = -EALREADY;
-               goto _end;
-       }
+           substream->pcm->nonatomic != substream1->pcm->nonatomic)
+               return -EBADFD;
+       if (snd_pcm_stream_linked(substream1))
+               return -EALREADY;
  
-       snd_pcm_stream_lock_irq(substream);
-       if (!snd_pcm_stream_linked(substream)) {
-               snd_pcm_group_assign(substream, group);
-               group = NULL; /* assigned, don't free this one below */
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               if (!snd_pcm_stream_linked(substream)) {
+                       snd_pcm_group_assign(substream, group);
+                       group = NULL; /* assigned, don't free this one below */
+               }
+               target_group = substream->group;
        }
-       target_group = substream->group;
-       snd_pcm_stream_unlock_irq(substream);
  
        snd_pcm_group_lock_irq(target_group, nonatomic);
        snd_pcm_stream_lock_nested(substream1);
        refcount_inc(&target_group->refs);
        snd_pcm_stream_unlock(substream1);
        snd_pcm_group_unlock_irq(target_group, nonatomic);
-  _end:
-       up_write(&snd_pcm_link_rwsem);
-  _nolock:
-       kfree(group);
-  _badf:
-       fdput(f);
-       return res;
+       return 0;
  }
  
  static void relink_to_local(struct snd_pcm_substream *substream)
@@@ -2348,14 -2290,11 +2295,11 @@@ static int snd_pcm_unlink(struct snd_pc
        struct snd_pcm_group *group;
        bool nonatomic = substream->pcm->nonatomic;
        bool do_free = false;
-       int res = 0;
  
-       down_write(&snd_pcm_link_rwsem);
+       guard(rwsem_write)(&snd_pcm_link_rwsem);
  
-       if (!snd_pcm_stream_linked(substream)) {
-               res = -EALREADY;
-               goto _end;
-       }
+       if (!snd_pcm_stream_linked(substream))
+               return -EALREADY;
  
        group = substream->group;
        snd_pcm_group_lock_irq(group, nonatomic);
        snd_pcm_group_unlock_irq(group, nonatomic);
        if (do_free)
                kfree(group);
-        _end:
-       up_write(&snd_pcm_link_rwsem);
-       return res;
+       return 0;
  }
  
  /*
@@@ -2950,10 -2886,10 +2891,10 @@@ static int snd_pcm_release(struct inod
        /* block until the device gets woken up as it may touch the hardware */
        snd_power_wait(pcm->card);
  
-       mutex_lock(&pcm->open_mutex);
-       snd_pcm_release_substream(substream);
-       kfree(pcm_file);
-       mutex_unlock(&pcm->open_mutex);
+       scoped_guard(mutex, &pcm->open_mutex) {
+               snd_pcm_release_substream(substream);
+               kfree(pcm_file);
+       }
        wake_up(&pcm->open_wait);
        module_put(pcm->card->module);
        snd_card_file_remove(pcm->card, file);
@@@ -3037,12 -2973,12 +2978,12 @@@ static snd_pcm_sframes_t snd_pcm_rewind
        if (frames == 0)
                return 0;
  
-       snd_pcm_stream_lock_irq(substream);
-       ret = do_pcm_hwsync(substream);
-       if (!ret)
-               ret = rewind_appl_ptr(substream, frames,
-                                     snd_pcm_hw_avail(substream));
-       snd_pcm_stream_unlock_irq(substream);
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               ret = do_pcm_hwsync(substream);
+               if (!ret)
+                       ret = rewind_appl_ptr(substream, frames,
+                                             snd_pcm_hw_avail(substream));
+       }
        if (ret >= 0)
                snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
        return ret;
@@@ -3056,12 -2992,12 +2997,12 @@@ static snd_pcm_sframes_t snd_pcm_forwar
        if (frames == 0)
                return 0;
  
-       snd_pcm_stream_lock_irq(substream);
-       ret = do_pcm_hwsync(substream);
-       if (!ret)
-               ret = forward_appl_ptr(substream, frames,
-                                      snd_pcm_avail(substream));
-       snd_pcm_stream_unlock_irq(substream);
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               ret = do_pcm_hwsync(substream);
+               if (!ret)
+                       ret = forward_appl_ptr(substream, frames,
+                                              snd_pcm_avail(substream));
+       }
        if (ret >= 0)
                snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
        return ret;
@@@ -3072,11 -3008,11 +3013,11 @@@ static int snd_pcm_delay(struct snd_pcm
  {
        int err;
  
-       snd_pcm_stream_lock_irq(substream);
-       err = do_pcm_hwsync(substream);
-       if (delay && !err)
-               *delay = snd_pcm_calc_delay(substream);
-       snd_pcm_stream_unlock_irq(substream);
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               err = do_pcm_hwsync(substream);
+               if (delay && !err)
+                       *delay = snd_pcm_calc_delay(substream);
+       }
        snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU);
  
        return err;
@@@ -3108,27 -3044,25 +3049,25 @@@ static int snd_pcm_sync_ptr(struct snd_
                if (err < 0)
                        return err;
        }
-       snd_pcm_stream_lock_irq(substream);
-       if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
-               err = pcm_lib_apply_appl_ptr(substream,
-                                            sync_ptr.c.control.appl_ptr);
-               if (err < 0) {
-                       snd_pcm_stream_unlock_irq(substream);
-                       return err;
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
+                       err = pcm_lib_apply_appl_ptr(substream,
+                                                    sync_ptr.c.control.appl_ptr);
+                       if (err < 0)
+                               return err;
+               } else {
+                       sync_ptr.c.control.appl_ptr = control->appl_ptr;
                }
-       } else {
-               sync_ptr.c.control.appl_ptr = control->appl_ptr;
+               if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+                       control->avail_min = sync_ptr.c.control.avail_min;
+               else
+                       sync_ptr.c.control.avail_min = control->avail_min;
+               sync_ptr.s.status.state = status->state;
+               sync_ptr.s.status.hw_ptr = status->hw_ptr;
+               sync_ptr.s.status.tstamp = status->tstamp;
+               sync_ptr.s.status.suspended_state = status->suspended_state;
+               sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
        }
-       if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
-               control->avail_min = sync_ptr.c.control.avail_min;
-       else
-               sync_ptr.c.control.avail_min = control->avail_min;
-       sync_ptr.s.status.state = status->state;
-       sync_ptr.s.status.hw_ptr = status->hw_ptr;
-       sync_ptr.s.status.tstamp = status->tstamp;
-       sync_ptr.s.status.suspended_state = status->suspended_state;
-       sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
-       snd_pcm_stream_unlock_irq(substream);
        if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
                snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
        if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
@@@ -3206,27 -3140,25 +3145,25 @@@ static int snd_pcm_ioctl_sync_ptr_compa
        boundary = recalculate_boundary(runtime);
        if (! boundary)
                boundary = 0x7fffffff;
-       snd_pcm_stream_lock_irq(substream);
-       /* FIXME: we should consider the boundary for the sync from app */
-       if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
-               err = pcm_lib_apply_appl_ptr(substream,
-                               scontrol.appl_ptr);
-               if (err < 0) {
-                       snd_pcm_stream_unlock_irq(substream);
-                       return err;
-               }
-       } else
-               scontrol.appl_ptr = control->appl_ptr % boundary;
-       if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
-               control->avail_min = scontrol.avail_min;
-       else
-               scontrol.avail_min = control->avail_min;
-       sstatus.state = status->state;
-       sstatus.hw_ptr = status->hw_ptr % boundary;
-       sstatus.tstamp = status->tstamp;
-       sstatus.suspended_state = status->suspended_state;
-       sstatus.audio_tstamp = status->audio_tstamp;
-       snd_pcm_stream_unlock_irq(substream);
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               /* FIXME: we should consider the boundary for the sync from app */
+               if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
+                       err = pcm_lib_apply_appl_ptr(substream,
+                                                    scontrol.appl_ptr);
+                       if (err < 0)
+                               return err;
+               } else
+                       scontrol.appl_ptr = control->appl_ptr % boundary;
+               if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+                       control->avail_min = scontrol.avail_min;
+               else
+                       scontrol.avail_min = control->avail_min;
+               sstatus.state = status->state;
+               sstatus.hw_ptr = status->hw_ptr % boundary;
+               sstatus.tstamp = status->tstamp;
+               sstatus.suspended_state = status->suspended_state;
+               sstatus.audio_tstamp = status->audio_tstamp;
+       }
        if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
                snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
        if (put_user(sstatus.state, &src->s.status.state) ||
@@@ -3284,7 -3216,7 +3221,7 @@@ static int snd_pcm_xfern_frames_ioctl(s
  {
        struct snd_xfern xfern;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       void *bufs;
+       void *bufs __free(kfree) = NULL;
        snd_pcm_sframes_t result;
  
        if (runtime->state == SNDRV_PCM_STATE_OPEN)
  
        bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels);
        if (IS_ERR(bufs))
-               return PTR_ERR(bufs);
+               return PTR_ERR(no_free_ptr(bufs));
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
        else
                result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
-       kfree(bufs);
        if (put_user(result, &_xfern->result))
                return -EFAULT;
        return result < 0 ? result : 0;
@@@ -3571,7 -3502,7 +3507,7 @@@ static ssize_t snd_pcm_readv(struct kio
        struct snd_pcm_runtime *runtime;
        snd_pcm_sframes_t result;
        unsigned long i;
-       void __user **bufs;
+       void __user **bufs __free(kfree) = NULL;
        snd_pcm_uframes_t frames;
        const struct iovec *iov = iter_iov(to);
  
        result = snd_pcm_lib_readv(substream, bufs, frames);
        if (result > 0)
                result = frames_to_bytes(runtime, result);
-       kfree(bufs);
        return result;
  }
  
@@@ -3611,7 -3541,7 +3546,7 @@@ static ssize_t snd_pcm_writev(struct ki
        struct snd_pcm_runtime *runtime;
        snd_pcm_sframes_t result;
        unsigned long i;
-       void __user **bufs;
+       void __user **bufs __free(kfree) = NULL;
        snd_pcm_uframes_t frames;
        const struct iovec *iov = iter_iov(from);
  
        result = snd_pcm_lib_writev(substream, bufs, frames);
        if (result > 0)
                result = frames_to_bytes(runtime, result);
-       kfree(bufs);
        return result;
  }
  
@@@ -3668,7 -3597,7 +3602,7 @@@ static __poll_t snd_pcm_poll(struct fil
        poll_wait(file, &runtime->sleep, wait);
  
        mask = 0;
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
        avail = snd_pcm_avail(substream);
        switch (runtime->state) {
        case SNDRV_PCM_STATE_RUNNING:
                mask = ok | EPOLLERR;
                break;
        }
-       snd_pcm_stream_unlock_irq(substream);
        return mask;
  }
  
@@@ -4081,8 -4009,8 +4014,8 @@@ static void snd_pcm_hw_convert_to_old_p
  static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
                                      struct snd_pcm_hw_params_old __user * _oparams)
  {
-       struct snd_pcm_hw_params *params;
-       struct snd_pcm_hw_params_old *oparams = NULL;
+       struct snd_pcm_hw_params *params __free(kfree) = NULL;
+       struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL;
        int err;
  
        params = kmalloc(sizeof(*params), GFP_KERNEL);
                return -ENOMEM;
  
        oparams = memdup_user(_oparams, sizeof(*oparams));
-       if (IS_ERR(oparams)) {
-               err = PTR_ERR(oparams);
-               goto out;
-       }
+       if (IS_ERR(oparams))
+               return PTR_ERR(no_free_ptr(oparams));
        snd_pcm_hw_convert_from_old_params(params, oparams);
        err = snd_pcm_hw_refine(substream, params);
        if (err < 0)
-               goto out_old;
+               return err;
  
        err = fixup_unreferenced_params(substream, params);
        if (err < 0)
-               goto out_old;
+               return err;
  
        snd_pcm_hw_convert_to_old_params(oparams, params);
        if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
-               err = -EFAULT;
- out_old:
-       kfree(oparams);
- out:
-       kfree(params);
-       return err;
+               return -EFAULT;
+       return 0;
  }
  
  static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
                                      struct snd_pcm_hw_params_old __user * _oparams)
  {
-       struct snd_pcm_hw_params *params;
-       struct snd_pcm_hw_params_old *oparams = NULL;
+       struct snd_pcm_hw_params *params __free(kfree) = NULL;
+       struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL;
        int err;
  
        params = kmalloc(sizeof(*params), GFP_KERNEL);
                return -ENOMEM;
  
        oparams = memdup_user(_oparams, sizeof(*oparams));
-       if (IS_ERR(oparams)) {
-               err = PTR_ERR(oparams);
-               goto out;
-       }
+       if (IS_ERR(oparams))
+               return PTR_ERR(no_free_ptr(oparams));
  
        snd_pcm_hw_convert_from_old_params(params, oparams);
        err = snd_pcm_hw_params(substream, params);
        if (err < 0)
-               goto out_old;
+               return err;
  
        snd_pcm_hw_convert_to_old_params(oparams, params);
        if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
-               err = -EFAULT;
- out_old:
-       kfree(oparams);
- out:
-       kfree(params);
-       return err;
+               return -EFAULT;
+       return 0;
  }
  #endif /* CONFIG_SND_SUPPORT_OLD_API */
  
@@@ -51,19 -51,30 +51,30 @@@ static const struct cs35l41_config cs35
        { "103C8A2E", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8A31", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8A6E", 4, EXTERNAL, { CS35L41_LEFT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_RIGHT }, 0, -1, -1, 0, 0, 0 },
        { "103C8BB3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BB4", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BDF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BE0", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BE1", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BE2", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BE9", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BE3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BE5", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BE6", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE7", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE8", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE9", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8B3A", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8C15", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+       { "103C8C16", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+       { "103C8C17", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+       { "103C8C4F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8C50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8C51", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8CDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8CDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 3900, 24 },
        { "104312AF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
        { "10431433", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
        { "10431463", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
@@@ -83,7 -94,6 +94,7 @@@
        { "104317F3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
        { "10431863", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
        { "104318D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
 +      { "10431A83", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
        { "10431C9F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
        { "10431CAF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
        { "10431CCF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
        { "10431F1F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },
        { "10431F62", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
        { "17AA386F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
 +      { "17AA38A9", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
 +      { "17AA38AB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
        { "17AA38B4", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
        { "17AA38B5", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
        { "17AA38B6", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
@@@ -210,6 -218,7 +221,7 @@@ static int generic_dsd_config(struct cs
        struct spi_device *spi;
        bool dsd_found;
        int ret;
+       int i;
  
        for (cfg = cs35l41_config_table; cfg->ssid; cfg++) {
                if (!strcasecmp(cfg->ssid, cs35l41->acpi_subsystem_id))
                        cs35l41->index = id == 0x40 ? 0 : 1;
        }
  
-       if (cfg->num_amps == 3)
-               /* 3 amps means a center channel, so no duplicate channels */
-               cs35l41->channel_index = 0;
-       else
-               /*
-                * if 4 amps, there are duplicate channels, so they need different indexes
-                * if 2 amps, no duplicate channels, channel_index would be 0
-                */
-               cs35l41->channel_index = cs35l41->index / 2;
        cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset",
                                                     cs35l41->index, GPIOD_OUT_LOW,
                                                     "cs35l41-reset");
  
        hw_cfg->spk_pos = cfg->channel[cs35l41->index];
  
+       cs35l41->channel_index = 0;
+       for (i = 0; i < cs35l41->index; i++)
+               if (cfg->channel[i] == hw_cfg->spk_pos)
+                       cs35l41->channel_index++;
        if (cfg->boost_type == INTERNAL) {
                hw_cfg->bst_type = CS35L41_INT_BOOST;
                hw_cfg->bst_ind = cfg->boost_ind_nanohenry;
        return 0;
  }
  
+ /*
+  * Systems 103C8C66, 103C8C67, 103C8C68, 103C8C6A use a dual speaker id system - each speaker has
+  * its own speaker id.
+  */
+ static int hp_i2c_int_2amp_dual_spkid(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+                                     const char *hid)
+ {
+       struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+       /* If _DSD exists for this laptop, we cannot support it through here */
+       if (acpi_dev_has_props(cs35l41->dacpi))
+               return -ENOENT;
+       /* check I2C address to assign the index */
+       cs35l41->index = id == 0x40 ? 0 : 1;
+       cs35l41->channel_index = 0;
+       cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
+       if (cs35l41->index == 0)
+               cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 1);
+       else
+               cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);
+       hw_cfg->spk_pos = cs35l41->index;
+       hw_cfg->gpio2.func = CS35L41_INTERRUPT;
+       hw_cfg->gpio2.valid = true;
+       hw_cfg->valid = true;
+       hw_cfg->bst_type = CS35L41_INT_BOOST;
+       hw_cfg->bst_ind = 1000;
+       hw_cfg->bst_ipk = 4100;
+       hw_cfg->bst_cap = 24;
+       hw_cfg->gpio1.func = CS35L41_NOT_USED;
+       hw_cfg->gpio1.valid = true;
+       return 0;
+ }
  /*
   * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work.
   * And devices created by serial-multi-instantiate don't have their device struct
@@@ -392,19 -432,34 +435,34 @@@ static const struct cs35l41_prop_model 
        { "CSC3551", "103C8A2E", generic_dsd_config },
        { "CSC3551", "103C8A30", generic_dsd_config },
        { "CSC3551", "103C8A31", generic_dsd_config },
+       { "CSC3551", "103C8A6E", generic_dsd_config },
        { "CSC3551", "103C8BB3", generic_dsd_config },
        { "CSC3551", "103C8BB4", generic_dsd_config },
+       { "CSC3551", "103C8BDD", generic_dsd_config },
+       { "CSC3551", "103C8BDE", generic_dsd_config },
        { "CSC3551", "103C8BDF", generic_dsd_config },
        { "CSC3551", "103C8BE0", generic_dsd_config },
        { "CSC3551", "103C8BE1", generic_dsd_config },
        { "CSC3551", "103C8BE2", generic_dsd_config },
-       { "CSC3551", "103C8BE9", generic_dsd_config },
-       { "CSC3551", "103C8BDD", generic_dsd_config },
-       { "CSC3551", "103C8BDE", generic_dsd_config },
        { "CSC3551", "103C8BE3", generic_dsd_config },
        { "CSC3551", "103C8BE5", generic_dsd_config },
        { "CSC3551", "103C8BE6", generic_dsd_config },
+       { "CSC3551", "103C8BE7", generic_dsd_config },
+       { "CSC3551", "103C8BE8", generic_dsd_config },
+       { "CSC3551", "103C8BE9", generic_dsd_config },
        { "CSC3551", "103C8B3A", generic_dsd_config },
+       { "CSC3551", "103C8C15", generic_dsd_config },
+       { "CSC3551", "103C8C16", generic_dsd_config },
+       { "CSC3551", "103C8C17", generic_dsd_config },
+       { "CSC3551", "103C8C4F", generic_dsd_config },
+       { "CSC3551", "103C8C50", generic_dsd_config },
+       { "CSC3551", "103C8C51", generic_dsd_config },
+       { "CSC3551", "103C8C66", hp_i2c_int_2amp_dual_spkid },
+       { "CSC3551", "103C8C67", hp_i2c_int_2amp_dual_spkid },
+       { "CSC3551", "103C8C68", hp_i2c_int_2amp_dual_spkid },
+       { "CSC3551", "103C8C6A", hp_i2c_int_2amp_dual_spkid },
+       { "CSC3551", "103C8CDD", generic_dsd_config },
+       { "CSC3551", "103C8CDE", generic_dsd_config },
        { "CSC3551", "104312AF", generic_dsd_config },
        { "CSC3551", "10431433", generic_dsd_config },
        { "CSC3551", "10431463", generic_dsd_config },
        { "CSC3551", "104317F3", generic_dsd_config },
        { "CSC3551", "10431863", generic_dsd_config },
        { "CSC3551", "104318D3", generic_dsd_config },
 +      { "CSC3551", "10431A83", generic_dsd_config },
        { "CSC3551", "10431C9F", generic_dsd_config },
        { "CSC3551", "10431CAF", generic_dsd_config },
        { "CSC3551", "10431CCF", generic_dsd_config },
        { "CSC3551", "10431F1F", generic_dsd_config },
        { "CSC3551", "10431F62", generic_dsd_config },
        { "CSC3551", "17AA386F", generic_dsd_config },
 +      { "CSC3551", "17AA38A9", generic_dsd_config },
 +      { "CSC3551", "17AA38AB", generic_dsd_config },
        { "CSC3551", "17AA38B4", generic_dsd_config },
        { "CSC3551", "17AA38B5", generic_dsd_config },
        { "CSC3551", "17AA38B6", generic_dsd_config },
@@@ -24,6 -24,7 +24,7 @@@
  
  #include <sound/core.h>
  #include <sound/initval.h>
+ #include <sound/pcm_params.h>
  #include "hda_controller.h"
  #include "hda_local.h"
  
@@@ -108,6 -109,7 +109,7 @@@ static int azx_pcm_hw_params(struct snd
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
        struct azx *chip = apcm->chip;
        struct azx_dev *azx_dev = get_azx_dev(substream);
+       struct hdac_stream *hdas = azx_stream(azx_dev);
        int ret = 0;
  
        trace_azx_pcm_hw_params(chip, azx_dev);
                goto unlock;
        }
  
-       azx_dev->core.bufsize = 0;
-       azx_dev->core.period_bytes = 0;
-       azx_dev->core.format_val = 0;
+       /* Set up BDLEs here, return -ENOMEM if too many BDLEs are required */
+       hdas->bufsize = params_buffer_bytes(hw_params);
+       hdas->period_bytes = params_period_bytes(hw_params);
+       hdas->format_val = 0;
+       hdas->no_period_wakeup =
+               (hw_params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
+               (hw_params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
+       if (snd_hdac_stream_setup_periods(hdas) < 0)
+               ret = -ENOMEM;
  
  unlock:
        dsp_unlock(azx_dev);
@@@ -1207,9 -1215,6 +1215,9 @@@ int azx_probe_codecs(struct azx *chip, 
                                dev_warn(chip->card->dev,
                                         "Codec #%d probe error; disabling it...\n", c);
                                bus->codec_mask &= ~(1 << c);
 +                              /* no codecs */
 +                              if (bus->codec_mask == 0)
 +                                      break;
                                /* More badly, accessing to a non-existing
                                 * codec often screws up the controller chip,
                                 * and disturbs the further communications.
@@@ -133,7 -133,6 +133,6 @@@ struct alc_spec 
        u8 alc_mute_keycode_map[1];
  
        /* component binding */
-       struct component_match *match;
        struct hda_component comps[HDA_MAX_COMPONENTS];
  };
  
@@@ -3684,7 -3683,6 +3683,7 @@@ static void alc285_hp_init(struct hda_c
        int i, val;
        int coef38, coef0d, coef36;
  
 +      alc_write_coefex_idx(codec, 0x58, 0x00, 0x1888); /* write default value */
        alc_update_coef_idx(codec, 0x4a, 1<<15, 1<<15); /* Reset HP JD */
        coef38 = alc_read_coef_idx(codec, 0x38); /* Amp control */
        coef0d = alc_read_coef_idx(codec, 0x0d); /* Digital Misc control */
@@@ -6720,91 -6718,30 +6719,30 @@@ static void alc287_fixup_legion_15imhg0
        }
  }
  
- #ifdef CONFIG_ACPI
  static void comp_acpi_device_notify(acpi_handle handle, u32 event, void *data)
  {
        struct hda_codec *cdc = data;
        struct alc_spec *spec = cdc->spec;
-       int i;
  
        codec_info(cdc, "ACPI Notification %d\n", event);
  
-       for (i = 0; i < HDA_MAX_COMPONENTS; i++) {
-               if (spec->comps[i].dev && spec->comps[i].acpi_notify)
-                       spec->comps[i].acpi_notify(acpi_device_handle(spec->comps[i].adev), event,
-                                                  spec->comps[i].dev);
-       }
- }
- static int comp_bind_acpi(struct device *dev)
- {
-       struct hda_codec *cdc = dev_to_hda_codec(dev);
-       struct alc_spec *spec = cdc->spec;
-       bool support_notifications = false;
-       struct acpi_device *adev;
-       int ret;
-       int i;
-       adev = spec->comps[0].adev;
-       if (!acpi_device_handle(adev))
-               return 0;
-       for (i = 0; i < HDA_MAX_COMPONENTS; i++)
-               support_notifications = support_notifications ||
-                       spec->comps[i].acpi_notifications_supported;
-       if (support_notifications) {
-               ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
-                                               comp_acpi_device_notify, cdc);
-               if (ret < 0) {
-                       codec_warn(cdc, "Failed to install notify handler: %d\n", ret);
-                       return 0;
-               }
-               codec_dbg(cdc, "Notify handler installed\n");
-       }
-       return 0;
+       hda_component_acpi_device_notify(spec->comps, ARRAY_SIZE(spec->comps),
+                                        handle, event, data);
  }
  
- static void comp_unbind_acpi(struct device *dev)
- {
-       struct hda_codec *cdc = dev_to_hda_codec(dev);
-       struct alc_spec *spec = cdc->spec;
-       struct acpi_device *adev;
-       int ret;
-       adev = spec->comps[0].adev;
-       if (!acpi_device_handle(adev))
-               return;
-       ret = acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
-                                        comp_acpi_device_notify);
-       if (ret < 0)
-               codec_warn(cdc, "Failed to uninstall notify handler: %d\n", ret);
- }
- #else
- static int comp_bind_acpi(struct device *dev)
- {
-       return 0;
- }
- static void comp_unbind_acpi(struct device *dev)
- {
- }
- #endif
  static int comp_bind(struct device *dev)
  {
        struct hda_codec *cdc = dev_to_hda_codec(dev);
        struct alc_spec *spec = cdc->spec;
        int ret;
  
-       ret = component_bind_all(dev, spec->comps);
+       ret = hda_component_manager_bind(cdc, spec->comps);
        if (ret)
                return ret;
  
-       return comp_bind_acpi(dev);
+       return hda_component_manager_bind_acpi_notifications(cdc,
+                                                            spec->comps, ARRAY_SIZE(spec->comps),
+                                                            comp_acpi_device_notify, cdc);
  }
  
  static void comp_unbind(struct device *dev)
        struct hda_codec *cdc = dev_to_hda_codec(dev);
        struct alc_spec *spec = cdc->spec;
  
-       comp_unbind_acpi(dev);
-       component_unbind_all(dev, spec->comps);
+       hda_component_manager_unbind_acpi_notifications(cdc, spec->comps, comp_acpi_device_notify);
+       hda_component_manager_unbind(cdc, spec->comps);
  }
  
  static const struct component_master_ops comp_master_ops = {
@@@ -6825,177 -6762,78 +6763,78 @@@ static void comp_generic_playback_hook(
                                       struct snd_pcm_substream *sub, int action)
  {
        struct alc_spec *spec = cdc->spec;
-       int i;
-       for (i = 0; i < HDA_MAX_COMPONENTS; i++) {
-               if (spec->comps[i].dev && spec->comps[i].pre_playback_hook)
-                       spec->comps[i].pre_playback_hook(spec->comps[i].dev, action);
-       }
-       for (i = 0; i < HDA_MAX_COMPONENTS; i++) {
-               if (spec->comps[i].dev && spec->comps[i].playback_hook)
-                       spec->comps[i].playback_hook(spec->comps[i].dev, action);
-       }
-       for (i = 0; i < HDA_MAX_COMPONENTS; i++) {
-               if (spec->comps[i].dev && spec->comps[i].post_playback_hook)
-                       spec->comps[i].post_playback_hook(spec->comps[i].dev, action);
-       }
- }
- struct scodec_dev_name {
-       const char *bus;
-       const char *hid;
-       int index;
- };
- /* match the device name in a slightly relaxed manner */
- static int comp_match_cs35l41_dev_name(struct device *dev, void *data)
- {
-       struct scodec_dev_name *p = data;
-       const char *d = dev_name(dev);
-       int n = strlen(p->bus);
-       char tmp[32];
-       /* check the bus name */
-       if (strncmp(d, p->bus, n))
-               return 0;
-       /* skip the bus number */
-       if (isdigit(d[n]))
-               n++;
-       /* the rest must be exact matching */
-       snprintf(tmp, sizeof(tmp), "-%s:00-cs35l41-hda.%d", p->hid, p->index);
-       return !strcmp(d + n, tmp);
- }
- static int comp_match_tas2781_dev_name(struct device *dev,
-       void *data)
- {
-       struct scodec_dev_name *p = data;
-       const char *d = dev_name(dev);
-       int n = strlen(p->bus);
-       char tmp[32];
-       /* check the bus name */
-       if (strncmp(d, p->bus, n))
-               return 0;
-       /* skip the bus number */
-       if (isdigit(d[n]))
-               n++;
-       /* the rest must be exact matching */
-       snprintf(tmp, sizeof(tmp), "-%s:00", p->hid);
-       return !strcmp(d + n, tmp);
- }
- static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
-                                 const char *hid, int count)
- {
-       struct device *dev = hda_codec_dev(cdc);
-       struct alc_spec *spec = cdc->spec;
-       struct scodec_dev_name *rec;
-       int ret, i;
  
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               for (i = 0; i < count; i++) {
-                       rec = devm_kmalloc(dev, sizeof(*rec), GFP_KERNEL);
-                       if (!rec)
-                               return;
-                       rec->bus = bus;
-                       rec->hid = hid;
-                       rec->index = i;
-                       spec->comps[i].codec = cdc;
-                       component_match_add(dev, &spec->match,
-                                           comp_match_cs35l41_dev_name, rec);
-               }
-               ret = component_master_add_with_match(dev, &comp_master_ops, spec->match);
-               if (ret)
-                       codec_err(cdc, "Fail to register component aggregator %d\n", ret);
-               else
-                       spec->gen.pcm_playback_hook = comp_generic_playback_hook;
-               break;
-       case HDA_FIXUP_ACT_FREE:
-               component_master_del(dev, &comp_master_ops);
-               break;
-       }
+       hda_component_manager_playback_hook(spec->comps, ARRAY_SIZE(spec->comps), action);
  }
  
- static void tas2781_generic_fixup(struct hda_codec *cdc, int action,
-       const char *bus, const char *hid)
+ static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
+                              const char *hid, const char *match_str, int count)
  {
-       struct device *dev = hda_codec_dev(cdc);
        struct alc_spec *spec = cdc->spec;
-       struct scodec_dev_name *rec;
        int ret;
  
        switch (action) {
        case HDA_FIXUP_ACT_PRE_PROBE:
-               rec = devm_kmalloc(dev, sizeof(*rec), GFP_KERNEL);
-               if (!rec)
-                       return;
-               rec->bus = bus;
-               rec->hid = hid;
-               rec->index = 0;
-               spec->comps[0].codec = cdc;
-               component_match_add(dev, &spec->match,
-                       comp_match_tas2781_dev_name, rec);
-               ret = component_master_add_with_match(dev, &comp_master_ops,
-                       spec->match);
+               ret = hda_component_manager_init(cdc, spec->comps, count, bus, hid,
+                                                match_str, &comp_master_ops);
                if (ret)
-                       codec_err(cdc,
-                               "Fail to register component aggregator %d\n",
-                               ret);
-               else
-                       spec->gen.pcm_playback_hook =
-                               comp_generic_playback_hook;
+                       return;
+               spec->gen.pcm_playback_hook = comp_generic_playback_hook;
                break;
        case HDA_FIXUP_ACT_FREE:
-               component_master_del(dev, &comp_master_ops);
+               hda_component_manager_free(cdc, &comp_master_ops);
                break;
        }
  }
  
  static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
  {
-       cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 2);
+       comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
  }
  
  static void cs35l41_fixup_i2c_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
  {
-       cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 4);
+       comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
  }
  
  static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixup *fix, int action)
  {
-       cs35l41_generic_fixup(codec, action, "spi", "CSC3551", 2);
+       comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
  }
  
  static void cs35l41_fixup_spi_four(struct hda_codec *codec, const struct hda_fixup *fix, int action)
  {
-       cs35l41_generic_fixup(codec, action, "spi", "CSC3551", 4);
+       comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
  }
  
  static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
                                                 int action)
  {
-       cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0100", 2);
+       comp_generic_fixup(cdc, action, "i2c", "CLSA0100", "-%s:00-cs35l41-hda.%d", 2);
  }
  
  static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
                                                 int action)
  {
-       cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0101", 2);
+       comp_generic_fixup(cdc, action, "i2c", "CLSA0101", "-%s:00-cs35l41-hda.%d", 2);
+ }
+ static void cs35l56_fixup_spi_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+ {
+       comp_generic_fixup(cdc, action, "spi", "CSC3556", "-%s:00-cs35l56-hda.%d", 4);
  }
  
  static void tas2781_fixup_i2c(struct hda_codec *cdc,
        const struct hda_fixup *fix, int action)
  {
-        tas2781_generic_fixup(cdc, action, "i2c", "TIAS2781");
+       comp_generic_fixup(cdc, action, "i2c", "TIAS2781", "-%s:00", 1);
  }
  
  static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc,
        const struct hda_fixup *fix, int action)
  {
-        tas2781_generic_fixup(cdc, action, "i2c", "INT8866");
+       comp_generic_fixup(cdc, action, "i2c", "INT8866", "-%s:00", 1);
  }
  
  /* for alc295_fixup_hp_top_speakers */
@@@ -7445,7 -7283,6 +7284,7 @@@ enum 
        ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE,
        ALC287_FIXUP_YOGA7_14ITL_SPEAKERS,
        ALC298_FIXUP_LENOVO_C940_DUET7,
 +      ALC287_FIXUP_LENOVO_14IRP8_DUETITL,
        ALC287_FIXUP_13S_GEN2_SPEAKERS,
        ALC256_FIXUP_SET_COEF_DEFAULTS,
        ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
        ALC2XX_FIXUP_HEADSET_MIC,
        ALC289_FIXUP_DELL_CS35L41_SPI_2,
        ALC294_FIXUP_CS35L41_I2C_2,
+       ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED,
  };
  
  /* A special fixup for Lenovo C940 and Yoga Duet 7;
@@@ -7497,26 -7335,6 +7337,26 @@@ static void alc298_fixup_lenovo_c940_du
        __snd_hda_apply_fixup(codec, id, action, 0);
  }
  
 +/* A special fixup for Lenovo Slim/Yoga Pro 9 14IRP8 and Yoga DuetITL 2021;
 + * 14IRP8 PCI SSID will mistakenly be matched with the DuetITL codec SSID,
 + * so we need to apply a different fixup in this case. The only DuetITL codec
 + * SSID reported so far is the 17aa:3802 while the 14IRP8 has the 17aa:38be
 + * and 17aa:38bf. If it weren't for the PCI SSID, the 14IRP8 models would
 + * have matched correctly by their codecs.
 + */
 +static void alc287_fixup_lenovo_14irp8_duetitl(struct hda_codec *codec,
 +                                            const struct hda_fixup *fix,
 +                                            int action)
 +{
 +      int id;
 +
 +      if (codec->core.subsystem_id == 0x17aa3802)
 +              id = ALC287_FIXUP_YOGA7_14ITL_SPEAKERS; /* DuetITL */
 +      else
 +              id = ALC287_FIXUP_TAS2781_I2C; /* 14IRP8 */
 +      __snd_hda_apply_fixup(codec, id, action, 0);
 +}
 +
  static const struct hda_fixup alc269_fixups[] = {
        [ALC269_FIXUP_GPIO2] = {
                .type = HDA_FIXUP_FUNC,
                .type = HDA_FIXUP_FUNC,
                .v.func = alc298_fixup_lenovo_c940_duet7,
        },
 +      [ALC287_FIXUP_LENOVO_14IRP8_DUETITL] = {
 +              .type = HDA_FIXUP_FUNC,
 +              .v.func = alc287_fixup_lenovo_14irp8_duetitl,
 +      },
        [ALC287_FIXUP_13S_GEN2_SPEAKERS] = {
                .type = HDA_FIXUP_VERBS,
                .v.verbs = (const struct hda_verb[]) {
                .type = HDA_FIXUP_FUNC,
                .v.func = tas2781_fixup_i2c,
                .chained = true,
 -              .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
 +              .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
        },
        [ALC287_FIXUP_YOGA7_14ARB7_I2C] = {
                .type = HDA_FIXUP_FUNC,
                .type = HDA_FIXUP_FUNC,
                .v.func = cs35l41_fixup_i2c_two,
        },
+       [ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l56_fixup_spi_four,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_HP_GPIO_LED,
+       },
  };
  
  static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x89d3, "HP EliteBook 645 G9 (MB 89D2)", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x89e7, "HP Elite x2 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8a0f, "HP Pavilion 14-ec1xxx", ALC287_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8a20, "HP Laptop 15s-fq5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
        SND_PCI_QUIRK(0x103c, 0x8a25, "HP Victus 16-d1xxx (MB 8A25)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+       SND_PCI_QUIRK(0x103c, 0x8a28, "HP Envy 13", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a29, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2b, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2c, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2d, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a30, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a31, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4),
        SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ad8, "HP 800 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b0f, "HP Elite mt645 G7 Mobile Thin Client U81", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8b2f, "HP 255 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x8b3a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8b3f, "HP mt440 Mobile Thin Client U91", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b42, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b43, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b92, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8bdd, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8bde, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8bdf, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be0, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be1, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be2, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be3, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be5, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be6, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be7, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be8, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be9, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre 14", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c47, "HP EliteBook 840 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c48, "HP EliteBook 860 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c49, "HP Elite x360 830 2-in-1 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c4f, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c50, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c51, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c52, "HP EliteBook 1040 G11", ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c53, "HP Elite x360 1040 2-in-1 G11", ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c66, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c67, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c68, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c6a, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8c70, "HP EliteBook 835 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c71, "HP EliteBook 845 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
 +      SND_PCI_QUIRK(0x103c, 0x8c8a, "HP EliteBook 630", ALC236_FIXUP_HP_GPIO_LED),
 +      SND_PCI_QUIRK(0x103c, 0x8c8c, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED),
 +      SND_PCI_QUIRK(0x103c, 0x8c90, "HP EliteBook 640", ALC236_FIXUP_HP_GPIO_LED),
 +      SND_PCI_QUIRK(0x103c, 0x8c91, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8c97, "HP ZBook", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8ca1, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8ca2, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8cde, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
        SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK(0x10ec, 0x12cc, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+       SND_PCI_QUIRK(0x10ec, 0x12f6, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE),
        SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
        SND_PCI_QUIRK(0x17aa, 0x31af, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340),
        SND_PCI_QUIRK(0x17aa, 0x334b, "Lenovo ThinkCentre M70 Gen5", ALC283_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
 -      SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
 +      SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8 / DuetITL 2021", ALC287_FIXUP_LENOVO_14IRP8_DUETITL),
        SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7),
        SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO DUAL", ALC287_FIXUP_TAS2781_I2C),
        SND_PCI_QUIRK(0x17aa, 0x38a7, "Y780P AMD YG dual", ALC287_FIXUP_TAS2781_I2C),
        SND_PCI_QUIRK(0x17aa, 0x38a8, "Y780P AMD VECO dual", ALC287_FIXUP_TAS2781_I2C),
 +      SND_PCI_QUIRK(0x17aa, 0x38a9, "Thinkbook 16P", ALC287_FIXUP_CS35L41_I2C_2),
 +      SND_PCI_QUIRK(0x17aa, 0x38ab, "Thinkbook 16P", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x17aa, 0x38b4, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x17aa, 0x38b5, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x17aa, 0x38b6, "Legion Slim 7 16APH8", ALC287_FIXUP_CS35L41_I2C_2),
@@@ -11001,8 -10856,6 +10888,8 @@@ static const struct snd_hda_pin_quirk a
   *   at most one tbl is allowed to define for the same vendor and same codec
   */
  static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = {
 +      SND_HDA_PIN_QUIRK(0x10ec0256, 0x1025, "Acer", ALC2XX_FIXUP_HEADSET_MIC,
 +              {0x19, 0x40000000}),
        SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
                {0x19, 0x40000000},
                {0x1b, 0x40000000}),
@@@ -11692,7 -11545,8 +11579,7 @@@ static void alc897_hp_automute_hook(str
  
        snd_hda_gen_hp_automute(codec, jack);
        vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
 -      snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 -                          vref);
 +      snd_hda_set_pin_ctl(codec, 0x1b, vref);
  }
  
  static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
        struct alc_spec *spec = codec->spec;
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
                spec->gen.hp_automute_hook = alc897_hp_automute_hook;
 +              spec->no_shutup_pins = 1;
 +      }
 +      if (action == HDA_FIXUP_ACT_PROBE) {
 +              snd_hda_set_pin_ctl_cache(codec, 0x1a, PIN_IN | AC_PINCTL_VREF_100);
        }
  }
  
@@@ -12674,6 -12524,7 +12561,7 @@@ MODULE_DEVICE_TABLE(hdaudio, snd_hda_id
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Realtek HD-audio codec");
+ MODULE_IMPORT_NS(SND_HDA_SCODEC_COMPONENT);
  
  static struct hda_codec_driver realtek_driver = {
        .id = snd_hda_id_realtek,
@@@ -335,7 -335,6 +335,7 @@@ void cs35l56_wait_min_reset_pulse(void
  EXPORT_SYMBOL_NS_GPL(cs35l56_wait_min_reset_pulse, SND_SOC_CS35L56_SHARED);
  
  static const struct reg_sequence cs35l56_system_reset_seq[] = {
 +      REG_SEQ0(CS35L56_DSP1_HALO_STATE, 0),
        REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
  };
  
@@@ -693,13 -692,17 +693,17 @@@ int cs35l56_hw_init(struct cs35l56_bas
        devid &= CS35L56_DEVID_MASK;
  
        switch (devid) {
+       case 0x35A54:
        case 0x35A56:
+       case 0x35A57:
                break;
        default:
                dev_err(cs35l56_base->dev, "Unknown device %x\n", devid);
                return ret;
        }
  
+       cs35l56_base->type = devid & 0xFF;
        ret = regmap_read(cs35l56_base->regmap, CS35L56_DSP_RESTRICT_STS1, &secured);
        if (ret) {
                dev_err(cs35l56_base->dev, "Get Secure status failed\n");
        if (ret)
                return ret;
  
-       dev_info(cs35l56_base->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d fw:%d.%d.%d (patched=%u)\n",
-                cs35l56_base->secured ? "s" : "", cs35l56_base->rev, otpid,
+       dev_info(cs35l56_base->dev, "Cirrus Logic CS35L%02X%s Rev %02X OTP%d fw:%d.%d.%d (patched=%u)\n",
+                cs35l56_base->type, cs35l56_base->secured ? "s" : "", cs35l56_base->rev, otpid,
                 fw_ver >> 16, (fw_ver >> 8) & 0xff, fw_ver & 0xff, !fw_missing);
  
        /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */
@@@ -114,7 -114,7 +114,7 @@@ static int cs35l56_sync_asp1_mixer_widg
                        name = full_name;
                }
  
 -              kcontrol = snd_soc_card_get_kcontrol(dapm->card, name);
 +              kcontrol = snd_soc_card_get_kcontrol_locked(dapm->card, name);
                if (!kcontrol) {
                        dev_warn(cs35l56->base.dev, "Could not find control %s\n", name);
                        continue;
@@@ -972,6 -972,10 +972,10 @@@ static int cs35l56_component_probe(stru
                return -ENODEV;
        }
  
+       cs35l56->dsp.part = kasprintf(GFP_KERNEL, "cs35l%02x", cs35l56->base.type);
+       if (!cs35l56->dsp.part)
+               return -ENOMEM;
        cs35l56->component = component;
        wm_adsp2_component_probe(&cs35l56->dsp, component);
  
@@@ -1002,6 -1006,9 +1006,9 @@@ static void cs35l56_component_remove(st
  
        wm_adsp2_component_remove(&cs35l56->dsp, component);
  
+       kfree(cs35l56->dsp.part);
+       cs35l56->dsp.part = NULL;
        kfree(cs35l56->dsp.fwf_name);
        cs35l56->dsp.fwf_name = NULL;
  
@@@ -1221,7 -1228,12 +1228,12 @@@ static int cs35l56_dsp_init(struct cs35
  
        dsp = &cs35l56->dsp;
        cs35l56_init_cs_dsp(&cs35l56->base, &dsp->cs_dsp);
-       dsp->part = "cs35l56";
+       /*
+        * dsp->part is filled in later as it is based on the DEVID. In a
+        * SoundWire system that cannot be read until enumeration has occurred
+        * and the device has attached.
+        */
        dsp->fw = 12;
        dsp->wmfw_optional = true;