Skip to content

Commit c8a4556

Browse files
Srinivasa Rao Mandadapubroonie
authored andcommitted
ASoC: qcom: lpass-cpu: Fix pop noise during audio capture begin
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. (am from https://patchwork.kernel.org/patch/12276369/) (also found at https://lore.kernel.org/r/[email protected]) Co-developed-by: Judy Hsiao <[email protected]> Signed-off-by: Judy Hsiao <[email protected]> Signed-off-by: Srinivasa Rao Mandadapu <[email protected]> Reviewed-by: Srinivas Kandagatla <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 49783c6 commit c8a4556

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

sound/soc/qcom/lpass-cpu.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,30 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
9393
struct snd_soc_dai *dai)
9494
{
9595
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
96+
struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
97+
unsigned int id = dai->driver->id;
9698

9799
clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
100+
/*
101+
* Ensure LRCLK is disabled even in device node validation.
102+
* Will not impact if disabled in lpass_cpu_daiops_trigger()
103+
* suspend.
104+
*/
105+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
106+
regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_DISABLE);
107+
else
108+
regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_DISABLE);
109+
110+
/*
111+
* BCLK may not be enabled if lpass_cpu_daiops_prepare is called before
112+
* lpass_cpu_daiops_shutdown. It's paired with the clk_enable in
113+
* lpass_cpu_daiops_prepare.
114+
*/
115+
if (drvdata->mi2s_was_prepared[dai->driver->id]) {
116+
drvdata->mi2s_was_prepared[dai->driver->id] = false;
117+
clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
118+
}
119+
98120
clk_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
99121
}
100122

@@ -275,6 +297,18 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
275297
case SNDRV_PCM_TRIGGER_START:
276298
case SNDRV_PCM_TRIGGER_RESUME:
277299
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
300+
/*
301+
* Ensure lpass BCLK/LRCLK is enabled during
302+
* device resume as lpass_cpu_daiops_prepare() is not called
303+
* after the device resumes. We don't check mi2s_was_prepared before
304+
* enable/disable BCLK in trigger events because:
305+
* 1. These trigger events are paired, so the BCLK
306+
* enable_count is balanced.
307+
* 2. the BCLK can be shared (ex: headset and headset mic),
308+
* we need to increase the enable_count so that we don't
309+
* turn off the shared BCLK while other devices are using
310+
* it.
311+
*/
278312
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
279313
ret = regmap_fields_write(i2sctl->spken, id,
280314
LPAIF_I2SCTL_SPKEN_ENABLE);
@@ -296,6 +330,10 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
296330
case SNDRV_PCM_TRIGGER_STOP:
297331
case SNDRV_PCM_TRIGGER_SUSPEND:
298332
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
333+
/*
334+
* To ensure lpass BCLK/LRCLK is disabled during
335+
* device suspend.
336+
*/
299337
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
300338
ret = regmap_fields_write(i2sctl->spken, id,
301339
LPAIF_I2SCTL_SPKEN_DISABLE);
@@ -315,12 +353,53 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
315353
return ret;
316354
}
317355

356+
static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
357+
struct snd_soc_dai *dai)
358+
{
359+
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
360+
struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
361+
unsigned int id = dai->driver->id;
362+
int ret;
363+
364+
/*
365+
* Ensure lpass BCLK/LRCLK is enabled bit before playback/capture
366+
* data flow starts. This allows other codec to have some delay before
367+
* the data flow.
368+
* (ex: to drop start up pop noise before capture starts).
369+
*/
370+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
371+
ret = regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_ENABLE);
372+
else
373+
ret = regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_ENABLE);
374+
375+
if (ret) {
376+
dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
377+
return ret;
378+
}
379+
380+
/*
381+
* Check mi2s_was_prepared before enabling BCLK as lpass_cpu_daiops_prepare can
382+
* be called multiple times. It's paired with the clk_disable in
383+
* lpass_cpu_daiops_shutdown.
384+
*/
385+
if (!drvdata->mi2s_was_prepared[dai->driver->id]) {
386+
ret = clk_enable(drvdata->mi2s_bit_clk[id]);
387+
if (ret) {
388+
dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
389+
return ret;
390+
}
391+
drvdata->mi2s_was_prepared[dai->driver->id] = true;
392+
}
393+
return 0;
394+
}
395+
318396
const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
319397
.set_sysclk = lpass_cpu_daiops_set_sysclk,
320398
.startup = lpass_cpu_daiops_startup,
321399
.shutdown = lpass_cpu_daiops_shutdown,
322400
.hw_params = lpass_cpu_daiops_hw_params,
323401
.trigger = lpass_cpu_daiops_trigger,
402+
.prepare = lpass_cpu_daiops_prepare,
324403
};
325404
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
326405

sound/soc/qcom/lpass.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ struct lpass_data {
6767
/* MI2S SD lines to use for playback/capture */
6868
unsigned int mi2s_playback_sd_mode[LPASS_MAX_MI2S_PORTS];
6969
unsigned int mi2s_capture_sd_mode[LPASS_MAX_MI2S_PORTS];
70+
71+
/* The state of MI2S prepare dai_ops was called */
72+
bool mi2s_was_prepared[LPASS_MAX_MI2S_PORTS];
73+
7074
int hdmi_port_enable;
7175

7276
/* low-power audio interface (LPAIF) registers */

0 commit comments

Comments
 (0)