Merge tag 'sound-6.9-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Mar 2024 21:54:49 +0000 (14:54 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Mar 2024 21:54:49 +0000 (14:54 -0700)
Pull sound fixes from Takashi Iwai:
 "A collection of device-specific small fixes: a series of fixes for
  TAS2781 HD-audio codec, ASoC SOF, Cirrus CS35L56 and a couple of
  legacy drivers"

* tag 'sound-6.9-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: hda/tas2781: remove useless dev_dbg from playback_hook
  ALSA: hda/tas2781: add debug statements to kcontrols
  ALSA: hda/tas2781: add locks to kcontrols
  ALSA: hda/tas2781: remove digital gain kcontrol
  ALSA: aoa: avoid false-positive format truncation warning
  ALSA: sh: aica: reorder cleanup operations to avoid UAF bugs
  ALSA: hda: cs35l56: Set the init_done flag before component_add()
  ALSA: hda: cs35l56: Raise device name message log level
  ASoC: SOF: ipc4-topology: support NHLT device type
  ALSA: hda: intel-nhlt: add intel_nhlt_ssp_device_type() function

include/sound/intel-nhlt.h
sound/aoa/soundbus/i2sbus/core.c
sound/hda/intel-nhlt.c
sound/pci/hda/cs35l56_hda.c
sound/pci/hda/tas2781_hda_i2c.c
sound/sh/aica.c
sound/soc/sof/ipc4-topology.c

index 53470d6a28d659db09e9e58e85e24ffe5e862db5..24dbe16684ae3349bae5a7f74ac5c80fd16e6211 100644 (file)
@@ -143,6 +143,9 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
                             u32 bus_id, u8 link_type, u8 vbps, u8 bps,
                             u8 num_ch, u32 rate, u8 dir, u8 dev_type);
 
+int intel_nhlt_ssp_device_type(struct device *dev, struct nhlt_acpi_table *nhlt,
+                              u8 virtual_bus_id);
+
 #else
 
 static inline struct nhlt_acpi_table *intel_nhlt_init(struct device *dev)
@@ -184,6 +187,13 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
        return NULL;
 }
 
+static inline int intel_nhlt_ssp_device_type(struct device *dev,
+                                            struct nhlt_acpi_table *nhlt,
+                                            u8 virtual_bus_id)
+{
+       return -EINVAL;
+}
+
 #endif
 
 #endif
index b8ff5cccd0c811fd76050be0f9cf50efa899a3cc..5431d2c49421067e0185158f9aa3e004f619c91e 100644 (file)
@@ -158,7 +158,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
        struct device_node *child, *sound = NULL;
        struct resource *r;
        int i, layout = 0, rlen, ok = force;
-       char node_name[6];
+       char node_name[8];
        static const char *rnames[] = { "i2sbus: %pOFn (control)",
                                        "i2sbus: %pOFn (tx)",
                                        "i2sbus: %pOFn (rx)" };
index 696a958d93e9c336dea68748e59685e4c0569ee9..088cff799e0bee5003f8d09ae0cb0087cc46ab33 100644 (file)
@@ -343,3 +343,29 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
        return NULL;
 }
 EXPORT_SYMBOL(intel_nhlt_get_endpoint_blob);
+
+int intel_nhlt_ssp_device_type(struct device *dev, struct nhlt_acpi_table *nhlt,
+                              u8 virtual_bus_id)
+{
+       struct nhlt_endpoint *epnt;
+       int i;
+
+       if (!nhlt)
+               return -EINVAL;
+
+       epnt = (struct nhlt_endpoint *)nhlt->desc;
+       for (i = 0; i < nhlt->endpoint_count; i++) {
+               /* for SSP link the virtual bus id is the SSP port number */
+               if (epnt->linktype == NHLT_LINK_SSP &&
+                   epnt->virtual_bus_id == virtual_bus_id) {
+                       dev_dbg(dev, "SSP%d: dev_type=%d\n", virtual_bus_id,
+                               epnt->device_type);
+                       return epnt->device_type;
+               }
+
+               epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
+       }
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL(intel_nhlt_ssp_device_type);
index 41974b3897a723ccd429a8e51032245d35ec2e48..1a3f84599cb584331f9766ca6bd5b00bacaa580d 100644 (file)
@@ -1024,8 +1024,8 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
                goto err;
        }
 
-       dev_dbg(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n",
-               cs35l56->system_name, cs35l56->amp_name);
+       dev_info(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n",
+                cs35l56->system_name, cs35l56->amp_name);
 
        regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config,
                               ARRAY_SIZE(cs35l56_hda_dai_config));
@@ -1045,14 +1045,14 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
        pm_runtime_mark_last_busy(cs35l56->base.dev);
        pm_runtime_enable(cs35l56->base.dev);
 
+       cs35l56->base.init_done = true;
+
        ret = component_add(cs35l56->base.dev, &cs35l56_hda_comp_ops);
        if (ret) {
                dev_err(cs35l56->base.dev, "Register component failed: %d\n", ret);
                goto pm_err;
        }
 
-       cs35l56->base.init_done = true;
-
        return 0;
 
 pm_err:
index 4475cea8e9f70382113c3e6f496eebc854c92b40..48dae3339305048fca2262821e5ebfea6bcf237a 100644 (file)
@@ -89,7 +89,7 @@ struct tas2781_hda {
        struct snd_kcontrol *dsp_prog_ctl;
        struct snd_kcontrol *dsp_conf_ctl;
        struct snd_kcontrol *prof_ctl;
-       struct snd_kcontrol *snd_ctls[3];
+       struct snd_kcontrol *snd_ctls[2];
 };
 
 static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)
@@ -161,8 +161,6 @@ static void tas2781_hda_playback_hook(struct device *dev, int action)
                pm_runtime_put_autosuspend(dev);
                break;
        default:
-               dev_dbg(tas_hda->dev, "Playback action not supported: %d\n",
-                       action);
                break;
        }
 }
@@ -185,8 +183,15 @@ static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
 {
        struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
 
+       mutex_lock(&tas_priv->codec_lock);
+
        ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
 
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
+               __func__, kcontrol->id.name, tas_priv->rcabin.profile_cfg_id);
+
+       mutex_unlock(&tas_priv->codec_lock);
+
        return 0;
 }
 
@@ -200,11 +205,19 @@ static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
 
        val = clamp(nr_profile, 0, max);
 
+       mutex_lock(&tas_priv->codec_lock);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
+               __func__, kcontrol->id.name,
+               tas_priv->rcabin.profile_cfg_id, val);
+
        if (tas_priv->rcabin.profile_cfg_id != val) {
                tas_priv->rcabin.profile_cfg_id = val;
                ret = 1;
        }
 
+       mutex_unlock(&tas_priv->codec_lock);
+
        return ret;
 }
 
@@ -241,8 +254,15 @@ static int tasdevice_program_get(struct snd_kcontrol *kcontrol,
 {
        struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
 
+       mutex_lock(&tas_priv->codec_lock);
+
        ucontrol->value.integer.value[0] = tas_priv->cur_prog;
 
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
+               __func__, kcontrol->id.name, tas_priv->cur_prog);
+
+       mutex_unlock(&tas_priv->codec_lock);
+
        return 0;
 }
 
@@ -257,11 +277,18 @@ static int tasdevice_program_put(struct snd_kcontrol *kcontrol,
 
        val = clamp(nr_program, 0, max);
 
+       mutex_lock(&tas_priv->codec_lock);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
+               __func__, kcontrol->id.name, tas_priv->cur_prog, val);
+
        if (tas_priv->cur_prog != val) {
                tas_priv->cur_prog = val;
                ret = 1;
        }
 
+       mutex_unlock(&tas_priv->codec_lock);
+
        return ret;
 }
 
@@ -270,8 +297,15 @@ static int tasdevice_config_get(struct snd_kcontrol *kcontrol,
 {
        struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
 
+       mutex_lock(&tas_priv->codec_lock);
+
        ucontrol->value.integer.value[0] = tas_priv->cur_conf;
 
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
+               __func__, kcontrol->id.name, tas_priv->cur_conf);
+
+       mutex_unlock(&tas_priv->codec_lock);
+
        return 0;
 }
 
@@ -286,54 +320,39 @@ static int tasdevice_config_put(struct snd_kcontrol *kcontrol,
 
        val = clamp(nr_config, 0, max);
 
+       mutex_lock(&tas_priv->codec_lock);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
+               __func__, kcontrol->id.name, tas_priv->cur_conf, val);
+
        if (tas_priv->cur_conf != val) {
                tas_priv->cur_conf = val;
                ret = 1;
        }
 
+       mutex_unlock(&tas_priv->codec_lock);
+
        return ret;
 }
 
-/*
- * tas2781_digital_getvol - get the volum control
- * @kcontrol: control pointer
- * @ucontrol: User data
- * Customer Kcontrol for tas2781 is primarily for regmap booking, paging
- * depends on internal regmap mechanism.
- * tas2781 contains book and page two-level register map, especially
- * book switching will set the register BXXP00R7F, after switching to the
- * correct book, then leverage the mechanism for paging to access the
- * register.
- */
-static int tas2781_digital_getvol(struct snd_kcontrol *kcontrol,
+static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
        struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
+       int ret;
 
-       return tasdevice_digital_getvol(tas_priv, ucontrol, mc);
-}
+       mutex_lock(&tas_priv->codec_lock);
 
-static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
+       ret = tasdevice_amp_getvol(tas_priv, ucontrol, mc);
 
-       return tasdevice_amp_getvol(tas_priv, ucontrol, mc);
-}
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %ld\n",
+               __func__, kcontrol->id.name, ucontrol->value.integer.value[0]);
 
-static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
+       mutex_unlock(&tas_priv->codec_lock);
 
-       /* The check of the given value is in tasdevice_digital_putvol. */
-       return tasdevice_digital_putvol(tas_priv, ucontrol, mc);
+       return ret;
 }
 
 static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
@@ -342,9 +361,19 @@ static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
        struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
+       int ret;
+
+       mutex_lock(&tas_priv->codec_lock);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: -> %ld\n",
+               __func__, kcontrol->id.name, ucontrol->value.integer.value[0]);
 
        /* The check of the given value is in tasdevice_amp_putvol. */
-       return tasdevice_amp_putvol(tas_priv, ucontrol, mc);
+       ret = tasdevice_amp_putvol(tas_priv, ucontrol, mc);
+
+       mutex_unlock(&tas_priv->codec_lock);
+
+       return ret;
 }
 
 static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
@@ -352,9 +381,13 @@ static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
 {
        struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
 
+       mutex_lock(&tas_priv->codec_lock);
+
        ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status;
-       dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
-                       tas_priv->force_fwload_status ? "ON" : "OFF");
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
+               __func__, kcontrol->id.name, tas_priv->force_fwload_status);
+
+       mutex_unlock(&tas_priv->codec_lock);
 
        return 0;
 }
@@ -365,14 +398,20 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
        struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
        bool change, val = (bool)ucontrol->value.integer.value[0];
 
+       mutex_lock(&tas_priv->codec_lock);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
+               __func__, kcontrol->id.name,
+               tas_priv->force_fwload_status, val);
+
        if (tas_priv->force_fwload_status == val)
                change = false;
        else {
                change = true;
                tas_priv->force_fwload_status = val;
        }
-       dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
-               tas_priv->force_fwload_status ? "ON" : "OFF");
+
+       mutex_unlock(&tas_priv->codec_lock);
 
        return change;
 }
@@ -381,9 +420,6 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = {
        ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL,
                1, 0, 20, 0, tas2781_amp_getvol,
                tas2781_amp_putvol, amp_vol_tlv),
-       ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain", TAS2781_DVC_LVL,
-               0, 0, 200, 1, tas2781_digital_getvol,
-               tas2781_digital_putvol, dvc_tlv),
        ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
                tas2781_force_fwload_get, tas2781_force_fwload_put),
 };
index 320ac792c7fe2459b10024afd05719af2082772d..3182c634464d4288dd1bb8faca39481b5806e85e 100644 (file)
@@ -278,7 +278,8 @@ static void run_spu_dma(struct work_struct *work)
                dreamcastcard->clicks++;
                if (unlikely(dreamcastcard->clicks >= AICA_PERIOD_NUMBER))
                        dreamcastcard->clicks %= AICA_PERIOD_NUMBER;
-               mod_timer(&dreamcastcard->timer, jiffies + 1);
+               if (snd_pcm_running(dreamcastcard->substream))
+                       mod_timer(&dreamcastcard->timer, jiffies + 1);
        }
 }
 
@@ -290,6 +291,8 @@ static void aica_period_elapsed(struct timer_list *t)
        /*timer function - so cannot sleep */
        int play_period;
        struct snd_pcm_runtime *runtime;
+       if (!snd_pcm_running(substream))
+               return;
        runtime = substream->runtime;
        dreamcastcard = substream->pcm->private_data;
        /* Have we played out an additional period? */
@@ -350,12 +353,19 @@ static int snd_aicapcm_pcm_open(struct snd_pcm_substream
        return 0;
 }
 
+static int snd_aicapcm_pcm_sync_stop(struct snd_pcm_substream *substream)
+{
+       struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+
+       del_timer_sync(&dreamcastcard->timer);
+       cancel_work_sync(&dreamcastcard->spu_dma_work);
+       return 0;
+}
+
 static int snd_aicapcm_pcm_close(struct snd_pcm_substream
                                 *substream)
 {
        struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
-       flush_work(&(dreamcastcard->spu_dma_work));
-       del_timer(&dreamcastcard->timer);
        dreamcastcard->substream = NULL;
        kfree(dreamcastcard->channel);
        spu_disable();
@@ -401,6 +411,7 @@ static const struct snd_pcm_ops snd_aicapcm_playback_ops = {
        .prepare = snd_aicapcm_pcm_prepare,
        .trigger = snd_aicapcm_pcm_trigger,
        .pointer = snd_aicapcm_pcm_pointer,
+       .sync_stop = snd_aicapcm_pcm_sync_stop,
 };
 
 /* TO DO: set up to handle more than one pcm instance */
index da4a83afb87a8a2c4163f34a8d6e9993b92bde77..f28edd9830c1b3e25961add70dff87a489cfa119 100644 (file)
@@ -1356,6 +1356,7 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
        int sample_rate, channel_count;
        int bit_depth, ret;
        u32 nhlt_type;
+       int dev_type = 0;
 
        /* convert to NHLT type */
        switch (linktype) {
@@ -1371,18 +1372,30 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
                                                   &bit_depth);
                if (ret < 0)
                        return ret;
+
+               /*
+                * We need to know the type of the external device attached to a SSP
+                * port to retrieve the blob from NHLT. However, device type is not
+                * specified in topology.
+                * Query the type for the port and then pass that information back
+                * to the blob lookup function.
+                */
+               dev_type = intel_nhlt_ssp_device_type(sdev->dev, ipc4_data->nhlt,
+                                                     dai_index);
+               if (dev_type < 0)
+                       return dev_type;
                break;
        default:
                return 0;
        }
 
-       dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n",
-               dai_index, nhlt_type, dir);
+       dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d dev type %d\n",
+               dai_index, nhlt_type, dir, dev_type);
 
        /* find NHLT blob with matching params */
        cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
                                           bit_depth, bit_depth, channel_count, sample_rate,
-                                          dir, 0);
+                                          dir, dev_type);
 
        if (!cfg) {
                dev_err(sdev->dev,