On 5/6/26 8:33 PM, Val Packett wrote:
> These port clocks were never being turned off, leading to increased
> power consumption after a sound was played through any of these ports
> for the first time. Use enable counters to disable the clocks in the
> shutdown callback, similar to how it's done for sdm845.
>
> Signed-off-by: Val Packett <[email protected]>
> ---
> sound/soc/qcom/sm8250.c | 150 +++++++++++++++++++++++++++++++---------
> 1 file changed, 119 insertions(+), 31 deletions(-)
>
> diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
> index b64fd3970ba1..9f0f846a14bb 100644
> --- a/sound/soc/qcom/sm8250.c
> +++ b/sound/soc/qcom/sm8250.c
> @@ -24,6 +24,7 @@ static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16,
> 20, 24, 28};
>
> struct sm8250_snd_data {
> bool stream_prepared[AFE_PORT_MAX];
> + uint32_t clk_count[AFE_PORT_MAX];
In your setup are you sharing BE dais to multiple FE?
if not you would really not need the count, startup and shutdown are
paired for single PCM stream.
If yes, then you need some protection against these counters.
> struct snd_soc_card *card;
> struct snd_soc_jack jack;
> struct snd_soc_jack usb_offload_jack;
> @@ -163,83 +164,95 @@ static int sm8250_snd_startup(struct snd_pcm_substream
> *substream)
> unsigned int fmt = SND_SOC_DAIFMT_BP_FP;
> unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC;
> struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
> + struct snd_soc_card *card = rtd->card;
> + struct sm8250_snd_data *data = snd_soc_card_get_drvdata(card);
> struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
> struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
>
> switch (cpu_dai->id) {
> case PRIMARY_MI2S_RX:
> codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
> - snd_soc_dai_set_sysclk(cpu_dai,
> - Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
> - MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> + if (++(data->clk_count[PRIMARY_MI2S_RX]) == 1)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
> + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> snd_soc_dai_set_fmt(cpu_dai, fmt);
> snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
> break;
> case SECONDARY_MI2S_RX:
> codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
> - snd_soc_dai_set_sysclk(cpu_dai,
> - Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
> - MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> + if (++(data->clk_count[SECONDARY_MI2S_RX]) == 1)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
> + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> snd_soc_dai_set_fmt(cpu_dai, fmt);
> snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
> break;
> case TERTIARY_MI2S_RX:
> codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
> - snd_soc_dai_set_sysclk(cpu_dai,
> - Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
> - MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> + if (++(data->clk_count[TERTIARY_MI2S_RX]) == 1)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
> + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> snd_soc_dai_set_fmt(cpu_dai, fmt);
> snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
> break;
> case QUINARY_MI2S_RX:
> codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
> - snd_soc_dai_set_sysclk(cpu_dai,
> - Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT,
> - MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> + if (++(data->clk_count[QUINARY_MI2S_RX]) == 1)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT,
> + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> snd_soc_dai_set_fmt(cpu_dai, fmt);
> snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
> break;
> case SENARY_MI2S_RX:
> codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
> - snd_soc_dai_set_sysclk(cpu_dai,
> - Q6AFE_LPASS_CLK_ID_SEN_MI2S_IBIT,
> - MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> + if (++(data->clk_count[SENARY_MI2S_RX]) == 1)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_SEN_MI2S_IBIT,
> + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
> 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);
> + if (++(data->clk_count[PRIMARY_TDM_RX_0]) == 1)
> + 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);
> + if (++(data->clk_count[SECONDARY_TDM_RX_0]) == 1)
> + 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);
> + if (++(data->clk_count[TERTIARY_TDM_RX_0]) == 1)
> + 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);
> + if (++(data->clk_count[QUATERNARY_TDM_RX_0]) == 1)
> + 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);
> + if (++(data->clk_count[QUINARY_TDM_RX_0]) == 1)
> + 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:
> @@ -249,6 +262,81 @@ static int sm8250_snd_startup(struct snd_pcm_substream
> *substream)
> return qcom_snd_sdw_startup(substream);
> }
>
> +static void sm8250_snd_shutdown(struct snd_pcm_substream *substream)
> +{
> + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
> + struct snd_soc_card *card = rtd->card;
> + struct sm8250_snd_data *data = snd_soc_card_get_drvdata(card);
> + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
> +
> + switch (cpu_dai->id) {
> + case PRIMARY_MI2S_RX:
> + if (--(data->clk_count[PRIMARY_MI2S_RX]) == 0)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
> + 0, SNDRV_PCM_STREAM_PLAYBACK);
> + break;
> + case SECONDARY_MI2S_RX:
> + if (--(data->clk_count[SECONDARY_MI2S_RX]) == 0)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
> + 0, SNDRV_PCM_STREAM_PLAYBACK);
> + break;
> + case TERTIARY_MI2S_RX:
> + if (--(data->clk_count[TERTIARY_MI2S_RX]) == 0)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
> + 0, SNDRV_PCM_STREAM_PLAYBACK);
> + break;
> + case QUINARY_MI2S_RX:
> + if (--(data->clk_count[QUINARY_MI2S_RX]) == 0)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT,
> + 0, SNDRV_PCM_STREAM_PLAYBACK);
> + break;
> + case SENARY_MI2S_RX:
> + if (--(data->clk_count[SENARY_MI2S_RX]) == 0)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_SEN_MI2S_IBIT,
> + 0, SNDRV_PCM_STREAM_PLAYBACK);
> + break;
> + case PRIMARY_TDM_RX_0:
> + if (--(data->clk_count[PRIMARY_TDM_RX_0]) == 0)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT,
> + 0, SNDRV_PCM_STREAM_PLAYBACK);
> + break;
> + case SECONDARY_TDM_RX_0:
> + if (--(data->clk_count[SECONDARY_TDM_RX_0]) == 0)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT,
> + 0, SNDRV_PCM_STREAM_PLAYBACK);
> + break;
> + case TERTIARY_TDM_RX_0:
> + if (--(data->clk_count[TERTIARY_TDM_RX_0]) == 0)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT,
> + 0, SNDRV_PCM_STREAM_PLAYBACK);
> + break;
> + case QUATERNARY_TDM_RX_0:
> + if (--(data->clk_count[QUATERNARY_TDM_RX_0]) == 0)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
> + 0, SNDRV_PCM_STREAM_PLAYBACK);
> + break;
> + case QUINARY_TDM_RX_0:
> + if (--(data->clk_count[QUINARY_TDM_RX_0]) == 0)
> + snd_soc_dai_set_sysclk(cpu_dai,
> + Q6AFE_LPASS_CLK_ID_QUIN_TDM_IBIT,
> + 0, SNDRV_PCM_STREAM_PLAYBACK);
> + break;
> + default:
> + break;
> + }
> +
> + qcom_snd_sdw_shutdown(substream);
> +}
> +
> static int sm8250_snd_prepare(struct snd_pcm_substream *substream)
> {
> struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
> @@ -287,7 +375,7 @@ static int sm8250_snd_hw_params(struct snd_pcm_substream
> *substream,
>
> static const struct snd_soc_ops sm8250_be_ops = {
> .startup = sm8250_snd_startup,
> - .shutdown = qcom_snd_sdw_shutdown,
> + .shutdown = sm8250_snd_shutdown,
> .hw_free = sm8250_snd_hw_free,
> .hw_params = sm8250_snd_hw_params,
> .prepare = sm8250_snd_prepare,