diff options
Diffstat (limited to 'sound/soc/codecs/twl4030.c')
-rw-r--r-- | sound/soc/codecs/twl4030.c | 128 |
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] = { | |||
122 | struct twl4030_priv { | 122 | struct 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 | ||
728 | static 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) | |||
1521 | static int twl4030_set_bias_level(struct snd_soc_codec *codec, | 1462 | static 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); |