diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-03-28 22:54:49 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-03-28 22:54:49 +0100 |
commit | 529b10c0091d6bda6d54fc72711a28f3ea01a72c (patch) | |
tree | e9608842a0fa3d984a0779ac26032efc1d39f316 | |
parent | Merge tag 'iommu-fixes-v6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel... (diff) | |
parent | ALSA: hda/tas2781: remove useless dev_dbg from playback_hook (diff) | |
download | linux-529b10c0091d6bda6d54fc72711a28f3ea01a72c.tar.xz linux-529b10c0091d6bda6d54fc72711a28f3ea01a72c.zip |
Merge tag 'sound-6.9-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
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
-rw-r--r-- | include/sound/intel-nhlt.h | 10 | ||||
-rw-r--r-- | sound/aoa/soundbus/i2sbus/core.c | 2 | ||||
-rw-r--r-- | sound/hda/intel-nhlt.c | 26 | ||||
-rw-r--r-- | sound/pci/hda/cs35l56_hda.c | 8 | ||||
-rw-r--r-- | sound/pci/hda/tas2781_hda_i2c.c | 118 | ||||
-rw-r--r-- | sound/sh/aica.c | 17 | ||||
-rw-r--r-- | sound/soc/sof/ipc4-topology.c | 19 |
7 files changed, 148 insertions, 52 deletions
diff --git a/include/sound/intel-nhlt.h b/include/sound/intel-nhlt.h index 53470d6a28d6..24dbe16684ae 100644 --- a/include/sound/intel-nhlt.h +++ b/include/sound/intel-nhlt.h @@ -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 diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index b8ff5cccd0c8..5431d2c49421 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -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)" }; diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index 696a958d93e9..088cff799e0b 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -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); diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 41974b3897a7..1a3f84599cb5 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -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: diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 4475cea8e9f7..48dae3339305 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -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), }; diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 320ac792c7fe..3182c634464d 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -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 */ diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index da4a83afb87a..f28edd9830c1 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -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, |