ASoC: TWL4030: Add digital loopback support
authorPeter Ujfalusi <peter.ujfalusi@nokia.com>
Wed, 18 Feb 2009 12:39:05 +0000 (14:39 +0200)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 18 Feb 2009 17:14:23 +0000 (17:14 +0000)
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>
sound/soc/codecs/twl4030.c

index c26854b398d389202cfa5c89629e5370292e9a09..535d8ce2c3287ef5b6eb19e4c4a6ee3f4d311815 100644 (file)
@@ -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)
 {
@@ -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)
@@ -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,
@@ -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)