diff options
Diffstat (limited to 'sound/soc/codecs/wm_hubs.c')
-rw-r--r-- | sound/soc/codecs/wm_hubs.c | 148 |
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 | ||
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), |
@@ -640,9 +670,8 @@ SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0), | |||
640 | 670 | ||
641 | SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, | 671 | 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), | 672 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), |
643 | SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, | 673 | SND_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 | ||
647 | SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, | 676 | SND_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 | ||
658 | SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0), | 687 | 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, | 688 | SND_SOC_DAPM_OUT_DRV("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0, |
660 | NULL, 0), | 689 | NULL, 0), |
661 | SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0, | 690 | SND_SOC_DAPM_OUT_DRV("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0, |
662 | NULL, 0), | 691 | NULL, 0), |
663 | 692 | ||
664 | SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0, | 693 | SND_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, | |||
675 | SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0, | 704 | SND_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 | ||
678 | SND_SOC_DAPM_PGA("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0, | 707 | SND_SOC_DAPM_OUT_DRV_E("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0, |
679 | NULL, 0), | 708 | NULL, 0, lineout_event, |
680 | SND_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), | 710 | 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, | 711 | NULL, 0, lineout_event, |
683 | NULL, 0), | 712 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
684 | SND_SOC_DAPM_PGA("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0, | 713 | SND_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), | ||
716 | SND_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 | ||
687 | SND_SOC_DAPM_OUTPUT("SPKOUTLP"), | 720 | SND_SOC_DAPM_OUTPUT("SPKOUTLP"), |
688 | SND_SOC_DAPM_OUTPUT("SPKOUTLN"), | 721 | SND_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 | } |
985 | EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata); | 1017 | EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata); |
986 | 1018 | ||
1019 | void 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 | } | ||
1033 | EXPORT_SYMBOL_GPL(wm_hubs_vmid_ena); | ||
1034 | |||
1035 | void 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 | } | ||
1085 | EXPORT_SYMBOL_GPL(wm_hubs_set_bias_level); | ||
1086 | |||
987 | MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); | 1087 | MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); |
988 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 1088 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
989 | MODULE_LICENSE("GPL"); | 1089 | MODULE_LICENSE("GPL"); |