From: Mac Chiang mac.chiang@intel.com
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 --- .../devicetree/bindings/sound/max98357a.txt | 4 ++ sound/soc/codecs/max98357a.c | 50 ++++++++++++++++++---- 2 files changed, 45 insertions(+), 9 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/max98357a.txt b/Documentation/devicetree/bindings/sound/max98357a.txt index 28645a2..4bce14c 100644 --- a/Documentation/devicetree/bindings/sound/max98357a.txt +++ b/Documentation/devicetree/bindings/sound/max98357a.txt @@ -9,6 +9,10 @@ Optional properties: - sdmode-gpios : GPIO specifier for the chip's SD_MODE pin. If this option is not specified then driver does not manage the pin state (e.g. chip is always on). +- sdmode-delay : specify delay time for SD_MODE pin. + If this option is specified, which means it's required i2s clocks + ready before SD_MODE is unmuted in order to avoid the speaker pop noise. + It's observed that 5ms is sufficient.
Example:
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index d037a3e..2141fb4 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -27,24 +27,43 @@ #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 snd_soc_component *component = dai->component; + struct max98357a_priv *max98357a = snd_soc_component_get_drvdata(component);
- 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; }
@@ -61,19 +80,32 @@ static const struct snd_soc_dapm_route max98357a_dapm_routes[] = {
static int max98357a_component_probe(struct snd_soc_component *component) { - struct gpio_desc *sdmode; + struct max98357a_priv *max98357a = snd_soc_component_get_drvdata(component); + + max98357a->sdmode = devm_gpiod_get_optional(component->dev, + "sdmode", GPIOD_OUT_LOW);
- sdmode = devm_gpiod_get_optional(component->dev, "sdmode", GPIOD_OUT_LOW); - if (IS_ERR(sdmode)) - return PTR_ERR(sdmode); + if (IS_ERR(max98357a->sdmode)) + return PTR_ERR(max98357a->sdmode);
- snd_soc_component_set_drvdata(component, sdmode); + snd_soc_component_set_drvdata(component, max98357a); + + INIT_DELAYED_WORK(&max98357a->enable_sdmode_work, + max98357a_enable_sdmode_work);
return 0; }
+static void max98357a_component_remove(struct snd_soc_component *component) +{ + struct max98357a_priv *max98357a = snd_soc_component_get_drvdata(component); + + cancel_delayed_work_sync(&max98357a->enable_sdmode_work); +} + static const struct snd_soc_component_driver max98357a_component_driver = { .probe = max98357a_component_probe, + .remove = max98357a_component_remove, .dapm_widgets = max98357a_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(max98357a_dapm_widgets), .dapm_routes = max98357a_dapm_routes,