]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: Intel: maxim-common: rewrite max_98373_hw_params function
authorBrent Lu <brent.lu@intel.com>
Mon, 27 May 2024 19:35:50 +0000 (14:35 -0500)
committerMark Brown <broonie@kernel.org>
Wed, 29 May 2024 10:10:57 +0000 (11:10 +0100)
Rewrite max_98373_hw_params() function to get tdm slot number from
topology in runtime because earlier platforms use 4-slot setting
instead of 8. Also check if the interface is configured in TDM mode
before calling snd_soc_dai_set_tdm_slot() function.

Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Brent Lu <brent.lu@intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://msgid.link/r/20240527193552.165567-17-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/intel/boards/sof_maxim_common.c

index 6c40ecc04723c8856787057d9785b825bcafe671..f965b172fa365509c1ab87f52d0c4dcd6d01f9dd 100644 (file)
@@ -9,6 +9,7 @@
 #include <sound/soc-acpi.h>
 #include <sound/soc-dai.h>
 #include <sound/soc-dapm.h>
+#include <sound/sof.h>
 #include <uapi/sound/asound.h>
 #include "../common/soc-intel-quirks.h"
 #include "sof_maxim_common.h"
@@ -72,26 +73,85 @@ static struct snd_soc_dai_link_component max_98373_components[] = {
        },
 };
 
+/*
+ * According to the definition of 'DAI Sel Mux' mixer in max98373.c, rx mask
+ * should choose two channels from TDM slots, the LSB of rx mask is left channel
+ * and the other one is right channel.
+ *
+ * For tx mask, each codec requires two channels: one for V-sense and the other
+ * one for I-sense. Must match the device property "maxim,vmon-slot-no" and
+ * "maxim,imon-slot-no" in ACPI table.
+ */
+static const struct {
+       unsigned int tx;
+       unsigned int rx;
+} max_98373_tdm_mask[] = {
+       {.tx = 0x03, .rx = 0x3},
+       {.tx = 0x0c, .rx = 0x3},
+};
+
 static int max_98373_hw_params(struct snd_pcm_substream *substream,
                               struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+       struct snd_soc_dai_link *dai_link = rtd->dai_link;
        struct snd_soc_dai *codec_dai;
+       int i;
+       int tdm_slots;
        int ret = 0;
-       int j;
 
-       for_each_rtd_codec_dais(rtd, j, codec_dai) {
-               if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) {
-                       /* DEV0 tdm slot configuration */
-                       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32);
-               } else if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) {
-                       /* DEV1 tdm slot configuration */
-                       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32);
+       for_each_rtd_codec_dais(rtd, i, codec_dai) {
+               if (i >= ARRAY_SIZE(max_98373_tdm_mask)) {
+                       dev_err(codec_dai->dev, "only 2 amps are supported\n");
+                       return -EINVAL;
                }
-               if (ret < 0) {
-                       dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
-                               ret);
-                       return ret;
+
+               switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+               case SND_SOC_DAIFMT_DSP_A:
+               case SND_SOC_DAIFMT_DSP_B:
+                       /* get the tplg configured tdm slot number */
+                       tdm_slots = sof_dai_get_tdm_slots(rtd);
+                       if (tdm_slots <= 0) {
+                               dev_err(rtd->dev, "invalid tdm slots %d\n",
+                                       tdm_slots);
+                               return -EINVAL;
+                       }
+
+                       /*
+                        * check if tdm slot number is too small for channel
+                        * allocation
+                        */
+                       if (fls(max_98373_tdm_mask[i].tx) > tdm_slots) {
+                               dev_err(codec_dai->dev, "slot mismatch, tx %d slots %d\n",
+                                       fls(max_98373_tdm_mask[i].tx), tdm_slots);
+                               return -EINVAL;
+                       }
+
+                       if (fls(max_98373_tdm_mask[i].rx) > tdm_slots) {
+                               dev_err(codec_dai->dev, "slot mismatch, rx %d slots %d\n",
+                                       fls(max_98373_tdm_mask[i].rx), tdm_slots);
+                               return -EINVAL;
+                       }
+
+                       dev_dbg(codec_dai->dev, "set tdm slot: tx 0x%x rx 0x%x slots %d width %d\n",
+                               max_98373_tdm_mask[i].tx,
+                               max_98373_tdm_mask[i].rx,
+                               tdm_slots, params_width(params));
+
+                       ret = snd_soc_dai_set_tdm_slot(codec_dai,
+                                                      max_98373_tdm_mask[i].tx,
+                                                      max_98373_tdm_mask[i].rx,
+                                                      tdm_slots,
+                                                      params_width(params));
+                       if (ret < 0) {
+                               dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
+                                       ret);
+                               return ret;
+                       }
+                       break;
+               default:
+                       dev_dbg(codec_dai->dev, "codec is in I2S mode\n");
+                       break;
                }
        }
        return 0;