diff options
40 files changed, 485 insertions, 132 deletions
diff --git a/sound/soc/codecs/adau1977-spi.c b/sound/soc/codecs/adau1977-spi.c index 8370bec27a9c..207c5c95f35a 100644 --- a/sound/soc/codecs/adau1977-spi.c +++ b/sound/soc/codecs/adau1977-spi.c @@ -55,7 +55,7 @@ static const struct spi_device_id adau1977_spi_ids[] = { }; MODULE_DEVICE_TABLE(spi, adau1977_spi_ids); -static const struct of_device_id adau1977_spi_of_match[] = { +static const struct of_device_id adau1977_spi_of_match[] __maybe_unused = { { .compatible = "adi,adau1977" }, { .compatible = "adi,adau1978" }, { .compatible = "adi,adau1979" }, diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 4a4f09f924bc..e3d398b8f54e 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -968,6 +968,8 @@ int da7219_aad_init(struct snd_soc_component *component) INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work); INIT_WORK(&da7219_aad->jack_det_work, da7219_aad_jack_det_work); + mutex_init(&da7219_aad->jack_det_mutex); + ret = request_threaded_irq(da7219_aad->irq, da7219_aad_pre_irq_thread, da7219_aad_irq_thread, IRQF_TRIGGER_LOW | IRQF_ONESHOT, diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 01e8ffda2a4b..6d980fbc4207 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -428,8 +428,13 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + bool has_capture = !hcp->hcd.no_i2s_capture; + bool has_playback = !hcp->hcd.no_i2s_playback; int ret = 0; + if (!((has_playback && tx) || (has_capture && !tx))) + return 0; + mutex_lock(&hcp->lock); if (hcp->busy) { dev_err(dai->dev, "Only one simultaneous stream supported!\n"); @@ -468,6 +473,12 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + bool has_capture = !hcp->hcd.no_i2s_capture; + bool has_playback = !hcp->hcd.no_i2s_playback; + + if (!((has_playback && tx) || (has_capture && !tx))) + return; hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index bf27bdd5be20..473d3cd39554 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -242,7 +242,7 @@ enum { struct tx_mute_work { struct tx_macro *tx; - u32 decimator; + u8 decimator; struct delayed_work dwork; }; @@ -635,7 +635,7 @@ exit: return 0; } -static bool is_amic_enabled(struct snd_soc_component *component, int decimator) +static bool is_amic_enabled(struct snd_soc_component *component, u8 decimator) { u16 adc_mux_reg, adc_reg, adc_n; @@ -849,7 +849,7 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - unsigned int decimator; + u8 decimator; u16 tx_vol_ctl_reg, dec_cfg_reg, hpf_gate_reg, tx_gain_ctl_reg; u8 hpf_cut_off_freq; int hpf_delay = TX_MACRO_DMIC_HPF_DELAY_MS; @@ -1064,7 +1064,8 @@ static int tx_macro_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; - u32 decimator, sample_rate; + u32 sample_rate; + u8 decimator; int tx_fs_rate; struct tx_macro *tx = snd_soc_component_get_drvdata(component); @@ -1128,7 +1129,7 @@ static int tx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream) { struct snd_soc_component *component = dai->component; struct tx_macro *tx = snd_soc_component_get_drvdata(component); - u16 decimator; + u8 decimator; /* active decimator not set yet */ if (tx->active_decimator[dai->id] == -1) diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index b54610b27906..d7b157ddc9a8 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -429,7 +429,7 @@ static int mt6358_put_volsw(struct snd_kcontrol *kcontrol, struct mt6358_priv *priv = snd_soc_component_get_drvdata(component); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg; + unsigned int reg = 0; int ret; ret = snd_soc_put_volsw(kcontrol, ucontrol); diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c index c9a453ce8a2a..cb487e63615c 100644 --- a/sound/soc/codecs/mt6359.c +++ b/sound/soc/codecs/mt6359.c @@ -358,7 +358,7 @@ static int mt6359_put_volsw(struct snd_kcontrol *kcontrol, struct mt6359_priv *priv = snd_soc_component_get_drvdata(component); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg; + unsigned int reg = 0; int index = ucontrol->value.integer.value[0]; int ret; diff --git a/sound/soc/codecs/pcm179x-spi.c b/sound/soc/codecs/pcm179x-spi.c index ebf63ea90a1c..192fee90c971 100644 --- a/sound/soc/codecs/pcm179x-spi.c +++ b/sound/soc/codecs/pcm179x-spi.c @@ -29,7 +29,7 @@ static int pcm179x_spi_probe(struct spi_device *spi) return pcm179x_common_init(&spi->dev, regmap); } -static const struct of_device_id pcm179x_of_match[] = { +static const struct of_device_id pcm179x_of_match[] __maybe_unused = { { .compatible = "ti,pcm1792a", }, { } }; diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c index 49f527c61a7a..dff2596c81eb 100644 --- a/sound/soc/codecs/rt1019.c +++ b/sound/soc/codecs/rt1019.c @@ -546,7 +546,7 @@ static const struct i2c_device_id rt1019_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt1019_i2c_id); -static const struct of_device_id rt1019_of_match[] = { +static const struct of_device_id rt1019_of_match[] __maybe_unused = { { .compatible = "realtek,rt1019", }, {}, }; diff --git a/sound/soc/codecs/sma1303.c b/sound/soc/codecs/sma1303.c index fa4b0a60f8a9..b6c132edf3bd 100644 --- a/sound/soc/codecs/sma1303.c +++ b/sound/soc/codecs/sma1303.c @@ -1591,7 +1591,7 @@ static const struct snd_soc_component_driver sma1303_component = { .num_dapm_routes = ARRAY_SIZE(sma1303_audio_map), }; -const struct regmap_config sma_i2c_regmap = { +static const struct regmap_config sma_i2c_regmap = { .reg_bits = 8, .val_bits = 8, diff --git a/sound/soc/codecs/src4xxx-i2c.c b/sound/soc/codecs/src4xxx-i2c.c index 27026030704a..a40fd20df984 100644 --- a/sound/soc/codecs/src4xxx-i2c.c +++ b/sound/soc/codecs/src4xxx-i2c.c @@ -24,7 +24,7 @@ static const struct i2c_device_id src4xxx_i2c_ids[] = { }; MODULE_DEVICE_TABLE(i2c, src4xxx_i2c_ids); -static const struct of_device_id src4xxx_of_match[] = { +static const struct of_device_id src4xxx_of_match[] __maybe_unused = { { .compatible = "ti,src4392", }, { } }; diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c index c3d0a2a7c36f..28c92d90299e 100644 --- a/sound/soc/codecs/zl38060.c +++ b/sound/soc/codecs/zl38060.c @@ -608,7 +608,7 @@ static int zl38_spi_probe(struct spi_device *spi) &zl38_dai, 1); } -static const struct of_device_id zl38_dt_ids[] = { +static const struct of_device_id zl38_dt_ids[] __maybe_unused = { { .compatible = "mscc,zl38060", }, { /* sentinel */ } }; diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 17db29c25d96..725c530a3636 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -303,6 +303,10 @@ config SND_SOC_IMX_SGTL5000 Say Y if you want to add support for SoC audio on an i.MX board with a sgtl5000 codec. + Note that this is an old driver. Consider enabling + SND_SOC_FSL_ASOC_CARD and SND_SOC_SGTL5000 to use the newer + driver. + config SND_SOC_IMX_SPDIF tristate "SoC Audio support for i.MX boards with S/PDIF" select SND_SOC_IMX_PCM_DMA diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index acd43b6108e9..1a1d572cc1d0 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -117,6 +117,26 @@ static void avs_da7219_codec_exit(struct snd_soc_pcm_runtime *rtd) snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL); } +static int +avs_da7219_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate, *channels; + struct snd_mask *fmt; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP0 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + return 0; +} + static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, struct snd_soc_dai_link **dai_link) { @@ -148,6 +168,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->num_platforms = 1; dl->id = 0; dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->be_hw_params_fixup = avs_da7219_be_fixup; dl->init = avs_da7219_codec_init; dl->exit = avs_da7219_codec_exit; dl->nonatomic = 1; diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c index 921f42caf7e0..183123d08c5a 100644 --- a/sound/soc/intel/avs/boards/max98357a.c +++ b/sound/soc/intel/avs/boards/max98357a.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <linux/platform_device.h> +#include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/soc-acpi.h> #include <sound/soc-dapm.h> @@ -24,6 +25,26 @@ static const struct snd_soc_dapm_route card_base_routes[] = { { "Spk", NULL, "Speaker" }, }; +static int +avs_max98357a_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate, *channels; + struct snd_mask *fmt; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP0 to 16 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + return 0; +} + static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, struct snd_soc_dai_link **dai_link) { @@ -55,6 +76,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->num_platforms = 1; dl->id = 0; dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->be_hw_params_fixup = avs_max98357a_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; dl->dpcm_playback = 1; diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c index b31fa931ba8b..b69fc5567135 100644 --- a/sound/soc/intel/avs/boards/nau8825.c +++ b/sound/soc/intel/avs/boards/nau8825.c @@ -33,15 +33,15 @@ avs_nau8825_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *co return -EINVAL; } - if (!SND_SOC_DAPM_EVENT_ON(event)) { + if (SND_SOC_DAPM_EVENT_ON(event)) + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_MCLK, 24000000, + SND_SOC_CLOCK_IN); + else ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "set sysclk err = %d\n", ret); - return ret; - } - } + if (ret < 0) + dev_err(card->dev, "Set sysclk failed: %d\n", ret); - return 0; + return ret; } static const struct snd_kcontrol_new card_controls[] = { diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c index 473e9fe5d0bf..b2c2ba93dcb5 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -169,6 +169,27 @@ static const struct snd_soc_ops avs_rt5682_ops = { .hw_params = avs_rt5682_hw_params, }; +static int +avs_rt5682_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate, *channels; + struct snd_mask *fmt; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSPN to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, struct snd_soc_dai_link **dai_link) { @@ -201,6 +222,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->id = 0; dl->init = avs_rt5682_codec_init; dl->exit = avs_rt5682_codec_exit; + dl->be_hw_params_fixup = avs_rt5682_be_fixup; dl->ops = &avs_rt5682_ops; dl->nonatomic = 1; dl->no_pcm = 1; diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c index c5db69612762..2b7f5ad92aca 100644 --- a/sound/soc/intel/avs/boards/ssm4567.c +++ b/sound/soc/intel/avs/boards/ssm4567.c @@ -15,7 +15,6 @@ #include <sound/soc-acpi.h> #include "../../../codecs/nau8825.h" -#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" #define SKL_SSM_CODEC_DAI "ssm4567-hifi" static struct snd_soc_codec_conf card_codec_conf[] = { @@ -34,41 +33,11 @@ static const struct snd_kcontrol_new card_controls[] = { SOC_DAPM_PIN_SWITCH("Right Speaker"), }; -static int -platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret; - - codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found\n"); - return -EINVAL; - } - - if (SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_MCLK, 24000000, - SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(card->dev, "set sysclk err = %d\n", ret); - } else { - ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(card->dev, "set sysclk err = %d\n", ret); - } - - return ret; -} - static const struct snd_soc_dapm_widget card_widgets[] = { SND_SOC_DAPM_SPK("Left Speaker", NULL), SND_SOC_DAPM_SPK("Right Speaker", NULL), SND_SOC_DAPM_SPK("DP1", NULL), SND_SOC_DAPM_SPK("DP2", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_route card_base_routes[] = { diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 4fe448295a90..2eec32846078 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -1109,7 +1109,9 @@ static const struct platform_device_id board_ids[] = { SOF_SPEAKER_AMP_PRESENT | SOF_RT1019_SPEAKER_AMP_PRESENT | SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(4)), + SOF_RT5682_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), }, { .name = "mtl_mx98357_rt5682", diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index 56ee5fef66a8..28dd2046e4ac 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -559,7 +559,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { { .comp_ids = &essx_83x6, .drv_name = "sof-essx8336", - .sof_tplg_filename = "sof-adl-es83x6", /* the tplg suffix is added at run time */ + .sof_tplg_filename = "sof-adl-es8336", /* the tplg suffix is added at run time */ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER | SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-adda.c b/sound/soc/mediatek/mt8195/mt8195-dai-adda.c index f04bd1781356..0dd35255066b 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-adda.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-adda.c @@ -704,13 +704,18 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream, { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_adda_priv *adda_priv = afe_priv->dai_priv[dai->id]; + struct mtk_dai_adda_priv *adda_priv; unsigned int rate = params_rate(params); - int id = dai->id; - int ret = 0; + int ret; + + if (dai->id != MT8195_AFE_IO_DL_SRC && + dai->id != MT8195_AFE_IO_UL_SRC1 && + dai->id != MT8195_AFE_IO_UL_SRC2) + return -EINVAL; + adda_priv = afe_priv->dai_priv[dai->id]; dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", - __func__, id, substream->stream, rate); + __func__, dai->id, substream->stream, rate); if (rate > ADDA_HIRES_THRES) adda_priv->hires_required = 1; @@ -718,9 +723,9 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream, adda_priv->hires_required = 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ret = mtk_dai_da_configure(afe, rate, id); + ret = mtk_dai_da_configure(afe, rate, dai->id); else - ret = mtk_dai_ad_configure(afe, rate, id); + ret = mtk_dai_ad_configure(afe, rate, dai->id); return ret; } diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c index f2c9a1fdbe0d..eedb9165f911 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c @@ -137,6 +137,38 @@ static const struct mtk_dai_etdm_rate mt8195_etdm_rates[] = { { .rate = 352800, .reg_value = 21, }, }; +static bool mt8195_afe_etdm_is_valid(int id) +{ + switch (id) { + case MT8195_AFE_IO_ETDM1_IN: + fallthrough; + case MT8195_AFE_IO_ETDM2_IN: + fallthrough; + case MT8195_AFE_IO_ETDM1_OUT: + fallthrough; + case MT8195_AFE_IO_ETDM2_OUT: + fallthrough; + case MT8195_AFE_IO_DPTX: + fallthrough; + case MT8195_AFE_IO_ETDM3_OUT: + return true; + default: + return false; + } +} + +static bool mt8195_afe_hdmitx_dptx_is_valid(int id) +{ + switch (id) { + case MT8195_AFE_IO_DPTX: + fallthrough; + case MT8195_AFE_IO_ETDM3_OUT: + return true; + default: + return false; + } +} + static int get_etdm_fs_timing(unsigned int rate) { int i; @@ -236,8 +268,12 @@ static int is_cowork_mode(struct snd_soc_dai *dai) { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id]; + struct mtk_dai_etdm_priv *etdm_data; + if (!mt8195_afe_etdm_is_valid(dai->id)) + return -EINVAL; + + etdm_data = afe_priv->dai_priv[dai->id]; return (etdm_data->cowork_slv_count > 0 || etdm_data->cowork_source_id != COWORK_ETDM_NONE); } @@ -264,8 +300,14 @@ static int get_etdm_cowork_master_id(struct snd_soc_dai *dai) { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id]; - int dai_id = etdm_data->cowork_source_id; + struct mtk_dai_etdm_priv *etdm_data; + int dai_id; + + if (!mt8195_afe_etdm_is_valid(dai->id)) + return -EINVAL; + + etdm_data = afe_priv->dai_priv[dai->id]; + dai_id = etdm_data->cowork_source_id; if (dai_id == COWORK_ETDM_NONE) dai_id = dai->id; @@ -1276,9 +1318,13 @@ static int mt8195_afe_enable_etdm(struct mtk_base_afe *afe, int dai_id) int ret = 0; struct etdm_con_reg etdm_reg; struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id]; + struct mtk_dai_etdm_priv *etdm_data; unsigned long flags; + if (!mt8195_afe_etdm_is_valid(dai_id)) + return -EINVAL; + + etdm_data = afe_priv->dai_priv[dai_id]; spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags); etdm_data->en_ref_cnt++; if (etdm_data->en_ref_cnt == 1) { @@ -1299,9 +1345,13 @@ static int mt8195_afe_disable_etdm(struct mtk_base_afe *afe, int dai_id) int ret = 0; struct etdm_con_reg etdm_reg; struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id]; + struct mtk_dai_etdm_priv *etdm_data; unsigned long flags; + if (!mt8195_afe_etdm_is_valid(dai_id)) + return -EINVAL; + + etdm_data = afe_priv->dai_priv[dai_id]; spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags); if (etdm_data->en_ref_cnt > 0) { etdm_data->en_ref_cnt--; @@ -1357,12 +1407,16 @@ static int etdm_cowork_slv_sel(int id, int slave_mode) static int mt8195_etdm_sync_mode_configure(struct mtk_base_afe *afe, int dai_id) { struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id]; + struct mtk_dai_etdm_priv *etdm_data; unsigned int reg = 0; unsigned int mask; unsigned int val; int cowork_source_sel; + if (!mt8195_afe_etdm_is_valid(dai_id)) + return -EINVAL; + + etdm_data = afe_priv->dai_priv[dai_id]; if (etdm_data->cowork_source_id == COWORK_ETDM_NONE) return 0; @@ -1532,8 +1586,10 @@ static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream, if (is_cowork_mode(dai)) { mst_dai_id = get_etdm_cowork_master_id(dai); - mtk_dai_etdm_enable_mclk(afe, mst_dai_id); + if (!mt8195_afe_etdm_is_valid(mst_dai_id)) + return -EINVAL; + mtk_dai_etdm_enable_mclk(afe, mst_dai_id); cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(mst_dai_id); if (cg_id >= 0) mt8195_afe_enable_clk(afe, afe_priv->clk[cg_id]); @@ -1571,6 +1627,9 @@ static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream, if (is_cowork_mode(dai)) { mst_dai_id = get_etdm_cowork_master_id(dai); + if (!mt8195_afe_etdm_is_valid(mst_dai_id)) + return; + cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(mst_dai_id); if (cg_id >= 0) mt8195_afe_disable_clk(afe, afe_priv->clk[cg_id]); @@ -1631,16 +1690,24 @@ static int mtk_dai_etdm_in_configure(struct mtk_base_afe *afe, int dai_id) { struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id]; + struct mtk_dai_etdm_priv *etdm_data; struct etdm_con_reg etdm_reg; - bool slave_mode = etdm_data->slave_mode; - unsigned int data_mode = etdm_data->data_mode; - unsigned int lrck_width = etdm_data->lrck_width; + bool slave_mode; + unsigned int data_mode; + unsigned int lrck_width; unsigned int val = 0; unsigned int mask = 0; int i; int ret; + if (!mt8195_afe_etdm_is_valid(dai_id)) + return -EINVAL; + + etdm_data = afe_priv->dai_priv[dai_id]; + slave_mode = etdm_data->slave_mode; + data_mode = etdm_data->data_mode; + lrck_width = etdm_data->lrck_width; + dev_dbg(afe->dev, "%s rate %u channels %u, id %d\n", __func__, rate, channels, dai_id); @@ -1748,15 +1815,22 @@ static int mtk_dai_etdm_out_configure(struct mtk_base_afe *afe, int dai_id) { struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id]; + struct mtk_dai_etdm_priv *etdm_data; struct etdm_con_reg etdm_reg; - bool slave_mode = etdm_data->slave_mode; - unsigned int lrck_width = etdm_data->lrck_width; + bool slave_mode; + unsigned int lrck_width; unsigned int val = 0; unsigned int mask = 0; int ret; int fs = 0; + if (!mt8195_afe_etdm_is_valid(dai_id)) + return -EINVAL; + + etdm_data = afe_priv->dai_priv[dai_id]; + slave_mode = etdm_data->slave_mode; + lrck_width = etdm_data->lrck_width; + dev_dbg(afe->dev, "%s rate %u channels %u, id %d\n", __func__, rate, channels, dai_id); @@ -1837,7 +1911,7 @@ static int mtk_dai_etdm_out_configure(struct mtk_base_afe *afe, static int mtk_dai_etdm_mclk_configure(struct mtk_base_afe *afe, int dai_id) { struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id]; + struct mtk_dai_etdm_priv *etdm_data; int clk_id = mtk_dai_etdm_get_clk_id_by_dai_id(dai_id); int clkdiv_id = mtk_dai_etdm_get_clkdiv_id_by_dai_id(dai_id); int apll; @@ -1850,6 +1924,10 @@ static int mtk_dai_etdm_mclk_configure(struct mtk_base_afe *afe, int dai_id) if (clk_id < 0 || clkdiv_id < 0) return 0; + if (!mt8195_afe_etdm_is_valid(dai_id)) + return -EINVAL; + + etdm_data = afe_priv->dai_priv[dai_id]; ret = get_etdm_reg(dai_id, &etdm_reg); if (ret < 0) return ret; @@ -1888,9 +1966,9 @@ static int mtk_dai_etdm_configure(struct mtk_base_afe *afe, int dai_id) { struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id]; + struct mtk_dai_etdm_priv *etdm_data; struct etdm_con_reg etdm_reg; - bool slave_mode = etdm_data->slave_mode; + bool slave_mode; unsigned int etdm_channels; unsigned int val = 0; unsigned int mask = 0; @@ -1898,6 +1976,11 @@ static int mtk_dai_etdm_configure(struct mtk_base_afe *afe, unsigned int wlen = get_etdm_wlen(bit_width); int ret; + if (!mt8195_afe_etdm_is_valid(dai_id)) + return -EINVAL; + + etdm_data = afe_priv->dai_priv[dai_id]; + slave_mode = etdm_data->slave_mode; ret = get_etdm_reg(dai_id, &etdm_reg); if (ret < 0) return ret; @@ -1973,6 +2056,8 @@ static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream, if (is_cowork_mode(dai)) { mst_dai_id = get_etdm_cowork_master_id(dai); + if (!mt8195_afe_etdm_is_valid(mst_dai_id)) + return -EINVAL; ret = mtk_dai_etdm_mclk_configure(afe, mst_dai_id); if (ret) @@ -2024,6 +2109,9 @@ static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_RESUME: if (is_cowork_mode(dai)) { mst_dai_id = get_etdm_cowork_master_id(dai); + if (!mt8195_afe_etdm_is_valid(mst_dai_id)) + return -EINVAL; + mst_etdm_data = afe_priv->dai_priv[mst_dai_id]; //open master first @@ -2040,6 +2128,9 @@ static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_SUSPEND: if (is_cowork_mode(dai)) { mst_dai_id = get_etdm_cowork_master_id(dai); + if (!mt8195_afe_etdm_is_valid(mst_dai_id)) + return -EINVAL; + mst_etdm_data = afe_priv->dai_priv[mst_dai_id]; for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) { @@ -2061,10 +2152,14 @@ static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd, static int mtk_dai_etdm_cal_mclk(struct mtk_base_afe *afe, int freq, int dai_id) { struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id]; + struct mtk_dai_etdm_priv *etdm_data; int apll; int apll_rate; + if (!mt8195_afe_etdm_is_valid(dai_id)) + return -EINVAL; + + etdm_data = afe_priv->dai_priv[dai_id]; if (freq == 0) { etdm_data->mclk_freq = freq; return 0; @@ -2104,6 +2199,9 @@ static int mtk_dai_etdm_set_sysclk(struct snd_soc_dai *dai, else dai_id = dai->id; + if (!mt8195_afe_etdm_is_valid(dai_id)) + return -EINVAL; + etdm_data = afe_priv->dai_priv[dai_id]; etdm_data->mclk_dir = dir; return mtk_dai_etdm_cal_mclk(afe, freq, dai_id); @@ -2115,8 +2213,12 @@ static int mtk_dai_etdm_set_tdm_slot(struct snd_soc_dai *dai, { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id]; + struct mtk_dai_etdm_priv *etdm_data; + + if (!mt8195_afe_etdm_is_valid(dai->id)) + return -EINVAL; + etdm_data = afe_priv->dai_priv[dai->id]; dev_dbg(dai->dev, "%s id %d slot_width %d\n", __func__, dai->id, slot_width); @@ -2129,8 +2231,12 @@ static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id]; + struct mtk_dai_etdm_priv *etdm_data; + + if (!mt8195_afe_etdm_is_valid(dai->id)) + return -EINVAL; + etdm_data = afe_priv->dai_priv[dai->id]; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S; @@ -2248,13 +2354,18 @@ static int mtk_dai_hdmitx_dptx_hw_params(struct snd_pcm_substream *substream, { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id]; + struct mtk_dai_etdm_priv *etdm_data; unsigned int rate = params_rate(params); unsigned int channels = params_channels(params); snd_pcm_format_t format = params_format(params); int width = snd_pcm_format_physical_width(format); int ret = 0; + if (!mt8195_afe_hdmitx_dptx_is_valid(dai->id)) + return -EINVAL; + + etdm_data = afe_priv->dai_priv[dai->id]; + /* dptx configure */ if (dai->id == MT8195_AFE_IO_DPTX) { regmap_update_bits(afe->regmap, AFE_DPTX_CON, @@ -2331,7 +2442,12 @@ static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai, { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id]; + struct mtk_dai_etdm_priv *etdm_data; + + if (!mt8195_afe_hdmitx_dptx_is_valid(dai->id)) + return -EINVAL; + + etdm_data = afe_priv->dai_priv[dai->id]; dev_dbg(dai->dev, "%s id %d freq %u, dir %d\n", __func__, dai->id, freq, dir); @@ -2370,10 +2486,14 @@ static int mtk_dai_etdm_probe(struct snd_soc_dai *dai) { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id]; + struct mtk_dai_etdm_priv *etdm_data; dev_dbg(dai->dev, "%s id %d\n", __func__, dai->id); + if (!mt8195_afe_etdm_is_valid(dai->id)) + return -EINVAL; + + etdm_data = afe_priv->dai_priv[dai->id]; if (etdm_data->mclk_freq) { dev_dbg(afe->dev, "MCLK always on, rate %d\n", etdm_data->mclk_freq); @@ -2477,6 +2597,11 @@ static void mt8195_etdm_update_sync_info(struct mtk_base_afe *afe) etdm_data = afe_priv->dai_priv[i]; if (etdm_data->cowork_source_id != COWORK_ETDM_NONE) { mst_dai_id = etdm_data->cowork_source_id; + if (!mt8195_afe_etdm_is_valid(mst_dai_id)) { + dev_err(afe->dev, "%s invalid dai id %d\n", + __func__, mst_dai_id); + return; + } mst_data = afe_priv->dai_priv[mst_dai_id]; if (mst_data->cowork_source_id != COWORK_ETDM_NONE) dev_info(afe->dev, "%s [%d] wrong sync source\n" @@ -2513,6 +2638,12 @@ static void mt8195_dai_etdm_parse_of(struct mtk_base_afe *afe) for (i = 0; i < MT8195_AFE_IO_ETDM_NUM; i++) { dai_id = ETDM_TO_DAI_ID(i); + if (!mt8195_afe_etdm_is_valid(dai_id)) { + dev_err(afe->dev, "%s invalid dai id %d\n", + __func__, dai_id); + return; + } + etdm_data = afe_priv->dai_priv[dai_id]; ret = snprintf(prop, sizeof(prop), diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c index 051433689ff5..6d6d79300d51 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c @@ -122,17 +122,26 @@ static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream, struct snd_pcm_runtime * const runtime = substream->runtime; struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_pcmif_priv *pcmif_priv = afe_priv->dai_priv[dai->id]; - unsigned int slave_mode = pcmif_priv->slave_mode; - unsigned int lrck_inv = pcmif_priv->lrck_inv; - unsigned int bck_inv = pcmif_priv->bck_inv; - unsigned int fmt = pcmif_priv->format; + struct mtk_dai_pcmif_priv *pcmif_priv; + unsigned int slave_mode; + unsigned int lrck_inv; + unsigned int bck_inv; + unsigned int fmt; unsigned int bit_width = dai->sample_bits; unsigned int val = 0; unsigned int mask = 0; int fs = 0; int mode = 0; + if (dai->id != MT8195_AFE_IO_PCM) + return -EINVAL; + + pcmif_priv = afe_priv->dai_priv[dai->id]; + slave_mode = pcmif_priv->slave_mode; + lrck_inv = pcmif_priv->lrck_inv; + bck_inv = pcmif_priv->bck_inv; + fmt = pcmif_priv->format; + /* sync freq mode */ fs = mt8195_afe_fs_timing(runtime->rate); if (fs < 0) @@ -230,10 +239,15 @@ static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_pcmif_priv *pcmif_priv = afe_priv->dai_priv[dai->id]; + struct mtk_dai_pcmif_priv *pcmif_priv; dev_dbg(dai->dev, "%s fmt 0x%x\n", __func__, fmt); + if (dai->id != MT8195_AFE_IO_PCM) + return -EINVAL; + + pcmif_priv = afe_priv->dai_priv[dai->id]; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: pcmif_priv->format = MTK_DAI_PCM_FMT_I2S; diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c index 4682748d82be..ceca882ecff7 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c @@ -158,7 +158,7 @@ static int mt8195_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd) int mtkaif_phase_cycle[MT8195_MTKAIF_MISO_NUM]; int mtkaif_calibration_num_phase; bool mtkaif_calibration_ok; - unsigned int monitor; + unsigned int monitor = 0; int counter; int phase; int i; diff --git a/sound/soc/qcom/qdsp6/q6prm.c b/sound/soc/qcom/qdsp6/q6prm.c index 3aa63aac4a68..81554d202658 100644 --- a/sound/soc/qcom/qdsp6/q6prm.c +++ b/sound/soc/qcom/qdsp6/q6prm.c @@ -184,9 +184,9 @@ int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_ unsigned int freq) { if (freq) - return q6prm_request_lpass_clock(dev, clk_id, clk_attr, clk_attr, freq); + return q6prm_request_lpass_clock(dev, clk_id, clk_attr, clk_root, freq); - return q6prm_release_lpass_clock(dev, clk_id, clk_attr, clk_attr, freq); + return q6prm_release_lpass_clock(dev, clk_id, clk_attr, clk_root, freq); } EXPORT_SYMBOL_GPL(q6prm_set_lpass_clock); diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index a1037512da1f..e1dba6b79065 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -198,12 +198,15 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev) goto err; } + usleep_range(500, 1000); + /* exit HDA controller reset */ ret = hda_dsp_ctrl_link_reset(sdev, false); if (ret < 0) { dev_err(sdev->dev, "error: failed to exit HDA controller reset\n"); goto err; } + usleep_range(1000, 1200); hda_codec_detect_mask(sdev); diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index e3b69dbc1308..c9231aeacc53 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -392,6 +392,12 @@ static int hda_dsp_update_d0i3c_register(struct snd_sof_dev *sdev, u8 value) snd_sof_dsp_update8(sdev, HDA_DSP_HDA_BAR, chip->d0i3_offset, SOF_HDA_VS_D0I3C_I3, value); + /* + * The value written to the D0I3C::I3 bit may not be taken into account immediately. + * A delay is recommended before checking if D0I3C::CIP is cleared + */ + usleep_range(30, 40); + /* Wait for cmd in progress to be cleared before exiting the function */ ret = hda_dsp_wait_d0i3c_done(sdev); if (ret < 0) { @@ -400,6 +406,12 @@ static int hda_dsp_update_d0i3c_register(struct snd_sof_dev *sdev, u8 value) } reg = snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, chip->d0i3_offset); + /* Confirm d0i3 state changed with paranoia check */ + if ((reg ^ value) & SOF_HDA_VS_D0I3C_I3) { + dev_err(sdev->dev, "failed to update D0I3C!\n"); + return -EIO; + } + trace_sof_intel_D0I3C_updated(sdev, reg); return 0; diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c index 69279dcc92dc..aff6cb573c27 100644 --- a/sound/soc/sof/intel/pci-apl.c +++ b/sound/soc/sof/intel/pci-apl.c @@ -78,6 +78,7 @@ static const struct sof_dev_desc glk_desc = { .nocodec_tplg_filename = "sof-glk-nocodec.tplg", .ops = &sof_apl_ops, .ops_init = sof_apl_ops_init, + .ops_free = hda_ops_free, }; /* PCI IDs */ diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c index 8db3f8d15b55..4c0c1c369dcd 100644 --- a/sound/soc/sof/intel/pci-cnl.c +++ b/sound/soc/sof/intel/pci-cnl.c @@ -48,6 +48,7 @@ static const struct sof_dev_desc cnl_desc = { .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .ops_init = sof_cnl_ops_init, + .ops_free = hda_ops_free, }; static const struct sof_dev_desc cfl_desc = { @@ -111,6 +112,7 @@ static const struct sof_dev_desc cml_desc = { .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .ops_init = sof_cnl_ops_init, + .ops_free = hda_ops_free, }; /* PCI IDs */ diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c index d6cf75e357db..6785669113b3 100644 --- a/sound/soc/sof/intel/pci-icl.c +++ b/sound/soc/sof/intel/pci-icl.c @@ -79,6 +79,7 @@ static const struct sof_dev_desc jsl_desc = { .nocodec_tplg_filename = "sof-jsl-nocodec.tplg", .ops = &sof_cnl_ops, .ops_init = sof_cnl_ops_init, + .ops_free = hda_ops_free, }; /* PCI IDs */ diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c index 6e4e6d4ef5a5..b183dc0014b4 100644 --- a/sound/soc/sof/intel/pci-mtl.c +++ b/sound/soc/sof/intel/pci-mtl.c @@ -46,6 +46,7 @@ static const struct sof_dev_desc mtl_desc = { .nocodec_tplg_filename = "sof-mtl-nocodec.tplg", .ops = &sof_mtl_ops, .ops_init = sof_mtl_ops_init, + .ops_free = hda_ops_free, }; /* PCI IDs */ diff --git a/sound/soc/sof/intel/pci-skl.c b/sound/soc/sof/intel/pci-skl.c index 3a99dc444f92..5b4bccf81965 100644 --- a/sound/soc/sof/intel/pci-skl.c +++ b/sound/soc/sof/intel/pci-skl.c @@ -38,6 +38,7 @@ static struct sof_dev_desc skl_desc = { .nocodec_tplg_filename = "sof-skl-nocodec.tplg", .ops = &sof_skl_ops, .ops_init = sof_skl_ops_init, + .ops_free = hda_ops_free, }; static struct sof_dev_desc kbl_desc = { @@ -61,6 +62,7 @@ static struct sof_dev_desc kbl_desc = { .nocodec_tplg_filename = "sof-kbl-nocodec.tplg", .ops = &sof_skl_ops, .ops_init = sof_skl_ops_init, + .ops_free = hda_ops_free, }; /* PCI IDs */ diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index e80c4dfef85a..22e769e0831d 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -48,6 +48,7 @@ static const struct sof_dev_desc tgl_desc = { .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", .ops = &sof_tgl_ops, .ops_init = sof_tgl_ops_init, + .ops_free = hda_ops_free, }; static const struct sof_dev_desc tglh_desc = { @@ -110,6 +111,7 @@ static const struct sof_dev_desc ehl_desc = { .nocodec_tplg_filename = "sof-ehl-nocodec.tplg", .ops = &sof_tgl_ops, .ops_init = sof_tgl_ops_init, + .ops_free = hda_ops_free, }; static const struct sof_dev_desc adls_desc = { @@ -141,6 +143,7 @@ static const struct sof_dev_desc adls_desc = { .nocodec_tplg_filename = "sof-adl-nocodec.tplg", .ops = &sof_tgl_ops, .ops_init = sof_tgl_ops_init, + .ops_free = hda_ops_free, }; static const struct sof_dev_desc adl_desc = { @@ -172,6 +175,7 @@ static const struct sof_dev_desc adl_desc = { .nocodec_tplg_filename = "sof-adl-nocodec.tplg", .ops = &sof_tgl_ops, .ops_init = sof_tgl_ops_init, + .ops_free = hda_ops_free, }; static const struct sof_dev_desc adl_n_desc = { @@ -203,6 +207,7 @@ static const struct sof_dev_desc adl_n_desc = { .nocodec_tplg_filename = "sof-adl-nocodec.tplg", .ops = &sof_tgl_ops, .ops_init = sof_tgl_ops_init, + .ops_free = hda_ops_free, }; static const struct sof_dev_desc rpls_desc = { @@ -234,6 +239,7 @@ static const struct sof_dev_desc rpls_desc = { .nocodec_tplg_filename = "sof-rpl-nocodec.tplg", .ops = &sof_tgl_ops, .ops_init = sof_tgl_ops_init, + .ops_free = hda_ops_free, }; static const struct sof_dev_desc rpl_desc = { @@ -265,6 +271,7 @@ static const struct sof_dev_desc rpl_desc = { .nocodec_tplg_filename = "sof-rpl-nocodec.tplg", .ops = &sof_tgl_ops, .ops_init = sof_tgl_ops_init, + .ops_free = hda_ops_free, }; /* PCI IDs */ diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c index 5b2b409752c5..8c22a00266c0 100644 --- a/sound/soc/sof/intel/pci-tng.c +++ b/sound/soc/sof/intel/pci-tng.c @@ -75,11 +75,7 @@ static int tangier_pci_probe(struct snd_sof_dev *sdev) /* LPE base */ base = pci_resource_start(pci, desc->resindex_lpe_base) - IRAM_OFFSET; - size = pci_resource_len(pci, desc->resindex_lpe_base); - if (size < PCI_BAR_SIZE) { - dev_err(sdev->dev, "error: I/O region is too small.\n"); - return -ENODEV; - } + size = PCI_BAR_SIZE; dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); sdev->bar[DSP_BAR] = devm_ioremap(sdev->dev, base, size); diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index dceb78bfe17c..b1f425b39db9 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -2081,7 +2081,9 @@ static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * break; case SOF_DAI_INTEL_ALH: if (data) { - config->dai_index = data->dai_index; + /* save the dai_index during hw_params and reuse it for hw_free */ + if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) + config->dai_index = data->dai_index; config->alh.stream_id = data->dai_data; } break; @@ -2089,7 +2091,30 @@ static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * break; } - config->flags = flags; + /* + * The dai_config op is invoked several times and the flags argument varies as below: + * BE DAI hw_params: When the op is invoked during the BE DAI hw_params, flags contains + * SOF_DAI_CONFIG_FLAGS_HW_PARAMS along with quirks + * FE DAI hw_params: When invoked during FE DAI hw_params after the DAI widget has + * just been set up in the DSP, flags is set to SOF_DAI_CONFIG_FLAGS_HW_PARAMS with no + * quirks + * BE DAI trigger: When invoked during the BE DAI trigger, flags is set to + * SOF_DAI_CONFIG_FLAGS_PAUSE and contains no quirks + * BE DAI hw_free: When invoked during the BE DAI hw_free, flags is set to + * SOF_DAI_CONFIG_FLAGS_HW_FREE and contains no quirks + * FE DAI hw_free: When invoked during the FE DAI hw_free, flags is set to + * SOF_DAI_CONFIG_FLAGS_HW_FREE and contains no quirks + * + * The DAI_CONFIG IPC is sent to the DSP, only after the widget is set up during the FE + * DAI hw_params. But since the BE DAI hw_params precedes the FE DAI hw_params, the quirks + * need to be preserved when assigning the flags before sending the IPC. + * For the case of PAUSE/HW_FREE, since there are no quirks, flags can be used as is. + */ + + if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) + config->flags |= flags; + else + config->flags = flags; /* only send the IPC if the widget is set up in the DSP */ if (swidget->use_count > 0) { @@ -2097,6 +2122,9 @@ static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * &reply, sizeof(reply)); if (ret < 0) dev_err(sdev->dev, "Failed to set dai config for %s\n", dai->name); + + /* clear the flags once the IPC has been sent even if it fails */ + config->flags = SOF_DAI_CONFIG_FLAGS_NONE; } return ret; diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 3de64ea2dc9a..4493bbd7faf1 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -970,8 +970,9 @@ static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev) return; } - if (hdr.size < sizeof(hdr)) { - dev_err(sdev->dev, "The received message size is invalid\n"); + if (hdr.size < sizeof(hdr) || hdr.size > SOF_IPC_MSG_MAX_SIZE) { + dev_err(sdev->dev, "The received message size is invalid: %u\n", + hdr.size); return; } diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c index 38c2531e2f09..d26ed2a6029f 100644 --- a/sound/soc/sof/ipc4-control.c +++ b/sound/soc/sof/ipc4-control.c @@ -97,7 +97,8 @@ sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidge } /* set curve type and duration from topology */ - data.curve_duration = gain->data.curve_duration; + data.curve_duration_l = gain->data.curve_duration_l; + data.curve_duration_h = gain->data.curve_duration_h; data.curve_type = gain->data.curve_type; msg->data_ptr = &data; diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index d7ce95b9fa0f..7cc57e795f5a 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -111,7 +111,7 @@ static const struct sof_topology_token gain_tokens[] = { get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)}, {SOF_TKN_GAIN_RAMP_DURATION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_gain_data, curve_duration)}, + offsetof(struct sof_ipc4_gain_data, curve_duration_l)}, {SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)}, }; @@ -159,7 +159,7 @@ static void sof_ipc4_dbg_audio_format(struct device *dev, for (i = 0; i < num_format; i++, ptr = (u8 *)ptr + object_size) { fmt = ptr; dev_dbg(dev, - " #%d: %uKHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x)\n", + " #%d: %uHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x)\n", i, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map, fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg); } @@ -715,7 +715,7 @@ static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget) dev_dbg(scomp->dev, "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n", - swidget->widget->name, gain->data.curve_type, gain->data.curve_duration, + swidget->widget->name, gain->data.curve_type, gain->data.curve_duration_l, gain->data.init_val, gain->base_config.cpc); ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg); @@ -1003,6 +1003,7 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) ipc4_copier = dai->private; if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { + struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data; struct sof_ipc4_alh_configuration_blob *blob; unsigned int group_id; @@ -1012,6 +1013,9 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) ALH_MULTI_GTW_BASE; ida_free(&alh_group_ida, group_id); } + + /* clear the node ID */ + copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; } } @@ -2030,8 +2034,15 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * pipeline->skip_during_fe_trigger = true; fallthrough; case SOF_DAI_INTEL_ALH: - copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; - copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data); + /* + * Do not clear the node ID when this op is invoked with + * SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during + * unprepare. + */ + if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) { + copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; + copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data); + } break; case SOF_DAI_INTEL_DMIC: case SOF_DAI_INTEL_SSP: diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 7877f0638011..22900b572766 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -46,7 +46,7 @@ #define SOF_IPC4_NODE_INDEX_INTEL_SSP(x) (((x) & 0xf) << 4) /* Node ID for DMIC type DAI copiers */ -#define SOF_IPC4_NODE_INDEX_INTEL_DMIC(x) (((x) & 0x7) << 5) +#define SOF_IPC4_NODE_INDEX_INTEL_DMIC(x) ((x) & 0x7) #define SOF_IPC4_GAIN_ALL_CHANNELS_MASK 0xffffffff #define SOF_IPC4_VOL_ZERO_DB 0x7fffffff @@ -279,14 +279,16 @@ struct sof_ipc4_control_data { * @init_val: Initial value * @curve_type: Curve type * @reserved: reserved for future use - * @curve_duration: Curve duration + * @curve_duration_l: Curve duration low part + * @curve_duration_h: Curve duration high part */ struct sof_ipc4_gain_data { uint32_t channels; uint32_t init_val; uint32_t curve_type; uint32_t reserved; - uint32_t curve_duration; + uint32_t curve_duration_l; + uint32_t curve_duration_h; } __aligned(8); /** diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 760621bfc802..4f12e137ff63 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -50,9 +50,27 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev, /* reset route setup status for all routes that contain this widget */ sof_reset_route_setup_status(sdev, swidget); + /* free DAI config and continue to free widget even if it fails */ + if (WIDGET_IS_DAI(swidget->id)) { + struct snd_sof_dai_config_data data; + unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_FREE; + + data.dai_data = DMA_CHAN_INVALID; + + if (tplg_ops && tplg_ops->dai_config) { + err = tplg_ops->dai_config(sdev, swidget, flags, &data); + if (err < 0) + dev_err(sdev->dev, "failed to free config for widget %s\n", + swidget->widget->name); + } + } + /* continue to disable core even if IPC fails */ - if (tplg_ops && tplg_ops->widget_free) - err = tplg_ops->widget_free(sdev, swidget); + if (tplg_ops && tplg_ops->widget_free) { + ret = tplg_ops->widget_free(sdev, swidget); + if (ret < 0 && !err) + err = ret; + } /* * disable widget core. continue to route setup status and complete flag @@ -151,8 +169,12 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev, /* send config for DAI components */ if (WIDGET_IS_DAI(swidget->id)) { - unsigned int flags = SOF_DAI_CONFIG_FLAGS_NONE; + unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS; + /* + * The config flags saved during BE DAI hw_params will be used for IPC3. IPC4 does + * not use the flags argument. + */ if (tplg_ops && tplg_ops->dai_config) { ret = tplg_ops->dai_config(sdev, swidget, flags, NULL); if (ret < 0) @@ -258,9 +280,11 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget_list *list, int dir) { + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_soc_dapm_widget *widget; + struct snd_sof_route *sroute; struct snd_soc_dapm_path *p; - int ret; + int ret = 0; int i; /* @@ -303,6 +327,63 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, } } + /* + * The above loop handles connections between widgets that belong to the DAPM widget list. + * This is not sufficient to handle loopback cases between pipelines configured with + * different directions, e.g. a sidetone or an amplifier feedback connected to a speaker + * protection module. + */ + list_for_each_entry(sroute, &sdev->route_list, list) { + bool src_widget_in_dapm_list, sink_widget_in_dapm_list; + struct snd_sof_widget *swidget; + + if (sroute->setup) + continue; + + src_widget_in_dapm_list = widget_in_list(list, sroute->src_widget->widget); + sink_widget_in_dapm_list = widget_in_list(list, sroute->sink_widget->widget); + + /* + * if both source and sink are in the DAPM list, the route must already have been + * set up above. And if neither are in the DAPM list, the route shouldn't be + * handled now. + */ + if (src_widget_in_dapm_list == sink_widget_in_dapm_list) + continue; + + /* + * At this point either the source widget or the sink widget is in the DAPM list + * with a route that might need to be set up. Check the use_count of the widget + * that is not in the DAPM list to confirm if it is in use currently before setting + * up the route. + */ + if (src_widget_in_dapm_list) + swidget = sroute->sink_widget; + else + swidget = sroute->src_widget; + + mutex_lock(&swidget->setup_mutex); + if (!swidget->use_count) { + mutex_unlock(&swidget->setup_mutex); + continue; + } + + if (tplg_ops && tplg_ops->route_setup) { + /* + * this route will get freed when either the source widget or the sink + * widget is freed during hw_free + */ + ret = tplg_ops->route_setup(sdev, sroute); + if (!ret) + sroute->setup = true; + } + + mutex_unlock(&swidget->setup_mutex); + + if (ret < 0) + return ret; + } + return 0; } @@ -588,8 +669,8 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, dir, SOF_WIDGET_SETUP); if (ret < 0) { - ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, - dir, SOF_WIDGET_UNPREPARE); + sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, + dir, SOF_WIDGET_UNPREPARE); return ret; } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 4a62ccc71fcb..9f3a038fe21a 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1388,14 +1388,15 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, if (ret < 0) { dev_err(scomp->dev, "failed to parse component pin tokens for %s\n", w->name); - return ret; + goto widget_free; } if (swidget->num_sink_pins > SOF_WIDGET_MAX_NUM_PINS || swidget->num_source_pins > SOF_WIDGET_MAX_NUM_PINS) { dev_err(scomp->dev, "invalid pins for %s: [sink: %d, src: %d]\n", swidget->widget->name, swidget->num_sink_pins, swidget->num_source_pins); - return -EINVAL; + ret = -EINVAL; + goto widget_free; } if (swidget->num_sink_pins > 1) { @@ -1404,7 +1405,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, if (ret < 0) { dev_err(scomp->dev, "failed to parse sink pin binding for %s\n", w->name); - return ret; + goto widget_free; } } @@ -1414,7 +1415,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, if (ret < 0) { dev_err(scomp->dev, "failed to parse source pin binding for %s\n", w->name); - return ret; + goto widget_free; } } @@ -1436,9 +1437,8 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, case snd_soc_dapm_dai_out: dai = kzalloc(sizeof(*dai), GFP_KERNEL); if (!dai) { - kfree(swidget); - return -ENOMEM; - + ret = -ENOMEM; + goto widget_free; } ret = sof_widget_parse_tokens(scomp, swidget, tw, token_list, token_list_size); @@ -1496,8 +1496,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, tw->shift, swidget->id, tw->name, strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 ? tw->sname : "none"); - kfree(swidget); - return ret; + goto widget_free; } if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE)) { @@ -1518,10 +1517,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, if (ret) { dev_err(scomp->dev, "widget event binding failed for %s\n", swidget->widget->name); - kfree(swidget->private); - kfree(swidget->tuples); - kfree(swidget); - return ret; + goto free; } } } @@ -1532,10 +1528,8 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, spipe = kzalloc(sizeof(*spipe), GFP_KERNEL); if (!spipe) { - kfree(swidget->private); - kfree(swidget->tuples); - kfree(swidget); - return -ENOMEM; + ret = -ENOMEM; + goto free; } spipe->pipe_widget = swidget; @@ -1546,6 +1540,12 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, w->dobj.private = swidget; list_add(&swidget->list, &sdev->widget_list); return ret; +free: + kfree(swidget->private); + kfree(swidget->tuples); +widget_free: + kfree(swidget); + return ret; } static int sof_route_unload(struct snd_soc_component *scomp, |
