Skip to content

Commit

Permalink
ASoC: twl6040: Add digital mute support
Browse files Browse the repository at this point in the history
To reduce pop noise during playback stream start and stop the codec needs
to have the digital_mute callback implemented.
The codec need to be muted before the CPU dai has been stopped (McPDM).
Stopping the McPDM will generate a pop on the codec since no signal on the
PDM bus means full negative amplitude.
By managing the mute/unmute state of the outputs we can decrease the amount
of pop noise when playback starts or stops.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
  • Loading branch information
Peter Ujfalusi authored and Mark Brown committed Jun 24, 2013
1 parent 6889749 commit 98c5fb1
Showing 1 changed file with 90 additions and 1 deletion.
91 changes: 90 additions & 1 deletion sound/soc/codecs/twl6040.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ struct twl6040_data {
int pll_power_mode;
int hs_power_mode;
int hs_power_mode_locked;
bool dl1_unmuted;
bool dl2_unmuted;
unsigned int clk_in;
unsigned int sysclk;
struct twl6040_jack_data hs_jack;
Expand Down Expand Up @@ -228,6 +230,25 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
return value;
}

static bool twl6040_is_path_unmuted(struct snd_soc_codec *codec,
unsigned int reg)
{
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);

switch (reg) {
case TWL6040_REG_HSLCTL:
case TWL6040_REG_HSRCTL:
case TWL6040_REG_EARCTL:
/* DL1 path */
return priv->dl1_unmuted;
case TWL6040_REG_HFLCTL:
case TWL6040_REG_HFRCTL:
return priv->dl2_unmuted;
default:
return 1;
};
}

/*
* write to the twl6040 register space
*/
Expand All @@ -240,7 +261,8 @@ static int twl6040_write(struct snd_soc_codec *codec,
return -EIO;

twl6040_write_reg_cache(codec, reg, value);
if (likely(reg < TWL6040_REG_SW_SHADOW))
if (likely(reg < TWL6040_REG_SW_SHADOW) &&
twl6040_is_path_unmuted(codec, reg))
return twl6040_reg_write(twl6040, reg, value);
else
return 0;
Expand Down Expand Up @@ -1034,11 +1056,78 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
return 0;
}

static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id id,
int mute)
{
struct twl6040 *twl6040 = codec->control_data;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
int hslctl, hsrctl, earctl;
int hflctl, hfrctl;

switch (id) {
case TWL6040_DAI_DL1:
hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);
earctl = twl6040_read_reg_cache(codec, TWL6040_REG_EARCTL);

if (mute) {
/* Power down drivers and DACs */
earctl &= ~0x01;
hslctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA);
hsrctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA);

}

twl6040_reg_write(twl6040, TWL6040_REG_EARCTL, earctl);
twl6040_reg_write(twl6040, TWL6040_REG_HSLCTL, hslctl);
twl6040_reg_write(twl6040, TWL6040_REG_HSRCTL, hsrctl);
priv->dl1_unmuted = !mute;
break;
case TWL6040_DAI_DL2:
hflctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFLCTL);
hfrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFRCTL);

if (mute) {
/* Power down drivers and DACs */
hflctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA |
TWL6040_HFDRVENA);
hfrctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA |
TWL6040_HFDRVENA);
}

twl6040_reg_write(twl6040, TWL6040_REG_HFLCTL, hflctl);
twl6040_reg_write(twl6040, TWL6040_REG_HFRCTL, hfrctl);
priv->dl2_unmuted = !mute;
break;
default:
break;
};
}

static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute)
{
switch (dai->id) {
case TWL6040_DAI_LEGACY:
twl6040_mute_path(dai->codec, TWL6040_DAI_DL1, mute);
twl6040_mute_path(dai->codec, TWL6040_DAI_DL2, mute);
break;
case TWL6040_DAI_DL1:
case TWL6040_DAI_DL2:
twl6040_mute_path(dai->codec, dai->id, mute);
break;
default:
break;
}

return 0;
}

static const struct snd_soc_dai_ops twl6040_dai_ops = {
.startup = twl6040_startup,
.hw_params = twl6040_hw_params,
.prepare = twl6040_prepare,
.set_sysclk = twl6040_set_dai_sysclk,
.digital_mute = twl6040_digital_mute,
};

static struct snd_soc_dai_driver twl6040_dai[] = {
Expand Down

0 comments on commit 98c5fb1

Please sign in to comment.