[PATCH v2 4/6] ASoC: qcom: sc8280xp: Add per-DAI board configuration
From: Hongyang Zhao
Date: Wed Jul 15 2026 - 19:07:37 EST
The board data currently applies codec format, sysclk, MI2S clock and
jack setup policy to every backend DAI on a sound card. That works for
boards with a uniform audio topology, but it cannot describe a card
which connects codecs with different clock requirements to different
MI2S interfaces.
Introduce an optional per-DAI configuration table indexed by the CPU DAI
ID. Each entry can select the codec DAI format, override the MCLK rate,
enable CPU MCLK and BCLK programming, request codec sysclk setup and
choose the jack setup path. Use one jack setup enum instead of unrelated
boolean flags so a DAI cannot select conflicting setup methods.
Migrate the existing WCD headset cards to the new representation. All
in-tree WCD capture links handled by this driver use TX_CODEC_DMA_TX_3;
cards sharing a compatible but lacking that link simply have no matching
runtime. This preserves existing behavior while allowing mixed-codec
cards to configure each link independently.
Signed-off-by: Hongyang Zhao <hongyang.zhao@xxxxxxxxxxxxxxx>
---
sound/soc/qcom/sc8280xp.c | 138 ++++++++++++++++++++++++++++++++++++++--------
1 file changed, 115 insertions(+), 23 deletions(-)
diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c
index 109e39b93b2d..885ec1e3e575 100644
--- a/sound/soc/qcom/sc8280xp.c
+++ b/sound/soc/qcom/sc8280xp.c
@@ -37,6 +37,26 @@ static struct snd_soc_dapm_widget sc8280xp_dapm_widgets[] = {
SND_SOC_DAPM_SPK("DP7 Jack", NULL),
};
+enum sc8280xp_jack_setup {
+ SC8280XP_JACK_SETUP_NONE,
+ SC8280XP_JACK_SETUP_CODEC,
+ SC8280XP_JACK_SETUP_WCD,
+};
+
+struct sc8280xp_dai_data {
+ unsigned int id;
+ unsigned int codec_dai_fmt;
+ unsigned int mclk_rate;
+ bool codec_sysclk_set;
+ bool mi2s_mclk_enable;
+ bool mi2s_bclk_enable;
+ enum sc8280xp_jack_setup jack_setup;
+};
+
+#define SC8280XP_DAI_DATA(...) \
+ .dai_data = (const struct sc8280xp_dai_data[]) { __VA_ARGS__ }, \
+ .num_dai_data = ARRAY_SIZE(((const struct sc8280xp_dai_data[]) { __VA_ARGS__ }))
+
struct snd_soc_common {
const char *driver_name;
const struct snd_soc_dapm_widget *dapm_widgets;
@@ -45,11 +65,8 @@ struct snd_soc_common {
int num_dapm_routes;
const struct snd_kcontrol_new *controls;
int num_controls;
- unsigned int codec_dai_fmt;
- bool codec_sysclk_set;
- bool mi2s_mclk_enable;
- bool mi2s_bclk_enable;
- bool wcd_jack;
+ const struct sc8280xp_dai_data *dai_data;
+ size_t num_dai_data;
};
struct sc8280xp_snd_data {
@@ -61,6 +78,20 @@ struct sc8280xp_snd_data {
bool jack_setup;
};
+static const struct sc8280xp_dai_data *sc8280xp_get_dai_data(
+ const struct snd_soc_common *common,
+ unsigned int id)
+{
+ size_t i;
+
+ for (i = 0; i < common->num_dai_data; i++) {
+ if (common->dai_data[i].id == id)
+ return &common->dai_data[i];
+ }
+
+ return NULL;
+}
+
static inline int sc8280xp_get_mclk_freq(struct snd_pcm_hw_params *params)
{
int rate = params_rate(params);
@@ -88,10 +119,14 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
{
struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ const struct sc8280xp_dai_data *dai_data;
struct snd_soc_card *card = rtd->card;
struct snd_soc_jack *dp_jack = NULL;
int dp_pcm_id = 0;
+ dai_data = sc8280xp_get_dai_data(data->snd_soc_common_priv,
+ cpu_dai->id);
+
switch (cpu_dai->id) {
case WSA_CODEC_DMA_RX_0:
case WSA_CODEC_DMA_RX_1:
@@ -121,10 +156,18 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
if (dp_jack)
return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id);
- if (data->snd_soc_common_priv->wcd_jack)
- return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
+ if (!dai_data)
+ return 0;
- return 0;
+ switch (dai_data->jack_setup) {
+ case SC8280XP_JACK_SETUP_CODEC:
+ return qcom_snd_headset_jack_setup(rtd, &data->jack,
+ &data->jack_setup);
+ case SC8280XP_JACK_SETUP_WCD:
+ return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
+ default:
+ return 0;
+ }
}
static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -163,10 +206,17 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
- int mclk_freq = sc8280xp_get_mclk_freq(params);
+ const struct sc8280xp_dai_data *dai_data;
+ int mclk_freq;
int bclk_freq = sc8280xp_get_bclk_freq(params);
int ret;
+ dai_data = sc8280xp_get_dai_data(data->snd_soc_common_priv,
+ cpu_dai->id);
+ mclk_freq = dai_data && dai_data->mclk_rate ?
+ dai_data->mclk_rate :
+ sc8280xp_get_mclk_freq(params);
+
switch (cpu_dai->id) {
case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
@@ -175,14 +225,14 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream,
if (ret && ret != -EOPNOTSUPP)
return ret;
- if (data->snd_soc_common_priv->codec_dai_fmt) {
+ if (dai_data && dai_data->codec_dai_fmt) {
ret = snd_soc_dai_set_fmt(codec_dai,
- data->snd_soc_common_priv->codec_dai_fmt);
+ dai_data->codec_dai_fmt);
if (ret && ret != -EOPNOTSUPP)
return ret;
}
- if (data->snd_soc_common_priv->mi2s_mclk_enable) {
+ if (dai_data && dai_data->mi2s_mclk_enable) {
ret = snd_soc_dai_set_sysclk(cpu_dai,
LPAIF_MI2S_MCLK, mclk_freq,
SND_SOC_CLOCK_OUT);
@@ -190,7 +240,7 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- if (data->snd_soc_common_priv->mi2s_bclk_enable) {
+ if (dai_data && dai_data->mi2s_bclk_enable) {
ret = snd_soc_dai_set_sysclk(cpu_dai,
LPAIF_MI2S_BCLK, bclk_freq,
SND_SOC_CLOCK_OUT);
@@ -198,7 +248,7 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- if (data->snd_soc_common_priv->codec_sysclk_set) {
+ if (dai_data && dai_data->codec_sysclk_set) {
ret = snd_soc_dai_set_sysclk(codec_dai,
0, mclk_freq,
SND_SOC_CLOCK_IN);
@@ -231,6 +281,20 @@ static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream)
return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]);
}
+static void sc8280xp_snd_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ const struct sc8280xp_dai_data *dai_data;
+
+ dai_data = sc8280xp_get_dai_data(data->snd_soc_common_priv,
+ cpu_dai->id);
+ if (dai_data && dai_data->jack_setup == SC8280XP_JACK_SETUP_CODEC) {
+ qcom_snd_headset_jack_cleanup(rtd);
+ data->jack_setup = false;
+ }
+}
+
static const struct snd_soc_ops sc8280xp_be_ops = {
.startup = qcom_snd_sdw_startup,
.shutdown = qcom_snd_sdw_shutdown,
@@ -247,6 +311,7 @@ static void sc8280xp_add_be_ops(struct snd_soc_card *card)
for_each_card_prelinks(card, i, link) {
if (link->no_pcm == 1) {
link->init = sc8280xp_snd_init;
+ link->exit = sc8280xp_snd_exit;
link->be_hw_params_fixup = sc8280xp_be_hw_params_fixup;
link->ops = &sc8280xp_be_ops;
}
@@ -297,14 +362,20 @@ static const struct snd_soc_common eliza_priv_data = {
.driver_name = "eliza",
.dapm_widgets = sc8280xp_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
- .wcd_jack = true,
+ SC8280XP_DAI_DATA({
+ .id = TX_CODEC_DMA_TX_3,
+ .jack_setup = SC8280XP_JACK_SETUP_WCD,
+ }),
};
static const struct snd_soc_common kaanapali_priv_data = {
.driver_name = "kaanapali",
.dapm_widgets = sc8280xp_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
- .wcd_jack = true,
+ SC8280XP_DAI_DATA({
+ .id = TX_CODEC_DMA_TX_3,
+ .jack_setup = SC8280XP_JACK_SETUP_WCD,
+ }),
};
static const struct snd_soc_common qcs9100_priv_data = {
@@ -323,14 +394,20 @@ static const struct snd_soc_common qcm6490_priv_data = {
.driver_name = "qcm6490",
.dapm_widgets = sc8280xp_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
- .wcd_jack = true,
+ SC8280XP_DAI_DATA({
+ .id = TX_CODEC_DMA_TX_3,
+ .jack_setup = SC8280XP_JACK_SETUP_WCD,
+ }),
};
static const struct snd_soc_common qcs6490_priv_data = {
.driver_name = "qcs6490",
.dapm_widgets = sc8280xp_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
- .wcd_jack = true,
+ SC8280XP_DAI_DATA({
+ .id = TX_CODEC_DMA_TX_3,
+ .jack_setup = SC8280XP_JACK_SETUP_WCD,
+ }),
};
static const struct snd_soc_common qcs8275_priv_data = {
@@ -343,35 +420,50 @@ static const struct snd_soc_common sc8280xp_priv_data = {
.driver_name = "sc8280xp",
.dapm_widgets = sc8280xp_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
- .wcd_jack = true,
+ SC8280XP_DAI_DATA({
+ .id = TX_CODEC_DMA_TX_3,
+ .jack_setup = SC8280XP_JACK_SETUP_WCD,
+ }),
};
static const struct snd_soc_common sm8450_priv_data = {
.driver_name = "sm8450",
.dapm_widgets = sc8280xp_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
- .wcd_jack = true,
+ SC8280XP_DAI_DATA({
+ .id = TX_CODEC_DMA_TX_3,
+ .jack_setup = SC8280XP_JACK_SETUP_WCD,
+ }),
};
static const struct snd_soc_common sm8550_priv_data = {
.driver_name = "sm8550",
.dapm_widgets = sc8280xp_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
- .wcd_jack = true,
+ SC8280XP_DAI_DATA({
+ .id = TX_CODEC_DMA_TX_3,
+ .jack_setup = SC8280XP_JACK_SETUP_WCD,
+ }),
};
static const struct snd_soc_common sm8650_priv_data = {
.driver_name = "sm8650",
.dapm_widgets = sc8280xp_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
- .wcd_jack = true,
+ SC8280XP_DAI_DATA({
+ .id = TX_CODEC_DMA_TX_3,
+ .jack_setup = SC8280XP_JACK_SETUP_WCD,
+ }),
};
static const struct snd_soc_common sm8750_priv_data = {
.driver_name = "sm8750",
.dapm_widgets = sc8280xp_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
- .wcd_jack = true,
+ SC8280XP_DAI_DATA({
+ .id = TX_CODEC_DMA_TX_3,
+ .jack_setup = SC8280XP_JACK_SETUP_WCD,
+ }),
};
static const struct of_device_id snd_sc8280xp_dt_match[] = {
--
2.43.0