From 664f9a4c0e43006020295cfd9206f1e561578e82 Mon Sep 17 00:00:00 2001 From: Shyam Krishnan M Date: Thu, 16 Jun 2011 16:40:40 +0530 Subject: Ux500 ASoC:DistortionNoise fix for underrun AB5500 Underrun happens due to system load. This causes the msp and dma to start the channel again and again. The fix prevents the call to start the channel once it is started alredy.The fix also increases the start threshold of the buffer list so that the duration after which the usecase hits underrun is improved. ST-Ericsson Linux next: Not tested, ER 344102 ST-Ericsson ID: 344102 ST-Ericsson FOSS-OUT ID: STETL-FOSS-OUT-10006 Change-Id: I992f83efbf8f48ff652e4c164356eb2e75fd3ac0 Signed-off-by: Shyam Krishnan M Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/25261 Tested-by: Hemanth P SETHURAM Reviewed-by: QATOOLS Reviewed-by: QATEST Reviewed-by: Srinidhi KASAGAR --- sound/soc/codecs/ab3550.c | 3 +- sound/soc/codecs/ab5500.c | 63 ++++++++++++++++++++++++++++------------- sound/soc/ux500/ux500_msp_dai.c | 6 ++-- sound/soc/ux500/ux500_pcm.c | 8 ++++-- 4 files changed, 55 insertions(+), 25 deletions(-) diff --git a/sound/soc/codecs/ab3550.c b/sound/soc/codecs/ab3550.c index c2251c6b7d6..4a15ab64d32 100644 --- a/sound/soc/codecs/ab3550.c +++ b/sound/soc/codecs/ab3550.c @@ -680,9 +680,9 @@ static void power_widget_unlocked(enum enum_power onoff, unsigned long i; unsigned long *srcs = widget_pm_array[w].source_list; unsigned long *sinks = widget_pm_array[w].sink_list; - dev_dbg(ab3550_dev, "%s: processing widget %s.\n", __func__, widget_names[w]); + if (onoff == POWER_ON && !bitmap_empty(srcs, number_of_widgets) && !has_powered_neighbors(srcs)) { @@ -877,6 +877,7 @@ static void power_for_playback(enum enum_power onoff, int ifsel) { dev_dbg(ab3550_dev, "%s: interface %d power %s.\n", __func__, ifsel, onoff == POWER_ON ? "on" : "off"); + if (mutex_lock_interruptible(&ab3550_pm_mutex)) { dev_warn(ab3550_dev, "%s: Signal received while waiting on the PM mutex.\n", diff --git a/sound/soc/codecs/ab5500.c b/sound/soc/codecs/ab5500.c index 52c56c13631..1875db4fc77 100644 --- a/sound/soc/codecs/ab5500.c +++ b/sound/soc/codecs/ab5500.c @@ -34,8 +34,14 @@ #include #include "ab5500.h" +/* No of digital interface on the Codec */ +#define NO_CODEC_DAI_IF 2 + /* codec private data */ struct ab5500_codec_dai_data { + bool playback_active; + bool capture_active; + }; static struct device *ab5500_dev; @@ -85,8 +91,11 @@ static void mask_set_reg(u8 reg, u8 mask, u8 val) case AB5500_VIRTUAL_REG3: if ((diff & (1 << SPKR1_PWR_SHIFT))) { if ((val & (1 << SPKR1_PWR_SHIFT)) == 0) { - /* If the new value has PWR_SHIFT disabled, set the - * PWR_MASK to 0 */ + /* + * If the new value has PWR_SHIFT + * disabled, set the + * PWR_MASK to 0 + */ mask_set_reg(SPKR1, SPKRx_PWR_MASK, 0); } else { @@ -109,8 +118,11 @@ static void mask_set_reg(u8 reg, u8 mask, u8 val) } if ((diff & (1 << SPKR2_PWR_SHIFT))) { if ((val & (1 << SPKR2_PWR_SHIFT)) == 0) { - /* If the new value has PWR_SHIFT disabled, set the - * PWR_MASK to 0 */ + /* + * If the new value has PWR_SHIFT + * disabled, set the + * PWR_MASK to 0 + */ mask_set_reg(SPKR2, SPKRx_PWR_MASK, 0); } else { @@ -374,11 +386,15 @@ static const struct snd_soc_dapm_route intercon[] = { }; -struct codec_dai_private { - unsigned active_flags; -} privates[] = { - {0}, - {0} +struct ab5500_codec_dai_data ab5500_codec_privates[NO_CODEC_DAI_IF] = { + { + .playback_active = false, + .capture_active = false, + }, + { + .playback_active = false, + .capture_active = false, + } }; static const char *enum_rx_input_select[] = { @@ -882,9 +898,9 @@ static void power_widget_unlocked(enum enum_power onoff, enum enum_widget widget unsigned long i; unsigned long *srcs = widget_pm_array[w].source_list; unsigned long *sinks = widget_pm_array[w].sink_list; - - dev_info(ab5500_dev, "%s: processing widget %s.\n", + dev_dbg(ab5500_dev, "%s: processing widget %s.\n", __func__, widget_names[w]); + if (onoff == POWER_ON && !bitmap_empty(srcs, number_of_widgets) && !has_powered_neighbors(srcs)) { @@ -916,10 +932,9 @@ static void power_widget_unlocked(enum enum_power onoff, enum enum_widget widget mask_set_reg(widget_pm_array[w].reg, 1 << widget_pm_array[w].shift, onoff == POWER_ON ? 0xff : 0); - dev_info(ab5500_dev, "%s: widget %s powered %s.\n", + dev_dbg(ab5500_dev, "%s: widget %s powered %s.\n", __func__, widget_names[w], onoff == POWER_ON ? "on" : "off"); - if (onoff == POWER_ON && !bitmap_empty(sinks, number_of_widgets) && !has_powered_neighbors(sinks) && @@ -968,7 +983,7 @@ static void dump_registers(const char *where, ...) short reg = va_arg(ap, int); if (reg < 0) break; - dev_info(ab5500_dev, "%s from %s> 0x%02X : 0x%02X.\n", + dev_dbg(ab5500_dev, "%s from %s> 0x%02X : 0x%02X.\n", __func__, where, reg, read_reg(reg)); } while (1); va_end(ap); @@ -1080,7 +1095,7 @@ static int ab5500_add_widgets(struct snd_soc_codec *codec) static void power_for_playback(enum enum_power onoff, int ifsel) { - dev_info(ab5500_dev, "%s: interface %d power %s.\n", __func__, + dev_dbg(ab5500_dev, "%s: interface %d power %s.\n", __func__, ifsel, onoff == POWER_ON ? "on" : "off"); if (mutex_lock_interruptible(&ab5500_pm_mutex)) { dev_warn(ab5500_dev, @@ -1186,14 +1201,19 @@ static int ab5500_pcm_hw_params(struct snd_pcm_substream *substream, static int ab5500_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - dev_info(ab5500_dev, "%s called.\n", __func__); - + dev_dbg(ab5500_dev, "%s called.\n", __func__); /* Configure registers for either playback or capture */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) && + !(ab5500_codec_privates[dai->id].playback_active == true)) { power_for_playback(POWER_ON, dai->id); - else + ab5500_codec_privates[dai->id].playback_active = true; + } else if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) && + !(ab5500_codec_privates[dai->id].capture_active == true)) { power_for_capture(POWER_ON, dai->id); - dump_registers(__func__, RX1, AUXO1_ADDER, RX2, AUXO2_ADDER, RX1_DPGA, RX2_DPGA, AUXO1, AUXO2, -1); + ab5500_codec_privates[dai->id].capture_active = true; + } + dump_registers(__func__, RX1, AUXO1_ADDER, RX2, + AUXO2_ADDER, RX1_DPGA, RX2_DPGA, AUXO1, AUXO2, -1); return 0; } @@ -1204,8 +1224,11 @@ static void ab5500_pcm_shutdown(struct snd_pcm_substream *substream, dev_info(ab5500_dev, "%s called.\n", __func__); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { power_for_playback(POWER_OFF, dai->id); + ab5500_codec_privates[dai->id].playback_active = false; } else { power_for_capture(POWER_OFF, dai->id); + ab5500_codec_privates[dai->id].capture_active = false; + } if (!dai->playback_active && !dai->capture_active && (read_reg(iface) & I2Sx_MODE_MASK) == 0) diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 4558ea61f72..53f3982343b 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -536,10 +536,12 @@ static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream, /* If already configured -> not errors reported */ if (mode_playback) { - if (drvdata->configured & PLAYBACK_CONFIGURED) + if ((drvdata->configured & PLAYBACK_CONFIGURED) && + (drvdata->playback_active)) goto cleanup; } else { - if (drvdata->configured & CAPTURE_CONFIGURED) + if ((drvdata->configured & CAPTURE_CONFIGURED) && + (drvdata->capture_active)) goto cleanup; } diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index a0fa9723e4c..ee953f1b5e5 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c @@ -242,7 +242,6 @@ static int ux500_pcm_hw_free(struct snd_pcm_substream *substream) static int ux500_pcm_prepare(struct snd_pcm_substream *substream) { pr_debug("%s: Enter\n", __func__); - return 0; } @@ -258,6 +257,12 @@ static int ux500_pcm_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + pr_debug("%s: START/PAUSE-RELEASE\n", __func__); + if (runtime->status->state == SNDRV_PCM_STATE_XRUN) { + pr_debug("XRUN occurred\n"); + return 0; + } + private->no_of_underruns = 0; private->offset = 0; ret = ux500_msp_dai_i2s_configure_sg(runtime->dma_addr, @@ -305,7 +310,6 @@ static int ux500_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { struct snd_pcm_runtime *runtime = substream->runtime; - pr_debug("%s: Enter.\n", __func__); return dma_mmap_coherent( -- cgit v1.2.3