Merge tag 'asoc-fix-v5.4-rc4' of https://git.kernel.org/pub/scm/linux/kernel/git...
authorTakashi Iwai <tiwai@suse.de>
Mon, 21 Oct 2019 12:05:26 +0000 (14:05 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 21 Oct 2019 12:05:26 +0000 (14:05 +0200)
ASoC: Fixes for v5.4

A collection of fixes that have arrived since the merge window.  There
are a small number of core fixes here but they are smaller ones around
error handling.

26 files changed:
include/sound/simple_card_utils.h
sound/soc/codecs/max98373.c
sound/soc/codecs/msm8916-wcd-digital.c
sound/soc/codecs/rt5651.c
sound/soc/codecs/rt5682.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm_adsp.c
sound/soc/intel/boards/sof_rt5682.c
sound/soc/rockchip/rockchip_i2s.c
sound/soc/samsung/arndale_rt5631.c
sound/soc/sh/rcar/core.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/soc/sof/control.c
sound/soc/sof/intel/Kconfig
sound/soc/sof/intel/bdw.c
sound/soc/sof/intel/byt.c
sound/soc/sof/intel/hda-ctrl.c
sound/soc/sof/intel/hda-loader.c
sound/soc/sof/intel/hda-stream.c
sound/soc/sof/intel/hda.c
sound/soc/sof/intel/hda.h
sound/soc/sof/loader.c
sound/soc/sof/pcm.c
sound/soc/sof/topology.c
sound/soc/stm/stm32_sai_sub.c

index 985a5f583de4c7f10cf161267cd554999dad4bf8..31f76b6abf712463d4355c529be55e1519ed6dc7 100644 (file)
@@ -135,9 +135,9 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
                               struct link_info *li);
 
 #ifdef DEBUG
-inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,
-                                 char *name,
-                                 struct asoc_simple_dai *dai)
+static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,
+                                        char *name,
+                                        struct asoc_simple_dai *dai)
 {
        struct device *dev = simple_priv_to_dev(priv);
 
@@ -167,7 +167,7 @@ inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,
                dev_dbg(dev, "%s clk %luHz\n", name, clk_get_rate(dai->clk));
 }
 
-inline void asoc_simple_debug_info(struct asoc_simple_priv *priv)
+static inline void asoc_simple_debug_info(struct asoc_simple_priv *priv)
 {
        struct snd_soc_card *card = simple_priv_to_card(priv);
        struct device *dev = simple_priv_to_dev(priv);
index e609abcf3220e71f9c600cec0aebf71067fb2003..eb709d52825965f3c53aa7432e01191569ab3193 100644 (file)
@@ -901,16 +901,20 @@ static void max98373_slot_config(struct i2c_client *i2c,
                max98373->i_slot = value & 0xF;
        else
                max98373->i_slot = 1;
-
-       max98373->reset_gpio = of_get_named_gpio(dev->of_node,
+       if (dev->of_node) {
+               max98373->reset_gpio = of_get_named_gpio(dev->of_node,
                                                "maxim,reset-gpio", 0);
-       if (!gpio_is_valid(max98373->reset_gpio)) {
-               dev_err(dev, "Looking up %s property in node %s failed %d\n",
-                       "maxim,reset-gpio", dev->of_node->full_name,
-                       max98373->reset_gpio);
+               if (!gpio_is_valid(max98373->reset_gpio)) {
+                       dev_err(dev, "Looking up %s property in node %s failed %d\n",
+                               "maxim,reset-gpio", dev->of_node->full_name,
+                               max98373->reset_gpio);
+               } else {
+                       dev_dbg(dev, "maxim,reset-gpio=%d",
+                               max98373->reset_gpio);
+               }
        } else {
-               dev_dbg(dev, "maxim,reset-gpio=%d",
-                       max98373->reset_gpio);
+               /* this makes reset_gpio as invalid */
+               max98373->reset_gpio = -1;
        }
 
        if (!device_property_read_u32(dev, "maxim,spkfb-slot-no", &value))
index 9fa5d44fdc79f57a3b274393dea4cd7f08a4b2a5..58b2468fb2a7139b8d7dbb35085ecbe5acb8215f 100644 (file)
@@ -243,6 +243,10 @@ static const char *const rx_mix1_text[] = {
        "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
 };
 
+static const char * const rx_mix2_text[] = {
+       "ZERO", "IIR1", "IIR2"
+};
+
 static const char *const dec_mux_text[] = {
        "ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2"
 };
@@ -270,6 +274,16 @@ static const struct soc_enum rx3_mix1_inp_enum[] = {
        SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B2_CTL, 0, 6, rx_mix1_text),
 };
 
+/* RX1 MIX2 */
+static const struct soc_enum rx_mix2_inp1_chain_enum =
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B3_CTL,
+               0, 3, rx_mix2_text);
+
+/* RX2 MIX2 */
+static const struct soc_enum rx2_mix2_inp1_chain_enum =
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B3_CTL,
+               0, 3, rx_mix2_text);
+
 /* DEC */
 static const struct soc_enum dec1_mux_enum = SOC_ENUM_SINGLE(
                                LPASS_CDC_CONN_TX_B1_CTL, 0, 6, dec_mux_text);
@@ -309,6 +323,10 @@ static const struct snd_kcontrol_new rx3_mix1_inp2_mux = SOC_DAPM_ENUM(
                                "RX3 MIX1 INP2 Mux", rx3_mix1_inp_enum[1]);
 static const struct snd_kcontrol_new rx3_mix1_inp3_mux = SOC_DAPM_ENUM(
                                "RX3 MIX1 INP3 Mux", rx3_mix1_inp_enum[2]);
+static const struct snd_kcontrol_new rx1_mix2_inp1_mux = SOC_DAPM_ENUM(
+                               "RX1 MIX2 INP1 Mux", rx_mix2_inp1_chain_enum);
+static const struct snd_kcontrol_new rx2_mix2_inp1_mux = SOC_DAPM_ENUM(
+                               "RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
 
 /* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */
 static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0);
@@ -740,6 +758,10 @@ static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = {
                         &rx3_mix1_inp2_mux),
        SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
                         &rx3_mix1_inp3_mux),
+       SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+                        &rx1_mix2_inp1_mux),
+       SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+                        &rx2_mix2_inp1_mux),
 
        SND_SOC_DAPM_MUX("CIC1 MUX", SND_SOC_NOPM, 0, 0, &cic1_mux),
        SND_SOC_DAPM_MUX("CIC2 MUX", SND_SOC_NOPM, 0, 0, &cic2_mux),
index 762595de956c15662c245acf825c2cafb212b528..c506c9305043e115711cbac86fb22e77734b0d54 100644 (file)
@@ -1770,6 +1770,9 @@ static int rt5651_detect_headset(struct snd_soc_component *component)
 
 static bool rt5651_support_button_press(struct rt5651_priv *rt5651)
 {
+       if (!rt5651->hp_jack)
+               return false;
+
        /* Button press support only works with internal jack-detection */
        return (rt5651->hp_jack->status & SND_JACK_MICROPHONE) &&
                rt5651->gpiod_hp_det == NULL;
index 1ef470700ed5fea954321884d705fc50ba9ccc23..c50b75ce82e0b727cd91fb0d17caf93088890da1 100644 (file)
@@ -995,6 +995,16 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component,
 {
        struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
 
+       rt5682->hs_jack = hs_jack;
+
+       if (!hs_jack) {
+               regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
+                                  RT5682_JD1_EN_MASK, RT5682_JD1_DIS);
+               regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL,
+                                  RT5682_POW_JDH | RT5682_POW_JDL, 0);
+               return 0;
+       }
+
        switch (rt5682->pdata.jd_src) {
        case RT5682_JD1:
                snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_2,
@@ -1032,8 +1042,6 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component,
                break;
        }
 
-       rt5682->hs_jack = hs_jack;
-
        return 0;
 }
 
index c3d06e8bc54f20293f6490a56669e920eeae3a29..d5fb7f5dd551cb834ad77ae9b99ca453d7264008 100644 (file)
@@ -533,13 +533,10 @@ static SOC_ENUM_SINGLE_DECL(dac_osr,
 static SOC_ENUM_SINGLE_DECL(adc_osr,
                            WM8994_OVERSAMPLING, 1, osr_text);
 
-static const struct snd_kcontrol_new wm8994_snd_controls[] = {
+static const struct snd_kcontrol_new wm8994_common_snd_controls[] = {
 SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
                 WM8994_AIF1_ADC1_RIGHT_VOLUME,
                 1, 119, 0, digital_tlv),
-SOC_DOUBLE_R_TLV("AIF1ADC2 Volume", WM8994_AIF1_ADC2_LEFT_VOLUME,
-                WM8994_AIF1_ADC2_RIGHT_VOLUME,
-                1, 119, 0, digital_tlv),
 SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8994_AIF2_ADC_LEFT_VOLUME,
                 WM8994_AIF2_ADC_RIGHT_VOLUME,
                 1, 119, 0, digital_tlv),
@@ -556,8 +553,6 @@ SOC_ENUM("AIF2DACR Source", aif2dacr_src),
 
 SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8994_AIF1_DAC1_LEFT_VOLUME,
                 WM8994_AIF1_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
-SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME,
-                WM8994_AIF1_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
 SOC_DOUBLE_R_TLV("AIF2DAC Volume", WM8994_AIF2_DAC_LEFT_VOLUME,
                 WM8994_AIF2_DAC_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
 
@@ -565,17 +560,12 @@ SOC_SINGLE_TLV("AIF1 Boost Volume", WM8994_AIF1_CONTROL_2, 10, 3, 0, aif_tlv),
 SOC_SINGLE_TLV("AIF2 Boost Volume", WM8994_AIF2_CONTROL_2, 10, 3, 0, aif_tlv),
 
 SOC_SINGLE("AIF1DAC1 EQ Switch", WM8994_AIF1_DAC1_EQ_GAINS_1, 0, 1, 0),
-SOC_SINGLE("AIF1DAC2 EQ Switch", WM8994_AIF1_DAC2_EQ_GAINS_1, 0, 1, 0),
 SOC_SINGLE("AIF2 EQ Switch", WM8994_AIF2_EQ_GAINS_1, 0, 1, 0),
 
 WM8994_DRC_SWITCH("AIF1DAC1 DRC Switch", WM8994_AIF1_DRC1_1, 2),
 WM8994_DRC_SWITCH("AIF1ADC1L DRC Switch", WM8994_AIF1_DRC1_1, 1),
 WM8994_DRC_SWITCH("AIF1ADC1R DRC Switch", WM8994_AIF1_DRC1_1, 0),
 
-WM8994_DRC_SWITCH("AIF1DAC2 DRC Switch", WM8994_AIF1_DRC2_1, 2),
-WM8994_DRC_SWITCH("AIF1ADC2L DRC Switch", WM8994_AIF1_DRC2_1, 1),
-WM8994_DRC_SWITCH("AIF1ADC2R DRC Switch", WM8994_AIF1_DRC2_1, 0),
-
 WM8994_DRC_SWITCH("AIF2DAC DRC Switch", WM8994_AIF2_DRC_1, 2),
 WM8994_DRC_SWITCH("AIF2ADCL DRC Switch", WM8994_AIF2_DRC_1, 1),
 WM8994_DRC_SWITCH("AIF2ADCR DRC Switch", WM8994_AIF2_DRC_1, 0),
@@ -594,9 +584,6 @@ SOC_SINGLE("Sidetone HPF Switch", WM8994_SIDETONE, 6, 1, 0),
 SOC_ENUM("AIF1ADC1 HPF Mode", aif1adc1_hpf),
 SOC_DOUBLE("AIF1ADC1 HPF Switch", WM8994_AIF1_ADC1_FILTERS, 12, 11, 1, 0),
 
-SOC_ENUM("AIF1ADC2 HPF Mode", aif1adc2_hpf),
-SOC_DOUBLE("AIF1ADC2 HPF Switch", WM8994_AIF1_ADC2_FILTERS, 12, 11, 1, 0),
-
 SOC_ENUM("AIF2ADC HPF Mode", aif2adc_hpf),
 SOC_DOUBLE("AIF2ADC HPF Switch", WM8994_AIF2_ADC_FILTERS, 12, 11, 1, 0),
 
@@ -637,6 +624,24 @@ SOC_SINGLE("AIF2DAC 3D Stereo Switch", WM8994_AIF2_DAC_FILTERS_2,
           8, 1, 0),
 };
 
+/* Controls not available on WM1811 */
+static const struct snd_kcontrol_new wm8994_snd_controls[] = {
+SOC_DOUBLE_R_TLV("AIF1ADC2 Volume", WM8994_AIF1_ADC2_LEFT_VOLUME,
+                WM8994_AIF1_ADC2_RIGHT_VOLUME,
+                1, 119, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME,
+                WM8994_AIF1_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+
+SOC_SINGLE("AIF1DAC2 EQ Switch", WM8994_AIF1_DAC2_EQ_GAINS_1, 0, 1, 0),
+
+WM8994_DRC_SWITCH("AIF1DAC2 DRC Switch", WM8994_AIF1_DRC2_1, 2),
+WM8994_DRC_SWITCH("AIF1ADC2L DRC Switch", WM8994_AIF1_DRC2_1, 1),
+WM8994_DRC_SWITCH("AIF1ADC2R DRC Switch", WM8994_AIF1_DRC2_1, 0),
+
+SOC_ENUM("AIF1ADC2 HPF Mode", aif1adc2_hpf),
+SOC_DOUBLE("AIF1ADC2 HPF Switch", WM8994_AIF1_ADC2_FILTERS, 12, 11, 1, 0),
+};
+
 static const struct snd_kcontrol_new wm8994_eq_controls[] = {
 SOC_SINGLE_TLV("AIF1DAC1 EQ1 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 11, 31, 0,
               eq_tlv),
@@ -4258,13 +4263,15 @@ static int wm8994_component_probe(struct snd_soc_component *component)
        wm8994_handle_pdata(wm8994);
 
        wm_hubs_add_analogue_controls(component);
-       snd_soc_add_component_controls(component, wm8994_snd_controls,
-                            ARRAY_SIZE(wm8994_snd_controls));
+       snd_soc_add_component_controls(component, wm8994_common_snd_controls,
+                                      ARRAY_SIZE(wm8994_common_snd_controls));
        snd_soc_dapm_new_controls(dapm, wm8994_dapm_widgets,
                                  ARRAY_SIZE(wm8994_dapm_widgets));
 
        switch (control->type) {
        case WM8994:
+               snd_soc_add_component_controls(component, wm8994_snd_controls,
+                                              ARRAY_SIZE(wm8994_snd_controls));
                snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets,
                                          ARRAY_SIZE(wm8994_specific_dapm_widgets));
                if (control->revision < 4) {
@@ -4284,8 +4291,10 @@ static int wm8994_component_probe(struct snd_soc_component *component)
                }
                break;
        case WM8958:
+               snd_soc_add_component_controls(component, wm8994_snd_controls,
+                                              ARRAY_SIZE(wm8994_snd_controls));
                snd_soc_add_component_controls(component, wm8958_snd_controls,
-                                    ARRAY_SIZE(wm8958_snd_controls));
+                                              ARRAY_SIZE(wm8958_snd_controls));
                snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
                                          ARRAY_SIZE(wm8958_dapm_widgets));
                if (control->revision < 1) {
index ae28d9907c30f58f2bd5a1ee8588b8b03fb9c399..9b8bb7bbe945daa4ad22db1264b44b0ac7f3a0f9 100644 (file)
@@ -1259,8 +1259,7 @@ static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len)
        }
 
        if (in) {
-               if (in & WMFW_CTL_FLAG_READABLE)
-                       out |= rd;
+               out |= rd;
                if (in & WMFW_CTL_FLAG_WRITEABLE)
                        out |= wr;
                if (in & WMFW_CTL_FLAG_VOLATILE)
@@ -3697,11 +3696,16 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
        u32 xmalg, addr, magic;
        int i, ret;
 
+       alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
+       if (!alg_region) {
+               adsp_err(dsp, "No algorithm region found\n");
+               return -EINVAL;
+       }
+
        buf = wm_adsp_buffer_alloc(dsp);
        if (!buf)
                return -ENOMEM;
 
-       alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
        xmalg = dsp->ops->sys_config_size / sizeof(__be32);
 
        addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
index a437567b8cee233a0dbebd52dfe1c70fe952dcce..4f6e58c3954a220fd0050c5d8c29089c0ee16622 100644 (file)
@@ -308,6 +308,9 @@ static const struct snd_soc_dapm_widget sof_widgets[] = {
        SND_SOC_DAPM_HP("Headphone Jack", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
        SND_SOC_DAPM_SPK("Spk", NULL),
+};
+
+static const struct snd_soc_dapm_widget dmic_widgets[] = {
        SND_SOC_DAPM_MIC("SoC DMIC", NULL),
 };
 
@@ -318,10 +321,6 @@ static const struct snd_soc_dapm_route sof_map[] = {
 
        /* other jacks */
        { "IN1P", NULL, "Headset Mic" },
-
-       /* digital mics */
-       {"DMic", NULL, "SoC DMIC"},
-
 };
 
 static const struct snd_soc_dapm_route speaker_map[] = {
@@ -329,6 +328,11 @@ static const struct snd_soc_dapm_route speaker_map[] = {
        { "Spk", NULL, "Speaker" },
 };
 
+static const struct snd_soc_dapm_route dmic_map[] = {
+       /* digital mics */
+       {"DMic", NULL, "SoC DMIC"},
+};
+
 static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_card *card = rtd->card;
@@ -342,6 +346,28 @@ static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd)
        return ret;
 }
 
+static int dmic_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       int ret;
+
+       ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
+                                       ARRAY_SIZE(dmic_widgets));
+       if (ret) {
+               dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
+               /* Don't need to add routes if widget addition failed */
+               return ret;
+       }
+
+       ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
+                                     ARRAY_SIZE(dmic_map));
+
+       if (ret)
+               dev_err(card->dev, "DMic map addition failed: %d\n", ret);
+
+       return ret;
+}
+
 /* sof audio machine driver for rt5682 codec */
 static struct snd_soc_card sof_audio_card_rt5682 = {
        .name = "sof_rt5682",
@@ -445,6 +471,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                links[id].name = "dmic01";
                links[id].cpus = &cpus[id];
                links[id].cpus->dai_name = "DMIC01 Pin";
+               links[id].init = dmic_init;
                if (dmic_be_num > 1) {
                        /* set up 2 BE links at most */
                        links[id + 1].name = "dmic16k";
@@ -576,6 +603,15 @@ static int sof_audio_probe(struct platform_device *pdev)
        /* need to get main clock from pmc */
        if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) {
                ctx->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
+               if (IS_ERR(ctx->mclk)) {
+                       ret = PTR_ERR(ctx->mclk);
+
+                       dev_err(&pdev->dev,
+                               "Failed to get MCLK from pmc_plt_clk_3: %d\n",
+                               ret);
+                       return ret;
+               }
+
                ret = clk_prepare_enable(ctx->mclk);
                if (ret < 0) {
                        dev_err(&pdev->dev,
@@ -621,8 +657,24 @@ static int sof_audio_probe(struct platform_device *pdev)
                                          &sof_audio_card_rt5682);
 }
 
+static int sof_rt5682_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct snd_soc_component *component = NULL;
+
+       for_each_card_components(card, component) {
+               if (!strcmp(component->name, rt5682_component[0].name)) {
+                       snd_soc_component_set_jack(component, NULL, NULL);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
 static struct platform_driver sof_audio = {
        .probe = sof_audio_probe,
+       .remove = sof_rt5682_remove,
        .driver = {
                .name = "sof_rt5682",
                .pm = &snd_soc_pm_ops,
index af2d5a6124c8e122a8055d482b376d8df8be76c3..61c984f10d8e61199b7c02e287532039c6f3d9ed 100644 (file)
@@ -677,7 +677,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
        ret = rockchip_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "Could not register PCM\n");
-               return ret;
+               goto err_suspend;
        }
 
        return 0;
index c213913eb98488f709c097e6d91b9f298bba5399..fd8c6642fb0dfbceeeb8a9170461287643667289 100644 (file)
@@ -5,6 +5,7 @@
 //  Author: Claude <claude@insginal.co.kr>
 
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 
@@ -74,6 +75,17 @@ static struct snd_soc_card arndale_rt5631 = {
        .num_links = ARRAY_SIZE(arndale_rt5631_dai),
 };
 
+static void arndale_put_of_nodes(struct snd_soc_card *card)
+{
+       struct snd_soc_dai_link *dai_link;
+       int i;
+
+       for_each_card_prelinks(card, i, dai_link) {
+               of_node_put(dai_link->cpus->of_node);
+               of_node_put(dai_link->codecs->of_node);
+       }
+}
+
 static int arndale_audio_probe(struct platform_device *pdev)
 {
        int n, ret;
@@ -103,18 +115,31 @@ static int arndale_audio_probe(struct platform_device *pdev)
                if (!arndale_rt5631_dai[0].codecs->of_node) {
                        dev_err(&pdev->dev,
                        "Property 'samsung,audio-codec' missing or invalid\n");
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto err_put_of_nodes;
                }
        }
 
        ret = devm_snd_soc_register_card(card->dev, card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
+               goto err_put_of_nodes;
+       }
+       return 0;
 
-       if (ret)
-               dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
-
+err_put_of_nodes:
+       arndale_put_of_nodes(card);
        return ret;
 }
 
+static int arndale_audio_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       arndale_put_of_nodes(card);
+       return 0;
+}
+
 static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = {
        { .compatible = "samsung,arndale-rt5631", },
        { .compatible = "samsung,arndale-alc5631", },
@@ -129,6 +154,7 @@ static struct platform_driver arndale_audio_driver = {
                .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
        },
        .probe = arndale_audio_probe,
+       .remove = arndale_audio_remove,
 };
 
 module_platform_driver(arndale_audio_driver);
index bda5b958d0dc5c17b1681212fe5cb96377fd2b31..e9596c2096cd585334e6c99710cc6e3194a4f792 100644 (file)
@@ -761,6 +761,7 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        }
 
        /* set format */
+       rdai->bit_clk_inv = 0;
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
                rdai->sys_delay = 0;
index e163dde5eab1d708a98b0767318811fa4f2491d8..b600d3eaaf5cd2c2c97c1a42e3d091f75970001a 100644 (file)
@@ -1070,7 +1070,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                        return ret;
        }
 
-       snd_soc_dai_trigger(cpu_dai, substream, cmd);
+       ret = snd_soc_dai_trigger(cpu_dai, substream, cmd);
        if (ret < 0)
                return ret;
 
@@ -1097,7 +1097,7 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
                        return ret;
        }
 
-       snd_soc_dai_bespoke_trigger(cpu_dai, substream, cmd);
+       ret = snd_soc_dai_bespoke_trigger(cpu_dai, substream, cmd);
        if (ret < 0)
                return ret;
 
@@ -1146,6 +1146,7 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
 {
        struct snd_soc_dpcm *dpcm;
        unsigned long flags;
+       char *name;
 
        /* only add new dpcms */
        for_each_dpcm_be(fe, stream, dpcm) {
@@ -1171,9 +1172,15 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
                        stream ? "<-" : "->", be->dai_link->name);
 
 #ifdef CONFIG_DEBUG_FS
-       dpcm->debugfs_state = debugfs_create_dir(be->dai_link->name,
-                                                fe->debugfs_dpcm_root);
-       debugfs_create_u32("state", 0644, dpcm->debugfs_state, &dpcm->state);
+       name = kasprintf(GFP_KERNEL, "%s:%s", be->dai_link->name,
+                        stream ? "capture" : "playback");
+       if (name) {
+               dpcm->debugfs_state = debugfs_create_dir(name,
+                                                        fe->debugfs_dpcm_root);
+               debugfs_create_u32("state", 0644, dpcm->debugfs_state,
+                                  &dpcm->state);
+               kfree(name);
+       }
 #endif
        return 1;
 }
index aa9a1fca46fa7832271ff0d3919959f94dfaa0a4..0fd032914a318b39d46f89ac8af1435de11ebba1 100644 (file)
@@ -1582,7 +1582,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
 
        /* map user to kernel widget ID */
        template.id = get_widget_id(le32_to_cpu(w->id));
-       if (template.id < 0)
+       if ((int)template.id < 0)
                return template.id;
 
        /* strings are allocated here, but used and freed by the widget */
index a4983f90ff5b31694197b2d72c6e1cdf309e8fb9..2b8711eda362b97362ef2501080c099b7616bc52 100644 (file)
@@ -60,13 +60,16 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
        struct snd_sof_dev *sdev = scontrol->sdev;
        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
        unsigned int i, channels = scontrol->num_channels;
+       bool change = false;
+       u32 value;
 
        /* update each channel */
        for (i = 0; i < channels; i++) {
-               cdata->chanv[i].value =
-                       mixer_to_ipc(ucontrol->value.integer.value[i],
+               value = mixer_to_ipc(ucontrol->value.integer.value[i],
                                     scontrol->volume_table, sm->max + 1);
+               change = change || (value != cdata->chanv[i].value);
                cdata->chanv[i].channel = i;
+               cdata->chanv[i].value = value;
        }
 
        /* notify DSP of mixer updates */
@@ -76,8 +79,7 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
                                              SOF_CTRL_TYPE_VALUE_CHAN_GET,
                                              SOF_CTRL_CMD_VOLUME,
                                              true);
-
-       return 0;
+       return change;
 }
 
 int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
@@ -105,11 +107,15 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
        struct snd_sof_dev *sdev = scontrol->sdev;
        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
        unsigned int i, channels = scontrol->num_channels;
+       bool change = false;
+       u32 value;
 
        /* update each channel */
        for (i = 0; i < channels; i++) {
-               cdata->chanv[i].value = ucontrol->value.integer.value[i];
+               value = ucontrol->value.integer.value[i];
+               change = change || (value != cdata->chanv[i].value);
                cdata->chanv[i].channel = i;
+               cdata->chanv[i].value = value;
        }
 
        /* notify DSP of mixer updates */
@@ -120,7 +126,7 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
                                              SOF_CTRL_CMD_SWITCH,
                                              true);
 
-       return 0;
+       return change;
 }
 
 int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
@@ -148,11 +154,15 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
        struct snd_sof_dev *sdev = scontrol->sdev;
        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
        unsigned int i, channels = scontrol->num_channels;
+       bool change = false;
+       u32 value;
 
        /* update each channel */
        for (i = 0; i < channels; i++) {
-               cdata->chanv[i].value = ucontrol->value.enumerated.item[i];
+               value = ucontrol->value.enumerated.item[i];
+               change = change || (value != cdata->chanv[i].value);
                cdata->chanv[i].channel = i;
+               cdata->chanv[i].value = value;
        }
 
        /* notify DSP of enum updates */
@@ -163,7 +173,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
                                              SOF_CTRL_CMD_ENUM,
                                              true);
 
-       return 0;
+       return change;
 }
 
 int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
index 479ba249e219af3ac4acbcd4f52622e51539d601..d62f51d33be148531916c887e6aa046328f5c2dc 100644 (file)
@@ -273,6 +273,16 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC
          Say Y if you want to enable HDAudio codecs with SOF.
          If unsure select "N".
 
+config SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1
+       bool "SOF enable DMI Link L1"
+       help
+         This option enables DMI L1 for both playback and capture
+         and disables known workarounds for specific HDaudio platforms.
+         Only use to look into power optimizations on platforms not
+         affected by DMI L1 issues. This option is not recommended.
+         Say Y if you want to enable DMI Link L1
+         If unsure, select "N".
+
 endif ## SND_SOC_SOF_HDA_COMMON
 
 config SND_SOC_SOF_HDA_LINK_BASELINE
index e282179263e8346f18a24d36389c2a71c8db9f47..80e2826fb447b28524268ccbf598f5f73e75abd7 100644 (file)
@@ -37,6 +37,7 @@
 #define MBOX_SIZE       0x1000
 #define MBOX_DUMP_SIZE 0x30
 #define EXCEPT_OFFSET  0x800
+#define EXCEPT_MAX_HDR_SIZE    0x400
 
 /* DSP peripherals */
 #define DMAC0_OFFSET    0xFE000
@@ -228,6 +229,11 @@ static void bdw_get_registers(struct snd_sof_dev *sdev,
        /* note: variable AR register array is not read */
 
        /* then get panic info */
+       if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) {
+               dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n",
+                       xoops->arch_hdr.totalsize);
+               return;
+       }
        offset += xoops->arch_hdr.totalsize;
        sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info));
 
@@ -451,6 +457,7 @@ static int bdw_probe(struct snd_sof_dev *sdev)
        /* TODO: add offsets */
        sdev->mmio_bar = BDW_DSP_BAR;
        sdev->mailbox_bar = BDW_DSP_BAR;
+       sdev->dsp_oops_offset = MBOX_OFFSET;
 
        /* PCI base */
        mmio = platform_get_resource(pdev, IORESOURCE_MEM,
index 5e7a6aaa627a82490448b9a0ce549eb47b08264e..a1e514f7173952fe899923bd9ffda4009753674f 100644 (file)
@@ -28,6 +28,7 @@
 #define MBOX_OFFSET            0x144000
 #define MBOX_SIZE              0x1000
 #define EXCEPT_OFFSET          0x800
+#define EXCEPT_MAX_HDR_SIZE    0x400
 
 /* DSP peripherals */
 #define DMAC0_OFFSET           0x098000
@@ -126,6 +127,11 @@ static void byt_get_registers(struct snd_sof_dev *sdev,
        /* note: variable AR register array is not read */
 
        /* then get panic info */
+       if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) {
+               dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n",
+                       xoops->arch_hdr.totalsize);
+               return;
+       }
        offset += xoops->arch_hdr.totalsize;
        sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info));
 
index bc41028a7a01de3d101412ebec768aeb3aa21d6f..df1909e1d95060b0b4ddba11d0294b490dca4b03 100644 (file)
@@ -139,20 +139,16 @@ void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable)
  */
 int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
 {
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       struct hdac_bus *bus = sof_to_bus(sdev);
-#endif
        u32 val;
 
        /* enable/disable audio dsp clock gating */
        val = enable ? PCI_CGCTL_ADSPDCGE : 0;
        snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val);
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       /* enable/disable L1 support */
-       val = enable ? SOF_HDA_VS_EM2_L1SEN : 0;
-       snd_hdac_chip_updatel(bus, VS_EM2, SOF_HDA_VS_EM2_L1SEN, val);
-#endif
+       /* enable/disable DMI Link L1 support */
+       val = enable ? HDA_VS_INTEL_EM2_L1SEN : 0;
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2,
+                               HDA_VS_INTEL_EM2_L1SEN, val);
 
        /* enable/disable audio dsp power gating */
        val = enable ? 0 : PCI_PGCTL_ADSPPGD;
index 6427f0b3a2f113b7a7a13e65ce66e3e9c7ac8fc0..65c2af3fcaab71ebc559d8e2a4a1b8e9b173b5d1 100644 (file)
@@ -44,6 +44,7 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
                return -ENODEV;
        }
        hstream = &dsp_stream->hstream;
+       hstream->substream = NULL;
 
        /* allocate DMA buffer */
        ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab);
index ad8d41f22e92ddcf958cd6ac7f4d13f789d8a5f8..2c744718840254fc30eec8a12dc39ac45d014a14 100644 (file)
@@ -185,6 +185,17 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction)
                        direction == SNDRV_PCM_STREAM_PLAYBACK ?
                        "playback" : "capture");
 
+       /*
+        * Disable DMI Link L1 entry when capture stream is opened.
+        * Workaround to address a known issue with host DMA that results
+        * in xruns during pause/release in capture scenarios.
+        */
+       if (!IS_ENABLED(SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1))
+               if (stream && direction == SNDRV_PCM_STREAM_CAPTURE)
+                       snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
+                                               HDA_VS_INTEL_EM2,
+                                               HDA_VS_INTEL_EM2_L1SEN, 0);
+
        return stream;
 }
 
@@ -193,23 +204,43 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag)
 {
        struct hdac_bus *bus = sof_to_bus(sdev);
        struct hdac_stream *s;
+       bool active_capture_stream = false;
+       bool found = false;
 
        spin_lock_irq(&bus->reg_lock);
 
-       /* find used stream */
+       /*
+        * close stream matching the stream tag
+        * and check if there are any open capture streams.
+        */
        list_for_each_entry(s, &bus->stream_list, list) {
-               if (s->direction == direction &&
-                   s->opened && s->stream_tag == stream_tag) {
+               if (!s->opened)
+                       continue;
+
+               if (s->direction == direction && s->stream_tag == stream_tag) {
                        s->opened = false;
-                       spin_unlock_irq(&bus->reg_lock);
-                       return 0;
+                       found = true;
+               } else if (s->direction == SNDRV_PCM_STREAM_CAPTURE) {
+                       active_capture_stream = true;
                }
        }
 
        spin_unlock_irq(&bus->reg_lock);
 
-       dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag);
-       return -ENODEV;
+       /* Enable DMI L1 entry if there are no capture streams open */
+       if (!IS_ENABLED(SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1))
+               if (!active_capture_stream)
+                       snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
+                                               HDA_VS_INTEL_EM2,
+                                               HDA_VS_INTEL_EM2_L1SEN,
+                                               HDA_VS_INTEL_EM2_L1SEN);
+
+       if (!found) {
+               dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag);
+               return -ENODEV;
+       }
+
+       return 0;
 }
 
 int hda_dsp_stream_trigger(struct snd_sof_dev *sdev,
index c72e9a09eee16a03da41267f127fdf0dbfc1b95d..06e84679087bc6bcb81a9988195475e6f042a354 100644 (file)
@@ -35,6 +35,8 @@
 #define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348)
 #define IS_CNL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9dc8)
 
+#define EXCEPT_MAX_HDR_SIZE    0x400
+
 /*
  * Debug
  */
@@ -131,6 +133,11 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
        /* note: variable AR register array is not read */
 
        /* then get panic info */
+       if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) {
+               dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n",
+                       xoops->arch_hdr.totalsize);
+               return;
+       }
        offset += xoops->arch_hdr.totalsize;
        sof_block_read(sdev, sdev->mmio_bar, offset,
                       panic_info, sizeof(*panic_info));
index 5591841a1b6faf9a72aec8a94b9082e1561f1e75..23e430d3e056881853cc193e549ede0334b624da 100644 (file)
@@ -39,7 +39,6 @@
 #define SOF_HDA_WAKESTS                        0x0E
 #define SOF_HDA_WAKESTS_INT_MASK       ((1 << 8) - 1)
 #define SOF_HDA_RIRBSTS                        0x5d
-#define SOF_HDA_VS_EM2_L1SEN            BIT(13)
 
 /* SOF_HDA_GCTL register bist */
 #define SOF_HDA_GCTL_RESET             BIT(0)
 #define HDA_DSP_REG_HIPCIE             (HDA_DSP_IPC_BASE + 0x0C)
 #define HDA_DSP_REG_HIPCCTL            (HDA_DSP_IPC_BASE + 0x10)
 
+/* Intel Vendor Specific Registers */
+#define HDA_VS_INTEL_EM2               0x1030
+#define HDA_VS_INTEL_EM2_L1SEN         BIT(13)
+
 /*  HIPCI */
 #define HDA_DSP_REG_HIPCI_BUSY         BIT(31)
 #define HDA_DSP_REG_HIPCI_MSG_MASK     0x7FFFFFFF
index d7f32745fefe42a793baf869c33318b57a9e44a0..9a9a381a908dee467665c979fecc7d31fb58e3bc 100644 (file)
@@ -546,10 +546,10 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
                                 msecs_to_jiffies(sdev->boot_timeout));
        if (ret == 0) {
                dev_err(sdev->dev, "error: firmware boot failure\n");
-               /* after this point FW_READY msg should be ignored */
-               sdev->boot_complete = true;
                snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
                        SOF_DBG_TEXT | SOF_DBG_PCI);
+               /* after this point FW_READY msg should be ignored */
+               sdev->boot_complete = true;
                return -EIO;
        }
 
index e3f6a6dc0f368af0614c1080cbfb678f9e832958..2b876d4974476bd359d4f530cabfeb92776b3164 100644 (file)
@@ -244,7 +244,7 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream)
                snd_soc_rtdcom_lookup(rtd, DRV_NAME);
        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
        struct snd_sof_pcm *spcm;
-       int ret;
+       int ret, err = 0;
 
        /* nothing to do for BE */
        if (rtd->dai_link->no_pcm)
@@ -254,26 +254,26 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream)
        if (!spcm)
                return -EINVAL;
 
-       if (!spcm->prepared[substream->stream])
-               return 0;
-
        dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id,
                substream->stream);
 
-       ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
+       if (spcm->prepared[substream->stream]) {
+               ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
+               if (ret < 0)
+                       err = ret;
+       }
 
        snd_pcm_lib_free_pages(substream);
 
        cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work);
 
-       if (ret < 0)
-               return ret;
-
        ret = snd_sof_pcm_platform_hw_free(sdev, substream);
-       if (ret < 0)
+       if (ret < 0) {
                dev_err(sdev->dev, "error: platform hw free failed\n");
+               err = ret;
+       }
 
-       return ret;
+       return err;
 }
 
 static int sof_pcm_prepare(struct snd_pcm_substream *substream)
@@ -323,6 +323,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        struct sof_ipc_stream stream;
        struct sof_ipc_reply reply;
        bool reset_hw_params = false;
+       bool ipc_first = false;
        int ret;
 
        /* nothing to do for BE */
@@ -343,6 +344,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE;
+               ipc_first = true;
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE;
@@ -363,6 +365,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
                stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
+               ipc_first = true;
                reset_hw_params = true;
                break;
        default:
@@ -370,12 +373,22 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                return -EINVAL;
        }
 
-       snd_sof_pcm_platform_trigger(sdev, substream, cmd);
+       /*
+        * DMA and IPC sequence is different for start and stop. Need to send
+        * STOP IPC before stop DMA
+        */
+       if (!ipc_first)
+               snd_sof_pcm_platform_trigger(sdev, substream, cmd);
 
        /* send IPC to the DSP */
        ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
                                 sizeof(stream), &reply, sizeof(reply));
 
+       /* need to STOP DMA even if STOP IPC failed */
+       if (ipc_first)
+               snd_sof_pcm_platform_trigger(sdev, substream, cmd);
+
+       /* free PCM if reset_hw_params is set and the STOP IPC is successful */
        if (!ret && reset_hw_params)
                ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
 
index fc85efbad378c7308e4c410b5a9e6f6d3683c07b..0aabb3190ddc9735aebdbc494805a28f9b97d035 100644 (file)
@@ -920,7 +920,9 @@ static void sof_parse_word_tokens(struct snd_soc_component *scomp,
                for (j = 0; j < count; j++) {
                        /* match token type */
                        if (!(tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_WORD ||
-                             tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_SHORT))
+                             tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_SHORT ||
+                             tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_BYTE ||
+                             tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_BOOL))
                                continue;
 
                        /* match token id */
index d7501f88aaa630afb61fe87352eb1bcb287b9700..a4060813bc74c7b088bdebfa39dc1d624a2b3cc6 100644 (file)
@@ -505,10 +505,20 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai,
        if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) {
                ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
                                         SAI_XCR1_NODIV,
-                                        (unsigned int)~SAI_XCR1_NODIV);
+                                        freq ? 0 : SAI_XCR1_NODIV);
                if (ret < 0)
                        return ret;
 
+               /* Assume shutdown if requested frequency is 0Hz */
+               if (!freq) {
+                       /* Release mclk rate only if rate was actually set */
+                       if (sai->mclk_rate) {
+                               clk_rate_exclusive_put(sai->sai_mclk);
+                               sai->mclk_rate = 0;
+                       }
+                       return 0;
+               }
+
                /* If master clock is used, set parent clock now */
                ret = stm32_sai_set_parent_clock(sai, freq);
                if (ret)
@@ -1093,15 +1103,6 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
 
        regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0);
 
-       regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV,
-                          SAI_XCR1_NODIV);
-
-       /* Release mclk rate only if rate was actually set */
-       if (sai->mclk_rate) {
-               clk_rate_exclusive_put(sai->sai_mclk);
-               sai->mclk_rate = 0;
-       }
-
        clk_disable_unprepare(sai->sai_ck);
 
        spin_lock_irqsave(&sai->irq_lock, flags);