summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
authorMac Chiang <mac.chiang@intel.com>2019-06-19 13:18:33 +0300
committerMark Brown <broonie@kernel.org>2019-07-02 17:53:38 +0300
commitcec5b01f8f1c6064037f3181e7690e3765ed995b (patch)
tree949b286a836edef11b1abb61976680a2bcbf94de /sound/soc
parent4b9b73b86571e8a03fb09232ff72177e66bf9ef9 (diff)
downloadlinux-cec5b01f8f1c6064037f3181e7690e3765ed995b.tar.xz
ASoC: max98357a: avoid speaker pop when playback startup
Loud speaker pop happens during playback even when in slience playback. Specify Max98357a amp delay times to make sure clocks are always earlier than sdmode on. Signed-off-by: Mac Chiang <mac.chiang@intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/max98357a.c55
1 files changed, 46 insertions, 9 deletions
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
index 6f724c9a3867..6f0e28f903bf 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -19,24 +19,42 @@
#include <sound/soc-dai.h>
#include <sound/soc-dapm.h>
+struct max98357a_priv {
+ struct delayed_work enable_sdmode_work;
+ struct gpio_desc *sdmode;
+ unsigned int sdmode_delay;
+};
+
+static void max98357a_enable_sdmode_work(struct work_struct *work)
+{
+ struct max98357a_priv *max98357a =
+ container_of(work, struct max98357a_priv,
+ enable_sdmode_work.work);
+
+ gpiod_set_value(max98357a->sdmode, 1);
+}
+
static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
- struct gpio_desc *sdmode = snd_soc_dai_get_drvdata(dai);
+ struct max98357a_priv *max98357a = snd_soc_dai_get_drvdata(dai);
- if (!sdmode)
+ if (!max98357a->sdmode)
return 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- gpiod_set_value(sdmode, 1);
+ queue_delayed_work(system_power_efficient_wq,
+ &max98357a->enable_sdmode_work,
+ msecs_to_jiffies(max98357a->sdmode_delay));
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- gpiod_set_value(sdmode, 0);
+ cancel_delayed_work_sync(&max98357a->enable_sdmode_work);
+ gpiod_set_value(max98357a->sdmode, 0);
break;
}
@@ -90,14 +108,33 @@ static struct snd_soc_dai_driver max98357a_dai_driver = {
static int max98357a_platform_probe(struct platform_device *pdev)
{
- struct gpio_desc *sdmode;
+ struct max98357a_priv *max98357a;
+ int ret;
- sdmode = devm_gpiod_get_optional(&pdev->dev,
+ max98357a = devm_kzalloc(&pdev->dev, sizeof(*max98357a), GFP_KERNEL);
+
+ if (!max98357a)
+ return -ENOMEM;
+
+ max98357a->sdmode = devm_gpiod_get_optional(&pdev->dev,
"sdmode", GPIOD_OUT_LOW);
- if (IS_ERR(sdmode))
- return PTR_ERR(sdmode);
- dev_set_drvdata(&pdev->dev, sdmode);
+ if (IS_ERR(max98357a->sdmode))
+ return PTR_ERR(max98357a->sdmode);
+
+ ret = device_property_read_u32(&pdev->dev, "sdmode-delay",
+ &max98357a->sdmode_delay);
+
+ if (ret) {
+ max98357a->sdmode_delay = 0;
+ dev_dbg(&pdev->dev,
+ "no optional property 'sdmode-delay' found, default: no delay\n");
+ }
+
+ dev_set_drvdata(&pdev->dev, max98357a);
+
+ INIT_DELAYED_WORK(&max98357a->enable_sdmode_work,
+ max98357a_enable_sdmode_work);
return devm_snd_soc_register_component(&pdev->dev,
&max98357a_component_driver,