aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm_hubs.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm_hubs.c')
-rw-r--r--sound/soc/codecs/wm_hubs.c152
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
503static 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
503static const struct snd_kcontrol_new in1l_pga[] = { 533static const struct snd_kcontrol_new in1l_pga[] = {
504SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0), 534SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0),
505SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0), 535SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0),
@@ -613,8 +643,6 @@ SND_SOC_DAPM_INPUT("IN2RP:VXRP"),
613SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, NULL, 0), 643SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
614SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, NULL, 0), 644SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
615 645
616SND_SOC_DAPM_SUPPLY("LINEOUT_VMID_BUF", WM8993_ANTIPOP1, 7, 0, NULL, 0),
617
618SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0, 646SND_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)),
620SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0, 648SND_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
641SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, 669SND_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),
643SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, 671SND_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
647SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, 674SND_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
658SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0), 685SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0),
659SND_SOC_DAPM_PGA("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0, 686SND_SOC_DAPM_OUT_DRV("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
660 NULL, 0), 687 NULL, 0),
661SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0, 688SND_SOC_DAPM_OUT_DRV("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
662 NULL, 0), 689 NULL, 0),
663 690
664SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0, 691SND_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,
675SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0, 702SND_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
678SND_SOC_DAPM_PGA("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0, 705SND_SOC_DAPM_OUT_DRV_E("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0,
679 NULL, 0), 706 NULL, 0, lineout_event,
680SND_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), 708SND_SOC_DAPM_OUT_DRV_E("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0,
682SND_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),
684SND_SOC_DAPM_PGA("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0, 711SND_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),
714SND_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
687SND_SOC_DAPM_OUTPUT("SPKOUTLP"), 718SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
688SND_SOC_DAPM_OUTPUT("SPKOUTLN"), 719SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
@@ -836,11 +867,9 @@ static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
836}; 867};
837 868
838static const struct snd_soc_dapm_route lineout1_se_routes[] = { 869static 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
859static const struct snd_soc_dapm_route lineout2_se_routes[] = { 888static 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}
985EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata); 1016EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata);
986 1017
1018void 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}
1032EXPORT_SYMBOL_GPL(wm_hubs_vmid_ena);
1033
1034void 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}
1079EXPORT_SYMBOL_GPL(wm_hubs_set_bias_level);
1080
987MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); 1081MODULE_DESCRIPTION("Shared support for Wolfson hubs products");
988MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 1082MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
989MODULE_LICENSE("GPL"); 1083MODULE_LICENSE("GPL");