Skip to content

Commit

Permalink
ASoC: TWL4030: Add digital loopback support
Browse files Browse the repository at this point in the history
This patch adds the digital loopback/bypass support for twl4030 codec.

The digital loopback will let the digimic0 (routed in the TX1 capture path
inside of TWL4030) data to be routed back to the RX2 playback path
(I2S stereo). It can also route the analog capture date routed through the
TX1 back to RX2.

Effectively the digital loopback is routing the audio from the TX1 capture path
to the RX2 playback path.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
  • Loading branch information
Peter Ujfalusi authored and Mark Brown committed Feb 18, 2009
1 parent 93b760b commit 6bab83f
Showing 1 changed file with 50 additions and 6 deletions.
56 changes: 50 additions & 6 deletions sound/soc/codecs/twl4030.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,25 @@ static const struct snd_kcontrol_new twl4030_dapm_abypassr2_control =
static const struct snd_kcontrol_new twl4030_dapm_abypassl2_control =
SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXL2_APGA_CTL, 2, 1, 0);

/* Digital bypass gain, 0 mutes the bypass */
static const unsigned int twl4030_dapm_dbypass_tlv[] = {
TLV_DB_RANGE_HEAD(2),
0, 3, TLV_DB_SCALE_ITEM(-2400, 0, 1),
4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0),
};

/* Digital bypass left (TX1L -> RX2L) */
static const struct snd_kcontrol_new twl4030_dapm_dbypassl_control =
SOC_DAPM_SINGLE_TLV("Volume",
TWL4030_REG_ATX2ARXPGA, 3, 7, 0,
twl4030_dapm_dbypass_tlv);

/* Digital bypass right (TX1R -> RX2R) */
static const struct snd_kcontrol_new twl4030_dapm_dbypassr_control =
SOC_DAPM_SINGLE_TLV("Volume",
TWL4030_REG_ATX2ARXPGA, 0, 7, 0,
twl4030_dapm_dbypass_tlv);

static int micpath_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
Expand Down Expand Up @@ -608,12 +627,22 @@ static int bypass_event(struct snd_soc_dapm_widget *w,
unsigned char reg;

reg = twl4030_read_reg_cache(w->codec, m->reg);
if (reg & (1 << m->shift))
twl4030->bypass_state |=
(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
else
twl4030->bypass_state &=
~(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));

if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) {
/* Analog bypass */
if (reg & (1 << m->shift))
twl4030->bypass_state |=
(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
else
twl4030->bypass_state &=
~(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
} else {
/* Digital bypass */
if (reg & (0x7 << m->shift))
twl4030->bypass_state |= (1 << (m->shift ? 5 : 4));
else
twl4030->bypass_state &= ~(1 << (m->shift ? 5 : 4));
}

if (w->codec->bias_level == SND_SOC_BIAS_STANDBY) {
if (twl4030->bypass_state)
Expand Down Expand Up @@ -934,6 +963,14 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
&twl4030_dapm_abypassl2_control,
bypass_event, SND_SOC_DAPM_POST_REG),

/* Digital bypasses */
SND_SOC_DAPM_SWITCH_E("Left Digital Loopback", SND_SOC_NOPM, 0, 0,
&twl4030_dapm_dbypassl_control, bypass_event,
SND_SOC_DAPM_POST_REG),
SND_SOC_DAPM_SWITCH_E("Right Digital Loopback", SND_SOC_NOPM, 0, 0,
&twl4030_dapm_dbypassr_control, bypass_event,
SND_SOC_DAPM_POST_REG),

SND_SOC_DAPM_MIXER("Analog R1 Playback Mixer", TWL4030_REG_AVDAC_CTL,
0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("Analog L1 Playback Mixer", TWL4030_REG_AVDAC_CTL,
Expand Down Expand Up @@ -1118,6 +1155,13 @@ static const struct snd_soc_dapm_route intercon[] = {
{"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"},
{"Analog L2 Playback Mixer", NULL, "Left2 Analog Loopback"},

/* Digital bypass routes */
{"Right Digital Loopback", "Volume", "TX1 Capture Route"},
{"Left Digital Loopback", "Volume", "TX1 Capture Route"},

{"Analog R2 Playback Mixer", NULL, "Right Digital Loopback"},
{"Analog L2 Playback Mixer", NULL, "Left Digital Loopback"},

};

static int twl4030_add_widgets(struct snd_soc_codec *codec)
Expand Down

0 comments on commit 6bab83f

Please sign in to comment.