Re: [PATCH v2 4/6] ASoC: qcom: sm8250: add TDM RX support

Srinivas Kandagatla <[email protected]>
Newsgroups org.kernel.vger.phone-devel,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-kernel,org.kernel.vger.linux-sound
Message-ID <[email protected]>
On 5/6/26 8:33 PM, Val Packett wrote:
> Add support for TDM RX DAIs which are used on some devices to send audio
> data to speaker amplifiers. Channels are assigned based on the codec
> DAI names for a quad-speaker setup such as on the xiaomi-pipa tablet.
> 
> Signed-off-by: Val Packett <[email protected]>
> ---
>  sound/soc/qcom/sm8250.c | 141 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 141 insertions(+)
> 
> diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
> index a675913da943..b64fd3970ba1 100644
> --- a/sound/soc/qcom/sm8250.c
> +++ b/sound/soc/qcom/sm8250.c
> @@ -17,6 +17,10 @@
>  #include "sdw.h"
>  
>  #define MI2S_BCLK_RATE		1536000
> +#define TDM_BCLK_RATE		6144000
> +#define NUM_TDM_SLOTS		8
> +
> +static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
static const ?

>  
>  struct sm8250_snd_data {
>  	bool stream_prepared[AFE_PORT_MAX];
> @@ -55,6 +59,89 @@ static void sm8250_snd_exit(struct snd_soc_pcm_runtime *rtd)
>  
>  }
>  
> +static int sm8250_tdm_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 snd_soc_dai *codec_dai;
> +	unsigned int rx_mask;
> +	int ret = 0, j;
> +	int channels, slot_width;
> +
> +	switch (params_format(params)) {
> +	case SNDRV_PCM_FORMAT_S16_LE:
> +		slot_width = 16;
> +		break;

Any reason only S16?

> +	default:
> +		dev_err(rtd->dev, "%s: invalid param format 0x%x\n",
> +				__func__, params_format(params));
> +		return -EINVAL;
> +	}
> +
> +	channels = params_channels(params);
> +
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> +		ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0x3,
Please define the magic constants like 0x3 here.

> +				8, slot_width);
> +		if (ret < 0) {
> +			dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
> +					__func__, ret);
> +			goto end;
> +		}
> +
> +		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
> +				channels, tdm_slot_offset);
> +		if (ret < 0) {
> +			dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
> +					__func__, ret);
> +			goto end;
> +		}
> +	} else {
> +		ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xf, 0,
> +				8, slot_width);
> +		if (ret < 0) {
> +			dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
> +					__func__, ret);
> +			goto end;
> +		}
> +
> +		ret = snd_soc_dai_set_channel_map(cpu_dai, channels,
> +				tdm_slot_offset, 0, NULL);

> +		if (ret < 0) {
> +			dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
> +					__func__, ret);
> +			goto end;
> +		}
> +	}
> +
> +	for_each_rtd_codec_dais(rtd, j, codec_dai) {
> +		if (strstr(codec_dai->component->name_prefix, "PL")) {
name prefix can be null.

> +			rx_mask = BIT(0);
> +		} else if (strstr(codec_dai->component->name_prefix, "PR")) {
name prefix comparision is fragile design, this will break very soon.
and this is not a binding too.


This also raises question about the using this generic driver for such
specific combination. Can these be made specific to compatible ?


> +			rx_mask = BIT(1);
> +		} else if (strstr(codec_dai->component->name_prefix, "SL")) {
> +			rx_mask = BIT(2);
> +		} else if (strstr(codec_dai->component->name_prefix, "SR")) {
> +			rx_mask = BIT(3);
> +		} else {
> +			rx_mask = 0;
> +			dev_warn(rtd->dev, "%s: codec DAI name '%s' not recognized\n",
> +				__func__, codec_dai->component->name_prefix);
> +		}
> +		ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, rx_mask,
> +				NUM_TDM_SLOTS, slot_width);



> +		if (ret < 0) {
Can we handle -ENOSUPP?

> +			dev_err(rtd->dev, "%s: failed to set TDM slot, err:%d\n",
> +				__func__, ret);
> +			goto end;
> +		}
> +	}
> +
> +end:
> +	return ret;
> +}
> +
>  static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
>  				     struct snd_pcm_hw_params *params)
>  {
> @@ -120,6 +207,41 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream)
>  		snd_soc_dai_set_fmt(cpu_dai, fmt);
>  		snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
>  		break;
> +	case PRIMARY_TDM_RX_0:
> +		codec_dai_fmt |= SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B;
> +		snd_soc_dai_set_sysclk(cpu_dai,
> +			Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT,
> +			TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> +		snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
> +		break;
> +	case SECONDARY_TDM_RX_0:
> +		codec_dai_fmt |= SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B;
> +		snd_soc_dai_set_sysclk(cpu_dai,
> +			Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT,
> +			TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> +		snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
> +		break;
> +	case TERTIARY_TDM_RX_0:
> +		codec_dai_fmt |= SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B;
> +		snd_soc_dai_set_sysclk(cpu_dai,
> +			Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT,
> +			TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> +		snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
> +		break;
> +	case QUATERNARY_TDM_RX_0:
> +		codec_dai_fmt |= SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B;
> +		snd_soc_dai_set_sysclk(cpu_dai,
> +			Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
> +			TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> +		snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
> +		break;
> +	case QUINARY_TDM_RX_0:
> +		codec_dai_fmt |= SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B;
> +		snd_soc_dai_set_sysclk(cpu_dai,
> +			Q6AFE_LPASS_CLK_ID_QUIN_TDM_IBIT,
> +			TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> +		snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
> +		break;
>  	default:
>  		break;
>  	}
> @@ -145,10 +267,29 @@ static int sm8250_snd_hw_free(struct snd_pcm_substream *substream)
>  	return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]);
>  }
>  
> +static int sm8250_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);
> +	int ret = 0;
> +
> +	switch (cpu_dai->id) {
> +	case PRIMARY_TDM_RX_0...QUINARY_TDM_TX_7:
> +		ret = sm8250_tdm_snd_hw_params(substream, params);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
>  static const struct snd_soc_ops sm8250_be_ops = {
>  	.startup = sm8250_snd_startup,
>  	.shutdown = qcom_snd_sdw_shutdown,
>  	.hw_free = sm8250_snd_hw_free,
> +	.hw_params = sm8250_snd_hw_params,
>  	.prepare = sm8250_snd_prepare,
>  };
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.