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.c148
1 files changed, 124 insertions, 24 deletions
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 8a68cea4a3ee..c08d1c2f346f 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),
@@ -640,9 +670,8 @@ SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0),
640 670
641SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, 671SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event,
642 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), 672 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
643SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, 673SND_SOC_DAPM_OUT_DRV_E("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
644 NULL, 0, 674 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 675
647SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, 676SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
648 earpiece_mixer, ARRAY_SIZE(earpiece_mixer)), 677 earpiece_mixer, ARRAY_SIZE(earpiece_mixer)),
@@ -656,10 +685,10 @@ SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0,
656 right_speaker_boost, ARRAY_SIZE(right_speaker_boost)), 685 right_speaker_boost, ARRAY_SIZE(right_speaker_boost)),
657 686
658SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0), 687SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0),
659SND_SOC_DAPM_PGA("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0, 688SND_SOC_DAPM_OUT_DRV("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
660 NULL, 0), 689 NULL, 0),
661SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0, 690SND_SOC_DAPM_OUT_DRV("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
662 NULL, 0), 691 NULL, 0),
663 692
664SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0, 693SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0,
665 line1_mix, ARRAY_SIZE(line1_mix)), 694 line1_mix, ARRAY_SIZE(line1_mix)),
@@ -675,14 +704,18 @@ SND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0,
675SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0, 704SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0,
676 line2p_mix, ARRAY_SIZE(line2p_mix)), 705 line2p_mix, ARRAY_SIZE(line2p_mix)),
677 706
678SND_SOC_DAPM_PGA("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0, 707SND_SOC_DAPM_OUT_DRV_E("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0,
679 NULL, 0), 708 NULL, 0, lineout_event,
680SND_SOC_DAPM_PGA("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0, 709 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
681 NULL, 0), 710SND_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, 711 NULL, 0, lineout_event,
683 NULL, 0), 712 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
684SND_SOC_DAPM_PGA("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0, 713SND_SOC_DAPM_OUT_DRV_E("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0,
685 NULL, 0), 714 NULL, 0, lineout_event,
715 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
716SND_SOC_DAPM_OUT_DRV_E("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0,
717 NULL, 0, lineout_event,
718 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
686 719
687SND_SOC_DAPM_OUTPUT("SPKOUTLP"), 720SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
688SND_SOC_DAPM_OUTPUT("SPKOUTLN"), 721SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
@@ -901,7 +934,7 @@ int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec)
901 WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU, 934 WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
902 WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU); 935 WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);
903 936
904 snd_soc_add_controls(codec, analogue_snd_controls, 937 snd_soc_add_codec_controls(codec, analogue_snd_controls,
905 ARRAY_SIZE(analogue_snd_controls)); 938 ARRAY_SIZE(analogue_snd_controls));
906 939
907 snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets, 940 snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets,
@@ -949,6 +982,11 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
949 int jd_scthr, int jd_thr, int micbias1_lvl, 982 int jd_scthr, int jd_thr, int micbias1_lvl,
950 int micbias2_lvl) 983 int micbias2_lvl)
951{ 984{
985 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
986
987 hubs->lineout1_se = !lineout1_diff;
988 hubs->lineout2_se = !lineout2_diff;
989
952 if (!lineout1_diff) 990 if (!lineout1_diff)
953 snd_soc_update_bits(codec, WM8993_LINE_MIXER1, 991 snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
954 WM8993_LINEOUT1_MODE, 992 WM8993_LINEOUT1_MODE,
@@ -958,12 +996,6 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
958 WM8993_LINEOUT2_MODE, 996 WM8993_LINEOUT2_MODE,
959 WM8993_LINEOUT2_MODE); 997 WM8993_LINEOUT2_MODE);
960 998
961 /* If the line outputs are differential then we aren't presenting
962 * VMID as an output and can disable it.
963 */
964 if (lineout1_diff && lineout2_diff)
965 codec->dapm.idle_bias_off = 1;
966
967 if (lineout1fb) 999 if (lineout1fb)
968 snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, 1000 snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
969 WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB); 1001 WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
@@ -984,6 +1016,74 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
984} 1016}
985EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata); 1017EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata);
986 1018
1019void wm_hubs_vmid_ena(struct snd_soc_codec *codec)
1020{
1021 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
1022 int val = 0;
1023
1024 if (hubs->lineout1_se)
1025 val |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA;
1026
1027 if (hubs->lineout2_se)
1028 val |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA;
1029
1030 /* Enable the line outputs while we power up */
1031 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3, val, val);
1032}
1033EXPORT_SYMBOL_GPL(wm_hubs_vmid_ena);
1034
1035void wm_hubs_set_bias_level(struct snd_soc_codec *codec,
1036 enum snd_soc_bias_level level)
1037{
1038 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
1039 int val;
1040
1041 switch (level) {
1042 case SND_SOC_BIAS_STANDBY:
1043 /* Clamp the inputs to VMID while we ramp to charge caps */
1044 snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG,
1045 WM8993_INPUTS_CLAMP, WM8993_INPUTS_CLAMP);
1046 break;
1047
1048 case SND_SOC_BIAS_ON:
1049 /* Turn off any unneded single ended outputs */
1050 val = 0;
1051
1052 if (hubs->lineout1_se && hubs->lineout1n_ena)
1053 val |= WM8993_LINEOUT1N_ENA;
1054
1055 if (hubs->lineout1_se && hubs->lineout1p_ena)
1056 val |= WM8993_LINEOUT1P_ENA;
1057
1058 if (hubs->lineout2_se && hubs->lineout2n_ena)
1059 val |= WM8993_LINEOUT2N_ENA;
1060
1061 if (hubs->lineout2_se && hubs->lineout2p_ena)
1062 val |= WM8993_LINEOUT2P_ENA;
1063
1064 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3,
1065 WM8993_LINEOUT1N_ENA |
1066 WM8993_LINEOUT1P_ENA |
1067 WM8993_LINEOUT2N_ENA |
1068 WM8993_LINEOUT2P_ENA,
1069 val);
1070
1071 if (!hubs->lineout1n_ena && !hubs->lineout1p_ena &&
1072 !hubs->lineout2n_ena && !hubs->lineout2p_ena)
1073 snd_soc_update_bits(codec, WM8993_ANTIPOP1,
1074 WM8993_LINEOUT_VMID_BUF_ENA, 0);
1075
1076 /* Remove the input clamps */
1077 snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG,
1078 WM8993_INPUTS_CLAMP, 0);
1079 break;
1080
1081 default:
1082 break;
1083 }
1084}
1085EXPORT_SYMBOL_GPL(wm_hubs_set_bias_level);
1086
987MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); 1087MODULE_DESCRIPTION("Shared support for Wolfson hubs products");
988MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 1088MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
989MODULE_LICENSE("GPL"); 1089MODULE_LICENSE("GPL");