Merge branch 'for-5.4' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorMark Brown <broonie@kernel.org>
Wed, 6 Nov 2019 16:29:34 +0000 (16:29 +0000)
committerMark Brown <broonie@kernel.org>
Wed, 6 Nov 2019 16:29:34 +0000 (16:29 +0000)
13 files changed:
1  2 
include/sound/simple_card_utils.h
sound/core/compress_offload.c
sound/soc/codecs/hdac_hda.c
sound/soc/codecs/msm8916-wcd-analog.c
sound/soc/intel/boards/sof_rt5682.c
sound/soc/rockchip/rockchip_max98090.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/dma.c
sound/soc/soc-pcm.c
sound/soc/sof/control.c
sound/soc/sof/debug.c
sound/soc/sof/intel/hda-stream.c
sound/soc/sof/ipc.c

index 293ff8115960f14312015a1267785e7aa9b1fd86,31f76b6abf712463d4355c529be55e1519ed6dc7..bbdd1542d6f130a5efdf44378bde5e950d0f61b0
@@@ -8,7 -8,6 +8,7 @@@
  #ifndef __SIMPLE_CARD_UTILS_H
  #define __SIMPLE_CARD_UTILS_H
  
 +#include <linux/clk.h>
  #include <sound/soc.h>
  
  #define asoc_simple_init_hp(card, sjack, prefix) \
@@@ -136,9 -135,9 +136,9 @@@ int asoc_simple_init_priv(struct asoc_s
                               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);
  
                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 41905afada63fee667d34478301217e05b98d3c5,942af8c29b79f6a87331874898732eb6434c5335..f34ce564d92c481791c4121c5b4c8b64f953be9e
@@@ -528,7 -528,7 +528,7 @@@ static int snd_compress_check_input(str
  {
        /* first let's check the buffer parameter's */
        if (params->buffer.fragment_size == 0 ||
-           params->buffer.fragments > INT_MAX / params->buffer.fragment_size ||
+           params->buffer.fragments > U32_MAX / params->buffer.fragment_size ||
            params->buffer.fragments == 0)
                return -EINVAL;
  
@@@ -574,7 -574,10 +574,7 @@@ snd_compr_set_params(struct snd_compr_s
                stream->metadata_set = false;
                stream->next_track = false;
  
 -              if (stream->direction == SND_COMPRESS_PLAYBACK)
 -                      stream->runtime->state = SNDRV_PCM_STATE_SETUP;
 -              else
 -                      stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
 +              stream->runtime->state = SNDRV_PCM_STATE_SETUP;
        } else {
                return -EPERM;
        }
@@@ -690,17 -693,8 +690,17 @@@ static int snd_compr_start(struct snd_c
  {
        int retval;
  
 -      if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED)
 +      switch (stream->runtime->state) {
 +      case SNDRV_PCM_STATE_SETUP:
 +              if (stream->direction != SND_COMPRESS_CAPTURE)
 +                      return -EPERM;
 +              break;
 +      case SNDRV_PCM_STATE_PREPARED:
 +              break;
 +      default:
                return -EPERM;
 +      }
 +
        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START);
        if (!retval)
                stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
@@@ -711,15 -705,9 +711,15 @@@ static int snd_compr_stop(struct snd_co
  {
        int retval;
  
 -      if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
 -                      stream->runtime->state == SNDRV_PCM_STATE_SETUP)
 +      switch (stream->runtime->state) {
 +      case SNDRV_PCM_STATE_OPEN:
 +      case SNDRV_PCM_STATE_SETUP:
 +      case SNDRV_PCM_STATE_PREPARED:
                return -EPERM;
 +      default:
 +              break;
 +      }
 +
        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
        if (!retval) {
                snd_compr_drain_notify(stream);
@@@ -807,17 -795,9 +807,17 @@@ static int snd_compr_drain(struct snd_c
  {
        int retval;
  
 -      if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
 -                      stream->runtime->state == SNDRV_PCM_STATE_SETUP)
 +      switch (stream->runtime->state) {
 +      case SNDRV_PCM_STATE_OPEN:
 +      case SNDRV_PCM_STATE_SETUP:
 +      case SNDRV_PCM_STATE_PREPARED:
 +      case SNDRV_PCM_STATE_PAUSED:
                return -EPERM;
 +      case SNDRV_PCM_STATE_XRUN:
 +              return -EPIPE;
 +      default:
 +              break;
 +      }
  
        retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
        if (retval) {
@@@ -837,10 -817,6 +837,10 @@@ static int snd_compr_next_track(struct 
        if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
                return -EPERM;
  
 +      /* next track doesn't have any meaning for capture streams */
 +      if (stream->direction == SND_COMPRESS_CAPTURE)
 +              return -EPERM;
 +
        /* you can signal next track if this is intended to be a gapless stream
         * and current track metadata is set
         */
  static int snd_compr_partial_drain(struct snd_compr_stream *stream)
  {
        int retval;
 -      if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
 -                      stream->runtime->state == SNDRV_PCM_STATE_SETUP)
 +
 +      switch (stream->runtime->state) {
 +      case SNDRV_PCM_STATE_OPEN:
 +      case SNDRV_PCM_STATE_SETUP:
 +      case SNDRV_PCM_STATE_PREPARED:
 +      case SNDRV_PCM_STATE_PAUSED:
 +              return -EPERM;
 +      case SNDRV_PCM_STATE_XRUN:
 +              return -EPIPE;
 +      default:
 +              break;
 +      }
 +
 +      /* partial drain doesn't have any meaning for capture streams */
 +      if (stream->direction == SND_COMPRESS_CAPTURE)
                return -EPERM;
 +
        /* stream can be drained only when next track has been signalled */
        if (stream->next_track == false)
                return -EPERM;
index 298761a26180b6f4855338c4c3f6ff57d6151082,4570f662fb48b4090979be99b13087c3c0507a62..6803d39e09a5fed0bb922cf9d66a0eb2ca6de32c
  #include <sound/pcm_params.h>
  #include <sound/soc.h>
  #include <sound/hdaudio_ext.h>
 +#include <sound/hda_i915.h>
  #include <sound/hda_codec.h>
  #include <sound/hda_register.h>
 -#include "hdac_hda.h"
  
 -#define HDAC_ANALOG_DAI_ID            0
 -#define HDAC_DIGITAL_DAI_ID           1
 -#define HDAC_ALT_ANALOG_DAI_ID                2
 +#include "hdac_hda.h"
  
  #define STUB_FORMATS  (SNDRV_PCM_FMTBIT_S8 | \
                        SNDRV_PCM_FMTBIT_U8 | \
                        SNDRV_PCM_FMTBIT_U32_LE | \
                        SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
  
 +#define STUB_HDMI_RATES       (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
 +                               SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
 +                               SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
 +                               SNDRV_PCM_RATE_192000)
 +
  static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai);
  static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
@@@ -124,46 -121,7 +124,46 @@@ static struct snd_soc_dai_driver hdac_h
                .formats = STUB_FORMATS,
                .sig_bits = 24,
        },
 -}
 +},
 +{
 +      .id = HDAC_HDMI_0_DAI_ID,
 +      .name = "intel-hdmi-hifi1",
 +      .ops = &hdac_hda_dai_ops,
 +      .playback = {
 +              .stream_name    = "hifi1",
 +              .channels_min   = 1,
 +              .channels_max   = 32,
 +              .rates          = STUB_HDMI_RATES,
 +              .formats        = STUB_FORMATS,
 +              .sig_bits = 24,
 +      },
 +},
 +{
 +      .id = HDAC_HDMI_1_DAI_ID,
 +      .name = "intel-hdmi-hifi2",
 +      .ops = &hdac_hda_dai_ops,
 +      .playback = {
 +              .stream_name    = "hifi2",
 +              .channels_min   = 1,
 +              .channels_max   = 32,
 +              .rates          = STUB_HDMI_RATES,
 +              .formats        = STUB_FORMATS,
 +              .sig_bits = 24,
 +      },
 +},
 +{
 +      .id = HDAC_HDMI_2_DAI_ID,
 +      .name = "intel-hdmi-hifi3",
 +      .ops = &hdac_hda_dai_ops,
 +      .playback = {
 +              .stream_name    = "hifi3",
 +              .channels_min   = 1,
 +              .channels_max   = 32,
 +              .rates          = STUB_HDMI_RATES,
 +              .formats        = STUB_FORMATS,
 +              .sig_bits = 24,
 +      },
 +},
  
  };
  
@@@ -177,11 -135,10 +177,11 @@@ static int hdac_hda_dai_set_tdm_slot(st
  
        hda_pvt = snd_soc_component_get_drvdata(component);
        pcm = &hda_pvt->pcm[dai->id];
 +
        if (tx_mask)
 -              pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
 +              pcm->stream_tag[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
        else
 -              pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
 +              pcm->stream_tag[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
  
        return 0;
  }
@@@ -321,12 -278,6 +321,12 @@@ static struct hda_pcm *snd_soc_find_pcm
        struct hda_pcm *cpcm;
        const char *pcm_name;
  
 +      /*
 +       * map DAI ID to the closest matching PCM name, using the naming
 +       * scheme used by hda-codec snd_hda_gen_build_pcms() and for
 +       * HDMI in hda_codec patch_hdmi.c)
 +       */
 +
        switch (dai->id) {
        case HDAC_ANALOG_DAI_ID:
                pcm_name = "Analog";
        case HDAC_ALT_ANALOG_DAI_ID:
                pcm_name = "Alt Analog";
                break;
 +      case HDAC_HDMI_0_DAI_ID:
 +              pcm_name = "HDMI 0";
 +              break;
 +      case HDAC_HDMI_1_DAI_ID:
 +              pcm_name = "HDMI 1";
 +              break;
 +      case HDAC_HDMI_2_DAI_ID:
 +              pcm_name = "HDMI 2";
 +              break;
        default:
                dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id);
                return NULL;
        }
  
        list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) {
 -              if (strpbrk(cpcm->name, pcm_name))
 +              if (strstr(cpcm->name, pcm_name))
                        return cpcm;
        }
  
        return NULL;
  }
  
 +static bool is_hdmi_codec(struct hda_codec *hcodec)
 +{
 +      struct hda_pcm *cpcm;
 +
 +      list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) {
 +              if (cpcm->pcm_type == HDA_PCM_TYPE_HDMI)
 +                      return true;
 +      }
 +
 +      return false;
 +}
 +
  static int hdac_hda_codec_probe(struct snd_soc_component *component)
  {
        struct hdac_hda_priv *hda_pvt =
  
        snd_hdac_ext_bus_link_get(hdev->bus, hlink);
  
 +      /*
 +       * Ensure any HDA display is powered at codec probe.
 +       * After snd_hda_codec_device_new(), display power is
 +       * managed by runtime PM.
 +       */
 +      if (hda_pvt->need_display_power)
 +              snd_hdac_display_power(hdev->bus,
 +                                     HDA_CODEC_IDX_CONTROLLER, true);
 +
        ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card,
                                       hdev->addr, hcodec);
        if (ret < 0) {
                dev_dbg(&hdev->dev, "no patch file found\n");
        }
  
 +      /* configure codec for 1:1 PCM:DAI mapping */
 +      hcodec->mst_no_extra_pcms = 1;
 +
        ret = snd_hda_codec_parse_pcms(hcodec);
        if (ret < 0) {
                dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
                goto error;
        }
  
 -      ret = snd_hda_codec_build_controls(hcodec);
 -      if (ret < 0) {
 -              dev_err(&hdev->dev, "unable to create controls %d\n", ret);
 -              goto error;
 +      /* HDMI controls need to be created in machine drivers */
 +      if (!is_hdmi_codec(hcodec)) {
 +              ret = snd_hda_codec_build_controls(hcodec);
 +              if (ret < 0) {
 +                      dev_err(&hdev->dev, "unable to create controls %d\n",
 +                              ret);
 +                      goto error;
 +              }
        }
  
        hcodec->core.lazy_cache = true;
  
 +      if (hda_pvt->need_display_power)
 +              snd_hdac_display_power(hdev->bus,
 +                                     HDA_CODEC_IDX_CONTROLLER, false);
 +
        /*
         * hdac_device core already sets the state to active and calls
         * get_noresume. So enable runtime and set the device to suspend.
@@@ -500,8 -410,8 +500,8 @@@ static void hdac_hda_codec_remove(struc
                return;
        }
  
-       snd_hdac_ext_bus_link_put(hdev->bus, hlink);
        pm_runtime_disable(&hdev->dev);
+       snd_hdac_ext_bus_link_put(hdev->bus, hlink);
  }
  
  static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = {
index 4168b0a0aafb02a4490b83f804bdd081cc8450a0,e3d311fb510e0a7497fa0e0b7c26aef1204353ef..f53235be77d94f94179f7c1a87829f61b57181b4
  #define CDC_A_RX_EAR_CTL                      (0xf19E)
  #define RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK               BIT(0)
  #define RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE     BIT(0)
 +#define RX_EAR_CTL_PA_EAR_PA_EN_MASK          BIT(6)
 +#define RX_EAR_CTL_PA_EAR_PA_EN_ENABLE                BIT(6)
 +#define RX_EAR_CTL_PA_SEL_MASK                        BIT(7)
 +#define RX_EAR_CTL_PA_SEL                     BIT(7)
  
  #define CDC_A_SPKR_DAC_CTL            (0xf1B0)
  #define SPKR_DAC_CTL_DAC_RESET_MASK   BIT(4)
@@@ -310,13 -306,12 +310,13 @@@ struct pm8916_wcd_analog_priv 
  };
  
  static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
- static const char *const rdac2_mux_text[] = { "ZERO", "RX2", "RX1" };
+ static const char *const rdac2_mux_text[] = { "RX1", "RX2" };
  static const char *const hph_text[] = { "ZERO", "Switch", };
  
  static const struct soc_enum hph_enum = SOC_ENUM_SINGLE_VIRT(
                                        ARRAY_SIZE(hph_text), hph_text);
  
 +static const struct snd_kcontrol_new ear_mux = SOC_DAPM_ENUM("EAR_S", hph_enum);
  static const struct snd_kcontrol_new hphl_mux = SOC_DAPM_ENUM("HPHL", hph_enum);
  static const struct snd_kcontrol_new hphr_mux = SOC_DAPM_ENUM("HPHR", hph_enum);
  
@@@ -326,7 -321,7 +326,7 @@@ static const struct soc_enum adc2_enum 
  
  /* RDAC2 MUX */
  static const struct soc_enum rdac2_mux_enum = SOC_ENUM_SINGLE(
-                       CDC_D_CDC_CONN_HPHR_DAC_CTL, 0, 3, rdac2_mux_text);
+                       CDC_D_CDC_CONN_HPHR_DAC_CTL, 0, 2, rdac2_mux_text);
  
  static const struct snd_kcontrol_new spkr_switch[] = {
        SOC_DAPM_SINGLE("Switch", CDC_A_SPKR_DAC_CTL, 7, 1, 0)
@@@ -690,34 -685,6 +690,34 @@@ static int pm8916_wcd_analog_enable_spk
        return 0;
  }
  
 +static int pm8916_wcd_analog_enable_ear_pa(struct snd_soc_dapm_widget *w,
 +                                          struct snd_kcontrol *kcontrol,
 +                                          int event)
 +{
 +      struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 +
 +      switch (event) {
 +      case SND_SOC_DAPM_PRE_PMU:
 +              snd_soc_component_update_bits(component, CDC_A_RX_EAR_CTL,
 +                                  RX_EAR_CTL_PA_SEL_MASK, RX_EAR_CTL_PA_SEL);
 +              break;
 +      case SND_SOC_DAPM_POST_PMU:
 +              snd_soc_component_update_bits(component, CDC_A_RX_EAR_CTL,
 +                                  RX_EAR_CTL_PA_EAR_PA_EN_MASK,
 +                                  RX_EAR_CTL_PA_EAR_PA_EN_ENABLE);
 +              break;
 +      case SND_SOC_DAPM_POST_PMD:
 +              snd_soc_component_update_bits(component, CDC_A_RX_EAR_CTL,
 +                                  RX_EAR_CTL_PA_EAR_PA_EN_MASK, 0);
 +              /* Delay to reduce ear turn off pop */
 +              usleep_range(7000, 7100);
 +              snd_soc_component_update_bits(component, CDC_A_RX_EAR_CTL,
 +                                  RX_EAR_CTL_PA_SEL_MASK, 0);
 +              break;
 +      }
 +      return 0;
 +}
 +
  static const struct reg_default wcd_reg_defaults_2_0[] = {
        {CDC_A_RX_COM_OCP_CTL, 0xD1},
        {CDC_A_RX_COM_OCP_COUNT, 0xFF},
@@@ -834,20 -801,12 +834,20 @@@ static const struct snd_soc_dapm_route 
        {"PDM_TX", NULL, "A_MCLK2"},
        {"A_MCLK2", NULL, "A_MCLK"},
  
 +      /* Earpiece (RX MIX1) */
 +      {"EAR", NULL, "EAR_S"},
 +      {"EAR_S", "Switch", "EAR PA"},
 +      {"EAR PA", NULL, "RX_BIAS"},
 +      {"EAR PA", NULL, "HPHL DAC"},
 +      {"EAR PA", NULL, "HPHR DAC"},
 +      {"EAR PA", NULL, "EAR CP"},
 +
        /* Headset (RX MIX1 and RX MIX2) */
        {"HEADPHONE", NULL, "HPHL PA"},
        {"HEADPHONE", NULL, "HPHR PA"},
  
 -      {"HPHL PA", NULL, "EAR_HPHL_CLK"},
 -      {"HPHR PA", NULL, "EAR_HPHR_CLK"},
 +      {"HPHL DAC", NULL, "EAR_HPHL_CLK"},
 +      {"HPHR DAC", NULL, "EAR_HPHR_CLK"},
  
        {"CP", NULL, "NCP_CLK"},
  
@@@ -888,20 -847,11 +888,20 @@@ static const struct snd_soc_dapm_widge
        SND_SOC_DAPM_INPUT("AMIC1"),
        SND_SOC_DAPM_INPUT("AMIC3"),
        SND_SOC_DAPM_INPUT("AMIC2"),
 +      SND_SOC_DAPM_OUTPUT("EAR"),
        SND_SOC_DAPM_OUTPUT("HEADPHONE"),
  
        /* RX stuff */
        SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
  
 +      SND_SOC_DAPM_PGA_E("EAR PA", SND_SOC_NOPM,
 +                         0, 0, NULL, 0,
 +                         pm8916_wcd_analog_enable_ear_pa,
 +                         SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
 +                         SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 +      SND_SOC_DAPM_MUX("EAR_S", SND_SOC_NOPM, 0, 0, &ear_mux),
 +      SND_SOC_DAPM_SUPPLY("EAR CP", CDC_A_NCP_EN, 4, 0, NULL, 0),
 +
        SND_SOC_DAPM_PGA("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
        SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, &hphl_mux),
        SND_SOC_DAPM_MIXER("HPHL DAC", CDC_A_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL,
index 6164d54fc9923b6f956940ba0904255ffb1b8d95,4f6e58c3954a220fd0050c5d8c29089c0ee16622..751b8ea6ae1f5ca4bda64eb3d35c9aa4d79d9dbc
@@@ -21,7 -21,6 +21,7 @@@
  #include "../../codecs/rt5682.h"
  #include "../../codecs/hdac_hdmi.h"
  #include "../common/soc-intel-quirks.h"
 +#include "hda_dsp_common.h"
  
  #define NAME_SIZE 32
  
@@@ -54,7 -53,6 +54,7 @@@ struct sof_card_private 
        struct clk *mclk;
        struct snd_soc_jack sof_headset;
        struct list_head hdmi_pcm_list;
 +      bool common_hdmi_codec_drv;
  };
  
  static int sof_rt5682_quirk_cb(const struct dmi_system_id *id)
@@@ -276,13 -274,6 +276,13 @@@ static int sof_card_late_probe(struct s
        if (is_legacy_cpu)
                return 0;
  
 +      pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
 +                             head);
 +      component = pcm->codec_dai->component;
 +
 +      if (ctx->common_hdmi_codec_drv)
 +              return hda_dsp_hdmi_build_controls(card, component);
 +
        list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
                component = pcm->codec_dai->component;
                snprintf(jack_name, sizeof(jack_name),
@@@ -379,7 -370,7 +379,7 @@@ static int dmic_init(struct snd_soc_pcm
  
  /* sof audio machine driver for rt5682 codec */
  static struct snd_soc_card sof_audio_card_rt5682 = {
 -      .name = "sof_rt5682",
 +      .name = "rt5682", /* the sof- prefix is added by the core */
        .owner = THIS_MODULE,
        .controls = sof_controls,
        .num_controls = ARRAY_SIZE(sof_controls),
@@@ -612,6 -603,15 +612,15 @@@ static int sof_audio_probe(struct platf
        /* 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,
        if (ret)
                return ret;
  
 +      ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
 +
        snd_soc_card_set_drvdata(&sof_audio_card_rt5682, ctx);
  
        return devm_snd_soc_register_card(&pdev->dev,
index 5c2504a465f42130c1efe9315819118d1b01155a,e80b09143b63edf970e8921366cc074dd6c43ef9..60930fa85aa495767b9ec0e0423083125201939f
@@@ -6,13 -6,11 +6,13 @@@
   */
  
  #include <linux/module.h>
 +#include <linux/of_device.h>
  #include <linux/platform_device.h>
  #include <linux/slab.h>
  #include <linux/gpio.h>
  #include <linux/of_gpio.h>
  #include <sound/core.h>
 +#include <sound/hdmi-codec.h>
  #include <sound/jack.h>
  #include <sound/pcm.h>
  #include <sound/pcm_params.h>
@@@ -38,73 -36,28 +38,73 @@@ static struct snd_soc_jack_pin headset_
  
  };
  
 -static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
 -      SND_SOC_DAPM_HP("Headphone", NULL),
 -      SND_SOC_DAPM_MIC("Headset Mic", NULL),
 -      SND_SOC_DAPM_MIC("Int Mic", NULL),
 -      SND_SOC_DAPM_SPK("Speaker", NULL),
 +#define RK_MAX98090_WIDGETS \
 +      SND_SOC_DAPM_HP("Headphone", NULL), \
 +      SND_SOC_DAPM_MIC("Headset Mic", NULL), \
 +      SND_SOC_DAPM_MIC("Int Mic", NULL), \
 +      SND_SOC_DAPM_SPK("Speaker", NULL)
 +
 +#define RK_HDMI_WIDGETS \
 +      SND_SOC_DAPM_LINE("HDMI", NULL)
 +
 +static const struct snd_soc_dapm_widget rk_max98090_dapm_widgets[] = {
 +      RK_MAX98090_WIDGETS,
 +};
 +
 +static const struct snd_soc_dapm_widget rk_hdmi_dapm_widgets[] = {
 +      RK_HDMI_WIDGETS,
 +};
 +
 +static const struct snd_soc_dapm_widget rk_max98090_hdmi_dapm_widgets[] = {
 +      RK_MAX98090_WIDGETS,
 +      RK_HDMI_WIDGETS,
 +};
 +
 +#define RK_MAX98090_AUDIO_MAP \
 +      {"IN34", NULL, "Headset Mic"}, \
 +      {"Headset Mic", NULL, "MICBIAS"}, \
 +      {"DMICL", NULL, "Int Mic"}, \
 +      {"Headphone", NULL, "HPL"}, \
 +      {"Headphone", NULL, "HPR"}, \
 +      {"Speaker", NULL, "SPKL"}, \
 +      {"Speaker", NULL, "SPKR"}
 +
 +#define RK_HDMI_AUDIO_MAP \
 +      {"HDMI", NULL, "TX"}
 +
 +static const struct snd_soc_dapm_route rk_max98090_audio_map[] = {
 +      RK_MAX98090_AUDIO_MAP,
 +};
 +
 +static const struct snd_soc_dapm_route rk_hdmi_audio_map[] = {
 +      RK_HDMI_AUDIO_MAP,
 +};
 +
 +static const struct snd_soc_dapm_route rk_max98090_hdmi_audio_map[] = {
 +      RK_MAX98090_AUDIO_MAP,
 +      RK_HDMI_AUDIO_MAP,
 +};
 +
 +#define RK_MAX98090_CONTROLS \
 +      SOC_DAPM_PIN_SWITCH("Headphone"), \
 +      SOC_DAPM_PIN_SWITCH("Headset Mic"), \
 +      SOC_DAPM_PIN_SWITCH("Int Mic"), \
 +      SOC_DAPM_PIN_SWITCH("Speaker")
 +
 +#define RK_HDMI_CONTROLS \
 +      SOC_DAPM_PIN_SWITCH("HDMI")
 +
 +static const struct snd_kcontrol_new rk_max98090_controls[] = {
 +      RK_MAX98090_CONTROLS,
  };
  
 -static const struct snd_soc_dapm_route rk_audio_map[] = {
 -      {"IN34", NULL, "Headset Mic"},
 -      {"Headset Mic", NULL, "MICBIAS"},
 -      {"DMICL", NULL, "Int Mic"},
 -      {"Headphone", NULL, "HPL"},
 -      {"Headphone", NULL, "HPR"},
 -      {"Speaker", NULL, "SPKL"},
 -      {"Speaker", NULL, "SPKR"},
 +static const struct snd_kcontrol_new rk_hdmi_controls[] = {
 +      RK_HDMI_CONTROLS,
  };
  
 -static const struct snd_kcontrol_new rk_mc_controls[] = {
 -      SOC_DAPM_PIN_SWITCH("Headphone"),
 -      SOC_DAPM_PIN_SWITCH("Headset Mic"),
 -      SOC_DAPM_PIN_SWITCH("Int Mic"),
 -      SOC_DAPM_PIN_SWITCH("Speaker"),
 +static const struct snd_kcontrol_new rk_max98090_hdmi_controls[] = {
 +      RK_MAX98090_CONTROLS,
 +      RK_HDMI_CONTROLS,
  };
  
  static int rk_jack_event(struct notifier_block *nb, unsigned long event,
        struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
        struct snd_soc_dapm_context *dapm = &jack->card->dapm;
  
-       if (event & SND_JACK_MICROPHONE)
+       if (event & SND_JACK_MICROPHONE) {
                snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
-       else
+               snd_soc_dapm_force_enable_pin(dapm, "SHDN");
+       } else {
                snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+               snd_soc_dapm_disable_pin(dapm, "SHDN");
+       }
  
        snd_soc_dapm_sync(dapm);
  
@@@ -169,20 -125,15 +172,20 @@@ static int rk_aif1_hw_params(struct snd
  
        ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
                                     SND_SOC_CLOCK_OUT);
 -      if (ret < 0) {
 -              dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret);
 +      if (ret) {
 +              dev_err(cpu_dai->dev, "Can't set cpu dai clock %d\n", ret);
                return ret;
        }
  
        ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
                                     SND_SOC_CLOCK_IN);
 -      if (ret < 0) {
 -              dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret);
 +
 +      /* HDMI codec dai does not need to set sysclk. */
 +      if (!strcmp(rtd->dai_link->name, "HDMI"))
 +              return 0;
 +
 +      if (ret) {
 +              dev_err(codec_dai->dev, "Can't set codec dai clock %d\n", ret);
                return ret;
        }
  
@@@ -204,88 -155,20 +207,88 @@@ static const struct snd_soc_ops rk_aif1
        .startup = rk_aif1_startup,
  };
  
 -SND_SOC_DAILINK_DEFS(hifi,
 -      DAILINK_COMP_ARRAY(COMP_EMPTY()),
 -      DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
 -      DAILINK_COMP_ARRAY(COMP_EMPTY()));
 -
 -static struct snd_soc_dai_link rk_dailink = {
 -      .name = "max98090",
 -      .stream_name = "Audio",
 -      .init = rk_init,
 -      .ops = &rk_aif1_ops,
 -      /* set max98090 as slave */
 -      .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 -              SND_SOC_DAIFMT_CBS_CFS,
 -      SND_SOC_DAILINK_REG(hifi),
 +SND_SOC_DAILINK_DEFS(analog,
 +                   DAILINK_COMP_ARRAY(COMP_EMPTY()),
 +                   DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
 +                   DAILINK_COMP_ARRAY(COMP_EMPTY()));
 +
 +SND_SOC_DAILINK_DEFS(hdmi,
 +                   DAILINK_COMP_ARRAY(COMP_EMPTY()),
 +                   DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),
 +                   DAILINK_COMP_ARRAY(COMP_EMPTY()));
 +
 +enum {
 +      DAILINK_MAX98090,
 +      DAILINK_HDMI,
 +};
 +
 +static struct snd_soc_jack rk_hdmi_jack;
 +
 +static int rk_hdmi_init(struct snd_soc_pcm_runtime *runtime)
 +{
 +      struct snd_soc_card *card = runtime->card;
 +      struct snd_soc_component *component = runtime->codec_dai->component;
 +      int ret;
 +
 +      /* enable jack detection */
 +      ret = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT,
 +                                  &rk_hdmi_jack, NULL, 0);
 +      if (ret) {
 +              dev_err(card->dev, "Can't new HDMI Jack %d\n", ret);
 +              return ret;
 +      }
 +
 +      return hdmi_codec_set_jack_detect(component, &rk_hdmi_jack);
 +}
 +
 +/* max98090 dai_link */
 +static struct snd_soc_dai_link rk_max98090_dailinks[] = {
 +      {
 +              .name = "max98090",
 +              .stream_name = "Analog",
 +              .init = rk_init,
 +              .ops = &rk_aif1_ops,
 +              /* set max98090 as slave */
 +              .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 +                      SND_SOC_DAIFMT_CBS_CFS,
 +              SND_SOC_DAILINK_REG(analog),
 +      },
 +};
 +
 +/* HDMI codec dai_link */
 +static struct snd_soc_dai_link rk_hdmi_dailinks[] = {
 +      {
 +              .name = "HDMI",
 +              .stream_name = "HDMI",
 +              .init = rk_hdmi_init,
 +              .ops = &rk_aif1_ops,
 +              .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 +                      SND_SOC_DAIFMT_CBS_CFS,
 +              SND_SOC_DAILINK_REG(hdmi),
 +      }
 +};
 +
 +/* max98090 and HDMI codec dai_link */
 +static struct snd_soc_dai_link rk_max98090_hdmi_dailinks[] = {
 +      [DAILINK_MAX98090] = {
 +              .name = "max98090",
 +              .stream_name = "Analog",
 +              .init = rk_init,
 +              .ops = &rk_aif1_ops,
 +              /* set max98090 as slave */
 +              .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 +                      SND_SOC_DAIFMT_CBS_CFS,
 +              SND_SOC_DAILINK_REG(analog),
 +      },
 +      [DAILINK_HDMI] = {
 +              .name = "HDMI",
 +              .stream_name = "HDMI",
 +              .init = rk_hdmi_init,
 +              .ops = &rk_aif1_ops,
 +              .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 +                      SND_SOC_DAIFMT_CBS_CFS,
 +              SND_SOC_DAILINK_REG(hdmi),
 +      }
  };
  
  static int rk_98090_headset_init(struct snd_soc_component *component);
@@@ -295,47 -178,19 +298,47 @@@ static struct snd_soc_aux_dev rk_98090_
        .init = rk_98090_headset_init,
  };
  
 -static struct snd_soc_card snd_soc_card_rk = {
 +static struct snd_soc_card rockchip_max98090_card = {
        .name = "ROCKCHIP-I2S",
        .owner = THIS_MODULE,
 -      .dai_link = &rk_dailink,
 -      .num_links = 1,
 +      .dai_link = rk_max98090_dailinks,
 +      .num_links = ARRAY_SIZE(rk_max98090_dailinks),
 +      .aux_dev = &rk_98090_headset_dev,
 +      .num_aux_devs = 1,
 +      .dapm_widgets = rk_max98090_dapm_widgets,
 +      .num_dapm_widgets = ARRAY_SIZE(rk_max98090_dapm_widgets),
 +      .dapm_routes = rk_max98090_audio_map,
 +      .num_dapm_routes = ARRAY_SIZE(rk_max98090_audio_map),
 +      .controls = rk_max98090_controls,
 +      .num_controls = ARRAY_SIZE(rk_max98090_controls),
 +};
 +
 +static struct snd_soc_card rockchip_hdmi_card = {
 +      .name = "ROCKCHIP-HDMI",
 +      .owner = THIS_MODULE,
 +      .dai_link = rk_hdmi_dailinks,
 +      .num_links = ARRAY_SIZE(rk_hdmi_dailinks),
 +      .dapm_widgets = rk_hdmi_dapm_widgets,
 +      .num_dapm_widgets = ARRAY_SIZE(rk_hdmi_dapm_widgets),
 +      .dapm_routes = rk_hdmi_audio_map,
 +      .num_dapm_routes = ARRAY_SIZE(rk_hdmi_audio_map),
 +      .controls = rk_hdmi_controls,
 +      .num_controls = ARRAY_SIZE(rk_hdmi_controls),
 +};
 +
 +static struct snd_soc_card rockchip_max98090_hdmi_card = {
 +      .name = "ROCKCHIP-MAX98090-HDMI",
 +      .owner = THIS_MODULE,
 +      .dai_link = rk_max98090_hdmi_dailinks,
 +      .num_links = ARRAY_SIZE(rk_max98090_hdmi_dailinks),
        .aux_dev = &rk_98090_headset_dev,
        .num_aux_devs = 1,
 -      .dapm_widgets = rk_dapm_widgets,
 -      .num_dapm_widgets = ARRAY_SIZE(rk_dapm_widgets),
 -      .dapm_routes = rk_audio_map,
 -      .num_dapm_routes = ARRAY_SIZE(rk_audio_map),
 -      .controls = rk_mc_controls,
 -      .num_controls = ARRAY_SIZE(rk_mc_controls),
 +      .dapm_widgets = rk_max98090_hdmi_dapm_widgets,
 +      .num_dapm_widgets = ARRAY_SIZE(rk_max98090_hdmi_dapm_widgets),
 +      .dapm_routes = rk_max98090_hdmi_audio_map,
 +      .num_dapm_routes = ARRAY_SIZE(rk_max98090_hdmi_audio_map),
 +      .controls = rk_max98090_hdmi_controls,
 +      .num_controls = ARRAY_SIZE(rk_max98090_hdmi_controls),
  };
  
  static int rk_98090_headset_init(struct snd_soc_component *component)
        int ret;
  
        /* Enable Headset and 4 Buttons Jack detection */
 -      ret = snd_soc_card_jack_new(&snd_soc_card_rk, "Headset Jack",
 +      ret = snd_soc_card_jack_new(component->card, "Headset Jack",
                                    SND_JACK_HEADSET |
                                    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
                                    SND_JACK_BTN_2 | SND_JACK_BTN_3,
        return ret;
  }
  
 +static int rk_parse_headset_from_of(struct device *dev, struct device_node *np)
 +{
 +      rk_98090_headset_dev.dlc.of_node = of_parse_phandle(
 +                      np, "rockchip,headset-codec", 0);
 +      if (!rk_98090_headset_dev.dlc.of_node) {
 +              dev_err(dev,
 +                      "Property 'rockchip,headset-codec' missing/invalid\n");
 +              return -EINVAL;
 +      }
 +      return 0;
 +}
 +
  static int snd_rk_mc_probe(struct platform_device *pdev)
  {
        int ret = 0;
 -      struct snd_soc_card *card = &snd_soc_card_rk;
 +      struct snd_soc_card *card;
 +      struct device *dev = &pdev->dev;
        struct device_node *np = pdev->dev.of_node;
 +      struct device_node *np_cpu;
 +      struct device_node *np_audio, *np_hdmi;
  
 -      /* register the soc card */
 -      card->dev = &pdev->dev;
 +      /* Parse DTS for I2S controller. */
 +      np_cpu = of_parse_phandle(np, "rockchip,i2s-controller", 0);
  
 -      rk_dailink.codecs->of_node = of_parse_phandle(np,
 -                      "rockchip,audio-codec", 0);
 -      if (!rk_dailink.codecs->of_node) {
 +      if (!np_cpu) {
                dev_err(&pdev->dev,
 -                      "Property 'rockchip,audio-codec' missing or invalid\n");
 +                      "Property 'rockchip,i2s-controller missing or invalid\n");
                return -EINVAL;
        }
  
 -      rk_dailink.cpus->of_node = of_parse_phandle(np,
 -                      "rockchip,i2s-controller", 0);
 -      if (!rk_dailink.cpus->of_node) {
 -              dev_err(&pdev->dev,
 -                      "Property 'rockchip,i2s-controller' missing or invalid\n");
 +      /*
 +       * Find the card to use based on the presences of audio codec
 +       * and hdmi codec in device property. Set their of_node accordingly.
 +       */
 +      np_audio = of_parse_phandle(np, "rockchip,audio-codec", 0);
 +      np_hdmi = of_parse_phandle(np, "rockchip,hdmi-codec", 0);
 +      if (np_audio && np_hdmi) {
 +              card = &rockchip_max98090_hdmi_card;
 +              card->dai_link[DAILINK_MAX98090].codecs->of_node = np_audio;
 +              card->dai_link[DAILINK_HDMI].codecs->of_node = np_hdmi;
 +              card->dai_link[DAILINK_MAX98090].cpus->of_node = np_cpu;
 +              card->dai_link[DAILINK_MAX98090].platforms->of_node = np_cpu;
 +              card->dai_link[DAILINK_HDMI].cpus->of_node = np_cpu;
 +              card->dai_link[DAILINK_HDMI].platforms->of_node = np_cpu;
 +      } else if (np_audio) {
 +              card = &rockchip_max98090_card;
 +              card->dai_link[0].codecs->of_node = np_audio;
 +              card->dai_link[0].cpus->of_node = np_cpu;
 +              card->dai_link[0].platforms->of_node = np_cpu;
 +      } else if (np_hdmi) {
 +              card = &rockchip_hdmi_card;
 +              card->dai_link[0].codecs->of_node = np_hdmi;
 +              card->dai_link[0].cpus->of_node = np_cpu;
 +              card->dai_link[0].platforms->of_node = np_cpu;
 +      } else {
 +              dev_err(dev, "At least one of codecs should be specified\n");
                return -EINVAL;
        }
  
 -      rk_dailink.platforms->of_node = rk_dailink.cpus->of_node;
 +      card->dev = dev;
  
 -      rk_98090_headset_dev.dlc.of_node = of_parse_phandle(np,
 -                      "rockchip,headset-codec", 0);
 -      if (!rk_98090_headset_dev.dlc.of_node) {
 -              dev_err(&pdev->dev,
 -                      "Property 'rockchip,headset-codec' missing/invalid\n");
 -              return -EINVAL;
 +      /* Parse headset detection codec. */
 +      if (np_audio) {
 +              ret = rk_parse_headset_from_of(dev, np);
 +              if (ret)
 +                      return ret;
        }
  
 +      /* Parse card name. */
        ret = snd_soc_of_parse_card_name(card, "rockchip,model");
        if (ret) {
                dev_err(&pdev->dev,
                return ret;
        }
  
 +      /* register the soc card */
        ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret) {
                dev_err(&pdev->dev,
diff --combined sound/soc/sh/rcar/core.c
index 871afe75ca42c6b21582ee1965af65934cf86d29,e9596c2096cd585334e6c99710cc6e3194a4f792..fc32cbbba78f6a5203a697ea92ee4b0f3bb67609
@@@ -302,7 -302,7 +302,7 @@@ int rsnd_runtime_channel_after_ctu_with
  
  int rsnd_channel_normalization(int chan)
  {
 -      if ((chan > 8) || (chan < 0))
 +      if (WARN_ON((chan > 8) || (chan < 0)))
                return 0;
  
        /* TDM Extend Mode needs 8ch */
@@@ -761,6 -761,7 +761,7 @@@ static int rsnd_soc_dai_set_fmt(struct 
        }
  
        /* set format */
+       rdai->bit_clk_inv = 0;
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
                rdai->sys_delay = 0;
@@@ -1075,10 -1076,7 +1076,10 @@@ static void rsnd_parse_tdm_split_mode(s
                        j++;
                }
  
 +              of_node_put(node);
        }
 +
 +      of_node_put(ssiu_np);
  }
  
  static void rsnd_parse_connect_simple(struct rsnd_priv *priv,
@@@ -1096,13 -1094,11 +1097,13 @@@ static void rsnd_parse_connect_graph(st
                                     struct device_node *endpoint)
  {
        struct device *dev = rsnd_priv_to_dev(priv);
 -      struct device_node *remote_node = of_graph_get_remote_port_parent(endpoint);
 +      struct device_node *remote_node;
  
        if (!rsnd_io_to_mod_ssi(io))
                return;
  
 +      remote_node = of_graph_get_remote_port_parent(endpoint);
 +
        /* HDMI0 */
        if (strstr(remote_node->full_name, "hdmi@fead0000")) {
                rsnd_flags_set(io, RSND_STREAM_HDMI0);
        }
  
        rsnd_parse_tdm_split_mode(priv, io, endpoint);
 +
 +      of_node_put(remote_node);
  }
  
  void rsnd_parse_connect_common(struct rsnd_dai *rdai,
@@@ -1380,9 -1374,8 +1381,9 @@@ static int rsnd_dai_probe(struct rsnd_p
  /*
   *            pcm ops
   */
 -static int rsnd_hw_params(struct snd_pcm_substream *substream,
 -                       struct snd_pcm_hw_params *hw_params)
 +static int rsnd_hw_params(struct snd_soc_component *component,
 +                        struct snd_pcm_substream *substream,
 +                        struct snd_pcm_hw_params *hw_params)
  {
        struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
                                        params_buffer_bytes(hw_params));
  }
  
 -static int rsnd_hw_free(struct snd_pcm_substream *substream)
 +static int rsnd_hw_free(struct snd_soc_component *component,
 +                      struct snd_pcm_substream *substream)
  {
        struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
        return snd_pcm_lib_free_pages(substream);
  }
  
 -static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream)
 +static snd_pcm_uframes_t rsnd_pointer(struct snd_soc_component *component,
 +                                    struct snd_pcm_substream *substream)
  {
        struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
        return pointer;
  }
  
 -static const struct snd_pcm_ops rsnd_pcm_ops = {
 -      .ioctl          = snd_pcm_lib_ioctl,
 -      .hw_params      = rsnd_hw_params,
 -      .hw_free        = rsnd_hw_free,
 -      .pointer        = rsnd_pointer,
 -};
 -
  /*
   *            snd_kcontrol
   */
@@@ -1650,11 -1648,8 +1651,11 @@@ int rsnd_kctrl_new(struct rsnd_mod *mod
   *            snd_soc_component
   */
  static const struct snd_soc_component_driver rsnd_soc_component = {
 -      .ops            = &rsnd_pcm_ops,
        .name           = "rsnd",
 +      .ioctl          = snd_soc_pcm_lib_ioctl,
 +      .hw_params      = rsnd_hw_params,
 +      .hw_free        = rsnd_hw_free,
 +      .pointer        = rsnd_pointer,
  };
  
  static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
diff --combined sound/soc/sh/rcar/dma.c
index bcb6d5960661e0118f649a62f2ebaf93929b487c,28f65eba2bb459fa354c03af97c455e3dd1270d8..95aa26d62e4fa4fd95013a9555e4c4aafe5bd96c
@@@ -165,40 -165,14 +165,40 @@@ static int rsnd_dmaen_start(struct rsnd
        struct device *dev = rsnd_priv_to_dev(priv);
        struct dma_async_tx_descriptor *desc;
        struct dma_slave_config cfg = {};
 +      enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
        int is_play = rsnd_io_is_play(io);
        int ret;
  
 +      /*
 +       * in case of monaural data writing or reading through Audio-DMAC
 +       * data is always in Left Justified format, so both src and dst
 +       * DMA Bus width need to be set equal to physical data width.
 +       */
 +      if (rsnd_runtime_channel_original(io) == 1) {
 +              struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
 +              int bits = snd_pcm_format_physical_width(runtime->format);
 +
 +              switch (bits) {
 +              case 8:
 +                      buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
 +                      break;
 +              case 16:
 +                      buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
 +                      break;
 +              case 32:
 +                      buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
 +                      break;
 +              default:
 +                      dev_err(dev, "invalid format width %d\n", bits);
 +                      return -EINVAL;
 +              }
 +      }
 +
        cfg.direction   = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
        cfg.src_addr    = dma->src_addr;
        cfg.dst_addr    = dma->dst_addr;
 -      cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 -      cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 +      cfg.src_addr_width = buswidth;
 +      cfg.dst_addr_width = buswidth;
  
        dev_dbg(dev, "%s %pad -> %pad\n",
                rsnd_mod_name(mod),
@@@ -534,10 -508,10 +534,10 @@@ static struct rsnd_mod_ops rsnd_dmapp_o
  #define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8)
  #define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc)
  
- #define RDMA_SSIU_I_N(addr, i, j) (addr ##_reg - 0x00441000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400))
+ #define RDMA_SSIU_I_N(addr, i, j) (addr ##_reg - 0x00441000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4)))
  #define RDMA_SSIU_O_N(addr, i, j) RDMA_SSIU_I_N(addr, i, j)
  
- #define RDMA_SSIU_I_P(addr, i, j) (addr ##_reg - 0x00141000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400))
+ #define RDMA_SSIU_I_P(addr, i, j) (addr ##_reg - 0x00141000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4)))
  #define RDMA_SSIU_O_P(addr, i, j) RDMA_SSIU_I_P(addr, i, j)
  
  #define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i))
diff --combined sound/soc/soc-pcm.c
index 1c00119b72e37bfa41ab31e72040485d1f154318,b600d3eaaf5cd2c2c97c1a42e3d091f75970001a..493a2e80e8936ffa0d073543e7e9dd79993ddbf6
@@@ -118,8 -118,11 +118,8 @@@ bool snd_soc_runtime_ignore_pmdown_time
        if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
                return true;
  
 -      for_each_rtdcom(rtd, rtdcom) {
 -              component = rtdcom->component;
 -
 +      for_each_rtd_components(rtd, rtdcom, component)
                ignore &= !component->driver->use_pmdown_time;
 -      }
  
        return ignore;
  }
@@@ -432,7 -435,8 +432,7 @@@ static int soc_pcm_components_open(stru
        struct snd_soc_component *component;
        int ret = 0;
  
 -      for_each_rtdcom(rtd, rtdcom) {
 -              component = rtdcom->component;
 +      for_each_rtd_components(rtd, rtdcom, component) {
                *last = component;
  
                ret = snd_soc_component_module_get_when_open(component);
@@@ -463,7 -467,9 +463,7 @@@ static int soc_pcm_components_close(str
        struct snd_soc_component *component;
        int ret = 0;
  
 -      for_each_rtdcom(rtd, rtdcom) {
 -              component = rtdcom->component;
 -
 +      for_each_rtd_components(rtd, rtdcom, component) {
                if (component == last)
                        break;
  
@@@ -494,7 -500,9 +494,7 @@@ static int soc_pcm_open(struct snd_pcm_
        for_each_rtd_codec_dai(rtd, i, codec_dai)
                pinctrl_pm_select_default_state(codec_dai->dev);
  
 -      for_each_rtdcom(rtd, rtdcom) {
 -              component = rtdcom->component;
 -
 +      for_each_rtd_components(rtd, rtdcom, component) {
                pm_runtime_get_sync(component->dev);
        }
  
@@@ -617,7 -625,9 +617,7 @@@ component_err
  out:
        mutex_unlock(&rtd->card->pcm_mutex);
  
 -      for_each_rtdcom(rtd, rtdcom) {
 -              component = rtdcom->component;
 -
 +      for_each_rtd_components(rtd, rtdcom, component) {
                pm_runtime_mark_last_busy(component->dev);
                pm_runtime_put_autosuspend(component->dev);
        }
@@@ -730,7 -740,9 +730,7 @@@ static int soc_pcm_close(struct snd_pcm
  
        mutex_unlock(&rtd->card->pcm_mutex);
  
 -      for_each_rtdcom(rtd, rtdcom) {
 -              component = rtdcom->component;
 -
 +      for_each_rtd_components(rtd, rtdcom, component) {
                pm_runtime_mark_last_busy(component->dev);
                pm_runtime_put_autosuspend(component->dev);
        }
@@@ -770,7 -782,9 +770,7 @@@ static int soc_pcm_prepare(struct snd_p
                }
        }
  
 -      for_each_rtdcom(rtd, rtdcom) {
 -              component = rtdcom->component;
 -
 +      for_each_rtd_components(rtd, rtdcom, component) {
                ret = snd_soc_component_prepare(component, substream);
                if (ret < 0) {
                        dev_err(component->dev,
@@@ -835,7 -849,9 +835,7 @@@ static int soc_pcm_components_hw_free(s
        struct snd_soc_component *component;
        int ret = 0;
  
 -      for_each_rtdcom(rtd, rtdcom) {
 -              component = rtdcom->component;
 -
 +      for_each_rtd_components(rtd, rtdcom, component) {
                if (component == last)
                        break;
  
@@@ -929,7 -945,9 +929,7 @@@ static int soc_pcm_hw_params(struct snd
  
        snd_soc_dapm_update_dai(substream, params, cpu_dai);
  
 -      for_each_rtdcom(rtd, rtdcom) {
 -              component = rtdcom->component;
 -
 +      for_each_rtd_components(rtd, rtdcom, component) {
                ret = snd_soc_component_hw_params(component, substream, params);
                if (ret < 0) {
                        dev_err(component->dev,
@@@ -1029,7 -1047,7 +1029,7 @@@ static int soc_pcm_hw_free(struct snd_p
        return 0;
  }
  
 -static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 +static int soc_pcm_trigger_start(struct snd_pcm_substream *substream, int cmd)
  {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_component *component;
        struct snd_soc_dai *codec_dai;
        int i, ret;
  
 +      if (rtd->dai_link->ops->trigger) {
 +              ret = rtd->dai_link->ops->trigger(substream, cmd);
 +              if (ret < 0)
 +                      return ret;
 +      }
 +
 +      for_each_rtd_components(rtd, rtdcom, component) {
 +              ret = snd_soc_component_trigger(component, substream, cmd);
 +              if (ret < 0)
 +                      return ret;
 +      }
 +
 +      ret = snd_soc_dai_trigger(cpu_dai, substream, cmd);
 +      if (ret < 0)
 +              return ret;
 +
        for_each_rtd_codec_dai(rtd, i, codec_dai) {
                ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
                if (ret < 0)
                        return ret;
        }
  
 -      for_each_rtdcom(rtd, rtdcom) {
 -              component = rtdcom->component;
 +      return 0;
 +}
 +
 +static int soc_pcm_trigger_stop(struct snd_pcm_substream *substream, int cmd)
 +{
 +      struct snd_soc_pcm_runtime *rtd = substream->private_data;
 +      struct snd_soc_component *component;
 +      struct snd_soc_rtdcom_list *rtdcom;
 +      struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 +      struct snd_soc_dai *codec_dai;
 +      int i, ret;
  
 -              ret = snd_soc_component_trigger(component, substream, cmd);
 +      for_each_rtd_codec_dai(rtd, i, codec_dai) {
 +              ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
                if (ret < 0)
                        return ret;
        }
        if (ret < 0)
                return ret;
  
 +      for_each_rtd_components(rtd, rtdcom, component) {
 +              ret = snd_soc_component_trigger(component, substream, cmd);
 +              if (ret < 0)
 +                      return ret;
 +      }
 +
        if (rtd->dai_link->ops->trigger) {
                ret = rtd->dai_link->ops->trigger(substream, cmd);
                if (ret < 0)
        return 0;
  }
  
 +static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 +{
 +      int ret;
 +
 +      switch (cmd) {
 +      case SNDRV_PCM_TRIGGER_START:
 +      case SNDRV_PCM_TRIGGER_RESUME:
 +      case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 +              ret = soc_pcm_trigger_start(substream, cmd);
 +              break;
 +      case SNDRV_PCM_TRIGGER_STOP:
 +      case SNDRV_PCM_TRIGGER_SUSPEND:
 +      case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 +              ret = soc_pcm_trigger_stop(substream, cmd);
 +              break;
 +      default:
 +              return -EINVAL;
 +      }
 +
 +      return ret;
 +}
 +
  static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
                                   int cmd)
  {
@@@ -1182,6 -1146,7 +1182,7 @@@ static int dpcm_be_connect(struct snd_s
  {
        struct snd_soc_dpcm *dpcm;
        unsigned long flags;
+       char *name;
  
        /* only add new dpcms */
        for_each_dpcm_be(fe, stream, dpcm) {
                        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;
  }
@@@ -1414,7 -1385,6 +1421,7 @@@ static int dpcm_prune_paths(struct snd_
        struct snd_soc_dapm_widget *widget;
        struct snd_soc_dai *dai;
        int prune = 0;
 +      int do_prune;
  
        /* Destroy any old FE <--> BE connections */
        for_each_dpcm_be(fe, stream, dpcm) {
                        continue;
  
                /* is there a valid CODEC DAI widget for this BE */
 +              do_prune = 1;
                for_each_rtd_codec_dai(dpcm->be, i, dai) {
                        widget = dai_get_widget(dai, stream);
  
                        /* prune the BE if it's no longer in our active list */
                        if (widget && widget_in_list(list, widget))
 -                              continue;
 +                              do_prune = 0;
                }
 +              if (!do_prune)
 +                      continue;
  
                dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
                        stream ? "capture" : "playback",
@@@ -2322,81 -2289,42 +2329,81 @@@ int dpcm_be_dai_trigger(struct snd_soc_
  }
  EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
  
 +static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
 +                                int cmd, bool fe_first)
 +{
 +      struct snd_soc_pcm_runtime *fe = substream->private_data;
 +      int ret;
 +
 +      /* call trigger on the frontend before the backend. */
 +      if (fe_first) {
 +              dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
 +                      fe->dai_link->name, cmd);
 +
 +              ret = soc_pcm_trigger(substream, cmd);
 +              if (ret < 0)
 +                      return ret;
 +
 +              ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
 +              return ret;
 +      }
 +
 +      /* call trigger on the frontend after the backend. */
 +      ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
 +      if (ret < 0)
 +              return ret;
 +
 +      dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
 +              fe->dai_link->name, cmd);
 +
 +      ret = soc_pcm_trigger(substream, cmd);
 +
 +      return ret;
 +}
 +
  static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
  {
        struct snd_soc_pcm_runtime *fe = substream->private_data;
 -      int stream = substream->stream, ret;
 +      int stream = substream->stream;
 +      int ret = 0;
        enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
  
        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
  
        switch (trigger) {
        case SND_SOC_DPCM_TRIGGER_PRE:
 -              /* call trigger on the frontend before the backend. */
 -
 -              dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
 -                              fe->dai_link->name, cmd);
 -
 -              ret = soc_pcm_trigger(substream, cmd);
 -              if (ret < 0) {
 -                      dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
 -                      goto out;
 +              switch (cmd) {
 +              case SNDRV_PCM_TRIGGER_START:
 +              case SNDRV_PCM_TRIGGER_RESUME:
 +              case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 +                      ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
 +                      break;
 +              case SNDRV_PCM_TRIGGER_STOP:
 +              case SNDRV_PCM_TRIGGER_SUSPEND:
 +              case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 +                      ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
 +                      break;
 +              default:
 +                      ret = -EINVAL;
 +                      break;
                }
 -
 -              ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
                break;
        case SND_SOC_DPCM_TRIGGER_POST:
 -              /* call trigger on the frontend after the backend. */
 -
 -              ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
 -              if (ret < 0) {
 -                      dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
 -                      goto out;
 +              switch (cmd) {
 +              case SNDRV_PCM_TRIGGER_START:
 +              case SNDRV_PCM_TRIGGER_RESUME:
 +              case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 +                      ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
 +                      break;
 +              case SNDRV_PCM_TRIGGER_STOP:
 +              case SNDRV_PCM_TRIGGER_SUSPEND:
 +              case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 +                      ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
 +                      break;
 +              default:
 +                      ret = -EINVAL;
 +                      break;
                }
 -
 -              dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
 -                              fe->dai_link->name, cmd);
 -
 -              ret = soc_pcm_trigger(substream, cmd);
                break;
        case SND_SOC_DPCM_TRIGGER_BESPOKE:
                /* bespoke trigger() - handles both FE and BEs */
                                fe->dai_link->name, cmd);
  
                ret = soc_pcm_bespoke_trigger(substream, cmd);
 -              if (ret < 0) {
 -                      dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
 -                      goto out;
 -              }
                break;
        default:
                dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
                goto out;
        }
  
 +      if (ret < 0) {
 +              dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n",
 +                      cmd, ret);
 +              goto out;
 +      }
 +
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
@@@ -2898,7 -2824,6 +2905,7 @@@ int soc_new_pcm(struct snd_soc_pcm_runt
        struct snd_soc_dai *codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_rtdcom_list *rtdcom;
 +      struct snd_soc_component *component;
        struct snd_pcm *pcm;
        char new_name[64];
        int ret = 0, playback = 0, capture = 0;
                rtd->ops.ioctl          = snd_soc_pcm_component_ioctl;
        }
  
 -      for_each_rtdcom(rtd, rtdcom) {
 -              const struct snd_pcm_ops *ops = rtdcom->component->driver->ops;
 -
 -              if (!ops)
 -                      continue;
 +      for_each_rtd_components(rtd, rtdcom, component) {
 +              const struct snd_soc_component_driver *drv = component->driver;
  
 -              if (ops->copy_user)
 +              if (drv->copy_user)
                        rtd->ops.copy_user      = snd_soc_pcm_component_copy_user;
 -              if (ops->page)
 +              if (drv->page)
                        rtd->ops.page           = snd_soc_pcm_component_page;
 -              if (ops->mmap)
 +              if (drv->mmap)
                        rtd->ops.mmap           = snd_soc_pcm_component_mmap;
        }
  
diff --combined sound/soc/sof/control.c
index 2c4abd406c4fa9852221a47e451822b1bc3d0500,2b8711eda362b97362ef2501080c099b7616bc52..7baf7f1507c3a3f80ebf4190f4122c77071fff55
  /* Mixer Controls */
  
  #include <linux/pm_runtime.h>
 +#include <linux/leds.h>
  #include "sof-priv.h"
  
 +static void update_mute_led(struct snd_sof_control *scontrol,
 +                          struct snd_kcontrol *kcontrol,
 +                          struct snd_ctl_elem_value *ucontrol)
 +{
 +      unsigned int temp = 0;
 +      unsigned int mask;
 +      int i;
 +
 +      mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 +
 +      for (i = 0; i < scontrol->num_channels; i++) {
 +              if (ucontrol->value.integer.value[i]) {
 +                      temp |= mask;
 +                      break;
 +              }
 +      }
 +
 +      if (temp == scontrol->led_ctl.led_value)
 +              return;
 +
 +      scontrol->led_ctl.led_value = temp;
 +
 +#if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
 +      if (!scontrol->led_ctl.direction)
 +              ledtrig_audio_set(LED_AUDIO_MUTE, temp ? LED_OFF : LED_ON);
 +      else
 +              ledtrig_audio_set(LED_AUDIO_MICMUTE, temp ? LED_OFF : LED_ON);
 +#endif
 +}
 +
  static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size)
  {
        if (value >= size)
@@@ -91,13 -60,16 +91,16 @@@ int snd_sof_volume_put(struct snd_kcont
        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 */
                                              SOF_CTRL_TYPE_VALUE_CHAN_GET,
                                              SOF_CTRL_CMD_VOLUME,
                                              true);
-       return 0;
+       return change;
  }
  
  int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
@@@ -136,16 -107,17 +138,20 @@@ int snd_sof_switch_put(struct snd_kcont
        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;
        }
  
 +      if (scontrol->led_ctl.use_led)
 +              update_mute_led(scontrol, kcontrol, ucontrol);
 +
        /* notify DSP of mixer updates */
        if (pm_runtime_active(sdev->dev))
                snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
                                              SOF_CTRL_CMD_SWITCH,
                                              true);
  
-       return 0;
+       return change;
  }
  
  int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
@@@ -182,11 -154,15 +188,15 @@@ int snd_sof_enum_put(struct snd_kcontro
        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 */
                                              SOF_CTRL_CMD_ENUM,
                                              true);
  
-       return 0;
+       return change;
  }
  
  int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
diff --combined sound/soc/sof/debug.c
index b8a4e899154c633e7960b7792ea11aa28fef1e8c,5529e8eeca462a9bebf8c5e3494a0bca9c6df8cd..d2b3b99d3a20446865fa91c33e1cb931926af98a
@@@ -152,8 -152,10 +152,10 @@@ static ssize_t sof_dfsentry_write(struc
         */
        dentry = file->f_path.dentry;
        if (strcmp(dentry->d_name.name, "ipc_flood_count") &&
-           strcmp(dentry->d_name.name, "ipc_flood_duration_ms"))
-               return -EINVAL;
+           strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) {
+               ret = -EINVAL;
+               goto out;
+       }
  
        if (!strcmp(dentry->d_name.name, "ipc_flood_duration_ms"))
                flood_duration_test = true;
@@@ -461,19 -463,3 +463,19 @@@ void snd_sof_free_debug(struct snd_sof_
        debugfs_remove_recursive(sdev->debugfs_root);
  }
  EXPORT_SYMBOL_GPL(snd_sof_free_debug);
 +
 +void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev)
 +{
 +      if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) ||
 +          (sof_core_debug & SOF_DBG_RETAIN_CTX)) {
 +              /* should we prevent DSP entering D3 ? */
 +              dev_info(sdev->dev, "info: preventing DSP entering D3 state to preserve context\n");
 +              pm_runtime_get_noresume(sdev->dev);
 +      }
 +
 +      /* dump vital information to the logs */
 +      snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
 +      snd_sof_ipc_dump(sdev);
 +      snd_sof_trace_notify_for_error(sdev);
 +}
 +EXPORT_SYMBOL(snd_sof_handle_fw_exception);
index 450f9c55785fa4828acb2c542fd329ad168fa0d6,0c11fceb28a7a234c1afde9b9c7bc52fe001bd53..29ab43281670164c90942ca0e48c474c44f84ff1
@@@ -190,7 -190,7 +190,7 @@@ hda_dsp_stream_get(struct snd_sof_dev *
         * 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 (!IS_ENABLED(CONFIG_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,
@@@ -228,7 -228,7 +228,7 @@@ int hda_dsp_stream_put(struct snd_sof_d
        spin_unlock_irq(&bus->reg_lock);
  
        /* Enable DMI L1 entry if there are no capture streams open */
-       if (!IS_ENABLED(SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1))
+       if (!IS_ENABLED(CONFIG_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,
@@@ -275,12 -275,8 +275,12 @@@ int hda_dsp_stream_trigger(struct snd_s
                                        HDA_DSP_REG_POLL_INTERVAL_US,
                                        HDA_DSP_STREAM_RUN_TIMEOUT);
  
 -              if (ret)
 +              if (ret < 0) {
 +                      dev_err(sdev->dev,
 +                              "error: %s: cmd %d: timeout on STREAM_SD_OFFSET read\n",
 +                              __func__, cmd);
                        return ret;
 +              }
  
                hstream->running = true;
                break;
                                                HDA_DSP_REG_POLL_INTERVAL_US,
                                                HDA_DSP_STREAM_RUN_TIMEOUT);
  
 -              if (ret)
 +              if (ret < 0) {
 +                      dev_err(sdev->dev,
 +                              "error: %s: cmd %d: timeout on STREAM_SD_OFFSET read\n",
 +                              __func__, cmd);
                        return ret;
 +              }
  
                snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset +
                                  SOF_HDA_ADSP_REG_CL_SD_STS,
@@@ -364,12 -356,8 +364,12 @@@ int hda_dsp_stream_hw_params(struct snd
                                            HDA_DSP_REG_POLL_INTERVAL_US,
                                            HDA_DSP_STREAM_RUN_TIMEOUT);
  
 -      if (ret)
 +      if (ret < 0) {
 +              dev_err(sdev->dev,
 +                      "error: %s: timeout on STREAM_SD_OFFSET read1\n",
 +                      __func__);
                return ret;
 +      }
  
        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
                                sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
                                            HDA_DSP_REG_POLL_INTERVAL_US,
                                            HDA_DSP_STREAM_RUN_TIMEOUT);
  
 -      if (ret)
 +      if (ret < 0) {
 +              dev_err(sdev->dev,
 +                      "error: %s: timeout on STREAM_SD_OFFSET read2\n",
 +                      __func__);
                return ret;
 +      }
  
        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
                                sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
diff --combined sound/soc/sof/ipc.c
index 26675dfe02404965c954cc80045b7b2149536e65,086eeeab8679555b4b5fe87b2bc312fa4b5ef1ef..5994e10733642afc2bcc710798c541ed7722884d
@@@ -210,7 -210,9 +210,7 @@@ static int tx_wait_done(struct snd_sof_
        if (ret == 0) {
                dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n",
                        hdr->cmd, hdr->size);
 -              snd_sof_dsp_dbg_dump(ipc->sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
 -              snd_sof_ipc_dump(ipc->sdev);
 -              snd_sof_trace_notify_for_error(ipc->sdev);
 +              snd_sof_handle_fw_exception(ipc->sdev);
                ret = -ETIMEDOUT;
        } else {
                /* copy the data returned from DSP */
@@@ -570,8 -572,10 +570,10 @@@ static int sof_set_get_large_ctrl_data(
        else
                err = sof_get_ctrl_copy_params(cdata->type, partdata, cdata,
                                               sparams);
-       if (err < 0)
+       if (err < 0) {
+               kfree(partdata);
                return err;
+       }
  
        msg_bytes = sparams->msg_bytes;
        pl_size = sparams->pl_size;
@@@ -792,6 -796,12 +794,6 @@@ struct snd_sof_ipc *snd_sof_ipc_init(st
        struct snd_sof_ipc *ipc;
        struct snd_sof_ipc_msg *msg;
  
 -      /* check if mandatory ops required for ipc are defined */
 -      if (!sof_ops(sdev)->fw_ready) {
 -              dev_err(sdev->dev, "error: ipc mandatory ops not defined\n");
 -              return NULL;
 -      }
 -
        ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL);
        if (!ipc)
                return NULL;