[alsa-devel] [PATCH] ASoC: TWL4030: Add EXT_MUTE gpio to reduce pop-noise effect
Peter Ujfalusi
peter.ujfalusi at nokia.com
Thu Jun 25 10:03:38 CEST 2009
On Thursday 25 June 2009 05:25:33 ext Jorge Eduardo Candelaria wrote:
> According to TRM, an external FET controlled by a 1.8V output signal
> can be used to reduce the pop-noise heard when the audio amplifier is
> switched on.
As a note: the TRM suggests to use GPIO6 of TWL for the external FET control
(which is than can be controlled by the HS_POP_SET:EXTMUTE bit).
>
> The signal is controlled by a gpio pin and should be defined in the
> machine driver. However, the codec driver takes care of enabling and
> disabling this output during the headset pop attenuation sequence.
>
> If the board does not have an EXT_MUTE, then the machine driver should
> set the value of ext_mute_gpio to -EINVAL through ramp delay setup data,
> to bypass execution of the code that manages the gpio line.
The intention of the twl4030_setup_data is broader than that. It is true, that
currently it is only used for the Headset click removal.
>
> Also add a delay to let VMID settle in ramp up sequence.
Probably it is a good idea to add this delay. Without it there can be cases,
when the first samples would have been played while the VMID is ramping up,
making it a bit distorted (or weaker).
>
> Signed-off-by: Jorge Eduardo Candelaria <x0107209 at ti.com>
> ---
> sound/soc/codecs/twl4030.c | 23 +++++++++++++++++++++++
> sound/soc/codecs/twl4030.h | 1 +
> 2 files changed, 24 insertions(+), 0 deletions(-)
>
> diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
> index df42fa2..e850b30 100644
> --- a/sound/soc/codecs/twl4030.c
> +++ b/sound/soc/codecs/twl4030.c
> @@ -27,6 +27,7 @@
> #include <linux/i2c.h>
> #include <linux/platform_device.h>
> #include <linux/i2c/twl4030.h>
> +#include <linux/gpio.h>
> #include <sound/core.h>
> #include <sound/pcm.h>
> #include <sound/pcm_params.h>
> @@ -620,6 +621,9 @@ static int handsfreerpga_event(struct
> snd_soc_dapm_widget *w,
>
> static void headset_ramp(struct snd_soc_codec *codec, int ramp)
> {
> + struct snd_soc_device *socdev = codec->socdev;
> + struct twl4030_setup_data *setup = socdev->codec_data;
> +
> unsigned char hs_gain, hs_pop;
> struct twl4030_priv *twl4030 = codec->private_data;
> /* Base values for ramp delay calculation: 2^19 - 2^26 */
> @@ -629,6 +633,11 @@ static void headset_ramp(struct snd_soc_codec *codec,
> int ramp) hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET);
> hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
>
> + /* Enable external mute, this dramatically reduces
> + * the pop-noise */
> + if (setup && gpio_is_valid(setup->ext_mute_gpio))
> + gpio_set_value(setup->ext_mute_gpio, 1);
> +
> if (ramp) {
> /* Headset ramp-up according to the TRM */
> hs_pop |= TWL4030_VMID_EN;
> @@ -636,6 +645,9 @@ static void headset_ramp(struct snd_soc_codec *codec,
> int ramp) twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hs_gain);
> hs_pop |= TWL4030_RAMP_EN;
> twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
> + /* Wait ramp delay time + 1, so the VMID can settle */
> + mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
> + twl4030->sysclk) + 1);
> } else {
> /* Headset ramp-down _not_ according to
> * the TRM, but in a way that it is working */
> @@ -652,6 +664,10 @@ static void headset_ramp(struct snd_soc_codec *codec,
> int ramp) hs_pop &= ~TWL4030_VMID_EN;
> twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
> }
> +
> + /* Disable external mute */
> + if (setup && gpio_is_valid(setup->ext_mute_gpio))
> + gpio_set_value(setup->ext_mute_gpio, 0);
> }
>
> static int headsetlpga_event(struct snd_soc_dapm_widget *w,
> @@ -2101,6 +2117,7 @@ static int twl4030_init(struct snd_soc_device
> *socdev) /* Configuration for headset ramp delay from setup data */
> if (setup) {
> unsigned char hs_pop;
> + unsigned int ext_mute;
>
> if (setup->sysclk)
> twl4030->sysclk = setup->sysclk;
> @@ -2111,6 +2128,12 @@ static int twl4030_init(struct snd_soc_device
> *socdev) hs_pop &= ~TWL4030_RAMP_DELAY;
> hs_pop |= (setup->ramp_delay_value << 2);
> twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
> +
> + if (gpio_is_valid(setup->ext_mute_gpio)) {
> + ext_mute = setup->ext_mute_gpio;
> + BUG_ON(gpio_request(ext_mute, "ext_mute") < 0);
Releasing the gpio?
> + gpio_direction_output(ext_mute, 0);
> + }
> } else {
> twl4030->sysclk = 26000;
> }
> diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
> index fe5f395..23a75e2 100644
> --- a/sound/soc/codecs/twl4030.h
> +++ b/sound/soc/codecs/twl4030.h
> @@ -274,6 +274,7 @@ extern struct snd_soc_codec_device
> soc_codec_dev_twl4030; struct twl4030_setup_data {
> unsigned int ramp_delay_value;
> unsigned int sysclk;
> + unsigned int ext_mute_gpio;
> };
>
> #endif /* End of __TWL4030_AUDIO_H__ */
I think the HS ext mute should be handled in a different way:
There should be a way to use also the HS_POP_SET:EXTMUTE (TWL GPIO6) or
external gpio for the extmute.
In order to use the TWL GPIO6 for extmute, the PMBR1:GPIO6_PWM0_MUTE should be
set to 0x2 initially in TWL, but this is not the job of the codec driver (it
is platform specific how this pin is used).
Anyways, I think the correct approach should be something like this:
In twl4030.h:
struct twl4030_setup_data {
unsigned int ramp_delay_value;
unsigned int sysclk;
+ unsigned int hs_extmute:1;
+ void (*set_hs_extmute)(int mute);
};
Than in the machine driver:
a) No extmute possible
Just don't set any of these new hs_extmute things.
b) extmute is used through TWL GPIO6
Set the hs_extmute to 1
Set the set_hs_extmute to NULL
c) extmute is used through some other ways
Set the hs_extmute to 1
Request the gpio (or whatever you need to control the extmute), also take care
of the cleanup.
Implement the something like this:
void zoom2_hs_extmute(int mute) {
gpio_set_value(GPIO_NUMBER, mute)
}
Set the set_hs_extmute to zoom2_hs_extmute
than in the codec driver:
If the hs_extmute is 0, than do nothing about the extmute,
If only the hs_extmute is set, than set/clear the HS_POP_SET:EXTMUTE bit
if both hs_extmute and set_hs_extmute are set, than call the set_hs_extmute
function.
What do you think?
--
Péter
More information about the Alsa-devel
mailing list