All of lore.kernel.org
 help / color / mirror / Atom feed
From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
To: Judy Hsiao <judyhsiao@chromium.org>, broonie@kernel.org
Cc: Taniya Das <tdas@codeaurora.org>,
	Rohit kumar <rohitkr@codeaurora.org>,
	Banajit Goswami <bgoswami@codeaurora.org>,
	Patrick Lai <plai@codeaurora.org>, Andy Gross <agross@kernel.org>,
	Bjorn Andersson <bjorn.andersson@linaro.org>,
	Liam Girdwood <lgirdwood@gmail.com>,
	Rob Herring <robh+dt@kernel.org>,
	Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.com>,
	Stephan Gerhold <stephan@gerhold.net>,
	dianders@chromium.org, dgreid@chromium.org, cychiang@google.com,
	judyhsiao@google.com, tzungbi@chromium.org, swboyd@chromium.org,
	linux-arm-kernel@lists.infradead.org,
	linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org,
	alsa-devel@alsa-project.org,
	Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Subject: Re: [v7] ASoC: qcom: lpass-cpu: Fix pop noise during audio capture begin
Date: Mon, 7 Jun 2021 15:32:22 +0100	[thread overview]
Message-ID: <0085836e-20d5-d74f-5a1e-1a6ea8252d02@linaro.org> (raw)
In-Reply-To: <20210604154545.1198337-1-judyhsiao@chromium.org>



On 04/06/2021 16:45, Judy Hsiao wrote:
> From: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
> 
> This patch fixes PoP noise of around 15ms observed during audio
> capture begin.
> Enables BCLK and LRCLK in snd_soc_dai_ops prepare call for
> introducing some delay before capture start.
> 
> Co-developed-by: Judy Hsiao <judyhsiao@chromium.org>
> Signed-off-by: Judy Hsiao <judyhsiao@chromium.org>
> Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
> (am from https://patchwork.kernel.org/patch/12276369/)
> (also found at https://lore.kernel.org/r/20210524142114.18676-1-srivasam@codeaurora.org)
> 

Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>


> ---
> Changes Since V6:
> 	-- Removed clk_disable OSR clock in lpass_cpu_daiops_prepare error case as failure
>             of prepare will result in calling shutdown which should take care of this.
> Changes Since V5:
>          -- Fixed nit.
>          -- Updated `mi2s_was_prepared[dai->driver->id] = true;` after checking for errors.
> Changes Since V4:
>          -- Replaced the __clk_is_enabled(BCLK) check by the self maintained.
>             mi2s_was_prepared bool state.
>          -- Removed unrelated changes.
>          -- Refined comments.
> Changes Since V3:
>          -- Checked BCLK is off before enabling it in lpass_cpu_daiops_prepare as
>             lpass_cpu_daiops_prepare can be called multiple times
>          -- Checked BCLK is on before disabling it in lpass_cpu_daiops_shutdown to
>             fix the WARN. It is because BCLK may not be enabled if
>             lpass_cpu_daiops_prepare is not called before lpass_cpu_daiops_shutdown
>          -- Added more comments
> Changes Since V2:
>          -- Updated comments as per linux style
>          -- Removed unrelated changes
> Changes Since V1:
>          -- Enabled BCLK and LRCLK in dai ops prepare API instead of startup API
>          -- Added comments
> 
>   sound/soc/qcom/lpass-cpu.c | 79 ++++++++++++++++++++++++++++++++++++++
>   sound/soc/qcom/lpass.h     |  4 ++
>   2 files changed, 83 insertions(+)
> 
> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
> index af8cb64924a0..647423a6cb57 100644
> --- a/sound/soc/qcom/lpass-cpu.c
> +++ b/sound/soc/qcom/lpass-cpu.c
> @@ -93,8 +93,30 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
>   		struct snd_soc_dai *dai)
>   {
>   	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> +	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
> +	unsigned int id = dai->driver->id;
>   
>   	clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
> +	/*
> +	 * Ensure LRCLK is disabled even in device node validation.
> +	 * Will not impact if disabled in lpass_cpu_daiops_trigger()
> +	 * suspend.
> +	 */
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +		regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_DISABLE);
> +	else
> +		regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_DISABLE);
> +
> +	/*
> +	 * BCLK may not be enabled if lpass_cpu_daiops_prepare is called before
> +	 * lpass_cpu_daiops_shutdown. It's paired with the clk_enable in
> +	 * lpass_cpu_daiops_prepare.
> +	 */
> +	if (drvdata->mi2s_was_prepared[dai->driver->id]) {
> +		drvdata->mi2s_was_prepared[dai->driver->id] = false;
> +		clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
> +	}
> +
>   	clk_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
>   }
>   
> @@ -275,6 +297,18 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
>   	case SNDRV_PCM_TRIGGER_START:
>   	case SNDRV_PCM_TRIGGER_RESUME:
>   	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +		/*
> +		 * Ensure lpass BCLK/LRCLK is enabled during
> +		 * device resume as lpass_cpu_daiops_prepare() is not called
> +		 * after the device resumes. We don't check mi2s_was_prepared before
> +		 * enable/disable BCLK in trigger events because:
> +		 *  1. These trigger events are paired, so the BCLK
> +		 *     enable_count is balanced.
> +		 *  2. the BCLK can be shared (ex: headset and headset mic),
> +		 *     we need to increase the enable_count so that we don't
> +		 *     turn off the shared BCLK while other devices are using
> +		 *     it.
> +		 */
>   		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>   			ret = regmap_fields_write(i2sctl->spken, id,
>   						 LPAIF_I2SCTL_SPKEN_ENABLE);
> @@ -296,6 +330,10 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
>   	case SNDRV_PCM_TRIGGER_STOP:
>   	case SNDRV_PCM_TRIGGER_SUSPEND:
>   	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +		/*
> +		 * To ensure lpass BCLK/LRCLK is disabled during
> +		 * device suspend.
> +		 */
>   		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>   			ret = regmap_fields_write(i2sctl->spken, id,
>   						 LPAIF_I2SCTL_SPKEN_DISABLE);
> @@ -315,12 +353,53 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
>   	return ret;
>   }
>   
> +static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
> +		struct snd_soc_dai *dai)
> +{
> +	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> +	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
> +	unsigned int id = dai->driver->id;
> +	int ret;
> +
> +	/*
> +	 * Ensure lpass BCLK/LRCLK is enabled bit before playback/capture
> +	 * data flow starts. This allows other codec to have some delay before
> +	 * the data flow.
> +	 * (ex: to drop start up pop noise before capture starts).
> +	 */
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +		ret = regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_ENABLE);
> +	else
> +		ret = regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_ENABLE);
> +
> +	if (ret) {
> +		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/*
> +	 * Check mi2s_was_prepared before enabling BCLK as lpass_cpu_daiops_prepare can
> +	 * be called multiple times. It's paired with the clk_disable in
> +	 * lpass_cpu_daiops_shutdown.
> +	 */
> +	if (!drvdata->mi2s_was_prepared[dai->driver->id]) {
> +		ret = clk_enable(drvdata->mi2s_bit_clk[id]);
> +		if (ret) {
> +			dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
> +			return ret;
> +		}
> +		drvdata->mi2s_was_prepared[dai->driver->id] = true;
> +	}
> +	return 0;
> +}
> +
>   const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
>   	.set_sysclk	= lpass_cpu_daiops_set_sysclk,
>   	.startup	= lpass_cpu_daiops_startup,
>   	.shutdown	= lpass_cpu_daiops_shutdown,
>   	.hw_params	= lpass_cpu_daiops_hw_params,
>   	.trigger	= lpass_cpu_daiops_trigger,
> +	.prepare	= lpass_cpu_daiops_prepare,
>   };
>   EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
>   
> diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
> index 83b2e08ade06..7f72214404ba 100644
> --- a/sound/soc/qcom/lpass.h
> +++ b/sound/soc/qcom/lpass.h
> @@ -67,6 +67,10 @@ struct lpass_data {
>   	/* MI2S SD lines to use for playback/capture */
>   	unsigned int mi2s_playback_sd_mode[LPASS_MAX_MI2S_PORTS];
>   	unsigned int mi2s_capture_sd_mode[LPASS_MAX_MI2S_PORTS];
> +
> +	/* The state of MI2S prepare dai_ops was called */
> +	bool mi2s_was_prepared[LPASS_MAX_MI2S_PORTS];
> +
>   	int hdmi_port_enable;
>   
>   	/* low-power audio interface (LPAIF) registers */
> 

WARNING: multiple messages have this Message-ID (diff)
From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
To: Judy Hsiao <judyhsiao@chromium.org>, broonie@kernel.org
Cc: Taniya Das <tdas@codeaurora.org>,
	alsa-devel@alsa-project.org,
	Banajit Goswami <bgoswami@codeaurora.org>,
	Liam Girdwood <lgirdwood@gmail.com>,
	Rohit kumar <rohitkr@codeaurora.org>,
	Patrick Lai <plai@codeaurora.org>, Andy Gross <agross@kernel.org>,
	dgreid@chromium.org, devicetree@vger.kernel.org,
	judyhsiao@google.com, tzungbi@chromium.org,
	Srinivasa Rao Mandadapu <srivasam@codeaurora.org>,
	Stephan Gerhold <stephan@gerhold.net>,
	linux-arm-msm@vger.kernel.org, swboyd@chromium.org,
	Rob Herring <robh+dt@kernel.org>,
	Bjorn Andersson <bjorn.andersson@linaro.org>,
	linux-arm-kernel@lists.infradead.org, dianders@chromium.org,
	cychiang@google.com, Takashi Iwai <tiwai@suse.com>
Subject: Re: [v7] ASoC: qcom: lpass-cpu: Fix pop noise during audio capture begin
Date: Mon, 7 Jun 2021 15:32:22 +0100	[thread overview]
Message-ID: <0085836e-20d5-d74f-5a1e-1a6ea8252d02@linaro.org> (raw)
In-Reply-To: <20210604154545.1198337-1-judyhsiao@chromium.org>



On 04/06/2021 16:45, Judy Hsiao wrote:
> From: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
> 
> This patch fixes PoP noise of around 15ms observed during audio
> capture begin.
> Enables BCLK and LRCLK in snd_soc_dai_ops prepare call for
> introducing some delay before capture start.
> 
> Co-developed-by: Judy Hsiao <judyhsiao@chromium.org>
> Signed-off-by: Judy Hsiao <judyhsiao@chromium.org>
> Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
> (am from https://patchwork.kernel.org/patch/12276369/)
> (also found at https://lore.kernel.org/r/20210524142114.18676-1-srivasam@codeaurora.org)
> 

Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>


> ---
> Changes Since V6:
> 	-- Removed clk_disable OSR clock in lpass_cpu_daiops_prepare error case as failure
>             of prepare will result in calling shutdown which should take care of this.
> Changes Since V5:
>          -- Fixed nit.
>          -- Updated `mi2s_was_prepared[dai->driver->id] = true;` after checking for errors.
> Changes Since V4:
>          -- Replaced the __clk_is_enabled(BCLK) check by the self maintained.
>             mi2s_was_prepared bool state.
>          -- Removed unrelated changes.
>          -- Refined comments.
> Changes Since V3:
>          -- Checked BCLK is off before enabling it in lpass_cpu_daiops_prepare as
>             lpass_cpu_daiops_prepare can be called multiple times
>          -- Checked BCLK is on before disabling it in lpass_cpu_daiops_shutdown to
>             fix the WARN. It is because BCLK may not be enabled if
>             lpass_cpu_daiops_prepare is not called before lpass_cpu_daiops_shutdown
>          -- Added more comments
> Changes Since V2:
>          -- Updated comments as per linux style
>          -- Removed unrelated changes
> Changes Since V1:
>          -- Enabled BCLK and LRCLK in dai ops prepare API instead of startup API
>          -- Added comments
> 
>   sound/soc/qcom/lpass-cpu.c | 79 ++++++++++++++++++++++++++++++++++++++
>   sound/soc/qcom/lpass.h     |  4 ++
>   2 files changed, 83 insertions(+)
> 
> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
> index af8cb64924a0..647423a6cb57 100644
> --- a/sound/soc/qcom/lpass-cpu.c
> +++ b/sound/soc/qcom/lpass-cpu.c
> @@ -93,8 +93,30 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
>   		struct snd_soc_dai *dai)
>   {
>   	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> +	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
> +	unsigned int id = dai->driver->id;
>   
>   	clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
> +	/*
> +	 * Ensure LRCLK is disabled even in device node validation.
> +	 * Will not impact if disabled in lpass_cpu_daiops_trigger()
> +	 * suspend.
> +	 */
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +		regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_DISABLE);
> +	else
> +		regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_DISABLE);
> +
> +	/*
> +	 * BCLK may not be enabled if lpass_cpu_daiops_prepare is called before
> +	 * lpass_cpu_daiops_shutdown. It's paired with the clk_enable in
> +	 * lpass_cpu_daiops_prepare.
> +	 */
> +	if (drvdata->mi2s_was_prepared[dai->driver->id]) {
> +		drvdata->mi2s_was_prepared[dai->driver->id] = false;
> +		clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
> +	}
> +
>   	clk_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
>   }
>   
> @@ -275,6 +297,18 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
>   	case SNDRV_PCM_TRIGGER_START:
>   	case SNDRV_PCM_TRIGGER_RESUME:
>   	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +		/*
> +		 * Ensure lpass BCLK/LRCLK is enabled during
> +		 * device resume as lpass_cpu_daiops_prepare() is not called
> +		 * after the device resumes. We don't check mi2s_was_prepared before
> +		 * enable/disable BCLK in trigger events because:
> +		 *  1. These trigger events are paired, so the BCLK
> +		 *     enable_count is balanced.
> +		 *  2. the BCLK can be shared (ex: headset and headset mic),
> +		 *     we need to increase the enable_count so that we don't
> +		 *     turn off the shared BCLK while other devices are using
> +		 *     it.
> +		 */
>   		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>   			ret = regmap_fields_write(i2sctl->spken, id,
>   						 LPAIF_I2SCTL_SPKEN_ENABLE);
> @@ -296,6 +330,10 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
>   	case SNDRV_PCM_TRIGGER_STOP:
>   	case SNDRV_PCM_TRIGGER_SUSPEND:
>   	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +		/*
> +		 * To ensure lpass BCLK/LRCLK is disabled during
> +		 * device suspend.
> +		 */
>   		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>   			ret = regmap_fields_write(i2sctl->spken, id,
>   						 LPAIF_I2SCTL_SPKEN_DISABLE);
> @@ -315,12 +353,53 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
>   	return ret;
>   }
>   
> +static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
> +		struct snd_soc_dai *dai)
> +{
> +	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> +	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
> +	unsigned int id = dai->driver->id;
> +	int ret;
> +
> +	/*
> +	 * Ensure lpass BCLK/LRCLK is enabled bit before playback/capture
> +	 * data flow starts. This allows other codec to have some delay before
> +	 * the data flow.
> +	 * (ex: to drop start up pop noise before capture starts).
> +	 */
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +		ret = regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_ENABLE);
> +	else
> +		ret = regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_ENABLE);
> +
> +	if (ret) {
> +		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/*
> +	 * Check mi2s_was_prepared before enabling BCLK as lpass_cpu_daiops_prepare can
> +	 * be called multiple times. It's paired with the clk_disable in
> +	 * lpass_cpu_daiops_shutdown.
> +	 */
> +	if (!drvdata->mi2s_was_prepared[dai->driver->id]) {
> +		ret = clk_enable(drvdata->mi2s_bit_clk[id]);
> +		if (ret) {
> +			dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
> +			return ret;
> +		}
> +		drvdata->mi2s_was_prepared[dai->driver->id] = true;
> +	}
> +	return 0;
> +}
> +
>   const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
>   	.set_sysclk	= lpass_cpu_daiops_set_sysclk,
>   	.startup	= lpass_cpu_daiops_startup,
>   	.shutdown	= lpass_cpu_daiops_shutdown,
>   	.hw_params	= lpass_cpu_daiops_hw_params,
>   	.trigger	= lpass_cpu_daiops_trigger,
> +	.prepare	= lpass_cpu_daiops_prepare,
>   };
>   EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
>   
> diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
> index 83b2e08ade06..7f72214404ba 100644
> --- a/sound/soc/qcom/lpass.h
> +++ b/sound/soc/qcom/lpass.h
> @@ -67,6 +67,10 @@ struct lpass_data {
>   	/* MI2S SD lines to use for playback/capture */
>   	unsigned int mi2s_playback_sd_mode[LPASS_MAX_MI2S_PORTS];
>   	unsigned int mi2s_capture_sd_mode[LPASS_MAX_MI2S_PORTS];
> +
> +	/* The state of MI2S prepare dai_ops was called */
> +	bool mi2s_was_prepared[LPASS_MAX_MI2S_PORTS];
> +
>   	int hdmi_port_enable;
>   
>   	/* low-power audio interface (LPAIF) registers */
> 

WARNING: multiple messages have this Message-ID (diff)
From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
To: Judy Hsiao <judyhsiao@chromium.org>, broonie@kernel.org
Cc: Taniya Das <tdas@codeaurora.org>,
	Rohit kumar <rohitkr@codeaurora.org>,
	Banajit Goswami <bgoswami@codeaurora.org>,
	Patrick Lai <plai@codeaurora.org>, Andy Gross <agross@kernel.org>,
	Bjorn Andersson <bjorn.andersson@linaro.org>,
	Liam Girdwood <lgirdwood@gmail.com>,
	Rob Herring <robh+dt@kernel.org>,
	Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.com>,
	Stephan Gerhold <stephan@gerhold.net>,
	dianders@chromium.org, dgreid@chromium.org, cychiang@google.com,
	judyhsiao@google.com, tzungbi@chromium.org, swboyd@chromium.org,
	linux-arm-kernel@lists.infradead.org,
	linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org,
	alsa-devel@alsa-project.org,
	Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Subject: Re: [v7] ASoC: qcom: lpass-cpu: Fix pop noise during audio capture begin
Date: Mon, 7 Jun 2021 15:32:22 +0100	[thread overview]
Message-ID: <0085836e-20d5-d74f-5a1e-1a6ea8252d02@linaro.org> (raw)
In-Reply-To: <20210604154545.1198337-1-judyhsiao@chromium.org>



On 04/06/2021 16:45, Judy Hsiao wrote:
> From: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
> 
> This patch fixes PoP noise of around 15ms observed during audio
> capture begin.
> Enables BCLK and LRCLK in snd_soc_dai_ops prepare call for
> introducing some delay before capture start.
> 
> Co-developed-by: Judy Hsiao <judyhsiao@chromium.org>
> Signed-off-by: Judy Hsiao <judyhsiao@chromium.org>
> Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
> (am from https://patchwork.kernel.org/patch/12276369/)
> (also found at https://lore.kernel.org/r/20210524142114.18676-1-srivasam@codeaurora.org)
> 

Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>


> ---
> Changes Since V6:
> 	-- Removed clk_disable OSR clock in lpass_cpu_daiops_prepare error case as failure
>             of prepare will result in calling shutdown which should take care of this.
> Changes Since V5:
>          -- Fixed nit.
>          -- Updated `mi2s_was_prepared[dai->driver->id] = true;` after checking for errors.
> Changes Since V4:
>          -- Replaced the __clk_is_enabled(BCLK) check by the self maintained.
>             mi2s_was_prepared bool state.
>          -- Removed unrelated changes.
>          -- Refined comments.
> Changes Since V3:
>          -- Checked BCLK is off before enabling it in lpass_cpu_daiops_prepare as
>             lpass_cpu_daiops_prepare can be called multiple times
>          -- Checked BCLK is on before disabling it in lpass_cpu_daiops_shutdown to
>             fix the WARN. It is because BCLK may not be enabled if
>             lpass_cpu_daiops_prepare is not called before lpass_cpu_daiops_shutdown
>          -- Added more comments
> Changes Since V2:
>          -- Updated comments as per linux style
>          -- Removed unrelated changes
> Changes Since V1:
>          -- Enabled BCLK and LRCLK in dai ops prepare API instead of startup API
>          -- Added comments
> 
>   sound/soc/qcom/lpass-cpu.c | 79 ++++++++++++++++++++++++++++++++++++++
>   sound/soc/qcom/lpass.h     |  4 ++
>   2 files changed, 83 insertions(+)
> 
> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
> index af8cb64924a0..647423a6cb57 100644
> --- a/sound/soc/qcom/lpass-cpu.c
> +++ b/sound/soc/qcom/lpass-cpu.c
> @@ -93,8 +93,30 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
>   		struct snd_soc_dai *dai)
>   {
>   	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> +	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
> +	unsigned int id = dai->driver->id;
>   
>   	clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
> +	/*
> +	 * Ensure LRCLK is disabled even in device node validation.
> +	 * Will not impact if disabled in lpass_cpu_daiops_trigger()
> +	 * suspend.
> +	 */
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +		regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_DISABLE);
> +	else
> +		regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_DISABLE);
> +
> +	/*
> +	 * BCLK may not be enabled if lpass_cpu_daiops_prepare is called before
> +	 * lpass_cpu_daiops_shutdown. It's paired with the clk_enable in
> +	 * lpass_cpu_daiops_prepare.
> +	 */
> +	if (drvdata->mi2s_was_prepared[dai->driver->id]) {
> +		drvdata->mi2s_was_prepared[dai->driver->id] = false;
> +		clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
> +	}
> +
>   	clk_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
>   }
>   
> @@ -275,6 +297,18 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
>   	case SNDRV_PCM_TRIGGER_START:
>   	case SNDRV_PCM_TRIGGER_RESUME:
>   	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +		/*
> +		 * Ensure lpass BCLK/LRCLK is enabled during
> +		 * device resume as lpass_cpu_daiops_prepare() is not called
> +		 * after the device resumes. We don't check mi2s_was_prepared before
> +		 * enable/disable BCLK in trigger events because:
> +		 *  1. These trigger events are paired, so the BCLK
> +		 *     enable_count is balanced.
> +		 *  2. the BCLK can be shared (ex: headset and headset mic),
> +		 *     we need to increase the enable_count so that we don't
> +		 *     turn off the shared BCLK while other devices are using
> +		 *     it.
> +		 */
>   		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>   			ret = regmap_fields_write(i2sctl->spken, id,
>   						 LPAIF_I2SCTL_SPKEN_ENABLE);
> @@ -296,6 +330,10 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
>   	case SNDRV_PCM_TRIGGER_STOP:
>   	case SNDRV_PCM_TRIGGER_SUSPEND:
>   	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +		/*
> +		 * To ensure lpass BCLK/LRCLK is disabled during
> +		 * device suspend.
> +		 */
>   		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>   			ret = regmap_fields_write(i2sctl->spken, id,
>   						 LPAIF_I2SCTL_SPKEN_DISABLE);
> @@ -315,12 +353,53 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
>   	return ret;
>   }
>   
> +static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
> +		struct snd_soc_dai *dai)
> +{
> +	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> +	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
> +	unsigned int id = dai->driver->id;
> +	int ret;
> +
> +	/*
> +	 * Ensure lpass BCLK/LRCLK is enabled bit before playback/capture
> +	 * data flow starts. This allows other codec to have some delay before
> +	 * the data flow.
> +	 * (ex: to drop start up pop noise before capture starts).
> +	 */
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +		ret = regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_ENABLE);
> +	else
> +		ret = regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_ENABLE);
> +
> +	if (ret) {
> +		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/*
> +	 * Check mi2s_was_prepared before enabling BCLK as lpass_cpu_daiops_prepare can
> +	 * be called multiple times. It's paired with the clk_disable in
> +	 * lpass_cpu_daiops_shutdown.
> +	 */
> +	if (!drvdata->mi2s_was_prepared[dai->driver->id]) {
> +		ret = clk_enable(drvdata->mi2s_bit_clk[id]);
> +		if (ret) {
> +			dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
> +			return ret;
> +		}
> +		drvdata->mi2s_was_prepared[dai->driver->id] = true;
> +	}
> +	return 0;
> +}
> +
>   const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
>   	.set_sysclk	= lpass_cpu_daiops_set_sysclk,
>   	.startup	= lpass_cpu_daiops_startup,
>   	.shutdown	= lpass_cpu_daiops_shutdown,
>   	.hw_params	= lpass_cpu_daiops_hw_params,
>   	.trigger	= lpass_cpu_daiops_trigger,
> +	.prepare	= lpass_cpu_daiops_prepare,
>   };
>   EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
>   
> diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
> index 83b2e08ade06..7f72214404ba 100644
> --- a/sound/soc/qcom/lpass.h
> +++ b/sound/soc/qcom/lpass.h
> @@ -67,6 +67,10 @@ struct lpass_data {
>   	/* MI2S SD lines to use for playback/capture */
>   	unsigned int mi2s_playback_sd_mode[LPASS_MAX_MI2S_PORTS];
>   	unsigned int mi2s_capture_sd_mode[LPASS_MAX_MI2S_PORTS];
> +
> +	/* The state of MI2S prepare dai_ops was called */
> +	bool mi2s_was_prepared[LPASS_MAX_MI2S_PORTS];
> +
>   	int hdmi_port_enable;
>   
>   	/* low-power audio interface (LPAIF) registers */
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2021-06-07 14:33 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-04 15:45 [v7] ASoC: qcom: lpass-cpu: Fix pop noise during audio capture begin Judy Hsiao
2021-06-04 15:45 ` Judy Hsiao
2021-06-04 15:45 ` Judy Hsiao
2021-06-07 14:32 ` Srinivas Kandagatla [this message]
2021-06-07 14:32   ` Srinivas Kandagatla
2021-06-07 14:32   ` Srinivas Kandagatla
2021-06-07 19:00 ` Mark Brown
2021-06-07 19:00   ` Mark Brown
2021-06-07 19:00   ` Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0085836e-20d5-d74f-5a1e-1a6ea8252d02@linaro.org \
    --to=srinivas.kandagatla@linaro.org \
    --cc=agross@kernel.org \
    --cc=alsa-devel@alsa-project.org \
    --cc=bgoswami@codeaurora.org \
    --cc=bjorn.andersson@linaro.org \
    --cc=broonie@kernel.org \
    --cc=cychiang@google.com \
    --cc=devicetree@vger.kernel.org \
    --cc=dgreid@chromium.org \
    --cc=dianders@chromium.org \
    --cc=judyhsiao@chromium.org \
    --cc=judyhsiao@google.com \
    --cc=lgirdwood@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=perex@perex.cz \
    --cc=plai@codeaurora.org \
    --cc=robh+dt@kernel.org \
    --cc=rohitkr@codeaurora.org \
    --cc=srivasam@codeaurora.org \
    --cc=stephan@gerhold.net \
    --cc=swboyd@chromium.org \
    --cc=tdas@codeaurora.org \
    --cc=tiwai@suse.com \
    --cc=tzungbi@chromium.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.