diff options
| -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); |
