diff options
Diffstat (limited to 'sound/soc/codecs/wm_hubs.c')
-rw-r--r-- | sound/soc/codecs/wm_hubs.c | 152 |
1 files changed, 123 insertions, 29 deletions
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 8a68cea4a3ee..f13f2886339c 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
@@ -172,7 +172,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) | |||
172 | break; | 172 | break; |
173 | default: | 173 | default: |
174 | WARN(1, "Unknown DCS readback method\n"); | 174 | WARN(1, "Unknown DCS readback method\n"); |
175 | break; | 175 | return; |
176 | } | 176 | } |
177 | 177 | ||
178 | dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r); | 178 | dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r); |
@@ -207,7 +207,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) | |||
207 | 207 | ||
208 | /* Save the callibrated offset if we're in class W mode and | 208 | /* Save the callibrated offset if we're in class W mode and |
209 | * therefore don't have any analogue signal mixed in. */ | 209 | * therefore don't have any analogue signal mixed in. */ |
210 | if (hubs->class_w) | 210 | if (hubs->class_w && !hubs->no_cache_class_w) |
211 | hubs->class_w_dcs = dcs_cfg; | 211 | hubs->class_w_dcs = dcs_cfg; |
212 | } | 212 | } |
213 | 213 | ||
@@ -500,6 +500,36 @@ static int earpiece_event(struct snd_soc_dapm_widget *w, | |||
500 | return 0; | 500 | return 0; |
501 | } | 501 | } |
502 | 502 | ||
503 | static int lineout_event(struct snd_soc_dapm_widget *w, | ||
504 | struct snd_kcontrol *control, int event) | ||
505 | { | ||
506 | struct snd_soc_codec *codec = w->codec; | ||
507 | struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); | ||
508 | bool *flag; | ||
509 | |||
510 | switch (w->shift) { | ||
511 | case WM8993_LINEOUT1N_ENA_SHIFT: | ||
512 | flag = &hubs->lineout1n_ena; | ||
513 | break; | ||
514 | case WM8993_LINEOUT1P_ENA_SHIFT: | ||
515 | flag = &hubs->lineout1p_ena; | ||
516 | break; | ||
517 | case WM8993_LINEOUT2N_ENA_SHIFT: | ||
518 | flag = &hubs->lineout2n_ena; | ||
519 | break; | ||
520 | case WM8993_LINEOUT2P_ENA_SHIFT: | ||
521 | flag = &hubs->lineout2p_ena; | ||
522 | break; | ||
523 | default: | ||
524 | WARN(1, "Unknown line output"); | ||
525 | return -EINVAL; | ||
526 | } | ||
527 | |||
528 | *flag = SND_SOC_DAPM_EVENT_ON(event); | ||
529 | |||
530 | return 0; | ||
531 | } | ||
532 | |||
503 | static const struct snd_kcontrol_new in1l_pga[] = { | 533 | static const struct snd_kcontrol_new in1l_pga[] = { |
504 | SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0), | 534 | SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0), |
505 | SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0), | 535 | SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0), |
@@ -613,8 +643,6 @@ SND_SOC_DAPM_INPUT("IN2RP:VXRP"), | |||
613 | SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, NULL, 0), | 643 | SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, NULL, 0), |
614 | SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, NULL, 0), | 644 | SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, NULL, 0), |
615 | 645 | ||
616 | SND_SOC_DAPM_SUPPLY("LINEOUT_VMID_BUF", WM8993_ANTIPOP1, 7, 0, NULL, 0), | ||
617 | |||
618 | SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0, | 646 | SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0, |
619 | in1l_pga, ARRAY_SIZE(in1l_pga)), | 647 | in1l_pga, ARRAY_SIZE(in1l_pga)), |
620 | SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0, | 648 | SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0, |
@@ -640,9 +668,8 @@ SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0), | |||
640 | 668 | ||
641 | SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, | 669 | SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, |
642 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), | 670 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), |
643 | SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, | 671 | SND_SOC_DAPM_OUT_DRV_E("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0, |
644 | NULL, 0, | 672 | hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
645 | hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
646 | 673 | ||
647 | SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, | 674 | SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, |
648 | earpiece_mixer, ARRAY_SIZE(earpiece_mixer)), | 675 | earpiece_mixer, ARRAY_SIZE(earpiece_mixer)), |
@@ -656,10 +683,10 @@ SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0, | |||
656 | right_speaker_boost, ARRAY_SIZE(right_speaker_boost)), | 683 | right_speaker_boost, ARRAY_SIZE(right_speaker_boost)), |
657 | 684 | ||
658 | SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0), | 685 | SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0), |
659 | SND_SOC_DAPM_PGA("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0, | 686 | SND_SOC_DAPM_OUT_DRV("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0, |
660 | NULL, 0), | 687 | NULL, 0), |
661 | SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0, | 688 | SND_SOC_DAPM_OUT_DRV("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0, |
662 | NULL, 0), | 689 | NULL, 0), |
663 | 690 | ||
664 | SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0, | 691 | SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0, |
665 | line1_mix, ARRAY_SIZE(line1_mix)), | 692 | line1_mix, ARRAY_SIZE(line1_mix)), |
@@ -675,14 +702,18 @@ SND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0, | |||
675 | SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0, | 702 | SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0, |
676 | line2p_mix, ARRAY_SIZE(line2p_mix)), | 703 | line2p_mix, ARRAY_SIZE(line2p_mix)), |
677 | 704 | ||
678 | SND_SOC_DAPM_PGA("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0, | 705 | SND_SOC_DAPM_OUT_DRV_E("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0, |
679 | NULL, 0), | 706 | NULL, 0, lineout_event, |
680 | SND_SOC_DAPM_PGA("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0, | 707 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
681 | NULL, 0), | 708 | SND_SOC_DAPM_OUT_DRV_E("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0, |
682 | SND_SOC_DAPM_PGA("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0, | 709 | NULL, 0, lineout_event, |
683 | NULL, 0), | 710 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
684 | SND_SOC_DAPM_PGA("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0, | 711 | SND_SOC_DAPM_OUT_DRV_E("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0, |
685 | NULL, 0), | 712 | NULL, 0, lineout_event, |
713 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
714 | SND_SOC_DAPM_OUT_DRV_E("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0, | ||
715 | NULL, 0, lineout_event, | ||
716 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
686 | 717 | ||
687 | SND_SOC_DAPM_OUTPUT("SPKOUTLP"), | 718 | SND_SOC_DAPM_OUTPUT("SPKOUTLP"), |
688 | SND_SOC_DAPM_OUTPUT("SPKOUTLN"), | 719 | SND_SOC_DAPM_OUTPUT("SPKOUTLN"), |
@@ -836,11 +867,9 @@ static const struct snd_soc_dapm_route lineout1_diff_routes[] = { | |||
836 | }; | 867 | }; |
837 | 868 | ||
838 | static const struct snd_soc_dapm_route lineout1_se_routes[] = { | 869 | static const struct snd_soc_dapm_route lineout1_se_routes[] = { |
839 | { "LINEOUT1N Mixer", NULL, "LINEOUT_VMID_BUF" }, | ||
840 | { "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" }, | 870 | { "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" }, |
841 | { "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" }, | 871 | { "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" }, |
842 | 872 | ||
843 | { "LINEOUT1P Mixer", NULL, "LINEOUT_VMID_BUF" }, | ||
844 | { "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" }, | 873 | { "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" }, |
845 | 874 | ||
846 | { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" }, | 875 | { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" }, |
@@ -857,11 +886,9 @@ static const struct snd_soc_dapm_route lineout2_diff_routes[] = { | |||
857 | }; | 886 | }; |
858 | 887 | ||
859 | static const struct snd_soc_dapm_route lineout2_se_routes[] = { | 888 | static const struct snd_soc_dapm_route lineout2_se_routes[] = { |
860 | { "LINEOUT2N Mixer", NULL, "LINEOUT_VMID_BUF" }, | ||
861 | { "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" }, | 889 | { "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" }, |
862 | { "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" }, | 890 | { "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" }, |
863 | 891 | ||
864 | { "LINEOUT2P Mixer", NULL, "LINEOUT_VMID_BUF" }, | ||
865 | { "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" }, | 892 | { "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" }, |
866 | 893 | ||
867 | { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" }, | 894 | { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" }, |
@@ -901,7 +928,7 @@ int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec) | |||
901 | WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU, | 928 | WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU, |
902 | WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU); | 929 | WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU); |
903 | 930 | ||
904 | snd_soc_add_controls(codec, analogue_snd_controls, | 931 | snd_soc_add_codec_controls(codec, analogue_snd_controls, |
905 | ARRAY_SIZE(analogue_snd_controls)); | 932 | ARRAY_SIZE(analogue_snd_controls)); |
906 | 933 | ||
907 | snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets, | 934 | snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets, |
@@ -949,6 +976,11 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec, | |||
949 | int jd_scthr, int jd_thr, int micbias1_lvl, | 976 | int jd_scthr, int jd_thr, int micbias1_lvl, |
950 | int micbias2_lvl) | 977 | int micbias2_lvl) |
951 | { | 978 | { |
979 | struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); | ||
980 | |||
981 | hubs->lineout1_se = !lineout1_diff; | ||
982 | hubs->lineout2_se = !lineout2_diff; | ||
983 | |||
952 | if (!lineout1_diff) | 984 | if (!lineout1_diff) |
953 | snd_soc_update_bits(codec, WM8993_LINE_MIXER1, | 985 | snd_soc_update_bits(codec, WM8993_LINE_MIXER1, |
954 | WM8993_LINEOUT1_MODE, | 986 | WM8993_LINEOUT1_MODE, |
@@ -958,11 +990,10 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec, | |||
958 | WM8993_LINEOUT2_MODE, | 990 | WM8993_LINEOUT2_MODE, |
959 | WM8993_LINEOUT2_MODE); | 991 | WM8993_LINEOUT2_MODE); |
960 | 992 | ||
961 | /* If the line outputs are differential then we aren't presenting | 993 | if (!lineout1_diff && !lineout2_diff) |
962 | * VMID as an output and can disable it. | 994 | snd_soc_update_bits(codec, WM8993_ANTIPOP1, |
963 | */ | 995 | WM8993_LINEOUT_VMID_BUF_ENA, |
964 | if (lineout1_diff && lineout2_diff) | 996 | WM8993_LINEOUT_VMID_BUF_ENA); |
965 | codec->dapm.idle_bias_off = 1; | ||
966 | 997 | ||
967 | if (lineout1fb) | 998 | if (lineout1fb) |
968 | snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, | 999 | snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, |
@@ -984,6 +1015,69 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec, | |||
984 | } | 1015 | } |
985 | EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata); | 1016 | EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata); |
986 | 1017 | ||
1018 | void wm_hubs_vmid_ena(struct snd_soc_codec *codec) | ||
1019 | { | ||
1020 | struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); | ||
1021 | int val = 0; | ||
1022 | |||
1023 | if (hubs->lineout1_se) | ||
1024 | val |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA; | ||
1025 | |||
1026 | if (hubs->lineout2_se) | ||
1027 | val |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA; | ||
1028 | |||
1029 | /* Enable the line outputs while we power up */ | ||
1030 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3, val, val); | ||
1031 | } | ||
1032 | EXPORT_SYMBOL_GPL(wm_hubs_vmid_ena); | ||
1033 | |||
1034 | void wm_hubs_set_bias_level(struct snd_soc_codec *codec, | ||
1035 | enum snd_soc_bias_level level) | ||
1036 | { | ||
1037 | struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); | ||
1038 | int val; | ||
1039 | |||
1040 | switch (level) { | ||
1041 | case SND_SOC_BIAS_STANDBY: | ||
1042 | /* Clamp the inputs to VMID while we ramp to charge caps */ | ||
1043 | snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG, | ||
1044 | WM8993_INPUTS_CLAMP, WM8993_INPUTS_CLAMP); | ||
1045 | break; | ||
1046 | |||
1047 | case SND_SOC_BIAS_ON: | ||
1048 | /* Turn off any unneded single ended outputs */ | ||
1049 | val = 0; | ||
1050 | |||
1051 | if (hubs->lineout1_se && hubs->lineout1n_ena) | ||
1052 | val |= WM8993_LINEOUT1N_ENA; | ||
1053 | |||
1054 | if (hubs->lineout1_se && hubs->lineout1p_ena) | ||
1055 | val |= WM8993_LINEOUT1P_ENA; | ||
1056 | |||
1057 | if (hubs->lineout2_se && hubs->lineout2n_ena) | ||
1058 | val |= WM8993_LINEOUT2N_ENA; | ||
1059 | |||
1060 | if (hubs->lineout2_se && hubs->lineout2p_ena) | ||
1061 | val |= WM8993_LINEOUT2P_ENA; | ||
1062 | |||
1063 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3, | ||
1064 | WM8993_LINEOUT1N_ENA | | ||
1065 | WM8993_LINEOUT1P_ENA | | ||
1066 | WM8993_LINEOUT2N_ENA | | ||
1067 | WM8993_LINEOUT2P_ENA, | ||
1068 | val); | ||
1069 | |||
1070 | /* Remove the input clamps */ | ||
1071 | snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG, | ||
1072 | WM8993_INPUTS_CLAMP, 0); | ||
1073 | break; | ||
1074 | |||
1075 | default: | ||
1076 | break; | ||
1077 | } | ||
1078 | } | ||
1079 | EXPORT_SYMBOL_GPL(wm_hubs_set_bias_level); | ||
1080 | |||
987 | MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); | 1081 | MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); |
988 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 1082 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
989 | MODULE_LICENSE("GPL"); | 1083 | MODULE_LICENSE("GPL"); |