From 62a65145e171d3f09df9830c1f6568d911e2af26 Mon Sep 17 00:00:00 2001 From: Ravi Hothi Date: Tue, 30 Dec 2025 12:47:51 +0530 Subject: [PATCH] audioreach-driver: audioreach-common: add local SDW API for 6.18/6.19-rc2 compatibility Update backend (BE) ops to use qcs6490_snd_sdw_* APIs instead of the generic qcom_snd_sdw_* functions. This change ensures that the audioreach driver builds and works correctly across kernel versions 6.18 and 6.19-rc2, where platform-specific SoundWire handling is required. The modification aligns BE operations with QCS6490-specific SoundWire implementation, avoiding compatibility issues introduced by recent kernel changes. Tested on QCS6490/QCS9075 with both 6.18 and 6.19-rc2 kernels. Signed-off-by: Ravi Hothi --- audioreach-driver/audioreach_common.c | 200 +++++++++++++++++++++++++- 1 file changed, 195 insertions(+), 5 deletions(-) diff --git a/audioreach-driver/audioreach_common.c b/audioreach-driver/audioreach_common.c index 1f25fbe..345b62f 100644 --- a/audioreach-driver/audioreach_common.c +++ b/audioreach-driver/audioreach_common.c @@ -21,6 +21,7 @@ struct qcs6490_snd_data { bool stream_prepared[AFE_PORT_MAX]; struct snd_soc_card *card; + struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; struct snd_soc_jack jack; struct snd_soc_jack dp_jack[8]; bool jack_setup; @@ -62,6 +63,182 @@ static struct snd_soc_jack_pin qcs6490_headset_jack_pins[] = { }, }; +static int qcs6490_snd_sdw_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + u32 rx_ch[SDW_MAX_PORTS], tx_ch[SDW_MAX_PORTS]; + struct sdw_stream_runtime *sruntime; + struct snd_soc_dai *codec_dai; + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; + int ret, i, j; + + sruntime = sdw_alloc_stream(cpu_dai->name, SDW_STREAM_PCM); + if (!sruntime) + return -ENOMEM; + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + ret = snd_soc_dai_set_stream(codec_dai, sruntime, + substream->stream); + if (ret < 0 && ret != -ENOTSUPP) { + dev_err(rtd->dev, "Failed to set sdw stream on %s\n", codec_dai->name); + goto err_set_stream; + } else if (ret == -ENOTSUPP) { + /* Ignore unsupported */ + continue; + } + + ret = snd_soc_dai_get_channel_map(codec_dai, &tx_ch_cnt, tx_ch, + &rx_ch_cnt, rx_ch); + if (ret != 0 && ret != -ENOTSUPP) { + dev_err(rtd->dev, "Failed to get codec chan map %s\n", codec_dai->name); + goto err_set_stream; + } else if (ret == -ENOTSUPP) { + /* Ignore unsupported */ + continue; + } + } + + switch (cpu_dai->id) { + case RX_CODEC_DMA_RX_0: + case TX_CODEC_DMA_TX_3: + if (tx_ch_cnt || rx_ch_cnt) { + for_each_rtd_codec_dais(rtd, j, codec_dai) { + ret = snd_soc_dai_set_channel_map(codec_dai, + tx_ch_cnt, tx_ch, + rx_ch_cnt, rx_ch); + if (ret != 0 && ret != -ENOTSUPP) + goto err_set_stream; + } + } + } + + return 0; + +err_set_stream: + sdw_release_stream(sruntime); + + return ret; +} + +static int qcs6490_snd_sdw_prepare(struct snd_pcm_substream *substream, + struct sdw_stream_runtime *sruntime, + bool *stream_prepared) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + int ret; + + if (!sruntime) + return 0; + + switch (cpu_dai->id) { + case WSA_CODEC_DMA_RX_0: + case WSA_CODEC_DMA_RX_1: + case RX_CODEC_DMA_RX_0: + case RX_CODEC_DMA_RX_1: + case TX_CODEC_DMA_TX_0: + case TX_CODEC_DMA_TX_1: + case TX_CODEC_DMA_TX_2: + case TX_CODEC_DMA_TX_3: + break; + default: + return 0; + } + + if (*stream_prepared) + return 0; + + ret = sdw_prepare_stream(sruntime); + if (ret) + return ret; + + /** + * NOTE: there is a strict hw requirement about the ordering of port + * enables and actual WSA881x PA enable. PA enable should only happen + * after soundwire ports are enabled if not DC on the line is + * accumulated resulting in Click/Pop Noise + * PA enable/mute are handled as part of codec DAPM and digital mute. + */ + + ret = sdw_enable_stream(sruntime); + if (ret) { + sdw_deprepare_stream(sruntime); + return ret; + } + *stream_prepared = true; + + return ret; +} + +static int qcs6490_snd_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sdw_stream_runtime **psruntime) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai; + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sdw_stream_runtime *sruntime; + int i; + + switch (cpu_dai->id) { + case WSA_CODEC_DMA_RX_0: + case RX_CODEC_DMA_RX_0: + case RX_CODEC_DMA_RX_1: + case TX_CODEC_DMA_TX_0: + case TX_CODEC_DMA_TX_1: + case TX_CODEC_DMA_TX_2: + case TX_CODEC_DMA_TX_3: + for_each_rtd_codec_dais(rtd, i, codec_dai) { + sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream); + if (sruntime != ERR_PTR(-ENOTSUPP)) + *psruntime = sruntime; + } + break; + } + + return 0; +} + +static int qcs6490_snd_sdw_hw_free(struct snd_pcm_substream *substream, + struct sdw_stream_runtime *sruntime, + bool *stream_prepared) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + + switch (cpu_dai->id) { + case WSA_CODEC_DMA_RX_0: + case WSA_CODEC_DMA_RX_1: + case RX_CODEC_DMA_RX_0: + case RX_CODEC_DMA_RX_1: + case TX_CODEC_DMA_TX_0: + case TX_CODEC_DMA_TX_1: + case TX_CODEC_DMA_TX_2: + case TX_CODEC_DMA_TX_3: + if (sruntime && *stream_prepared) { + sdw_disable_stream(sruntime); + sdw_deprepare_stream(sruntime); + *stream_prepared = false; + } + break; + default: + break; + } + + return 0; +} + +static void qcs6490_snd_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct qcs6490_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); + struct sdw_stream_runtime *sruntime = pdata->sruntime[cpu_dai->id]; + + pdata->sruntime[cpu_dai->id] = NULL; + sdw_release_stream(sruntime); +} static int qcs6490_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd, struct snd_soc_jack *dp_jack, int dp_pcm_id) @@ -388,7 +565,7 @@ static int qcs6490_snd_init(struct snd_soc_pcm_runtime *rtd) } static int qcs6490_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params) { struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_interval *rate = hw_param_interval(params, @@ -414,13 +591,24 @@ static int qcs6490_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static int qcs6490_snd_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 *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct qcs6490_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); + + return qcs6490_snd_sdw_hw_params(substream, params, &pdata->sruntime[cpu_dai->id]); +} + static int qcs6490_snd_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct qcs6490_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; - return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]); + return qcs6490_snd_sdw_prepare(substream, sruntime, &data->stream_prepared[cpu_dai->id]); } static int qcs6490_snd_hw_free(struct snd_pcm_substream *substream) @@ -428,13 +616,15 @@ static int qcs6490_snd_hw_free(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct qcs6490_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; - return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]); + return qcs6490_snd_sdw_hw_free(substream, sruntime, &data->stream_prepared[cpu_dai->id]); } static const struct snd_soc_ops qcs6490_be_ops = { - .startup = qcom_snd_sdw_startup, - .shutdown = qcom_snd_sdw_shutdown, + .startup = qcs6490_snd_sdw_startup, + .shutdown = qcs6490_snd_shutdown, + .hw_params = qcs6490_snd_hw_params, .hw_free = qcs6490_snd_hw_free, .prepare = qcs6490_snd_prepare, };