Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 148293
b: refs/heads/master
c: 6943c92
h: refs/heads/master
i:
  148291: e62fcc6
v: v3
  • Loading branch information
Peter Ujfalusi authored and Mark Brown committed May 20, 2009
1 parent ca02be7 commit fdbcd07
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 26 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4005d39a5f5549f1f6afe88abceed78b2ab225b6
refs/heads/master: 6943c92e87c4aa2a6d7a1f4dbd79cf4a0b5fd67b
116 changes: 91 additions & 25 deletions trunk/sound/soc/codecs/twl4030.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ struct twl4030_priv {
unsigned int rate;
unsigned int sample_bits;
unsigned int channels;

unsigned int sysclk;

/* Headset output state handling */
unsigned int hsl_enabled;
unsigned int hsr_enabled;
};

/*
Expand Down Expand Up @@ -564,39 +570,85 @@ static int handsfree_event(struct snd_soc_dapm_widget *w,
return 0;
}

static int headsetl_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
static void headset_ramp(struct snd_soc_codec *codec, int ramp)
{
unsigned char hs_gain, hs_pop;
struct twl4030_priv *twl4030 = codec->private_data;
/* Base values for ramp delay calculation: 2^19 - 2^26 */
unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
8388608, 16777216, 33554432, 67108864};

/* Save the current volume */
hs_gain = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_GAIN_SET);
hs_pop = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_POPN_SET);
hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET);
hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);

switch (event) {
case SND_SOC_DAPM_POST_PMU:
/* Do the anti-pop/bias ramp enable according to the TRM */
if (ramp) {
/* Headset ramp-up according to the TRM */
hs_pop |= TWL4030_VMID_EN;
twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
/* Is this needed? Can we just use whatever gain here? */
twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET,
(hs_gain & (~0x0f)) | 0x0a);
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hs_gain);
hs_pop |= TWL4030_RAMP_EN;
twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);

/* Restore the original volume */
twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET, hs_gain);
break;
case SND_SOC_DAPM_POST_PMD:
/* Do the anti-pop/bias ramp disable according to the TRM */
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
} else {
/* Headset ramp-down _not_ according to
* the TRM, but in a way that it is working */
hs_pop &= ~TWL4030_RAMP_EN;
twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
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);
/* Bypass the reg_cache to mute the headset */
twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
hs_gain & (~0x0f),
TWL4030_REG_HS_GAIN_SET);

hs_pop &= ~TWL4030_VMID_EN;
twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
}
}

static int headsetlpga_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct twl4030_priv *twl4030 = w->codec->private_data;

switch (event) {
case SND_SOC_DAPM_POST_PMU:
/* Do the ramp-up only once */
if (!twl4030->hsr_enabled)
headset_ramp(w->codec, 1);

twl4030->hsl_enabled = 1;
break;
case SND_SOC_DAPM_POST_PMD:
/* Do the ramp-down only if both headsetL/R is disabled */
if (!twl4030->hsr_enabled)
headset_ramp(w->codec, 0);

twl4030->hsl_enabled = 0;
break;
}
return 0;
}

static int headsetrpga_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct twl4030_priv *twl4030 = w->codec->private_data;

switch (event) {
case SND_SOC_DAPM_POST_PMU:
/* Do the ramp-up only once */
if (!twl4030->hsl_enabled)
headset_ramp(w->codec, 1);

twl4030->hsr_enabled = 1;
break;
case SND_SOC_DAPM_POST_PMD:
/* Do the ramp-down only if both headsetL/R is disabled */
if (!twl4030->hsl_enabled)
headset_ramp(w->codec, 0);

twl4030->hsr_enabled = 0;
break;
}
return 0;
Expand Down Expand Up @@ -1116,13 +1168,18 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
&twl4030_dapm_predriver_controls[0],
ARRAY_SIZE(twl4030_dapm_predriver_controls)),
/* HeadsetL/R */
SND_SOC_DAPM_MIXER_E("HeadsetL Mixer", SND_SOC_NOPM, 0, 0,
SND_SOC_DAPM_MIXER("HeadsetL Mixer", SND_SOC_NOPM, 0, 0,
&twl4030_dapm_hsol_controls[0],
ARRAY_SIZE(twl4030_dapm_hsol_controls), headsetl_event,
ARRAY_SIZE(twl4030_dapm_hsol_controls)),
SND_SOC_DAPM_PGA_E("HeadsetL PGA", SND_SOC_NOPM,
0, 0, NULL, 0, headsetlpga_event,
SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MIXER("HeadsetR Mixer", SND_SOC_NOPM, 0, 0,
&twl4030_dapm_hsor_controls[0],
ARRAY_SIZE(twl4030_dapm_hsor_controls)),
SND_SOC_DAPM_PGA_E("HeadsetR PGA", SND_SOC_NOPM,
0, 0, NULL, 0, headsetrpga_event,
SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
/* CarkitL/R */
SND_SOC_DAPM_MIXER("CarkitL Mixer", SND_SOC_NOPM, 0, 0,
&twl4030_dapm_carkitl_controls[0],
Expand Down Expand Up @@ -1227,10 +1284,12 @@ static const struct snd_soc_dapm_route intercon[] = {
{"HeadsetL Mixer", "Voice", "Analog Voice Playback Mixer"},
{"HeadsetL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
{"HeadsetL Mixer", "AudioL2", "Analog L2 Playback Mixer"},
{"HeadsetL PGA", NULL, "HeadsetL Mixer"},
/* HeadsetR */
{"HeadsetR Mixer", "Voice", "Analog Voice Playback Mixer"},
{"HeadsetR Mixer", "AudioR1", "Analog R1 Playback Mixer"},
{"HeadsetR Mixer", "AudioR2", "Analog R2 Playback Mixer"},
{"HeadsetR PGA", NULL, "HeadsetR Mixer"},
/* CarkitL */
{"CarkitL Mixer", "Voice", "Analog Voice Playback Mixer"},
{"CarkitL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
Expand Down Expand Up @@ -1261,8 +1320,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"EARPIECE", NULL, "Earpiece Mixer"},
{"PREDRIVEL", NULL, "PredriveL Mixer"},
{"PREDRIVER", NULL, "PredriveR Mixer"},
{"HSOL", NULL, "HeadsetL Mixer"},
{"HSOR", NULL, "HeadsetR Mixer"},
{"HSOL", NULL, "HeadsetL PGA"},
{"HSOR", NULL, "HeadsetR PGA"},
{"CARKITL", NULL, "CarkitL Mixer"},
{"CARKITR", NULL, "CarkitR Mixer"},
{"HFL", NULL, "HandsfreeL Mux"},
Expand Down Expand Up @@ -1601,17 +1660,21 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct twl4030_priv *twl4030 = codec->private_data;
u8 infreq;

switch (freq) {
case 19200000:
infreq = TWL4030_APLL_INFREQ_19200KHZ;
twl4030->sysclk = 19200;
break;
case 26000000:
infreq = TWL4030_APLL_INFREQ_26000KHZ;
twl4030->sysclk = 26000;
break;
case 38400000:
infreq = TWL4030_APLL_INFREQ_38400KHZ;
twl4030->sysclk = 38400;
break;
default:
printk(KERN_ERR "TWL4030 set sysclk: unknown rate %d\n",
Expand Down Expand Up @@ -2000,6 +2063,9 @@ static int twl4030_probe(struct platform_device *pdev)
kfree(codec);
return -ENOMEM;
}
/* Set default sysclk (used by the headsetl/rpga_event callback for
* pop-attenuation) */
twl4030->sysclk = 26000;

codec->private_data = twl4030;
socdev->card->codec = codec;
Expand Down

0 comments on commit fdbcd07

Please sign in to comment.