]> Git Repo - linux.git/commitdiff
ASoC: Merge up fixes
authorMark Brown <[email protected]>
Wed, 9 Aug 2023 23:19:02 +0000 (00:19 +0100)
committerMark Brown <[email protected]>
Wed, 9 Aug 2023 23:19:02 +0000 (00:19 +0100)
For the benefit of CI

1  2 
sound/soc/codecs/max98363.c
sound/soc/fsl/fsl_micfil.c
sound/soc/fsl/fsl_micfil.h
sound/soc/intel/boards/sof_sdw.c
sound/soc/sof/intel/hda-dai-ops.c
sound/soc/sof/intel/hda-dai.c
sound/soc/sof/intel/hda.h
sound/soc/sof/ipc3.c
sound/soc/sof/ipc4-topology.c

index 9e3873e56e6d9c1cc80064734c6cb7cf6b4e46dd,2dfaf4fcfbd37ac3ad0faf96ea7eca48fbdbd2b8..a2cca3436c68ef14e6f2897cb53408a1be431c89
@@@ -160,24 -160,35 +160,24 @@@ static int max98363_io_init(struct sdw_
        struct max98363_priv *max98363 = dev_get_drvdata(dev);
        int ret, reg;
  
 -      if (max98363->first_hw_init) {
 -              regcache_cache_only(max98363->regmap, false);
 +      regcache_cache_only(max98363->regmap, false);
 +      if (max98363->first_hw_init)
                regcache_cache_bypass(max98363->regmap, true);
 -      }
  
        /*
 -       * PM runtime is only enabled when a Slave reports as Attached
 +       * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
 -      if (!max98363->first_hw_init) {
 -              /* set autosuspend parameters */
 -              pm_runtime_set_autosuspend_delay(dev, 3000);
 -              pm_runtime_use_autosuspend(dev);
 -
 +      if (!max98363->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(dev);
  
 -              /* make sure the device does not suspend immediately */
 -              pm_runtime_mark_last_busy(dev);
 -
 -              pm_runtime_enable(dev);
 -      }
 -
        pm_runtime_get_noresume(dev);
  
        ret = regmap_read(max98363->regmap, MAX98363_R21FF_REV_ID, &reg);
-       if (!ret) {
+       if (!ret)
                dev_info(dev, "Revision ID: %X\n", reg);
-               return ret;
-       }
+       else
+               goto out;
  
        if (max98363->first_hw_init) {
                regcache_cache_bypass(max98363->regmap, false);
        max98363->first_hw_init = true;
        max98363->hw_init = true;
  
+ out:
        pm_runtime_mark_last_busy(dev);
        pm_runtime_put_autosuspend(dev);
  
-       return 0;
+       return ret;
  }
  
  #define MAX98363_RATES SNDRV_PCM_RATE_8000_192000
@@@ -398,8 -410,6 +399,8 @@@ static int max98363_init(struct sdw_sla
        max98363->regmap = regmap;
        max98363->slave = slave;
  
 +      regcache_cache_only(max98363->regmap, true);
 +
        max98363->hw_init = false;
        max98363->first_hw_init = false;
  
        ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98363,
                                              max98363_dai,
                                              ARRAY_SIZE(max98363_dai));
 -      if (ret < 0)
 +      if (ret < 0) {
                dev_err(dev, "Failed to register codec: %d\n", ret);
 +              return ret;
 +      }
  
 -      return ret;
 +      /* set autosuspend parameters */
 +      pm_runtime_set_autosuspend_delay(dev, 3000);
 +      pm_runtime_use_autosuspend(dev);
 +
 +      /* make sure the device does not suspend immediately */
 +      pm_runtime_mark_last_busy(dev);
 +
 +      pm_runtime_enable(dev);
 +
 +      /* important note: the device is NOT tagged as 'active' and will remain
 +       * 'suspended' until the hardware is enumerated/initialized. This is required
 +       * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
 +       * fail with -EACCESS because of race conditions between card creation and enumeration
 +       */
 +      return 0;
  }
  
  static int max98363_sdw_probe(struct sdw_slave *slave,
index b07c27c780d9ad9fdf2ff4abfe53ca3d4a8f1e73,9d01225dedd9a1470c45e45df999861c99630677..bbaad6ec2e72648dd1d99079bf6eaaff0068e94f
@@@ -1,4 -1,4 +1,4 @@@
- // SPDX-License-Identifier: GPL-2.0
+ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
  // Copyright 2018 NXP
  
  #include <linux/bitfield.h>
@@@ -56,8 -56,6 +56,8 @@@ struct fsl_micfil 
        int vad_init_mode;
        int vad_enabled;
        int vad_detected;
 +      struct fsl_micfil_verid verid;
 +      struct fsl_micfil_param param;
  };
  
  struct fsl_micfil_soc_data {
@@@ -66,7 -64,6 +66,7 @@@
        unsigned int dataline;
        bool imx;
        bool use_edma;
 +      bool use_verid;
        u64  formats;
  };
  
@@@ -93,7 -90,6 +93,7 @@@ static struct fsl_micfil_soc_data fsl_m
        .dataline =  0xf,
        .formats = SNDRV_PCM_FMTBIT_S32_LE,
        .use_edma = true,
 +      .use_verid = true,
  };
  
  static const struct of_device_id fsl_micfil_dt_ids[] = {
@@@ -360,49 -356,6 +360,49 @@@ static const struct snd_kcontrol_new fs
        SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL),
  };
  
 +static int fsl_micfil_use_verid(struct device *dev)
 +{
 +      struct fsl_micfil *micfil = dev_get_drvdata(dev);
 +      unsigned int val;
 +      int ret;
 +
 +      if (!micfil->soc->use_verid)
 +              return 0;
 +
 +      ret = regmap_read(micfil->regmap, REG_MICFIL_VERID, &val);
 +      if (ret < 0)
 +              return ret;
 +
 +      dev_dbg(dev, "VERID: 0x%016X\n", val);
 +
 +      micfil->verid.version = val &
 +              (MICFIL_VERID_MAJOR_MASK | MICFIL_VERID_MINOR_MASK);
 +      micfil->verid.version >>= MICFIL_VERID_MINOR_SHIFT;
 +      micfil->verid.feature = val & MICFIL_VERID_FEATURE_MASK;
 +
 +      ret = regmap_read(micfil->regmap, REG_MICFIL_PARAM, &val);
 +      if (ret < 0)
 +              return ret;
 +
 +      dev_dbg(dev, "PARAM: 0x%016X\n", val);
 +
 +      micfil->param.hwvad_num = (val & MICFIL_PARAM_NUM_HWVAD_MASK) >>
 +              MICFIL_PARAM_NUM_HWVAD_SHIFT;
 +      micfil->param.hwvad_zcd = val & MICFIL_PARAM_HWVAD_ZCD;
 +      micfil->param.hwvad_energy_mode = val & MICFIL_PARAM_HWVAD_ENERGY_MODE;
 +      micfil->param.hwvad = val & MICFIL_PARAM_HWVAD;
 +      micfil->param.dc_out_bypass = val & MICFIL_PARAM_DC_OUT_BYPASS;
 +      micfil->param.dc_in_bypass = val & MICFIL_PARAM_DC_IN_BYPASS;
 +      micfil->param.low_power = val & MICFIL_PARAM_LOW_POWER;
 +      micfil->param.fil_out_width = val & MICFIL_PARAM_FIL_OUT_WIDTH;
 +      micfil->param.fifo_ptrwid = (val & MICFIL_PARAM_FIFO_PTRWID_MASK) >>
 +              MICFIL_PARAM_FIFO_PTRWID_SHIFT;
 +      micfil->param.npair = (val & MICFIL_PARAM_NPAIR_MASK) >>
 +              MICFIL_PARAM_NPAIR_SHIFT;
 +
 +      return 0;
 +}
 +
  /* The SRES is a self-negated bit which provides the CPU with the
   * capability to initialize the PDM Interface module through the
   * slave-bus interface. This bit always reads as zero, and this
@@@ -872,9 -825,6 +872,9 @@@ static bool fsl_micfil_readable_reg(str
        case REG_MICFIL_DC_CTRL:
        case REG_MICFIL_OUT_CTRL:
        case REG_MICFIL_OUT_STAT:
 +      case REG_MICFIL_FSYNC_CTRL:
 +      case REG_MICFIL_VERID:
 +      case REG_MICFIL_PARAM:
        case REG_MICFIL_VAD0_CTRL1:
        case REG_MICFIL_VAD0_CTRL2:
        case REG_MICFIL_VAD0_STAT:
@@@ -899,7 -849,6 +899,7 @@@ static bool fsl_micfil_writeable_reg(st
        case REG_MICFIL_DC_CTRL:
        case REG_MICFIL_OUT_CTRL:
        case REG_MICFIL_OUT_STAT:       /* Write 1 to Clear */
 +      case REG_MICFIL_FSYNC_CTRL:
        case REG_MICFIL_VAD0_CTRL1:
        case REG_MICFIL_VAD0_CTRL2:
        case REG_MICFIL_VAD0_STAT:      /* Write 1 to Clear */
@@@ -924,8 -873,6 +924,8 @@@ static bool fsl_micfil_volatile_reg(str
        case REG_MICFIL_DATACH5:
        case REG_MICFIL_DATACH6:
        case REG_MICFIL_DATACH7:
 +      case REG_MICFIL_VERID:
 +      case REG_MICFIL_PARAM:
        case REG_MICFIL_VAD0_STAT:
        case REG_MICFIL_VAD0_NDATA:
                return true;
@@@ -1084,9 -1031,6 +1084,9 @@@ static irqreturn_t hwvad_err_isr(int ir
        return IRQ_HANDLED;
  }
  
 +static int fsl_micfil_runtime_suspend(struct device *dev);
 +static int fsl_micfil_runtime_resume(struct device *dev);
 +
  static int fsl_micfil_probe(struct platform_device *pdev)
  {
        struct device_node *np = pdev->dev.of_node;
                return -ENOMEM;
  
        micfil->pdev = pdev;
 -      strncpy(micfil->name, np->name, sizeof(micfil->name) - 1);
 +      strscpy(micfil->name, np->name, sizeof(micfil->name));
  
        micfil->soc = of_device_get_match_data(&pdev->dev);
  
        platform_set_drvdata(pdev, micfil);
  
        pm_runtime_enable(&pdev->dev);
 +      if (!pm_runtime_enabled(&pdev->dev)) {
 +              ret = fsl_micfil_runtime_resume(&pdev->dev);
 +              if (ret)
 +                      goto err_pm_disable;
 +      }
 +
 +      ret = pm_runtime_resume_and_get(&pdev->dev);
 +      if (ret < 0)
 +              goto err_pm_get_sync;
 +
 +      /* Get micfil version */
 +      ret = fsl_micfil_use_verid(&pdev->dev);
 +      if (ret < 0)
 +              dev_warn(&pdev->dev, "Error reading MICFIL version: %d\n", ret);
 +
 +      ret = pm_runtime_put_sync(&pdev->dev);
 +      if (ret < 0 && ret != -ENOSYS)
 +              goto err_pm_get_sync;
 +
        regcache_cache_only(micfil->regmap, true);
  
        /*
  
        return ret;
  
 +err_pm_get_sync:
 +      if (!pm_runtime_status_suspended(&pdev->dev))
 +              fsl_micfil_runtime_suspend(&pdev->dev);
  err_pm_disable:
        pm_runtime_disable(&pdev->dev);
  
@@@ -1263,7 -1185,7 +1263,7 @@@ static void fsl_micfil_remove(struct pl
        pm_runtime_disable(&pdev->dev);
  }
  
 -static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev)
 +static int fsl_micfil_runtime_suspend(struct device *dev)
  {
        struct fsl_micfil *micfil = dev_get_drvdata(dev);
  
        return 0;
  }
  
 -static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev)
 +static int fsl_micfil_runtime_resume(struct device *dev)
  {
        struct fsl_micfil *micfil = dev_get_drvdata(dev);
        int ret;
        return 0;
  }
  
 -static int __maybe_unused fsl_micfil_suspend(struct device *dev)
 -{
 -      pm_runtime_force_suspend(dev);
 -
 -      return 0;
 -}
 -
 -static int __maybe_unused fsl_micfil_resume(struct device *dev)
 -{
 -      pm_runtime_force_resume(dev);
 -
 -      return 0;
 -}
 -
  static const struct dev_pm_ops fsl_micfil_pm_ops = {
        SET_RUNTIME_PM_OPS(fsl_micfil_runtime_suspend,
                           fsl_micfil_runtime_resume,
                           NULL)
 -      SET_SYSTEM_SLEEP_PM_OPS(fsl_micfil_suspend,
 -                              fsl_micfil_resume)
 +      SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 +                              pm_runtime_force_resume)
  };
  
  static struct platform_driver fsl_micfil_driver = {
@@@ -1318,4 -1254,4 +1318,4 @@@ module_platform_driver(fsl_micfil_drive
  
  MODULE_AUTHOR("Cosmin-Gabriel Samoila <[email protected]>");
  MODULE_DESCRIPTION("NXP PDM Microphone Interface (MICFIL) driver");
- MODULE_LICENSE("GPL v2");
+ MODULE_LICENSE("Dual BSD/GPL");
index 231a52aff024623e08d95e8a9954a6a2ec3a0d9b,fee9fe3d91199146b326b09aa022653fd35f44c3..c6b902ba0a5317d4ead1ce6ec320d8901f0fb69b
@@@ -1,4 -1,4 +1,4 @@@
- /* SPDX-License-Identifier: GPL-2.0 */
+ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
  /*
   * PDM Microphone Interface for the NXP i.MX SoC
   * Copyright 2018 NXP
@@@ -24,9 -24,6 +24,9 @@@
  #define REG_MICFIL_DC_CTRL            0x64
  #define REG_MICFIL_OUT_CTRL           0x74
  #define REG_MICFIL_OUT_STAT           0x7C
 +#define REG_MICFIL_FSYNC_CTRL         0x80
 +#define REG_MICFIL_VERID              0x84
 +#define REG_MICFIL_PARAM              0x88
  #define REG_MICFIL_VAD0_CTRL1         0x90
  #define REG_MICFIL_VAD0_CTRL2         0x94
  #define REG_MICFIL_VAD0_STAT          0x98
@@@ -42,8 -39,6 +42,8 @@@
  #define MICFIL_CTRL1_DBG              BIT(28)
  #define MICFIL_CTRL1_SRES             BIT(27)
  #define MICFIL_CTRL1_DBGE             BIT(26)
 +#define MICFIL_CTRL1_DECFILS          BIT(20)
 +#define MICFIL_CTRL1_FSYNCEN          BIT(16)
  
  #define MICFIL_CTRL1_DISEL_DISABLE    0
  #define MICFIL_CTRL1_DISEL_DMA                1
  #define MICFIL_DC_CUTOFF_152Hz         2
  #define MICFIL_DC_BYPASS               3
  
 +/* MICFIL VERID Register -- REG_MICFIL_VERID */
 +#define MICFIL_VERID_MAJOR_SHIFT        24
 +#define MICFIL_VERID_MAJOR_MASK         GENMASK(31, 24)
 +#define MICFIL_VERID_MINOR_SHIFT        16
 +#define MICFIL_VERID_MINOR_MASK         GENMASK(23, 16)
 +#define MICFIL_VERID_FEATURE_SHIFT      0
 +#define MICFIL_VERID_FEATURE_MASK       GENMASK(15, 0)
 +
 +/* MICFIL PARAM Register -- REG_MICFIL_PARAM */
 +#define MICFIL_PARAM_NUM_HWVAD_SHIFT    24
 +#define MICFIL_PARAM_NUM_HWVAD_MASK     GENMASK(27, 24)
 +#define MICFIL_PARAM_HWVAD_ZCD          BIT(19)
 +#define MICFIL_PARAM_HWVAD_ENERGY_MODE  BIT(17)
 +#define MICFIL_PARAM_HWVAD              BIT(16)
 +#define MICFIL_PARAM_DC_OUT_BYPASS      BIT(11)
 +#define MICFIL_PARAM_DC_IN_BYPASS       BIT(10)
 +#define MICFIL_PARAM_LOW_POWER          BIT(9)
 +#define MICFIL_PARAM_FIL_OUT_WIDTH      BIT(8)
 +#define MICFIL_PARAM_FIFO_PTRWID_SHIFT  4
 +#define MICFIL_PARAM_FIFO_PTRWID_MASK   GENMASK(7, 4)
 +#define MICFIL_PARAM_NPAIR_SHIFT        0
 +#define MICFIL_PARAM_NPAIR_MASK         GENMASK(3, 0)
 +
  /* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/
  #define MICFIL_VAD0_CTRL1_CHSEL               GENMASK(26, 24)
  #define MICFIL_VAD0_CTRL1_CICOSR      GENMASK(19, 16)
  #define MICFIL_HWVAD_ENVELOPE_MODE    0
  #define MICFIL_HWVAD_ENERGY_MODE      1
  
 +/**
 + * struct fsl_micfil_verid - version id data
 + * @version: version number
 + * @feature: feature specification number
 + */
 +struct fsl_micfil_verid {
 +      u32 version;
 +      u32 feature;
 +};
 +
 +/**
 + * struct fsl_micfil_param - parameter data
 + * @hwvad_num: the number of HWVADs
 + * @hwvad_zcd: HWVAD zero-cross detector is active
 + * @hwvad_energy_mode: HWVAD energy mode is active
 + * @hwvad: HWVAD is active
 + * @dc_out_bypass: points out if the output DC remover is disabled
 + * @dc_in_bypass: points out if the input DC remover is disabled
 + * @low_power: low power decimation filter
 + * @fil_out_width: filter output width
 + * @fifo_ptrwid: FIFO pointer width
 + * @npair: number of microphone pairs
 + */
 +struct fsl_micfil_param {
 +      u32 hwvad_num;
 +      bool hwvad_zcd;
 +      bool hwvad_energy_mode;
 +      bool hwvad;
 +      bool dc_out_bypass;
 +      bool dc_in_bypass;
 +      bool low_power;
 +      bool fil_out_width;
 +      u32 fifo_ptrwid;
 +      u32 npair;
 +};
 +
  #endif /* _FSL_MICFIL_H */
index f283c0d528dfc9957aa7bf651707bcf18c24ca51,0201029899cad62991da5090e501f14eebf9cb48..5a1c750e6ae6aeb368b53c7d6f801119960502b0
@@@ -307,16 -307,6 +307,16 @@@ static const struct dmi_system_id sof_s
                .driver_data = (void *)(SOF_SDW_TGL_HDMI |
                                        SOF_SDW_FOUR_SPK),
        },
 +      {
 +              .callback = sof_sdw_quirk_cb,
 +              .matches = {
 +                      DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 +                      DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
 +              },
 +              .driver_data = (void *)(SOF_SDW_TGL_HDMI |
 +                                      RT711_JD2 |
 +                                      SOF_SDW_FOUR_SPK),
 +      },
        {
                .callback = sof_sdw_quirk_cb,
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Rex"),
                },
 -              .driver_data = (void *)(SOF_SDW_PCH_DMIC),
 +              .driver_data = (void *)(SOF_SDW_PCH_DMIC |
 +                                      SOF_BT_OFFLOAD_SSP(1) |
 +                                      SOF_SSP_BT_OFFLOAD_PRESENT),
        },
        /* LunarLake devices */
        {
                        DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"),
                },
-               .driver_data = (void *)(RT711_JD2_100K),
+               .driver_data = (void *)(RT711_JD2),
        },
        {}
  };
@@@ -523,8 -511,9 +523,8 @@@ int sdw_prepare(struct snd_pcm_substrea
        dai = asoc_rtd_to_cpu(rtd, 0);
  
        sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
 -
        if (IS_ERR(sdw_stream)) {
 -              dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
 +              dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
                return PTR_ERR(sdw_stream);
        }
  
@@@ -542,8 -531,9 +542,8 @@@ int sdw_trigger(struct snd_pcm_substrea
        dai = asoc_rtd_to_cpu(rtd, 0);
  
        sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
 -
        if (IS_ERR(sdw_stream)) {
 -              dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
 +              dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
                return PTR_ERR(sdw_stream);
        }
  
        }
  
        if (ret)
 -              dev_err(rtd->dev, "%s trigger %d failed: %d", __func__, cmd, ret);
 +              dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret);
  
        return ret;
  }
@@@ -629,8 -619,9 +629,8 @@@ int sdw_hw_free(struct snd_pcm_substrea
        dai = asoc_rtd_to_cpu(rtd, 0);
  
        sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
 -
        if (IS_ERR(sdw_stream)) {
 -              dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
 +              dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
                return PTR_ERR(sdw_stream);
        }
  
@@@ -903,19 -894,6 +903,19 @@@ static struct sof_sdw_codec_info codec_
                },
                .dai_num = 1,
        },
 +      {
 +              .part_id = 0x3556,
 +              .dais = {
 +                      {
 +                              .direction = {true, true},
 +                              .dai_name = "cs35l56-sdw1",
 +                              .dai_type = SOF_SDW_DAI_TYPE_AMP,
 +                              .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
 +                              .init = sof_sdw_cs_amp_init,
 +                      },
 +              },
 +              .dai_num = 1,
 +      },
        {
                .part_id = 0x4242,
                .dais = {
                .version_id = 0,
                .dais = {
                        {
 -                              .direction = {true, false},
 +                              .direction = {true, true},
                                .dai_name = "sdw-mockup-aif1",
                                .dai_type = SOF_SDW_DAI_TYPE_AMP,
 -                              .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
 +                              .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
                                .init = NULL,
                        },
                },
        },
  };
  
 -static inline int find_codec_info_part(u64 adr)
 +static inline int find_codec_info_part(const u64 adr)
  {
        unsigned int part_id, sdw_version;
        int i;
@@@ -1016,10 -994,14 +1016,10 @@@ static inline int find_codec_info_acpi(
                return -EINVAL;
  
        for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
 -              if (!memcmp(codec_info_list[i].acpi_id, acpi_id,
 -                          ACPI_ID_LEN))
 -                      break;
 -
 -      if (i == ARRAY_SIZE(codec_info_list))
 -              return -EINVAL;
 +              if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN))
 +                      return i;
  
 -      return i;
 +      return -EINVAL;
  }
  
  /*
   * Since some sdw slaves may be aggregated, the CPU DAI number
   * may be larger than the number of BE dailinks.
   */
 -static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_link_adr *links,
 -                              int *sdw_be_num, int *sdw_cpu_dai_num)
 +static int get_dailink_info(struct device *dev,
 +                          const struct snd_soc_acpi_link_adr *adr_link,
 +                          int *sdw_be_num, int *sdw_cpu_dai_num, int *codecs_num)
  {
 -      const struct snd_soc_acpi_link_adr *link;
        bool group_visited[SDW_MAX_GROUPS];
        bool no_aggregation;
        int i;
        *sdw_cpu_dai_num = 0;
        *sdw_be_num  = 0;
  
 -      if (!links)
 +      if (!adr_link)
                return -EINVAL;
  
        for (i = 0; i < SDW_MAX_GROUPS; i++)
                group_visited[i] = false;
  
 -      for (link = links; link->num_adr; link++) {
 +      for (; adr_link->num_adr; adr_link++) {
                const struct snd_soc_acpi_endpoint *endpoint;
                struct sof_sdw_codec_info *codec_info;
                int codec_index;
                int stream;
                u64 adr;
  
 -              for (i = 0; i < link->num_adr; i++) {
 -                      adr = link->adr_d[i].adr;
 +              /* make sure the link mask has a single bit set */
 +              if (!is_power_of_2(adr_link->mask))
 +                      return -EINVAL;
 +
 +              for (i = 0; i < adr_link->num_adr; i++) {
 +                      adr = adr_link->adr_d[i].adr;
                        codec_index = find_codec_info_part(adr);
                        if (codec_index < 0)
                                return codec_index;
 +
                        codec_info = &codec_info_list[codec_index];
  
 -                      endpoint = link->adr_d[i].endpoints;
 +                      *codecs_num += codec_info->dai_num;
 +
 +                      if (!adr_link->adr_d[i].name_prefix) {
 +                              dev_err(dev, "codec 0x%llx does not have a name prefix\n",
 +                                      adr_link->adr_d[i].adr);
 +                              return -EINVAL;
 +                      }
 +
 +                      endpoint = adr_link->adr_d[i].endpoints;
 +                      if (endpoint->aggregated && !endpoint->group_id) {
 +                              dev_err(dev, "invalid group id on link %x\n",
 +                                      adr_link->mask);
 +                              return -EINVAL;
 +                      }
  
                        for (j = 0; j < codec_info->dai_num; j++) {
                                /* count DAI number for playback and capture */
@@@ -1126,16 -1090,17 +1126,16 @@@ static void init_dai_link(struct devic
        dai_links->ops = ops;
  }
  
 -static bool is_unique_device(const struct snd_soc_acpi_link_adr *link,
 +static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link,
                             unsigned int sdw_version,
                             unsigned int mfg_id,
                             unsigned int part_id,
                             unsigned int class_id,
 -                           int index_in_link
 -                          )
 +                           int index_in_link)
  {
        int i;
  
 -      for (i = 0; i < link->num_adr; i++) {
 +      for (i = 0; i < adr_link->num_adr; i++) {
                unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
                u64 adr;
  
                if (i == index_in_link)
                        continue;
  
 -              adr = link->adr_d[i].adr;
 +              adr = adr_link->adr_d[i].adr;
  
                sdw1_version = SDW_VERSION(adr);
                mfg1_id = SDW_MFG_ID(adr);
        return true;
  }
  
 -static int create_codec_dai_name(struct device *dev,
 -                               const struct snd_soc_acpi_link_adr *link,
 -                               struct snd_soc_dai_link_component *codec,
 -                               int offset,
 -                               struct snd_soc_codec_conf *codec_conf,
 -                               int codec_count,
 -                               int *codec_conf_index,
 -                               int adr_index,
 -                               int dai_index)
 +static int fill_sdw_codec_dlc(struct device *dev,
 +                            const struct snd_soc_acpi_link_adr *adr_link,
 +                            struct snd_soc_dai_link_component *codec,
 +                            int adr_index, int dai_index)
  {
 -      int _codec_index = -1;
 -      int i;
 -
 -      /* sanity check */
 -      if (*codec_conf_index + link->num_adr - adr_index > codec_count) {
 -              dev_err(dev, "codec_conf: out-of-bounds access requested\n");
 -              return -EINVAL;
 -      }
 -
 -      for (i = adr_index; i < link->num_adr; i++) {
 -              unsigned int sdw_version, unique_id, mfg_id;
 -              unsigned int link_id, part_id, class_id;
 -              int codec_index, comp_index;
 -              char *codec_str;
 -              u64 adr;
 -
 -              adr = link->adr_d[i].adr;
 -
 -              sdw_version = SDW_VERSION(adr);
 -              link_id = SDW_DISCO_LINK_ID(adr);
 -              unique_id = SDW_UNIQUE_ID(adr);
 -              mfg_id = SDW_MFG_ID(adr);
 -              part_id = SDW_PART_ID(adr);
 -              class_id = SDW_CLASS_ID(adr);
 -
 -              comp_index = i - adr_index + offset;
 -              if (is_unique_device(link, sdw_version, mfg_id, part_id,
 -                                   class_id, i)) {
 -                      codec_str = "sdw:%01x:%04x:%04x:%02x";
 -                      codec[comp_index].name =
 -                              devm_kasprintf(dev, GFP_KERNEL, codec_str,
 -                                             link_id, mfg_id, part_id,
 -                                             class_id);
 -              } else {
 -                      codec_str = "sdw:%01x:%04x:%04x:%02x:%01x";
 -                      codec[comp_index].name =
 -                              devm_kasprintf(dev, GFP_KERNEL, codec_str,
 -                                             link_id, mfg_id, part_id,
 -                                             class_id, unique_id);
 -              }
 -
 -              if (!codec[comp_index].name)
 -                      return -ENOMEM;
 -
 -              codec_index = find_codec_info_part(adr);
 -              if (codec_index < 0)
 -                      return codec_index;
 -              if (_codec_index != -1 && codec_index != _codec_index) {
 -                      dev_dbg(dev, "Different devices on the same sdw link\n");
 -                      break;
 -              }
 -              _codec_index = codec_index;
 +      unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id;
 +      u64 adr = adr_link->adr_d[adr_index].adr;
 +      int codec_index;
  
 -              codec[comp_index].dai_name =
 -                      codec_info_list[codec_index].dais[dai_index].dai_name;
 +      codec_index = find_codec_info_part(adr);
 +      if (codec_index < 0)
 +              return codec_index;
  
 -              codec_conf[*codec_conf_index].dlc = codec[comp_index];
 -              codec_conf[*codec_conf_index].name_prefix = link->adr_d[i].name_prefix;
 +      sdw_version = SDW_VERSION(adr);
 +      link_id = SDW_DISCO_LINK_ID(adr);
 +      unique_id = SDW_UNIQUE_ID(adr);
 +      mfg_id = SDW_MFG_ID(adr);
 +      part_id = SDW_PART_ID(adr);
 +      class_id = SDW_CLASS_ID(adr);
 +
 +      if (codec_info_list[codec_index].codec_name)
 +              codec->name = devm_kstrdup(dev,
 +                                         codec_info_list[codec_index].codec_name,
 +                                         GFP_KERNEL);
 +      else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id,
 +                                class_id, adr_index))
 +              codec->name = devm_kasprintf(dev, GFP_KERNEL,
 +                                           "sdw:%01x:%04x:%04x:%02x", link_id,
 +                                           mfg_id, part_id, class_id);
 +      else
 +              codec->name = devm_kasprintf(dev, GFP_KERNEL,
 +                                           "sdw:%01x:%04x:%04x:%02x:%01x", link_id,
 +                                           mfg_id, part_id, class_id, unique_id);
 +
 +      if (!codec->name)
 +              return -ENOMEM;
  
 -              ++*codec_conf_index;
 -      }
 +      codec->dai_name = codec_info_list[codec_index].dais[dai_index].dai_name;
  
        return 0;
  }
  
  static int set_codec_init_func(struct snd_soc_card *card,
 -                             const struct snd_soc_acpi_link_adr *link,
 +                             const struct snd_soc_acpi_link_adr *adr_link,
                               struct snd_soc_dai_link *dai_links,
                               bool playback, int group_id, int adr_index, int dai_index)
  {
                 * Initialize the codec. If codec is part of an aggregated
                 * group (group_id>0), initialize all codecs belonging to
                 * same group.
 -               * The first link should start with link->adr_d[adr_index]
 +               * The first link should start with adr_link->adr_d[adr_index]
                 * because that is the device that we want to initialize and
                 * we should end immediately if it is not aggregated (group_id=0)
                 */
 -              for ( ; i < link->num_adr; i++) {
 +              for ( ; i < adr_link->num_adr; i++) {
                        int codec_index;
  
 -                      codec_index = find_codec_info_part(link->adr_d[i].adr);
 -
 +                      codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
                        if (codec_index < 0)
                                return codec_index;
  
                        /* The group_id is > 0 iff the codec is aggregated */
 -                      if (link->adr_d[i].endpoints->group_id != group_id)
 +                      if (adr_link->adr_d[i].endpoints->group_id != group_id)
                                continue;
  
                        if (codec_info_list[codec_index].dais[dai_index].init)
                                codec_info_list[codec_index].dais[dai_index].init(card,
 -                                              link,
 +                                              adr_link,
                                                dai_links,
                                                &codec_info_list[codec_index],
                                                playback);
                        if (!group_id)
                                return 0;
                }
 +
                i = 0;
 -              link++;
 -      } while (link->mask);
 +              adr_link++;
 +      } while (adr_link->mask);
  
        return 0;
  }
  static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link,
                          struct device *dev, int *cpu_dai_id, int *cpu_dai_num,
                          int *codec_num, unsigned int *group_id,
 -                        bool *group_generated, int adr_index)
 +                        int adr_index)
  {
 -      const struct snd_soc_acpi_adr_device *adr_d;
 -      const struct snd_soc_acpi_link_adr *adr_next;
 -      bool no_aggregation;
 -      int index = 0;
 +      bool no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
        int i;
  
 -      no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
 -      adr_d = &adr_link->adr_d[adr_index];
 -
 -      /* make sure the link mask has a single bit set */
 -      if (!is_power_of_2(adr_link->mask))
 -              return -EINVAL;
 -
 -      cpu_dai_id[index++] = ffs(adr_link->mask) - 1;
 -      if (!adr_d->endpoints->aggregated || no_aggregation) {
 +      if (!adr_link->adr_d[adr_index].endpoints->aggregated || no_aggregation) {
 +              cpu_dai_id[0] = ffs(adr_link->mask) - 1;
                *cpu_dai_num = 1;
                *codec_num = 1;
                *group_id = 0;
                return 0;
        }
  
 -      *group_id = adr_d->endpoints->group_id;
 -
 -      /* Count endpoints with the same group_id in the adr_link */
        *codec_num = 0;
 -      for (i = 0; i < adr_link->num_adr; i++) {
 -              if (adr_link->adr_d[i].endpoints->aggregated &&
 -                  adr_link->adr_d[i].endpoints->group_id == *group_id)
 -                      (*codec_num)++;
 -      }
 +      *cpu_dai_num = 0;
 +      *group_id = adr_link->adr_d[adr_index].endpoints->group_id;
  
 -      /* gather other link ID of slaves in the same group */
 -      for (adr_next = adr_link + 1; adr_next && adr_next->num_adr;
 -              adr_next++) {
 -              const struct snd_soc_acpi_endpoint *endpoint;
 +      /* Count endpoints with the same group_id in the adr_link */
 +      for (; adr_link && adr_link->num_adr; adr_link++) {
 +              unsigned int link_codecs = 0;
  
 -              endpoint = adr_next->adr_d->endpoints;
 -              if (!endpoint->aggregated ||
 -                  endpoint->group_id != *group_id)
 -                      continue;
 +              for (i = 0; i < adr_link->num_adr; i++) {
 +                      if (adr_link->adr_d[i].endpoints->aggregated &&
 +                          adr_link->adr_d[i].endpoints->group_id == *group_id)
 +                              link_codecs++;
 +              }
  
 -              /* make sure the link mask has a single bit set */
 -              if (!is_power_of_2(adr_next->mask))
 -                      return -EINVAL;
 +              if (link_codecs) {
 +                      *codec_num += link_codecs;
  
 -              if (index >= SDW_MAX_CPU_DAIS) {
 -                      dev_err(dev, " cpu_dai_id array overflows");
 -                      return -EINVAL;
 -              }
 +                      if (*cpu_dai_num >= SDW_MAX_CPU_DAIS) {
 +                              dev_err(dev, "cpu_dai_id array overflowed\n");
 +                              return -EINVAL;
 +                      }
  
 -              cpu_dai_id[index++] = ffs(adr_next->mask) - 1;
 -              for (i = 0; i < adr_next->num_adr; i++) {
 -                      if (adr_next->adr_d[i].endpoints->aggregated &&
 -                          adr_next->adr_d[i].endpoints->group_id == *group_id)
 -                              (*codec_num)++;
 +                      cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1;
                }
        }
  
 -      /*
 -       * indicate CPU DAIs for this group have been generated
 -       * to avoid generating CPU DAIs for this group again.
 -       */
 -      group_generated[*group_id] = true;
 -      *cpu_dai_num = index;
 -
        return 0;
  }
  
@@@ -1318,36 -1344,37 +1318,36 @@@ static void set_dailink_map(struct snd_
  
  static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
  
 -static int create_sdw_dailink(struct snd_soc_card *card,
 -                            struct device *dev, int *link_index,
 +static int create_sdw_dailink(struct snd_soc_card *card, int *link_index,
                              struct snd_soc_dai_link *dai_links,
                              int sdw_be_num, int sdw_cpu_dai_num,
                              struct snd_soc_dai_link_component *cpus,
 -                            const struct snd_soc_acpi_link_adr *link,
 -                            int *cpu_id, bool *group_generated,
 -                            struct snd_soc_codec_conf *codec_conf,
 -                            int codec_count, int *link_id,
 +                            const struct snd_soc_acpi_link_adr *adr_link,
 +                            int *cpu_id, struct snd_soc_codec_conf *codec_conf,
 +                            int codec_count, int *be_id,
                              int *codec_conf_index,
                              bool *ignore_pch_dmic,
                              bool append_dai_type,
                              int adr_index,
                              int dai_index)
  {
 -      const struct snd_soc_acpi_link_adr *link_next;
 +      struct device *dev = card->dev;
 +      const struct snd_soc_acpi_link_adr *adr_link_next;
        struct snd_soc_dai_link_component *codecs;
        struct sof_sdw_codec_info *codec_info;
        int cpu_dai_id[SDW_MAX_CPU_DAIS];
        int cpu_dai_num, cpu_dai_index;
        unsigned int group_id;
 -      int codec_idx = 0;
 +      int codec_dlc_index = 0;
        int codec_index;
        int codec_num;
        int stream;
        int i = 0;
 +      int j, k;
        int ret;
 -      int k;
  
 -      ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
 -                           &group_id, group_generated, adr_index);
 +      ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
 +                           &group_id, adr_index);
        if (ret)
                return ret;
  
                return -ENOMEM;
  
        /* generate codec name on different links in the same group */
 -      for (link_next = link; link_next && link_next->num_adr &&
 -           i < cpu_dai_num; link_next++) {
 -              const struct snd_soc_acpi_endpoint *endpoints;
 -
 -              endpoints = link_next->adr_d->endpoints;
 -              if (group_id && (!endpoints->aggregated ||
 -                               endpoints->group_id != group_id))
 -                      continue;
 -
 +      j = adr_index;
 +      for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr &&
 +           i < cpu_dai_num; adr_link_next++) {
                /* skip the link excluded by this processed group */
 -              if (cpu_dai_id[i] != ffs(link_next->mask) - 1)
 +              if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1)
                        continue;
  
 -              ret = create_codec_dai_name(dev, link_next, codecs, codec_idx,
 -                                          codec_conf, codec_count, codec_conf_index,
 -                                          adr_index, dai_index);
 -              if (ret < 0)
 -                      return ret;
 +              /* j reset after loop, adr_index only applies to first link */
 +              for (; j < adr_link_next->num_adr; j++) {
 +                      const struct snd_soc_acpi_endpoint *endpoints;
 +
 +                      endpoints = adr_link_next->adr_d[j].endpoints;
 +
 +                      if (group_id && (!endpoints->aggregated ||
 +                                       endpoints->group_id != group_id))
 +                              continue;
 +
 +                      /* sanity check */
 +                      if (*codec_conf_index >= codec_count) {
 +                              dev_err(dev, "codec_conf array overflowed\n");
 +                              return -EINVAL;
 +                      }
 +
 +                      ret = fill_sdw_codec_dlc(dev, adr_link_next,
 +                                               &codecs[codec_dlc_index],
 +                                               j, dai_index);
 +                      if (ret)
 +                              return ret;
 +
 +                      codec_conf[*codec_conf_index].dlc = codecs[codec_dlc_index];
 +                      codec_conf[*codec_conf_index].name_prefix =
 +                                      adr_link_next->adr_d[j].name_prefix;
 +
 +                      codec_dlc_index++;
 +                      (*codec_conf_index)++;
 +              }
 +              j = 0;
  
                /* check next link to create codec dai in the processed group */
                i++;
 -              codec_idx += link_next->num_adr;
        }
  
        /* find codec info to create BE DAI */
 -      codec_index = find_codec_info_part(link->adr_d[adr_index].adr);
 +      codec_index = find_codec_info_part(adr_link->adr_d[adr_index].adr);
        if (codec_index < 0)
                return codec_index;
        codec_info = &codec_info_list[codec_index];
                if (!codec_info->dais[dai_index].direction[stream])
                        continue;
  
 -              *link_id = codec_info->dais[dai_index].dailink[stream];
 -              if (*link_id < 0) {
 -                      dev_err(dev, "Invalid dailink id %d\n", *link_id);
 +              *be_id = codec_info->dais[dai_index].dailink[stream];
 +              if (*be_id < 0) {
 +                      dev_err(dev, "Invalid dailink id %d\n", *be_id);
                        return -EINVAL;
                }
  
                                return -ENOMEM;
  
                        if (cpu_dai_index >= sdw_cpu_dai_num) {
 -                              dev_err(dev, "invalid cpu dai index %d",
 +                              dev_err(dev, "invalid cpu dai index %d\n",
                                        cpu_dai_index);
                                return -EINVAL;
                        }
                 * not be larger than sdw_be_num
                 */
                if (*link_index >= sdw_be_num) {
 -                      dev_err(dev, "invalid dai link index %d", *link_index);
 +                      dev_err(dev, "invalid dai link index %d\n", *link_index);
                        return -EINVAL;
                }
  
                if (*cpu_id >= sdw_cpu_dai_num) {
 -                      dev_err(dev, " invalid cpu dai index %d", *cpu_id);
 +                      dev_err(dev, "invalid cpu dai index %d\n", *cpu_id);
                        return -EINVAL;
                }
  
                playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
                capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
 -              init_dai_link(dev, dai_links + *link_index, (*link_id)++, name,
 +              init_dai_link(dev, dai_links + *link_index, (*be_id)++, name,
                              playback, capture,
                              cpus + *cpu_id, cpu_dai_num,
                              codecs, codec_num,
  
                set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num);
                dai_links[*link_index].codec_ch_maps = sdw_codec_ch_maps;
 -              ret = set_codec_init_func(card, link, dai_links + (*link_index)++,
 +              ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++,
                                          playback, group_id, adr_index, dai_index);
                if (ret < 0) {
 -                      dev_err(dev, "failed to init codec %d", codec_index);
 +                      dev_err(dev, "failed to init codec %d\n", codec_index);
                        return ret;
                }
  
  
  #define IDISP_CODEC_MASK      0x4
  
 -static int sof_card_codec_conf_alloc(struct device *dev,
 -                                   struct snd_soc_acpi_mach_params *mach_params,
 -                                   struct snd_soc_codec_conf **codec_conf,
 -                                   int *codec_conf_count)
 +static int sof_card_dai_links_create(struct snd_soc_card *card)
  {
 -      const struct snd_soc_acpi_link_adr *adr_link;
 -      struct snd_soc_codec_conf *c_conf;
 -      int num_codecs = 0;
 -      int codec_index;
 -      int i;
 -
 -      adr_link = mach_params->links;
 -      if (!adr_link)
 -              return -EINVAL;
 -
 -      /* generate DAI links by each sdw link */
 -      for (; adr_link->num_adr; adr_link++) {
 -              for (i = 0; i < adr_link->num_adr; i++) {
 -                      if (!adr_link->adr_d[i].name_prefix) {
 -                              dev_err(dev, "codec 0x%llx does not have a name prefix\n",
 -                                      adr_link->adr_d[i].adr);
 -                              return -EINVAL;
 -                      }
 -                      codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
 -                      if (codec_index < 0)
 -                              return codec_index;
 -                      num_codecs += codec_info_list[codec_index].dai_num;
 -              }
 -      }
 -
 -      c_conf = devm_kzalloc(dev, num_codecs * sizeof(*c_conf), GFP_KERNEL);
 -      if (!c_conf)
 -              return -ENOMEM;
 -
 -      *codec_conf = c_conf;
 -      *codec_conf_count = num_codecs;
 -
 -      return 0;
 -}
 -
 -static int sof_card_dai_links_create(struct device *dev,
 -                                   struct snd_soc_acpi_mach *mach,
 -                                   struct snd_soc_card *card)
 -{
 -      int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num;
 +      struct device *dev = card->dev;
 +      struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
 +      int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, hdmi_num = 0, bt_num = 0;
        struct mc_private *ctx = snd_soc_card_get_drvdata(card);
        struct snd_soc_dai_link_component *idisp_components;
        struct snd_soc_dai_link_component *ssp_components;
 -      struct snd_soc_acpi_mach_params *mach_params;
 -      const struct snd_soc_acpi_link_adr *adr_link;
 +      struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
 +      const struct snd_soc_acpi_link_adr *adr_link = mach_params->links;
 +      bool aggregation = !(sof_sdw_quirk & SOF_SDW_NO_AGGREGATION);
        struct snd_soc_dai_link_component *cpus;
        struct snd_soc_codec_conf *codec_conf;
        bool append_dai_type = false;
        bool ignore_pch_dmic = false;
 -      int codec_conf_count;
 +      int codec_conf_num = 0;
        int codec_conf_index = 0;
 -      bool group_generated[SDW_MAX_GROUPS];
 +      bool group_generated[SDW_MAX_GROUPS] = { };
        int ssp_codec_index, ssp_mask;
 -      struct snd_soc_dai_link *links;
 +      struct snd_soc_dai_link *dai_links;
        int num_links, link_index = 0;
        char *name, *cpu_name;
        int total_cpu_dai_num;
        int i, j, be_id = 0;
        int codec_index;
        int cpu_id = 0;
 -      int comp_num;
        int ret;
  
 -      mach_params = &mach->mach_params;
 -
 -      /* allocate codec conf, will be populated when dailinks are created */
 -      ret = sof_card_codec_conf_alloc(dev, mach_params, &codec_conf, &codec_conf_count);
 -      if (ret < 0)
 +      ret = get_dailink_info(dev, adr_link, &sdw_be_num, &sdw_cpu_dai_num,
 +                             &codec_conf_num);
 +      if (ret < 0) {
 +              dev_err(dev, "failed to get sdw link info %d\n", ret);
                return ret;
 -
 -      /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
 -      for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
 -              codec_info_list[i].amp_num = 0;
 -
 -      if (mach_params->codec_mask & IDISP_CODEC_MASK) {
 -              ctx->idisp_codec = true;
 -
 -              if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
 -                      hdmi_num = SOF_TGL_HDMI_COUNT;
 -              else
 -                      hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
        }
  
 -      ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
        /*
         * on generic tgl platform, I2S or sdw mode is supported
         * based on board rework. A ACPI device is registered in
         * Here check ACPI ID to confirm I2S is supported.
         */
        ssp_codec_index = find_codec_info_acpi(mach->id);
 -      ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0;
 -      comp_num = hdmi_num + ssp_num;
 +      if (ssp_codec_index >= 0) {
 +              ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
 +              ssp_num = hweight_long(ssp_mask);
 +      }
  
 -      ret = get_sdw_dailink_info(dev, mach_params->links,
 -                                 &sdw_be_num, &sdw_cpu_dai_num);
 -      if (ret < 0) {
 -              dev_err(dev, "failed to get sdw link info %d", ret);
 -              return ret;
 +      if (mach_params->codec_mask & IDISP_CODEC_MASK) {
 +              ctx->idisp_codec = true;
 +
 +              if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
 +                      hdmi_num = SOF_TGL_HDMI_COUNT;
 +              else
 +                      hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
        }
  
        /* enable dmic01 & dmic16k */
 -      dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0;
 -      comp_num += dmic_num;
 +      if (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num)
 +              dmic_num = 2;
  
        if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
 -              comp_num++;
 +              bt_num = 1;
  
 -      dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num,
 -              dmic_num, ctx->idisp_codec ? hdmi_num : 0);
 +      dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n",
 +              sdw_be_num, ssp_num, dmic_num, hdmi_num, bt_num);
  
        /* allocate BE dailinks */
 -      num_links = comp_num + sdw_be_num;
 -      links = devm_kcalloc(dev, num_links, sizeof(*links), GFP_KERNEL);
 +      num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;
 +      dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
 +      if (!dai_links)
 +              return -ENOMEM;
  
        /* allocated CPU DAIs */
 -      total_cpu_dai_num = comp_num + sdw_cpu_dai_num;
 -      cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus),
 -                          GFP_KERNEL);
 +      total_cpu_dai_num = sdw_cpu_dai_num + ssp_num + dmic_num + hdmi_num + bt_num;
 +      cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus), GFP_KERNEL);
 +      if (!cpus)
 +              return -ENOMEM;
  
 -      if (!links || !cpus)
 +      /* allocate codec conf, will be populated when dailinks are created */
 +      codec_conf = devm_kcalloc(dev, codec_conf_num, sizeof(*codec_conf),
 +                                GFP_KERNEL);
 +      if (!codec_conf)
                return -ENOMEM;
  
        /* SDW */
        if (!sdw_be_num)
                goto SSP;
  
 -      adr_link = mach_params->links;
 -      if (!adr_link)
 -              return -EINVAL;
 -
 -      /*
 -       * SoundWire Slaves aggregated in the same group may be
 -       * located on different hardware links. Clear array to indicate
 -       * CPU DAIs for this group have not been generated.
 -       */
 -      for (i = 0; i < SDW_MAX_GROUPS; i++)
 -              group_generated[i] = false;
 -
        for (i = 0; i < SDW_MAX_LINKS; i++)
                sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE;
  
@@@ -1637,6 -1702,11 +1637,6 @@@ out
                        const struct snd_soc_acpi_endpoint *endpoint;
  
                        endpoint = adr_link->adr_d[i].endpoints;
 -                      if (endpoint->aggregated && !endpoint->group_id) {
 -                              dev_err(dev, "invalid group id on link %x",
 -                                      adr_link->mask);
 -                              continue;
 -                      }
  
                        /* this group has been generated */
                        if (endpoint->aggregated &&
                                return codec_index;
  
                        for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) {
 -                              ret = create_sdw_dailink(card, dev, &link_index, links, sdw_be_num,
 -                                                       sdw_cpu_dai_num, cpus, adr_link,
 -                                                       &cpu_id, group_generated,
 -                                                       codec_conf, codec_conf_count,
 +                              ret = create_sdw_dailink(card, &link_index, dai_links,
 +                                                       sdw_be_num, sdw_cpu_dai_num, cpus,
 +                                                       adr_link, &cpu_id,
 +                                                       codec_conf, codec_conf_num,
                                                         &be_id, &codec_conf_index,
                                                         &ignore_pch_dmic, append_dai_type, i, j);
                                if (ret < 0) {
 -                                      dev_err(dev, "failed to create dai link %d", link_index);
 +                                      dev_err(dev, "failed to create dai link %d\n", link_index);
                                        return ret;
                                }
                        }
 +
 +                      if (aggregation && endpoint->aggregated)
 +                              group_generated[endpoint->group_id] = true;
                }
        }
  
  
                playback = info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK];
                capture = info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE];
 -              init_dai_link(dev, links + link_index, be_id, name,
 +              init_dai_link(dev, dai_links + link_index, be_id, name,
                              playback, capture,
                              cpus + cpu_id, 1,
                              ssp_components, 1,
                              NULL, info->ops);
  
 -              ret = info->dais[0].init(card, NULL, links + link_index, info, 0);
 +              ret = info->dais[0].init(card, NULL, dai_links + link_index, info, 0);
                if (ret < 0)
                        return ret;
  
@@@ -1727,7 -1794,7 +1727,7 @@@ DMIC
                        goto HDMI;
                }
                cpus[cpu_id].dai_name = "DMIC01 Pin";
 -              init_dai_link(dev, links + link_index, be_id, "dmic01",
 +              init_dai_link(dev, dai_links + link_index, be_id, "dmic01",
                              0, 1, // DMIC only supports capture
                              cpus + cpu_id, 1,
                              dmic_component, 1,
                INC_ID(be_id, cpu_id, link_index);
  
                cpus[cpu_id].dai_name = "DMIC16k Pin";
 -              init_dai_link(dev, links + link_index, be_id, "dmic16k",
 +              init_dai_link(dev, dai_links + link_index, be_id, "dmic16k",
                              0, 1, // DMIC only supports capture
                              cpus + cpu_id, 1,
                              dmic_component, 1,
@@@ -1778,7 -1845,7 +1778,7 @@@ HDMI
                        return -ENOMEM;
  
                cpus[cpu_id].dai_name = cpu_name;
 -              init_dai_link(dev, links + link_index, be_id, name,
 +              init_dai_link(dev, dai_links + link_index, be_id, name,
                              1, 0, // HDMI only supports playback
                              cpus + cpu_id, 1,
                              idisp_components + i, 1,
                        return -ENOMEM;
  
                cpus[cpu_id].dai_name = cpu_name;
 -              init_dai_link(dev, links + link_index, be_id, name, 1, 1,
 -                              cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL);
 +              init_dai_link(dev, dai_links + link_index, be_id, name, 1, 1,
 +                            cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL);
        }
  
 -      card->dai_link = links;
 +      card->dai_link = dai_links;
        card->num_links = num_links;
  
        card->codec_conf = codec_conf;
 -      card->num_configs = codec_conf_count;
 +      card->num_configs = codec_conf_num;
  
        return 0;
  }
@@@ -1846,15 -1913,15 +1846,15 @@@ static struct snd_soc_card card_sof_sd
  static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card,
                                                       const char *dai_name)
  {
 -      struct snd_soc_dai_link *link;
 +      struct snd_soc_dai_link *dai_link;
        int i;
        int j;
  
 -      for_each_card_prelinks(card, i, link) {
 -              for (j = 0; j < link->num_codecs; j++) {
 +      for_each_card_prelinks(card, i, dai_link) {
 +              for (j = 0; j < dai_link->num_codecs; j++) {
                        /* Check each codec in a link */
 -                      if (!strcmp(link->codecs[j].dai_name, dai_name))
 -                              return link;
 +                      if (!strcmp(dai_link->codecs[j].dai_name, dai_name))
 +                              return dai_link;
                }
        }
        return NULL;
  
  static void mc_dailink_exit_loop(struct snd_soc_card *card)
  {
 -      struct snd_soc_dai_link *link;
 +      struct snd_soc_dai_link *dai_link;
        int ret;
        int i, j;
  
                         * We don't need to call .exit function if there is no matched
                         * dai link found.
                         */
 -                      link = mc_find_codec_dai_used(card, codec_info_list[i].dais[j].dai_name);
 -                      if (link) {
 +                      dai_link = mc_find_codec_dai_used(card,
 +                                                        codec_info_list[i].dais[j].dai_name);
 +                      if (dai_link) {
                                /* Do the .exit function if the codec dai is used in the link */
 -                              ret = codec_info_list[i].dais[j].exit(card, link);
 +                              ret = codec_info_list[i].dais[j].exit(card, dai_link);
                                if (ret)
                                        dev_warn(card->dev,
                                                 "codec exit failed %d\n",
  static int mc_probe(struct platform_device *pdev)
  {
        struct snd_soc_card *card = &card_sof_sdw;
 -      struct snd_soc_acpi_mach *mach;
 +      struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
        struct mc_private *ctx;
        int amp_num = 0, i;
        int ret;
  
 -      dev_dbg(&pdev->dev, "Entry\n");
 +      card->dev = &pdev->dev;
 +
 +      dev_dbg(card->dev, "Entry\n");
  
 -      ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 +      ctx = devm_kzalloc(card->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
  
 +      INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
 +
 +      snd_soc_card_set_drvdata(card, ctx);
 +
        dmi_check_system(sof_sdw_quirk_table);
  
        if (quirk_override != -1) {
 -              dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
 +              dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
                         sof_sdw_quirk, quirk_override);
                sof_sdw_quirk = quirk_override;
        }
 -      log_quirks(&pdev->dev);
  
 -      INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
 +      log_quirks(card->dev);
  
 -      card->dev = &pdev->dev;
 -      snd_soc_card_set_drvdata(card, ctx);
 +      /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
 +      for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
 +              codec_info_list[i].amp_num = 0;
  
 -      mach = pdev->dev.platform_data;
 -      ret = sof_card_dai_links_create(&pdev->dev, mach,
 -                                      card);
 +      ret = sof_card_dai_links_create(card);
        if (ret < 0)
                return ret;
  
        card->long_name = sdw_card_long_name;
  
        /* Register the card */
 -      ret = devm_snd_soc_register_card(&pdev->dev, card);
 +      ret = devm_snd_soc_register_card(card->dev, card);
        if (ret) {
                dev_err(card->dev, "snd_soc_register_card failed %d\n", ret);
                mc_dailink_exit_loop(card);
@@@ -1974,12 -2036,6 +1974,12 @@@ static void mc_remove(struct platform_d
        mc_dailink_exit_loop(card);
  }
  
 +static const struct platform_device_id mc_id_table[] = {
 +      { "sof_sdw", },
 +      {}
 +};
 +MODULE_DEVICE_TABLE(platform, mc_id_table);
 +
  static struct platform_driver sof_sdw_driver = {
        .driver = {
                .name = "sof_sdw",
        },
        .probe = mc_probe,
        .remove_new = mc_remove,
 +      .id_table = mc_id_table,
  };
  
  module_platform_driver(sof_sdw_driver);
@@@ -1997,5 -2052,6 +1997,5 @@@ MODULE_AUTHOR("Bard Liao <yung-chuan.li
  MODULE_AUTHOR("Rander Wang <[email protected]>");
  MODULE_AUTHOR("Pierre-Louis Bossart <[email protected]>");
  MODULE_LICENSE("GPL v2");
 -MODULE_ALIAS("platform:sof_sdw");
  MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
  MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
index ae4a5aa73bfc12e444bb1bd0c5e636a4f938f1c2,f33051eac1c096e1c1494dc84ce610195dd81b85..494ced2b746e116109a6ca8cebff3e74451d6766
@@@ -7,7 -7,6 +7,7 @@@
  
  #include <sound/pcm_params.h>
  #include <sound/hdaudio_ext.h>
 +#include <sound/hda-mlink.h>
  #include <sound/sof/ipc4/header.h>
  #include <uapi/sound/sof/header.h>
  #include "../ipc4-priv.h"
@@@ -145,17 -144,9 +145,17 @@@ static struct hdac_ext_stream *hda_assi
                                                      struct snd_soc_dai *cpu_dai,
                                                      struct snd_pcm_substream *substream)
  {
 +      struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 +      struct snd_soc_dai *dai;
        struct hdac_ext_stream *hext_stream;
  
 -      hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
 +      /* only allocate a stream_tag for the first DAI in the dailink */
 +      dai = asoc_rtd_to_cpu(rtd, 0);
 +      if (dai == cpu_dai)
 +              hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
 +      else
 +              hext_stream = snd_soc_dai_get_dma_data(dai, substream);
 +
        if (!hext_stream)
                return NULL;
  
@@@ -168,14 -159,9 +168,14 @@@ static void hda_release_hext_stream(str
                                    struct snd_pcm_substream *substream)
  {
        struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
 +      struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 +      struct snd_soc_dai *dai;
  
 +      /* only release a stream_tag for the first DAI in the dailink */
 +      dai = asoc_rtd_to_cpu(rtd, 0);
 +      if (dai == cpu_dai)
 +              snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
        snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
 -      snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
  }
  
  static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,
@@@ -233,77 -219,6 +233,77 @@@ static struct hdac_ext_link *hda_get_hl
        return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
  }
  
 +static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev,
 +                                             struct snd_pcm_substream *substream,
 +                                             struct snd_pcm_hw_params *params)
 +{
 +      unsigned int format_val;
 +
 +      format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params),
 +                                               params_format(params),
 +                                               params_physical_width(params),
 +                                               0);
 +
 +      dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
 +              params_rate(params), params_channels(params), params_format(params));
 +
 +      return format_val;
 +}
 +
 +static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev,
 +                                          struct snd_pcm_substream *substream,
 +                                          struct snd_pcm_hw_params *params)
 +{
 +      unsigned int format_val;
 +      snd_pcm_format_t format;
 +      unsigned int channels;
 +      unsigned int width;
 +
 +      channels = params_channels(params);
 +      format = params_format(params);
 +      width = params_physical_width(params);
 +
 +      if (format == SNDRV_PCM_FORMAT_S16_LE) {
 +              format = SNDRV_PCM_FORMAT_S32_LE;
 +              channels /= 2;
 +              width = 32;
 +      }
 +
 +      format_val = snd_hdac_calc_stream_format(params_rate(params), channels,
 +                                               format,
 +                                               width,
 +                                               0);
 +
 +      dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
 +              params_rate(params), channels, format);
 +
 +      return format_val;
 +}
 +
 +static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev,
 +                                         struct snd_pcm_substream *substream)
 +{
 +      struct hdac_bus *bus = sof_to_bus(sdev);
 +
 +      return hdac_bus_eml_ssp_get_hlink(bus);
 +}
 +
 +static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev,
 +                                          struct snd_pcm_substream *substream)
 +{
 +      struct hdac_bus *bus = sof_to_bus(sdev);
 +
 +      return hdac_bus_eml_dmic_get_hlink(bus);
 +}
 +
 +static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev,
 +                                         struct snd_pcm_substream *substream)
 +{
 +      struct hdac_bus *bus = sof_to_bus(sdev);
 +
 +      return hdac_bus_eml_sdw_get_hlink(bus);
 +}
 +
  static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
                                struct snd_pcm_substream *substream, int cmd)
  {
        pipe_widget = swidget->spipe->pipe_widget;
        pipeline = pipe_widget->private;
  
 +      if (pipe_widget->instance_id < 0)
 +              return 0;
 +
        mutex_lock(&ipc4_data->pipeline_state_mutex);
  
        switch (cmd) {
@@@ -385,9 -297,6 +385,9 @@@ static int hda_ipc4_post_trigger(struc
        pipe_widget = swidget->spipe->pipe_widget;
        pipeline = pipe_widget->private;
  
 +      if (pipe_widget->instance_id < 0)
 +              return 0;
 +
        mutex_lock(&ipc4_data->pipeline_state_mutex);
  
        switch (cmd) {
@@@ -434,28 -343,6 +434,28 @@@ out
        return ret;
  }
  
 +static struct hdac_ext_stream *sdw_hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev,
 +                                                          struct snd_soc_dai *cpu_dai,
 +                                                          struct snd_pcm_substream *substream)
 +{
 +      struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
 +      struct snd_sof_widget *swidget = w->dobj.private;
 +      struct snd_sof_dai *dai = swidget->private;
 +      struct sof_ipc4_copier *ipc4_copier = dai->private;
 +      struct sof_ipc4_alh_configuration_blob *blob;
 +
 +      blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
 +
 +      /*
 +       * Starting with ACE_2_0, re-setting the device_count is mandatory to avoid using
 +       * the multi-gateway firmware configuration. The DMA hardware can take care of
 +       * multiple links without needing any firmware assistance
 +       */
 +      blob->alh_cfg.device_count = 1;
 +
 +      return hda_ipc4_get_hext_stream(sdev, cpu_dai, substream);
 +}
 +
  static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
        .get_hext_stream = hda_ipc4_get_hext_stream,
        .assign_hext_stream = hda_assign_hext_stream,
        .get_hlink = hda_get_hlink,
  };
  
 +static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = {
 +      .get_hext_stream = hda_ipc4_get_hext_stream,
 +      .assign_hext_stream = hda_assign_hext_stream,
 +      .release_hext_stream = hda_release_hext_stream,
 +      .setup_hext_stream = hda_setup_hext_stream,
 +      .reset_hext_stream = hda_reset_hext_stream,
 +      .pre_trigger = hda_ipc4_pre_trigger,
 +      .trigger = hda_trigger,
 +      .post_trigger = hda_ipc4_post_trigger,
 +      .calc_stream_format = generic_calc_stream_format,
 +      .get_hlink = ssp_get_hlink,
 +};
 +
 +static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = {
 +      .get_hext_stream = hda_ipc4_get_hext_stream,
 +      .assign_hext_stream = hda_assign_hext_stream,
 +      .release_hext_stream = hda_release_hext_stream,
 +      .setup_hext_stream = hda_setup_hext_stream,
 +      .reset_hext_stream = hda_reset_hext_stream,
 +      .pre_trigger = hda_ipc4_pre_trigger,
 +      .trigger = hda_trigger,
 +      .post_trigger = hda_ipc4_post_trigger,
 +      .calc_stream_format = dmic_calc_stream_format,
 +      .get_hlink = dmic_get_hlink,
 +};
 +
 +static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = {
 +      .get_hext_stream = sdw_hda_ipc4_get_hext_stream,
 +      .assign_hext_stream = hda_assign_hext_stream,
 +      .release_hext_stream = hda_release_hext_stream,
 +      .setup_hext_stream = hda_setup_hext_stream,
 +      .reset_hext_stream = hda_reset_hext_stream,
 +      .pre_trigger = hda_ipc4_pre_trigger,
 +      .trigger = hda_trigger,
 +      .post_trigger = hda_ipc4_post_trigger,
 +      .calc_stream_format = generic_calc_stream_format,
 +      .get_hlink = sdw_get_hlink,
 +};
 +
  static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
        .get_hext_stream = hda_get_hext_stream,
        .assign_hext_stream = hda_assign_hext_stream,
  static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
                                 struct snd_pcm_substream *substream, int cmd)
  {
+       struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
        struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
  
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_STOP:
        {
                struct snd_sof_dai_config_data data = { 0 };
+               int ret;
  
                data.dai_data = DMA_CHAN_INVALID;
-               return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);
+               ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);
+               if (ret < 0)
+                       return ret;
+               if (cmd == SNDRV_PCM_TRIGGER_STOP)
+                       return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
+               break;
        }
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
@@@ -611,13 -468,8 +620,13 @@@ hda_select_dai_widget_ops(struct snd_so
        case SOF_INTEL_IPC4:
        {
                struct sof_ipc4_copier *ipc4_copier = sdai->private;
 +              const struct sof_intel_dsp_desc *chip;
  
 -              if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) {
 +              chip = get_chip_info(sdev->pdata);
 +
 +              switch (ipc4_copier->dai_type) {
 +              case SOF_DAI_INTEL_HDA:
 +              {
                        struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
                        struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
  
  
                        return &hda_ipc4_dma_ops;
                }
 +              case SOF_DAI_INTEL_SSP:
 +                      if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
 +                              return NULL;
 +                      return &ssp_ipc4_dma_ops;
 +              case SOF_DAI_INTEL_DMIC:
 +                      if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
 +                              return NULL;
 +                      return &dmic_ipc4_dma_ops;
 +              case SOF_DAI_INTEL_ALH:
 +                      if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
 +                              return NULL;
 +                      return &sdw_ipc4_dma_ops;
 +
 +              default:
 +                      break;
 +              }
                break;
        }
        default:
index c984fa79b1eff01557fb80e100eb001f7536add9,863865f3d77ebb88d9639ec137c248b6282eecb0..f3cefd86608120ce8ba1044091078e2e80022ed1
@@@ -10,8 -10,6 +10,8 @@@
  
  #include <sound/pcm_params.h>
  #include <sound/hdaudio_ext.h>
 +#include <sound/hda-mlink.h>
 +#include <sound/hda_register.h>
  #include <sound/intel-nhlt.h>
  #include <sound/sof/ipc4/header.h>
  #include <uapi/sound/sof/header.h>
@@@ -109,9 -107,8 +109,8 @@@ hda_dai_get_ops(struct snd_pcm_substrea
        return sdai->platform_private;
  }
  
- static int hda_link_dma_cleanup(struct snd_pcm_substream *substream,
-                               struct hdac_ext_stream *hext_stream,
-                               struct snd_soc_dai *cpu_dai)
+ int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream,
+                        struct snd_soc_dai *cpu_dai)
  {
        const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
        struct sof_intel_hda_stream *hda_stream;
@@@ -332,175 -329,6 +331,175 @@@ static const struct snd_soc_dai_ops hda
  
  #endif
  
 +static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w)
 +{
 +      struct snd_sof_widget *swidget = w->dobj.private;
 +      struct snd_sof_dai *sdai = swidget->private;
 +      struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)sdai->private;
 +
 +      return ipc4_copier;
 +}
 +
 +static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
 +                               struct snd_pcm_hw_params *params,
 +                               struct snd_soc_dai *cpu_dai)
 +{
 +      struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
 +      struct sof_ipc4_dma_config_tlv *dma_config_tlv;
 +      const struct hda_dai_widget_dma_ops *ops;
 +      struct sof_ipc4_dma_config *dma_config;
 +      struct sof_ipc4_copier *ipc4_copier;
 +      struct hdac_ext_stream *hext_stream;
 +      struct hdac_stream *hstream;
 +      struct snd_sof_dev *sdev;
 +      int stream_id;
 +      int ret;
 +
 +      ops = hda_dai_get_ops(substream, cpu_dai);
 +      if (!ops) {
 +              dev_err(cpu_dai->dev, "DAI widget ops not set\n");
 +              return -EINVAL;
 +      }
 +
 +      /* use HDaudio stream handling */
 +      ret = hda_dai_hw_params(substream, params, cpu_dai);
 +      if (ret < 0) {
 +              dev_err(cpu_dai->dev, "%s: hda_dai_hw_params failed: %d\n", __func__, ret);
 +              return ret;
 +      }
 +
 +      /* get stream_id */
 +      sdev = widget_to_sdev(w);
 +      hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
 +
 +      if (!hext_stream) {
 +              dev_err(cpu_dai->dev, "%s: no hext_stream found\n", __func__);
 +              return -ENODEV;
 +      }
 +
 +      hstream = &hext_stream->hstream;
 +      stream_id = hstream->stream_tag;
 +
 +      if (!stream_id) {
 +              dev_err(cpu_dai->dev, "%s: no stream_id allocated\n", __func__);
 +              return -ENODEV;
 +      }
 +
 +      /* configure TLV */
 +      ipc4_copier = widget_to_copier(w);
 +
 +      dma_config_tlv = &ipc4_copier->dma_config_tlv;
 +      dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID;
 +      /* dma_config_priv_size is zero */
 +      dma_config_tlv->length = sizeof(dma_config_tlv->dma_config);
 +
 +      dma_config = &dma_config_tlv->dma_config;
 +
 +      dma_config->dma_method = SOF_IPC4_DMA_METHOD_HDA;
 +      dma_config->pre_allocated_by_host = 1;
 +      dma_config->dma_channel_id = stream_id - 1;
 +      dma_config->stream_id = stream_id;
 +      dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */
 +      dma_config->dma_priv_config_size = 0;
 +
 +      return 0;
 +}
 +
 +static int non_hda_dai_prepare(struct snd_pcm_substream *substream,
 +                             struct snd_soc_dai *cpu_dai)
 +{
 +      struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 +      int stream = substream->stream;
 +
 +      return non_hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai);
 +}
 +
 +static const struct snd_soc_dai_ops ssp_dai_ops = {
 +      .hw_params = non_hda_dai_hw_params,
 +      .hw_free = hda_dai_hw_free,
 +      .trigger = hda_dai_trigger,
 +      .prepare = non_hda_dai_prepare,
 +};
 +
 +static const struct snd_soc_dai_ops dmic_dai_ops = {
 +      .hw_params = non_hda_dai_hw_params,
 +      .hw_free = hda_dai_hw_free,
 +      .trigger = hda_dai_trigger,
 +      .prepare = non_hda_dai_prepare,
 +};
 +
 +int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
 +                        struct snd_pcm_hw_params *params,
 +                        struct snd_soc_dai *cpu_dai,
 +                        int link_id)
 +{
 +      struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
 +      const struct hda_dai_widget_dma_ops *ops;
 +      struct hdac_ext_stream *hext_stream;
 +      struct snd_sof_dev *sdev;
 +      int ret;
 +
 +      ret = non_hda_dai_hw_params(substream, params, cpu_dai);
 +      if (ret < 0) {
 +              dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_params failed %d\n", __func__, ret);
 +              return ret;
 +      }
 +
 +      ops = hda_dai_get_ops(substream, cpu_dai);
 +      sdev = widget_to_sdev(w);
 +      hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
 +
 +      if (!hext_stream)
 +              return -ENODEV;
 +
 +      /* in the case of SoundWire we need to program the PCMSyCM registers */
 +      ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
 +                                           GENMASK(params_channels(params) - 1, 0),
 +                                           hdac_stream(hext_stream)->stream_tag,
 +                                           substream->stream);
 +      if (ret < 0) {
 +              dev_err(cpu_dai->dev, "%s:  hdac_bus_eml_sdw_map_stream_ch failed %d\n",
 +                      __func__, ret);
 +              return ret;
 +      }
 +
 +      return 0;
 +}
 +
 +int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
 +                      struct snd_soc_dai *cpu_dai,
 +                      int link_id)
 +{
 +      struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
 +      struct snd_sof_dev *sdev;
 +      int ret;
 +
 +      ret = hda_dai_hw_free(substream, cpu_dai);
 +      if (ret < 0) {
 +              dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_free failed %d\n", __func__, ret);
 +              return ret;
 +      }
 +
 +      sdev = widget_to_sdev(w);
 +
 +      /* in the case of SoundWire we need to reset the PCMSyCM registers */
 +      ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
 +                                           0, 0, substream->stream);
 +      if (ret < 0) {
 +              dev_err(cpu_dai->dev, "%s:  hdac_bus_eml_sdw_map_stream_ch failed %d\n",
 +                      __func__, ret);
 +              return ret;
 +      }
 +
 +      return 0;
 +}
 +
 +int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 +                      struct snd_soc_dai *cpu_dai)
 +{
 +      return hda_dai_trigger(substream, cmd, cpu_dai);
 +}
 +
  static int hda_dai_suspend(struct hdac_bus *bus)
  {
        struct snd_soc_pcm_runtime *rtd;
        return 0;
  }
  
 -#endif
 +static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
 +{
 +      const struct sof_intel_dsp_desc *chip;
 +      int i;
 +
 +      chip = get_chip_info(sdev->pdata);
 +
 +      if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
 +              for (i = 0; i < ops->num_drv; i++) {
 +                      if (strstr(ops->drv[i].name, "SSP"))
 +                              ops->drv[i].ops = &ssp_dai_ops;
 +              }
 +      }
 +}
 +
 +static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
 +{
 +      const struct sof_intel_dsp_desc *chip;
 +      int i;
 +
 +      chip = get_chip_info(sdev->pdata);
 +
 +      if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
 +              for (i = 0; i < ops->num_drv; i++) {
 +                      if (strstr(ops->drv[i].name, "DMIC"))
 +                              ops->drv[i].ops = &dmic_dai_ops;
 +              }
 +      }
 +}
 +
 +#else
 +
 +static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
 +static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
 +
 +#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */
  
  void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
  {
  #endif
        }
  
 +      ssp_set_dai_drv_ops(sdev, ops);
 +      dmic_set_dai_drv_ops(sdev, ops);
 +
        if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) {
                struct sof_ipc4_fw_data *ipc4_data = sdev->private;
  
index f19510e8ce876ef3ad7be4aac6f8c4fddb7251da,5b9e4ebcc18b24683ce7913ea57b3a98b564298d..5c517ec57d4a2033cc5c8a116bbc86f928080ef7
@@@ -785,7 -785,6 +785,7 @@@ int hda_sdw_check_lcount_ext(struct snd
  int hda_sdw_startup(struct snd_sof_dev *sdev);
  void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable);
  void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable);
 +bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev);
  void hda_sdw_process_wakeen(struct snd_sof_dev *sdev);
  bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev);
  
@@@ -814,11 -813,6 +814,11 @@@ static inline void hda_sdw_int_enable(s
  {
  }
  
 +static inline bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev)
 +{
 +      return false;
 +}
 +
  static inline void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
  {
  }
@@@ -830,18 -824,6 +830,18 @@@ static inline bool hda_common_check_sdw
  
  #endif
  
 +int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
 +                        struct snd_pcm_hw_params *params,
 +                        struct snd_soc_dai *cpu_dai,
 +                        int link_id);
 +
 +int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
 +                      struct snd_soc_dai *cpu_dai,
 +                      int link_id);
 +
 +int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 +                      struct snd_soc_dai *cpu_dai);
 +
  /* common dai driver */
  extern struct snd_soc_dai_driver skl_dai[];
  int hda_dsp_dais_suspend(struct snd_sof_dev *sdev);
@@@ -863,8 -845,6 +863,8 @@@ extern struct snd_sof_dsp_ops sof_icl_o
  int sof_icl_ops_init(struct snd_sof_dev *sdev);
  extern struct snd_sof_dsp_ops sof_mtl_ops;
  int sof_mtl_ops_init(struct snd_sof_dev *sdev);
 +extern struct snd_sof_dsp_ops sof_lnl_ops;
 +int sof_lnl_ops_init(struct snd_sof_dev *sdev);
  
  extern const struct sof_intel_dsp_desc skl_chip_info;
  extern const struct sof_intel_dsp_desc apl_chip_info;
@@@ -876,7 -856,6 +876,7 @@@ extern const struct sof_intel_dsp_desc 
  extern const struct sof_intel_dsp_desc jsl_chip_info;
  extern const struct sof_intel_dsp_desc adls_chip_info;
  extern const struct sof_intel_dsp_desc mtl_chip_info;
 +extern const struct sof_intel_dsp_desc lnl_chip_info;
  
  /* Probes support */
  #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
@@@ -984,5 -963,7 +984,7 @@@ const struct hda_dai_widget_dma_ops 
  hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
  int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
                   struct snd_sof_dai_config_data *data);
+ int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream,
+                        struct snd_soc_dai *cpu_dai);
  
  #endif
diff --combined sound/soc/sof/ipc3.c
index 09834205b119b834fa64156d1d3cc5dc724aa2fc,580960ff273d1c3ea940e4db474cd17291806624..33df028d48542a6abee2ba7f2a171b4876c158d0
@@@ -312,7 -312,7 +312,7 @@@ static int ipc3_wait_tx_done(struct snd
                } else {
                        if (sof_debug_check_flag(SOF_DBG_PRINT_IPC_SUCCESS_LOGS))
                                ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
 -                      if (msg->reply_size)
 +                      if (reply_data && msg->reply_size)
                                /* copy the data returned from DSP */
                                memcpy(reply_data, msg->reply_data,
                                       msg->reply_size);
@@@ -1001,7 -1001,7 +1001,7 @@@ void sof_ipc3_do_rx_work(struct snd_sof
  
        ipc3_log_header(sdev->dev, "ipc rx", hdr->cmd);
  
-       if (hdr->size < sizeof(hdr) || hdr->size > SOF_IPC_MSG_MAX_SIZE) {
+       if (hdr->size < sizeof(*hdr) || hdr->size > SOF_IPC_MSG_MAX_SIZE) {
                dev_err(sdev->dev, "The received message size is invalid: %u\n",
                        hdr->size);
                return;
index 0196cbfc0998a35a74f6f3a29d908ff7dae6bd99,11361e1cd6881b9ddde1b87a910c6449b62228c6..b436638226131f705e246fef70224fee48c02cb6
@@@ -1731,6 -1731,9 +1731,12 @@@ sof_ipc4_prepare_copier_module(struct s
  
        *ipc_config_size = ipc_size;
  
+       /* update pipeline memory usage */
+       sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
++      /* update pipeline memory usage */
++      sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
++
        /* copy IPC data */
        memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
        if (gtw_cfg_config_length)
                       gtw_cfg_config_length,
                       &ipc4_copier->dma_config_tlv, dma_config_tlv_size);
  
-       /* update pipeline memory usage */
-       sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
 +      /*
 +       * Restore gateway config length now that IPC payload is prepared. This avoids
 +       * counting the DMA CONFIG TLV multiple times
 +       */
 +      copier_data->gtw_cfg.config_length = gtw_cfg_config_length / 4;
 +
        return 0;
  }
  
@@@ -2325,7 -2319,6 +2328,7 @@@ static int sof_ipc4_widget_free(struct 
                pipeline->mem_usage = 0;
                pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
                ida_free(&pipeline_ida, swidget->instance_id);
 +              swidget->instance_id = -EINVAL;
        } else {
                struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
                struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
This page took 0.147445 seconds and 4 git commands to generate.