aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/twl4030.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/twl4030.c')
-rw-r--r--sound/soc/codecs/twl4030.c128
1 files changed, 30 insertions, 98 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 5c5a4c0a424f..24002269f03a 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -122,7 +122,6 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
122struct twl4030_priv { 122struct twl4030_priv {
123 struct snd_soc_codec codec; 123 struct snd_soc_codec codec;
124 124
125 unsigned int bypass_state;
126 unsigned int codec_powered; 125 unsigned int codec_powered;
127 unsigned int codec_muted; 126 unsigned int codec_muted;
128 127
@@ -725,67 +724,6 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w,
725 return 0; 724 return 0;
726} 725}
727 726
728static int bypass_event(struct snd_soc_dapm_widget *w,
729 struct snd_kcontrol *kcontrol, int event)
730{
731 struct soc_mixer_control *m =
732 (struct soc_mixer_control *)w->kcontrols->private_value;
733 struct twl4030_priv *twl4030 = w->codec->private_data;
734 unsigned char reg, misc;
735
736 reg = twl4030_read_reg_cache(w->codec, m->reg);
737
738 /*
739 * bypass_state[0:3] - analog HiFi bypass
740 * bypass_state[4] - analog voice bypass
741 * bypass_state[5] - digital voice bypass
742 * bypass_state[6:7] - digital HiFi bypass
743 */
744 if (m->reg == TWL4030_REG_VSTPGA) {
745 /* Voice digital bypass */
746 if (reg)
747 twl4030->bypass_state |= (1 << 5);
748 else
749 twl4030->bypass_state &= ~(1 << 5);
750 } else if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) {
751 /* Analog bypass */
752 if (reg & (1 << m->shift))
753 twl4030->bypass_state |=
754 (1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
755 else
756 twl4030->bypass_state &=
757 ~(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
758 } else if (m->reg == TWL4030_REG_VDL_APGA_CTL) {
759 /* Analog voice bypass */
760 if (reg & (1 << m->shift))
761 twl4030->bypass_state |= (1 << 4);
762 else
763 twl4030->bypass_state &= ~(1 << 4);
764 } else {
765 /* Digital bypass */
766 if (reg & (0x7 << m->shift))
767 twl4030->bypass_state |= (1 << (m->shift ? 7 : 6));
768 else
769 twl4030->bypass_state &= ~(1 << (m->shift ? 7 : 6));
770 }
771
772 /* Enable master analog loopback mode if any analog switch is enabled*/
773 misc = twl4030_read_reg_cache(w->codec, TWL4030_REG_MISC_SET_1);
774 if (twl4030->bypass_state & 0x1F)
775 misc |= TWL4030_FMLOOP_EN;
776 else
777 misc &= ~TWL4030_FMLOOP_EN;
778 twl4030_write(w->codec, TWL4030_REG_MISC_SET_1, misc);
779
780 if (w->codec->bias_level == SND_SOC_BIAS_STANDBY) {
781 if (twl4030->bypass_state)
782 twl4030_codec_mute(w->codec, 0);
783 else
784 twl4030_codec_mute(w->codec, 1);
785 }
786 return 0;
787}
788
789/* 727/*
790 * Some of the gain controls in TWL (mostly those which are associated with 728 * Some of the gain controls in TWL (mostly those which are associated with
791 * the outputs) are implemented in an interesting way: 729 * the outputs) are implemented in an interesting way:
@@ -1193,32 +1131,28 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
1193 SND_SOC_NOPM, 0, 0), 1131 SND_SOC_NOPM, 0, 0),
1194 1132
1195 /* Analog bypasses */ 1133 /* Analog bypasses */
1196 SND_SOC_DAPM_SWITCH_E("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0, 1134 SND_SOC_DAPM_SWITCH("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0,
1197 &twl4030_dapm_abypassr1_control, bypass_event, 1135 &twl4030_dapm_abypassr1_control),
1198 SND_SOC_DAPM_POST_REG), 1136 SND_SOC_DAPM_SWITCH("Left1 Analog Loopback", SND_SOC_NOPM, 0, 0,
1199 SND_SOC_DAPM_SWITCH_E("Left1 Analog Loopback", SND_SOC_NOPM, 0, 0, 1137 &twl4030_dapm_abypassl1_control),
1200 &twl4030_dapm_abypassl1_control, 1138 SND_SOC_DAPM_SWITCH("Right2 Analog Loopback", SND_SOC_NOPM, 0, 0,
1201 bypass_event, SND_SOC_DAPM_POST_REG), 1139 &twl4030_dapm_abypassr2_control),
1202 SND_SOC_DAPM_SWITCH_E("Right2 Analog Loopback", SND_SOC_NOPM, 0, 0, 1140 SND_SOC_DAPM_SWITCH("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0,
1203 &twl4030_dapm_abypassr2_control, 1141 &twl4030_dapm_abypassl2_control),
1204 bypass_event, SND_SOC_DAPM_POST_REG), 1142 SND_SOC_DAPM_SWITCH("Voice Analog Loopback", SND_SOC_NOPM, 0, 0,
1205 SND_SOC_DAPM_SWITCH_E("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0, 1143 &twl4030_dapm_abypassv_control),
1206 &twl4030_dapm_abypassl2_control, 1144
1207 bypass_event, SND_SOC_DAPM_POST_REG), 1145 /* Master analog loopback switch */
1208 SND_SOC_DAPM_SWITCH_E("Voice Analog Loopback", SND_SOC_NOPM, 0, 0, 1146 SND_SOC_DAPM_SUPPLY("FM Loop Enable", TWL4030_REG_MISC_SET_1, 5, 0,
1209 &twl4030_dapm_abypassv_control, 1147 NULL, 0),
1210 bypass_event, SND_SOC_DAPM_POST_REG),
1211 1148
1212 /* Digital bypasses */ 1149 /* Digital bypasses */
1213 SND_SOC_DAPM_SWITCH_E("Left Digital Loopback", SND_SOC_NOPM, 0, 0, 1150 SND_SOC_DAPM_SWITCH("Left Digital Loopback", SND_SOC_NOPM, 0, 0,
1214 &twl4030_dapm_dbypassl_control, bypass_event, 1151 &twl4030_dapm_dbypassl_control),
1215 SND_SOC_DAPM_POST_REG), 1152 SND_SOC_DAPM_SWITCH("Right Digital Loopback", SND_SOC_NOPM, 0, 0,
1216 SND_SOC_DAPM_SWITCH_E("Right Digital Loopback", SND_SOC_NOPM, 0, 0, 1153 &twl4030_dapm_dbypassr_control),
1217 &twl4030_dapm_dbypassr_control, bypass_event, 1154 SND_SOC_DAPM_SWITCH("Voice Digital Loopback", SND_SOC_NOPM, 0, 0,
1218 SND_SOC_DAPM_POST_REG), 1155 &twl4030_dapm_dbypassv_control),
1219 SND_SOC_DAPM_SWITCH_E("Voice Digital Loopback", SND_SOC_NOPM, 0, 0,
1220 &twl4030_dapm_dbypassv_control, bypass_event,
1221 SND_SOC_DAPM_POST_REG),
1222 1156
1223 /* Digital mixers, power control for the physical DACs */ 1157 /* Digital mixers, power control for the physical DACs */
1224 SND_SOC_DAPM_MIXER("Digital R1 Playback Mixer", 1158 SND_SOC_DAPM_MIXER("Digital R1 Playback Mixer",
@@ -1490,6 +1424,13 @@ static const struct snd_soc_dapm_route intercon[] = {
1490 {"Left2 Analog Loopback", "Switch", "Analog Left"}, 1424 {"Left2 Analog Loopback", "Switch", "Analog Left"},
1491 {"Voice Analog Loopback", "Switch", "Analog Left"}, 1425 {"Voice Analog Loopback", "Switch", "Analog Left"},
1492 1426
1427 /* Supply for the Analog loopbacks */
1428 {"Right1 Analog Loopback", NULL, "FM Loop Enable"},
1429 {"Left1 Analog Loopback", NULL, "FM Loop Enable"},
1430 {"Right2 Analog Loopback", NULL, "FM Loop Enable"},
1431 {"Left2 Analog Loopback", NULL, "FM Loop Enable"},
1432 {"Voice Analog Loopback", NULL, "FM Loop Enable"},
1433
1493 {"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"}, 1434 {"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"},
1494 {"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"}, 1435 {"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"},
1495 {"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"}, 1436 {"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"},
@@ -1521,25 +1462,16 @@ static int twl4030_add_widgets(struct snd_soc_codec *codec)
1521static int twl4030_set_bias_level(struct snd_soc_codec *codec, 1462static int twl4030_set_bias_level(struct snd_soc_codec *codec,
1522 enum snd_soc_bias_level level) 1463 enum snd_soc_bias_level level)
1523{ 1464{
1524 struct twl4030_priv *twl4030 = codec->private_data;
1525
1526 switch (level) { 1465 switch (level) {
1527 case SND_SOC_BIAS_ON: 1466 case SND_SOC_BIAS_ON:
1528 twl4030_codec_mute(codec, 0); 1467 twl4030_codec_mute(codec, 0);
1529 break; 1468 break;
1530 case SND_SOC_BIAS_PREPARE: 1469 case SND_SOC_BIAS_PREPARE:
1531 twl4030_power_up(codec);
1532 if (twl4030->bypass_state)
1533 twl4030_codec_mute(codec, 0);
1534 else
1535 twl4030_codec_mute(codec, 1);
1536 break; 1470 break;
1537 case SND_SOC_BIAS_STANDBY: 1471 case SND_SOC_BIAS_STANDBY:
1538 twl4030_power_up(codec); 1472 if (codec->bias_level == SND_SOC_BIAS_OFF)
1539 if (twl4030->bypass_state) 1473 twl4030_power_up(codec);
1540 twl4030_codec_mute(codec, 0); 1474 twl4030_codec_mute(codec, 1);
1541 else
1542 twl4030_codec_mute(codec, 1);
1543 break; 1475 break;
1544 case SND_SOC_BIAS_OFF: 1476 case SND_SOC_BIAS_OFF:
1545 twl4030_power_down(codec); 1477 twl4030_power_down(codec);