Merge tag 'asoc-fix-v5.5-rc6' of https://git.kernel.org/pub/scm/linux/kernel/git...
authorTakashi Iwai <tiwai@suse.de>
Thu, 16 Jan 2020 13:14:26 +0000 (14:14 +0100)
committerTakashi Iwai <tiwai@suse.de>
Thu, 16 Jan 2020 13:14:26 +0000 (14:14 +0100)
ASoC: Fixes for v5.5

This is mostly driver specific fixes, plus an error handling fix
in the core.  There is a rather large diffstat for the stm32 SAI
driver, this is a very large but mostly mechanical update which
wraps every register access in the driver to allow a fix to the
locking which avoids circular locks, the active change is much
smaller and more reasonably sized.

12 files changed:
sound/soc/codecs/cros_ec_codec.c
sound/soc/codecs/hdac_hda.c
sound/soc/codecs/msm8916-wcd-analog.c
sound/soc/codecs/msm8916-wcd-digital.c
sound/soc/codecs/rt5640.c
sound/soc/intel/boards/bytcht_es8316.c
sound/soc/soc-component.c
sound/soc/sof/intel/hda-codec.c
sound/soc/sof/intel/hda-loader.c
sound/soc/sti/uniperif_player.c
sound/soc/stm/stm32_adfsdm.c
sound/soc/stm/stm32_sai_sub.c

index 7b17f39..ce3ed05 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <crypto/hash.h>
 #include <crypto/sha.h>
+#include <linux/acpi.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/io.h>
@@ -1047,10 +1048,17 @@ static const struct of_device_id cros_ec_codec_of_match[] = {
 MODULE_DEVICE_TABLE(of, cros_ec_codec_of_match);
 #endif
 
+static const struct acpi_device_id cros_ec_codec_acpi_id[] = {
+       { "GOOG0013", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, cros_ec_codec_acpi_id);
+
 static struct platform_driver cros_ec_codec_platform_driver = {
        .driver = {
                .name = "cros-ec-codec",
                .of_match_table = of_match_ptr(cros_ec_codec_of_match),
+               .acpi_match_table = ACPI_PTR(cros_ec_codec_acpi_id),
        },
        .probe = cros_ec_codec_platform_probe,
 };
index 6803d39..4311015 100644 (file)
@@ -588,7 +588,9 @@ static int hdac_hda_dev_remove(struct hdac_device *hdev)
        struct hdac_hda_priv *hda_pvt;
 
        hda_pvt = dev_get_drvdata(&hdev->dev);
-       cancel_delayed_work_sync(&hda_pvt->codec.jackpoll_work);
+       if (hda_pvt && hda_pvt->codec.registered)
+               cancel_delayed_work_sync(&hda_pvt->codec.jackpoll_work);
+
        return 0;
 }
 
index f53235b..1f7964b 100644 (file)
@@ -396,9 +396,6 @@ static int pm8916_wcd_analog_enable_micbias_int(struct snd_soc_component
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               snd_soc_component_update_bits(component, CDC_A_MICB_1_INT_RBIAS,
-                                   MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
-                                   MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
                snd_soc_component_update_bits(component, reg, MICB_1_EN_PULL_DOWN_EN_MASK, 0);
                snd_soc_component_update_bits(component, CDC_A_MICB_1_EN,
                                    MICB_1_EN_OPA_STG2_TAIL_CURR_MASK,
@@ -448,6 +445,14 @@ static int pm8916_wcd_analog_enable_micbias_int1(struct
        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
        struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
 
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_component_update_bits(component, CDC_A_MICB_1_INT_RBIAS,
+                                   MICB_1_INT_TX1_INT_RBIAS_EN_MASK,
+                                   MICB_1_INT_TX1_INT_RBIAS_EN_ENABLE);
+               break;
+       }
+
        return pm8916_wcd_analog_enable_micbias_int(component, event, w->reg,
                                                     wcd->micbias1_cap_mode);
 }
@@ -558,6 +563,11 @@ static int pm8916_wcd_analog_enable_micbias_int2(struct
        struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
 
        switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_component_update_bits(component, CDC_A_MICB_1_INT_RBIAS,
+                                   MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
+                                   MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
+               break;
        case SND_SOC_DAPM_POST_PMU:
                pm8916_mbhc_configure_bias(wcd, true);
                break;
@@ -938,10 +948,10 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = {
 
        SND_SOC_DAPM_SUPPLY("MIC BIAS External1", CDC_A_MICB_1_EN, 7, 0,
                            pm8916_wcd_analog_enable_micbias_ext1,
-                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+                           SND_SOC_DAPM_POST_PMU),
        SND_SOC_DAPM_SUPPLY("MIC BIAS External2", CDC_A_MICB_2_EN, 7, 0,
                            pm8916_wcd_analog_enable_micbias_ext2,
-                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+                           SND_SOC_DAPM_POST_PMU),
 
        SND_SOC_DAPM_ADC_E("ADC1", NULL, CDC_A_TX_1_EN, 7, 0,
                           pm8916_wcd_analog_enable_adc,
index 58b2468..09fccac 100644 (file)
@@ -586,6 +586,12 @@ static int msm8916_wcd_digital_enable_interpolator(
                snd_soc_component_write(component, rx_gain_reg[w->shift],
                              snd_soc_component_read32(component, rx_gain_reg[w->shift]));
                break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_component_update_bits(component, LPASS_CDC_CLK_RX_RESET_CTL,
+                                             1 << w->shift, 1 << w->shift);
+               snd_soc_component_update_bits(component, LPASS_CDC_CLK_RX_RESET_CTL,
+                                             1 << w->shift, 0x0);
+               break;
        }
        return 0;
 }
index adbae1f..747ca24 100644 (file)
@@ -2432,6 +2432,13 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component)
 {
        struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 
+       /*
+        * soc_remove_component() force-disables jack and thus rt5640->jack
+        * could be NULL at the time of driver's module unloading.
+        */
+       if (!rt5640->jack)
+               return;
+
        disable_irq(rt5640->irq);
        rt5640_cancel_work(rt5640);
 
index 4661233..54e9745 100644 (file)
@@ -442,7 +442,8 @@ static const struct dmi_system_id byt_cht_es8316_quirk_table[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "IRBIS"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "NB41"),
                },
-               .driver_data = (void *)(BYT_CHT_ES8316_INTMIC_IN2_MAP
+               .driver_data = (void *)(BYT_CHT_ES8316_SSP0
+                                       | BYT_CHT_ES8316_INTMIC_IN2_MAP
                                        | BYT_CHT_ES8316_JD_INVERTED),
        },
        {       /* Teclast X98 Plus II */
index 9054558..b94680f 100644 (file)
@@ -539,6 +539,9 @@ void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_rtdcom_list *rtdcom;
        struct snd_soc_component *component;
 
+       if (!rtd->pcm)
+               return;
+
        for_each_rtd_components(rtd, rtdcom, component)
                if (component->driver->pcm_destruct)
                        component->driver->pcm_destruct(component, rtd->pcm);
index 827f84a..fbfa225 100644 (file)
 #define IDISP_VID_INTEL        0x80860000
 
 /* load the legacy HDA codec driver */
-#ifdef MODULE
-static void hda_codec_load_module(struct hda_codec *codec)
+static int hda_codec_load_module(struct hda_codec *codec)
 {
+#ifdef MODULE
        char alias[MODULE_NAME_LEN];
        const char *module = alias;
 
        snd_hdac_codec_modalias(&codec->core, alias, sizeof(alias));
        dev_dbg(&codec->core.dev, "loading codec module: %s\n", module);
        request_module(module);
-}
-#else
-static void hda_codec_load_module(struct hda_codec *codec) {}
 #endif
+       return device_attach(hda_codec_dev(codec));
+}
 
 /* enable controller wake up event for all codecs with jack connectors */
 void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev)
@@ -129,10 +128,16 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
        if ((mach_params && mach_params->common_hdmi_codec_drv) ||
            (resp & 0xFFFF0000) != IDISP_VID_INTEL) {
                hdev->type = HDA_DEV_LEGACY;
-               hda_codec_load_module(&hda_priv->codec);
+               ret = hda_codec_load_module(&hda_priv->codec);
+               /*
+                * handle ret==0 (no driver bound) as an error, but pass
+                * other return codes without modification
+                */
+               if (ret == 0)
+                       ret = -ENOENT;
        }
 
-       return 0;
+       return ret;
 #else
        hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL);
        if (!hdev)
index b178336..bae7ac3 100644 (file)
@@ -329,13 +329,13 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
                if (!ret)
                        break;
 
-               dev_err(sdev->dev, "error: Error code=0x%x: FW status=0x%x\n",
+               dev_dbg(sdev->dev, "iteration %d of Core En/ROM load failed: %d\n",
+                       i, ret);
+               dev_dbg(sdev->dev, "Error code=0x%x: FW status=0x%x\n",
                        snd_sof_dsp_read(sdev, HDA_DSP_BAR,
                                         HDA_DSP_SRAM_REG_ROM_ERROR),
                        snd_sof_dsp_read(sdev, HDA_DSP_BAR,
                                         HDA_DSP_SRAM_REG_ROM_STATUS));
-               dev_err(sdev->dev, "error: iteration %d of Core En/ROM load failed: %d\n",
-                       i, ret);
        }
 
        if (i == HDA_FW_BOOT_ATTEMPTS) {
index 48ea915..2ed92c9 100644 (file)
@@ -226,7 +226,6 @@ static void uni_player_set_channel_status(struct uniperif *player,
         * sampling frequency. If no sample rate is already specified, then
         * set one.
         */
-       mutex_lock(&player->ctrl_lock);
        if (runtime) {
                switch (runtime->rate) {
                case 22050:
@@ -303,7 +302,6 @@ static void uni_player_set_channel_status(struct uniperif *player,
                player->stream_settings.iec958.status[3 + (n * 4)] << 24;
                SET_UNIPERIF_CHANNEL_STA_REGN(player, n, status);
        }
-       mutex_unlock(&player->ctrl_lock);
 
        /* Update the channel status */
        if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
@@ -365,8 +363,10 @@ static int uni_player_prepare_iec958(struct uniperif *player,
 
        SET_UNIPERIF_CTRL_ZERO_STUFF_HW(player);
 
+       mutex_lock(&player->ctrl_lock);
        /* Update the channel status */
        uni_player_set_channel_status(player, runtime);
+       mutex_unlock(&player->ctrl_lock);
 
        /* Clear the user validity user bits */
        SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0);
@@ -598,7 +598,6 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol,
        iec958->status[1] = ucontrol->value.iec958.status[1];
        iec958->status[2] = ucontrol->value.iec958.status[2];
        iec958->status[3] = ucontrol->value.iec958.status[3];
-       mutex_unlock(&player->ctrl_lock);
 
        spin_lock_irqsave(&player->irq_lock, flags);
        if (player->substream && player->substream->runtime)
@@ -608,6 +607,8 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol,
                uni_player_set_channel_status(player, NULL);
 
        spin_unlock_irqrestore(&player->irq_lock, flags);
+       mutex_unlock(&player->ctrl_lock);
+
        return 0;
 }
 
index 81c407d..08696a4 100644 (file)
@@ -153,13 +153,13 @@ static const struct snd_soc_component_driver stm32_adfsdm_dai_component = {
        .name = "stm32_dfsdm_audio",
 };
 
-static void memcpy_32to16(void *dest, const void *src, size_t n)
+static void stm32_memcpy_32to16(void *dest, const void *src, size_t n)
 {
        unsigned int i = 0;
        u16 *d = (u16 *)dest, *s = (u16 *)src;
 
        s++;
-       for (i = n; i > 0; i--) {
+       for (i = n >> 1; i > 0; i--) {
                *d++ = *s++;
                s++;
        }
@@ -186,8 +186,8 @@ static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private)
 
        if ((priv->pos + src_size) > buff_size) {
                if (format == SNDRV_PCM_FORMAT_S16_LE)
-                       memcpy_32to16(&pcm_buff[priv->pos], src_buff,
-                                     buff_size - priv->pos);
+                       stm32_memcpy_32to16(&pcm_buff[priv->pos], src_buff,
+                                           buff_size - priv->pos);
                else
                        memcpy(&pcm_buff[priv->pos], src_buff,
                               buff_size - priv->pos);
@@ -196,8 +196,8 @@ static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private)
        }
 
        if (format == SNDRV_PCM_FORMAT_S16_LE)
-               memcpy_32to16(&pcm_buff[priv->pos],
-                             &src_buff[src_size - cur_size], cur_size);
+               stm32_memcpy_32to16(&pcm_buff[priv->pos],
+                                   &src_buff[src_size - cur_size], cur_size);
        else
                memcpy(&pcm_buff[priv->pos], &src_buff[src_size - cur_size],
                       cur_size);
index 48e629a..30bcd5d 100644 (file)
@@ -184,6 +184,56 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
        }
 }
 
+static int stm32_sai_sub_reg_up(struct stm32_sai_sub_data *sai,
+                               unsigned int reg, unsigned int mask,
+                               unsigned int val)
+{
+       int ret;
+
+       ret = clk_enable(sai->pdata->pclk);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_update_bits(sai->regmap, reg, mask, val);
+
+       clk_disable(sai->pdata->pclk);
+
+       return ret;
+}
+
+static int stm32_sai_sub_reg_wr(struct stm32_sai_sub_data *sai,
+                               unsigned int reg, unsigned int mask,
+                               unsigned int val)
+{
+       int ret;
+
+       ret = clk_enable(sai->pdata->pclk);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write_bits(sai->regmap, reg, mask, val);
+
+       clk_disable(sai->pdata->pclk);
+
+       return ret;
+}
+
+static int stm32_sai_sub_reg_rd(struct stm32_sai_sub_data *sai,
+                               unsigned int reg, unsigned int *val)
+{
+       int ret;
+
+       ret = clk_enable(sai->pdata->pclk);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_read(sai->regmap, reg, val);
+
+       clk_disable(sai->pdata->pclk);
+
+       return ret;
+}
+
 static const struct regmap_config stm32_sai_sub_regmap_config_f4 = {
        .reg_bits = 32,
        .reg_stride = 4,
@@ -295,7 +345,7 @@ static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai,
 
        mask = SAI_XCR1_MCKDIV_MASK(SAI_XCR1_MCKDIV_WIDTH(version));
        cr1 = SAI_XCR1_MCKDIV_SET(div);
-       ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, mask, cr1);
+       ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, mask, cr1);
        if (ret < 0)
                dev_err(&sai->pdev->dev, "Failed to update CR1 register\n");
 
@@ -372,8 +422,8 @@ static int stm32_sai_mclk_enable(struct clk_hw *hw)
 
        dev_dbg(&sai->pdev->dev, "Enable master clock\n");
 
-       return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
-                                 SAI_XCR1_MCKEN, SAI_XCR1_MCKEN);
+       return stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
+                                   SAI_XCR1_MCKEN, SAI_XCR1_MCKEN);
 }
 
 static void stm32_sai_mclk_disable(struct clk_hw *hw)
@@ -383,7 +433,7 @@ static void stm32_sai_mclk_disable(struct clk_hw *hw)
 
        dev_dbg(&sai->pdev->dev, "Disable master clock\n");
 
-       regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_MCKEN, 0);
+       stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, SAI_XCR1_MCKEN, 0);
 }
 
 static const struct clk_ops mclk_ops = {
@@ -446,15 +496,15 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
        unsigned int sr, imr, flags;
        snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
 
-       regmap_read(sai->regmap, STM_SAI_IMR_REGX, &imr);
-       regmap_read(sai->regmap, STM_SAI_SR_REGX, &sr);
+       stm32_sai_sub_reg_rd(sai, STM_SAI_IMR_REGX, &imr);
+       stm32_sai_sub_reg_rd(sai, STM_SAI_SR_REGX, &sr);
 
        flags = sr & imr;
        if (!flags)
                return IRQ_NONE;
 
-       regmap_write_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
-                         SAI_XCLRFR_MASK);
+       stm32_sai_sub_reg_wr(sai, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
+                            SAI_XCLRFR_MASK);
 
        if (!sai->substream) {
                dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
@@ -503,8 +553,8 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai,
        int ret;
 
        if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) {
-               ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
-                                        SAI_XCR1_NODIV,
+               ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
+                                          SAI_XCR1_NODIV,
                                         freq ? 0 : SAI_XCR1_NODIV);
                if (ret < 0)
                        return ret;
@@ -583,7 +633,7 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
 
        slotr_mask |= SAI_XSLOTR_SLOTEN_MASK;
 
-       regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX, slotr_mask, slotr);
+       stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX, slotr_mask, slotr);
 
        sai->slot_width = slot_width;
        sai->slots = slots;
@@ -665,7 +715,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        cr1_mask |= SAI_XCR1_CKSTR;
        frcr_mask |= SAI_XFRCR_FSPOL;
 
-       regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr);
+       stm32_sai_sub_reg_up(sai, STM_SAI_FRCR_REGX, frcr_mask, frcr);
 
        /* DAI clock master masks */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -693,7 +743,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        cr1_mask |= SAI_XCR1_SLAVE;
 
 conf_update:
-       ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
+       ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1);
        if (ret < 0) {
                dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
                return ret;
@@ -730,12 +780,12 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream,
        }
 
        /* Enable ITs */
-       regmap_write_bits(sai->regmap, STM_SAI_CLRFR_REGX,
-                         SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
+       stm32_sai_sub_reg_wr(sai, STM_SAI_CLRFR_REGX,
+                            SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
 
        imr = SAI_XIMR_OVRUDRIE;
        if (STM_SAI_IS_CAPTURE(sai)) {
-               regmap_read(sai->regmap, STM_SAI_CR2_REGX, &cr2);
+               stm32_sai_sub_reg_rd(sai, STM_SAI_CR2_REGX, &cr2);
                if (cr2 & SAI_XCR2_MUTECNT_MASK)
                        imr |= SAI_XIMR_MUTEDETIE;
        }
@@ -745,8 +795,8 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream,
        else
                imr |= SAI_XIMR_AFSDETIE | SAI_XIMR_LFSDETIE;
 
-       regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX,
-                          SAI_XIMR_MASK, imr);
+       stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX,
+                            SAI_XIMR_MASK, imr);
 
        return 0;
 }
@@ -763,10 +813,10 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
         * SAI fifo threshold is set to half fifo, to keep enough space
         * for DMA incoming bursts.
         */
-       regmap_write_bits(sai->regmap, STM_SAI_CR2_REGX,
-                         SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK,
-                         SAI_XCR2_FFLUSH |
-                         SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF));
+       stm32_sai_sub_reg_wr(sai, STM_SAI_CR2_REGX,
+                            SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK,
+                            SAI_XCR2_FFLUSH |
+                            SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF));
 
        /* DS bits in CR1 not set for SPDIF (size forced to 24 bits).*/
        if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
@@ -795,7 +845,7 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
        if ((sai->slots == 2) && (params_channels(params) == 1))
                cr1 |= SAI_XCR1_MONO;
 
-       ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
+       ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1);
        if (ret < 0) {
                dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
                return ret;
@@ -809,7 +859,7 @@ static int stm32_sai_set_slots(struct snd_soc_dai *cpu_dai)
        struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
        int slotr, slot_sz;
 
-       regmap_read(sai->regmap, STM_SAI_SLOTR_REGX, &slotr);
+       stm32_sai_sub_reg_rd(sai, STM_SAI_SLOTR_REGX, &slotr);
 
        /*
         * If SLOTSZ is set to auto in SLOTR, align slot width on data size
@@ -831,16 +881,16 @@ static int stm32_sai_set_slots(struct snd_soc_dai *cpu_dai)
                sai->slots = 2;
 
        /* The number of slots in the audio frame is equal to NBSLOT[3:0] + 1*/
-       regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX,
-                          SAI_XSLOTR_NBSLOT_MASK,
-                          SAI_XSLOTR_NBSLOT_SET((sai->slots - 1)));
+       stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX,
+                            SAI_XSLOTR_NBSLOT_MASK,
+                            SAI_XSLOTR_NBSLOT_SET((sai->slots - 1)));
 
        /* Set default slots mask if not already set from DT */
        if (!(slotr & SAI_XSLOTR_SLOTEN_MASK)) {
                sai->slot_mask = (1 << sai->slots) - 1;
-               regmap_update_bits(sai->regmap,
-                                  STM_SAI_SLOTR_REGX, SAI_XSLOTR_SLOTEN_MASK,
-                                  SAI_XSLOTR_SLOTEN_SET(sai->slot_mask));
+               stm32_sai_sub_reg_up(sai,
+                                    STM_SAI_SLOTR_REGX, SAI_XSLOTR_SLOTEN_MASK,
+                                    SAI_XSLOTR_SLOTEN_SET(sai->slot_mask));
        }
 
        dev_dbg(cpu_dai->dev, "Slots %d, slot width %d\n",
@@ -870,14 +920,14 @@ static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai)
        dev_dbg(cpu_dai->dev, "Frame length %d, frame active %d\n",
                sai->fs_length, fs_active);
 
-       regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr);
+       stm32_sai_sub_reg_up(sai, STM_SAI_FRCR_REGX, frcr_mask, frcr);
 
        if ((sai->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_LSB) {
                offset = sai->slot_width - sai->data_size;
 
-               regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX,
-                                  SAI_XSLOTR_FBOFF_MASK,
-                                  SAI_XSLOTR_FBOFF_SET(offset));
+               stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX,
+                                    SAI_XSLOTR_FBOFF_MASK,
+                                    SAI_XSLOTR_FBOFF_SET(offset));
        }
 }
 
@@ -994,9 +1044,9 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
                                        return -EINVAL;
                                }
 
-                               regmap_update_bits(sai->regmap,
-                                                  STM_SAI_CR1_REGX,
-                                                  SAI_XCR1_OSR, cr1);
+                               stm32_sai_sub_reg_up(sai,
+                                                    STM_SAI_CR1_REGX,
+                                                    SAI_XCR1_OSR, cr1);
 
                                div = stm32_sai_get_clk_div(sai, sai_clk_rate,
                                                            sai->mclk_rate);
@@ -1058,12 +1108,12 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                dev_dbg(cpu_dai->dev, "Enable DMA and SAI\n");
 
-               regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
-                                  SAI_XCR1_DMAEN, SAI_XCR1_DMAEN);
+               stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
+                                    SAI_XCR1_DMAEN, SAI_XCR1_DMAEN);
 
                /* Enable SAI */
-               ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
-                                        SAI_XCR1_SAIEN, SAI_XCR1_SAIEN);
+               ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
+                                          SAI_XCR1_SAIEN, SAI_XCR1_SAIEN);
                if (ret < 0)
                        dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
                break;
@@ -1072,16 +1122,16 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
        case SNDRV_PCM_TRIGGER_STOP:
                dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n");
 
-               regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX,
-                                  SAI_XIMR_MASK, 0);
+               stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX,
+                                    SAI_XIMR_MASK, 0);
 
-               regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
-                                  SAI_XCR1_SAIEN,
-                                  (unsigned int)~SAI_XCR1_SAIEN);
+               stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
+                                    SAI_XCR1_SAIEN,
+                                    (unsigned int)~SAI_XCR1_SAIEN);
 
-               ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
-                                        SAI_XCR1_DMAEN,
-                                        (unsigned int)~SAI_XCR1_DMAEN);
+               ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
+                                          SAI_XCR1_DMAEN,
+                                          (unsigned int)~SAI_XCR1_DMAEN);
                if (ret < 0)
                        dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
 
@@ -1101,7 +1151,7 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
        struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
        unsigned long flags;
 
-       regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0);
+       stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0);
 
        clk_disable_unprepare(sai->sai_ck);
 
@@ -1169,7 +1219,7 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
        cr1_mask |= SAI_XCR1_SYNCEN_MASK;
        cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
 
-       return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
+       return stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1);
 }
 
 static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
@@ -1322,8 +1372,13 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
        if (STM_SAI_HAS_PDM(sai) && STM_SAI_IS_SUB_A(sai))
                sai->regmap_config = &stm32_sai_sub_regmap_config_h7;
 
-       sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck",
-                                               base, sai->regmap_config);
+       /*
+        * Do not manage peripheral clock through regmap framework as this
+        * can lead to circular locking issue with sai master clock provider.
+        * Manage peripheral clock directly in driver instead.
+        */
+       sai->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+                                           sai->regmap_config);
        if (IS_ERR(sai->regmap)) {
                dev_err(&pdev->dev, "Failed to initialize MMIO\n");
                return PTR_ERR(sai->regmap);
@@ -1420,6 +1475,10 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
                return PTR_ERR(sai->sai_ck);
        }
 
+       ret = clk_prepare(sai->pdata->pclk);
+       if (ret < 0)
+               return ret;
+
        if (STM_SAI_IS_F4(sai->pdata))
                return 0;
 
@@ -1501,22 +1560,48 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
        return 0;
 }
 
+static int stm32_sai_sub_remove(struct platform_device *pdev)
+{
+       struct stm32_sai_sub_data *sai = dev_get_drvdata(&pdev->dev);
+
+       clk_unprepare(sai->pdata->pclk);
+
+       return 0;
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int stm32_sai_sub_suspend(struct device *dev)
 {
        struct stm32_sai_sub_data *sai = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_enable(sai->pdata->pclk);
+       if (ret < 0)
+               return ret;
 
        regcache_cache_only(sai->regmap, true);
        regcache_mark_dirty(sai->regmap);
+
+       clk_disable(sai->pdata->pclk);
+
        return 0;
 }
 
 static int stm32_sai_sub_resume(struct device *dev)
 {
        struct stm32_sai_sub_data *sai = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_enable(sai->pdata->pclk);
+       if (ret < 0)
+               return ret;
 
        regcache_cache_only(sai->regmap, false);
-       return regcache_sync(sai->regmap);
+       ret = regcache_sync(sai->regmap);
+
+       clk_disable(sai->pdata->pclk);
+
+       return ret;
 }
 #endif /* CONFIG_PM_SLEEP */
 
@@ -1531,6 +1616,7 @@ static struct platform_driver stm32_sai_sub_driver = {
                .pm = &stm32_sai_sub_pm_ops,
        },
        .probe = stm32_sai_sub_probe,
+       .remove = stm32_sai_sub_remove,
 };
 
 module_platform_driver(stm32_sai_sub_driver);