ASoC: soc-core: add snd_soc_runtime_get_dai_fmt()

ASoC is using dai_link which specify DAI format (= dai_link->dai_fmt),
and it is selected by "Sound Card" driver in corrent implementation.
In other words, Sound Card *needs* to setup it.
But, it should be possible to automatically selected from CPU and
Codec driver settings.

This patch adds new .auto_selectable_formats support
at snd_soc_dai_ops.

By this patch, dai_fmt can be automatically selected from each
driver if both CPU / Codec driver had it.
Automatically selectable *field* is depends on each drivers.

For example, some driver want to select format "automatically",
but want to select other fields "manually", because of complex limitation.
Or other example, in case of both CPU and Codec are possible to be
clock provider, but the quality was different.
In these case, user need/want to *manually* select each fields
from Sound Card driver.

This .auto_selectable_formats can set priority.
For example, no limitaion format can be HI priority,
supported but has picky limitation format can be next priority, etc.

It uses Sound Card specified fields preferentially, and try to select
non-specific fields from CPU and Codec driver automatically
if all drivers have .auto_selectable_formats.

In other words, we can select all dai_fmt via Sound Card driver
same as before.

Link: https://lore.kernel.org/r/871rb3hypy.wl-kuninori.morimoto.gx@renesas.com
Link: https://lore.kernel.org/r/871racbx0w.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87h7ionc8s.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 4df1aae..a56dcc8 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -134,6 +134,69 @@ int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
 
+int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dai *dai;
+	int i, max = 0;
+
+	/*
+	 * return max num if *ALL* DAIs have .auto_selectable_formats
+	 */
+	for_each_rtd_dais(rtd, i, dai) {
+		if (dai->driver->ops &&
+		    dai->driver->ops->num_auto_selectable_formats)
+			max = max(max, dai->driver->ops->num_auto_selectable_formats);
+		else
+			return 0;
+	}
+
+	return max;
+}
+
+/**
+ * snd_soc_dai_get_fmt - get supported audio format.
+ * @dai: DAI
+ * @priority: priority level of supported audio format.
+ *
+ * This should return only formats implemented with high
+ * quality by the DAI so that the core can configure a
+ * format which will work well with other devices.
+ * For example devices which don't support both edges of the
+ * LRCLK signal in I2S style formats should only list DSP
+ * modes.  This will mean that sometimes fewer formats
+ * are reported here than are supported by set_fmt().
+ */
+u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority)
+{
+	const struct snd_soc_dai_ops *ops = dai->driver->ops;
+	u64 fmt = 0;
+	int i, max = 0, until = priority;
+
+	/*
+	 * Collect auto_selectable_formats until priority
+	 *
+	 * ex)
+	 *	auto_selectable_formats[] = { A, B, C };
+	 *	(A, B, C = SND_SOC_POSSIBLE_DAIFMT_xxx)
+	 *
+	 * priority = 1 :	A
+	 * priority = 2 :	A | B
+	 * priority = 3 :	A | B | C
+	 * priority = 4 :	A | B | C
+	 * ...
+	 */
+	if (ops)
+		max = ops->num_auto_selectable_formats;
+
+	if (max < until)
+		until = max;
+
+	for (i = 0; i < until; i++)
+		fmt |= ops->auto_selectable_formats[i];
+
+	return fmt;
+}
+
 /**
  * snd_soc_dai_set_fmt - configure DAI hardware audio format.
  * @dai: DAI