Commit 89cdb224 authored by Zhu Ning's avatar Zhu Ning Committed by Mark Brown

ASoC: sof_es8336: reduce pop noise on speaker

The Speaker GPIO needs to be turned on slightly behind the codec turned on.
It also need to be turned off slightly before the codec turned down.
Current code uses delay in DAPM_EVENT to do it but the mdelay delays the
DAPM itself and thus has no effect. A delayed_work is added to turn on the
speaker.
The Speaker is turned off in .trigger since trigger is called slightly
before the DAPM events.
Signed-off-by: default avatarZhu Ning <zhuning@everest-semi.com>

------------

v1: cancel delayed work while disabling speaker.
Link: https://lore.kernel.org/r/20221028020456.90286-1-zhuning0077@gmail.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 3d59eaef
...@@ -63,6 +63,7 @@ struct sof_es8336_private { ...@@ -63,6 +63,7 @@ struct sof_es8336_private {
struct snd_soc_jack jack; struct snd_soc_jack jack;
struct list_head hdmi_pcm_list; struct list_head hdmi_pcm_list;
bool speaker_en; bool speaker_en;
struct delayed_work pcm_pop_work;
}; };
struct sof_hdmi_pcm { struct sof_hdmi_pcm {
...@@ -111,6 +112,46 @@ static void log_quirks(struct device *dev) ...@@ -111,6 +112,46 @@ static void log_quirks(struct device *dev)
dev_info(dev, "quirk headset at mic1 port enabled\n"); dev_info(dev, "quirk headset at mic1 port enabled\n");
} }
static void pcm_pop_work_events(struct work_struct *work)
{
struct sof_es8336_private *priv =
container_of(work, struct sof_es8336_private, pcm_pop_work.work);
gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_en);
if (quirk & SOF_ES8336_HEADPHONE_GPIO)
gpiod_set_value_cansleep(priv->gpio_headphone, priv->speaker_en);
}
static int sof_8336_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
if (priv->speaker_en == false)
if (substream->stream == 0) {
cancel_delayed_work(&priv->pcm_pop_work);
gpiod_set_value_cansleep(priv->gpio_speakers, true);
}
break;
default:
return -EINVAL;
}
return 0;
}
static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) struct snd_kcontrol *kcontrol, int event)
{ {
...@@ -122,19 +163,7 @@ static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, ...@@ -122,19 +163,7 @@ static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w,
priv->speaker_en = !SND_SOC_DAPM_EVENT_ON(event); priv->speaker_en = !SND_SOC_DAPM_EVENT_ON(event);
if (SND_SOC_DAPM_EVENT_ON(event)) queue_delayed_work(system_wq, &priv->pcm_pop_work, msecs_to_jiffies(70));
msleep(70);
gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_en);
if (!(quirk & SOF_ES8336_HEADPHONE_GPIO))
return 0;
if (SND_SOC_DAPM_EVENT_ON(event))
msleep(70);
gpiod_set_value_cansleep(priv->gpio_headphone, priv->speaker_en);
return 0; return 0;
} }
...@@ -344,6 +373,7 @@ static int sof_es8336_hw_params(struct snd_pcm_substream *substream, ...@@ -344,6 +373,7 @@ static int sof_es8336_hw_params(struct snd_pcm_substream *substream,
/* machine stream operations */ /* machine stream operations */
static struct snd_soc_ops sof_es8336_ops = { static struct snd_soc_ops sof_es8336_ops = {
.hw_params = sof_es8336_hw_params, .hw_params = sof_es8336_hw_params,
.trigger = sof_8336_trigger,
}; };
static struct snd_soc_dai_link_component platform_component[] = { static struct snd_soc_dai_link_component platform_component[] = {
...@@ -723,7 +753,8 @@ static int sof_es8336_probe(struct platform_device *pdev) ...@@ -723,7 +753,8 @@ static int sof_es8336_probe(struct platform_device *pdev)
} }
INIT_LIST_HEAD(&priv->hdmi_pcm_list); INIT_LIST_HEAD(&priv->hdmi_pcm_list);
INIT_DELAYED_WORK(&priv->pcm_pop_work,
pcm_pop_work_events);
snd_soc_card_set_drvdata(card, priv); snd_soc_card_set_drvdata(card, priv);
if (mach->mach_params.dmic_num > 0) { if (mach->mach_params.dmic_num > 0) {
...@@ -752,6 +783,7 @@ static int sof_es8336_remove(struct platform_device *pdev) ...@@ -752,6 +783,7 @@ static int sof_es8336_remove(struct platform_device *pdev)
struct snd_soc_card *card = platform_get_drvdata(pdev); struct snd_soc_card *card = platform_get_drvdata(pdev);
struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
cancel_delayed_work(&priv->pcm_pop_work);
gpiod_put(priv->gpio_speakers); gpiod_put(priv->gpio_speakers);
device_remove_software_node(priv->codec_dev); device_remove_software_node(priv->codec_dev);
put_device(priv->codec_dev); put_device(priv->codec_dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment