14 #include <linux/module.h>
19 #include <linux/i2c.h>
41 static const unsigned int spkboost_tlv[] = {
48 static const char *speaker_ref_text[] = {
53 static const struct soc_enum speaker_ref =
56 static const char *speaker_mode_text[] = {
61 static const struct soc_enum speaker_mode =
66 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
77 dev_dbg(codec->
dev,
"Waiting for DC servo...\n");
95 }
while (reg & op && count < timeout);
98 dev_err(codec->
dev,
"Timed out waiting for DC Servo %x\n",
112 static bool wm_hubs_dac_hp_direct(
struct snd_soc_codec *codec)
120 dev_vdbg(codec->
dev,
"Analogue paths connected: %x\n",
121 reg & ~WM8993_DACL_TO_HPOUT1L);
133 dev_vdbg(codec->
dev,
"Analogue paths connected: %x\n",
134 reg & ~WM8993_DACR_TO_HPOUT1R);
153 static bool wm_hubs_dcs_cache_get(
struct snd_soc_codec *codec,
156 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
167 if (cache->
left != left || cache->
right != right)
179 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
187 dev_err(codec->
dev,
"Failed to allocate DCS cache entry\n");
202 static void wm_hubs_read_dc_servo(
struct snd_soc_codec *codec,
205 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
238 WARN(1,
"Unknown DCS readback method\n");
248 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
264 if (wm_hubs_dac_hp_direct(codec) &&
265 wm_hubs_dcs_cache_get(codec, &cache)) {
266 dev_dbg(codec->
dev,
"Using cached DCS offset %x for %d,%d\n",
269 wait_for_dc_servo(codec,
280 wait_for_dc_servo(codec,
284 wait_for_dc_servo(codec,
289 wm_hubs_read_dc_servo(codec, ®_l, ®_r);
291 dev_dbg(codec->
dev,
"DCS input: %x %x\n", reg_l, reg_r);
296 "Applying %d/%d code DC servo correction\n",
301 dev_dbg(codec->
dev,
"DCS right %d->%d\n", offset,
308 dev_dbg(codec->
dev,
"DCS left %d->%d\n", offset,
311 dcs_cfg |= (
u8)offset;
313 dev_dbg(codec->
dev,
"DCS result: %x\n", dcs_cfg);
317 wait_for_dc_servo(codec,
327 if (wm_hubs_dac_hp_direct(codec))
328 wm_hubs_dcs_cache_set(codec, dcs_cfg);
334 static int wm8993_put_dc_servo(
struct snd_kcontrol *kcontrol,
338 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
448 5, 1, 1, wm_hubs_spkmix_tlv),
450 4, 1, 1, wm_hubs_spkmix_tlv),
452 3, 1, 1, wm_hubs_spkmix_tlv),
455 5, 1, 1, wm_hubs_spkmix_tlv),
457 4, 1, 1, wm_hubs_spkmix_tlv),
459 3, 1, 1, wm_hubs_spkmix_tlv),
463 0, 3, 1, spkmixout_tlv),
466 0, 63, 0, outpga_tlv),
475 SOC_ENUM(
"Speaker Reference", speaker_ref),
476 SOC_ENUM(
"Speaker Mode", speaker_mode),
503 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
526 dev_err(codec->
dev,
"Unknown HP startup mode %d\n",
563 enable_dc_servo(codec);
621 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
638 WARN(1,
"Unknown line output");
651 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
671 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
674 if (!wm_hubs_dac_hp_direct(codec))
680 dev_vdbg(codec->
dev,
"Class W %s\n", enable ?
"enabled" :
"disabled");
692 #define WM_HUBS_SINGLE_W(xname, reg, shift, max, invert) \
693 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
694 .info = snd_soc_info_volsw, \
695 .get = snd_soc_dapm_get_volsw, .put = class_w_put_volsw, \
696 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
698 static int class_w_put_volsw(
struct snd_kcontrol *kcontrol,
713 #define WM_HUBS_ENUM_W(xname, xenum) \
714 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
715 .info = snd_soc_info_enum_double, \
716 .get = snd_soc_dapm_get_enum_double, \
717 .put = class_w_put_double, \
718 .private_value = (unsigned long)&xenum }
720 static int class_w_put_double(
struct snd_kcontrol *kcontrol,
735 static const char *hp_mux_text[] = {
740 static const struct soc_enum hpl_enum =
747 static const struct soc_enum hpr_enum =
885 left_output_mixer,
ARRAY_SIZE(left_output_mixer)),
887 right_output_mixer,
ARRAY_SIZE(right_output_mixer)),
900 NULL, 0, earpiece_event,
904 left_speaker_boost,
ARRAY_SIZE(left_speaker_boost)),
906 right_speaker_boost,
ARRAY_SIZE(right_speaker_boost)),
929 NULL, 0, lineout_event,
932 NULL, 0, lineout_event,
935 NULL, 0, lineout_event,
938 NULL, 0, lineout_event,
956 {
"MICBIAS1",
NULL,
"CLK_SYS" },
957 {
"MICBIAS2",
NULL,
"CLK_SYS" },
959 {
"IN1L PGA",
"IN1LP Switch",
"IN1LP" },
960 {
"IN1L PGA",
"IN1LN Switch",
"IN1LN" },
962 {
"IN1L PGA",
NULL,
"VMID" },
963 {
"IN1R PGA",
NULL,
"VMID" },
964 {
"IN2L PGA",
NULL,
"VMID" },
965 {
"IN2R PGA",
NULL,
"VMID" },
967 {
"IN1R PGA",
"IN1RP Switch",
"IN1RP" },
968 {
"IN1R PGA",
"IN1RN Switch",
"IN1RN" },
970 {
"IN2L PGA",
"IN2LP Switch",
"IN2LP:VXRN" },
971 {
"IN2L PGA",
"IN2LN Switch",
"IN2LN" },
973 {
"IN2R PGA",
"IN2RP Switch",
"IN2RP:VXRP" },
974 {
"IN2R PGA",
"IN2RN Switch",
"IN2RN" },
976 {
"Direct Voice",
NULL,
"IN2LP:VXRN" },
977 {
"Direct Voice",
NULL,
"IN2RP:VXRP" },
979 {
"MIXINL",
"IN1L Switch",
"IN1L PGA" },
980 {
"MIXINL",
"IN2L Switch",
"IN2L PGA" },
981 {
"MIXINL",
NULL,
"Direct Voice" },
982 {
"MIXINL",
NULL,
"IN1LP" },
983 {
"MIXINL",
NULL,
"Left Output Mixer" },
984 {
"MIXINL",
NULL,
"VMID" },
986 {
"MIXINR",
"IN1R Switch",
"IN1R PGA" },
987 {
"MIXINR",
"IN2R Switch",
"IN2R PGA" },
988 {
"MIXINR",
NULL,
"Direct Voice" },
989 {
"MIXINR",
NULL,
"IN1RP" },
990 {
"MIXINR",
NULL,
"Right Output Mixer" },
991 {
"MIXINR",
NULL,
"VMID" },
993 {
"ADCL",
NULL,
"MIXINL" },
994 {
"ADCR",
NULL,
"MIXINR" },
996 {
"Left Output Mixer",
"Left Input Switch",
"MIXINL" },
997 {
"Left Output Mixer",
"Right Input Switch",
"MIXINR" },
998 {
"Left Output Mixer",
"IN2RN Switch",
"IN2RN" },
999 {
"Left Output Mixer",
"IN2LN Switch",
"IN2LN" },
1000 {
"Left Output Mixer",
"IN2LP Switch",
"IN2LP:VXRN" },
1001 {
"Left Output Mixer",
"IN1L Switch",
"IN1L PGA" },
1002 {
"Left Output Mixer",
"IN1R Switch",
"IN1R PGA" },
1004 {
"Right Output Mixer",
"Left Input Switch",
"MIXINL" },
1005 {
"Right Output Mixer",
"Right Input Switch",
"MIXINR" },
1006 {
"Right Output Mixer",
"IN2LN Switch",
"IN2LN" },
1007 {
"Right Output Mixer",
"IN2RN Switch",
"IN2RN" },
1008 {
"Right Output Mixer",
"IN2RP Switch",
"IN2RP:VXRP" },
1009 {
"Right Output Mixer",
"IN1L Switch",
"IN1L PGA" },
1010 {
"Right Output Mixer",
"IN1R Switch",
"IN1R PGA" },
1012 {
"Left Output PGA",
NULL,
"Left Output Mixer" },
1013 {
"Left Output PGA",
NULL,
"TOCLK" },
1015 {
"Right Output PGA",
NULL,
"Right Output Mixer" },
1016 {
"Right Output PGA",
NULL,
"TOCLK" },
1018 {
"Earpiece Mixer",
"Direct Voice Switch",
"Direct Voice" },
1019 {
"Earpiece Mixer",
"Left Output Switch",
"Left Output PGA" },
1020 {
"Earpiece Mixer",
"Right Output Switch",
"Right Output PGA" },
1022 {
"Earpiece Driver",
NULL,
"VMID" },
1023 {
"Earpiece Driver",
NULL,
"Earpiece Mixer" },
1024 {
"HPOUT2N",
NULL,
"Earpiece Driver" },
1025 {
"HPOUT2P",
NULL,
"Earpiece Driver" },
1027 {
"SPKL",
"Input Switch",
"MIXINL" },
1028 {
"SPKL",
"IN1LP Switch",
"IN1LP" },
1029 {
"SPKL",
"Output Switch",
"Left Output PGA" },
1030 {
"SPKL",
NULL,
"TOCLK" },
1032 {
"SPKR",
"Input Switch",
"MIXINR" },
1033 {
"SPKR",
"IN1RP Switch",
"IN1RP" },
1034 {
"SPKR",
"Output Switch",
"Right Output PGA" },
1035 {
"SPKR",
NULL,
"TOCLK" },
1037 {
"SPKL Boost",
"Direct Voice Switch",
"Direct Voice" },
1038 {
"SPKL Boost",
"SPKL Switch",
"SPKL" },
1039 {
"SPKL Boost",
"SPKR Switch",
"SPKR" },
1041 {
"SPKR Boost",
"Direct Voice Switch",
"Direct Voice" },
1042 {
"SPKR Boost",
"SPKR Switch",
"SPKR" },
1043 {
"SPKR Boost",
"SPKL Switch",
"SPKL" },
1045 {
"SPKL Driver",
NULL,
"VMID" },
1046 {
"SPKL Driver",
NULL,
"SPKL Boost" },
1047 {
"SPKL Driver",
NULL,
"CLK_SYS" },
1048 {
"SPKL Driver",
NULL,
"TSHUT" },
1050 {
"SPKR Driver",
NULL,
"VMID" },
1051 {
"SPKR Driver",
NULL,
"SPKR Boost" },
1052 {
"SPKR Driver",
NULL,
"CLK_SYS" },
1053 {
"SPKR Driver",
NULL,
"TSHUT" },
1055 {
"SPKOUTLP",
NULL,
"SPKL Driver" },
1056 {
"SPKOUTLN",
NULL,
"SPKL Driver" },
1057 {
"SPKOUTRP",
NULL,
"SPKR Driver" },
1058 {
"SPKOUTRN",
NULL,
"SPKR Driver" },
1060 {
"Left Headphone Mux",
"Mixer",
"Left Output PGA" },
1061 {
"Right Headphone Mux",
"Mixer",
"Right Output PGA" },
1063 {
"Headphone PGA",
NULL,
"Left Headphone Mux" },
1064 {
"Headphone PGA",
NULL,
"Right Headphone Mux" },
1065 {
"Headphone PGA",
NULL,
"VMID" },
1066 {
"Headphone PGA",
NULL,
"CLK_SYS" },
1067 {
"Headphone PGA",
NULL,
"Headphone Supply" },
1069 {
"HPOUT1L",
NULL,
"Headphone PGA" },
1070 {
"HPOUT1R",
NULL,
"Headphone PGA" },
1072 {
"LINEOUT1N Driver",
NULL,
"VMID" },
1073 {
"LINEOUT1P Driver",
NULL,
"VMID" },
1074 {
"LINEOUT2N Driver",
NULL,
"VMID" },
1075 {
"LINEOUT2P Driver",
NULL,
"VMID" },
1077 {
"LINEOUT1N",
NULL,
"LINEOUT1N Driver" },
1078 {
"LINEOUT1P",
NULL,
"LINEOUT1P Driver" },
1079 {
"LINEOUT2N",
NULL,
"LINEOUT2N Driver" },
1080 {
"LINEOUT2P",
NULL,
"LINEOUT2P Driver" },
1084 {
"LINEOUT1 Mixer",
"IN1L Switch",
"IN1L PGA" },
1085 {
"LINEOUT1 Mixer",
"IN1R Switch",
"IN1R PGA" },
1086 {
"LINEOUT1 Mixer",
"Output Switch",
"Left Output PGA" },
1088 {
"LINEOUT1N Driver",
NULL,
"LINEOUT1 Mixer" },
1089 {
"LINEOUT1P Driver",
NULL,
"LINEOUT1 Mixer" },
1093 {
"LINEOUT1N Mixer",
"Left Output Switch",
"Left Output PGA" },
1094 {
"LINEOUT1N Mixer",
"Right Output Switch",
"Right Output PGA" },
1096 {
"LINEOUT1P Mixer",
"Left Output Switch",
"Left Output PGA" },
1098 {
"LINEOUT1N Driver",
NULL,
"LINEOUT1N Mixer" },
1099 {
"LINEOUT1P Driver",
NULL,
"LINEOUT1P Mixer" },
1103 {
"LINEOUT2 Mixer",
"IN1L Switch",
"IN1L PGA" },
1104 {
"LINEOUT2 Mixer",
"IN1R Switch",
"IN1R PGA" },
1105 {
"LINEOUT2 Mixer",
"Output Switch",
"Right Output PGA" },
1107 {
"LINEOUT2N Driver",
NULL,
"LINEOUT2 Mixer" },
1108 {
"LINEOUT2P Driver",
NULL,
"LINEOUT2 Mixer" },
1112 {
"LINEOUT2N Mixer",
"Left Output Switch",
"Left Output PGA" },
1113 {
"LINEOUT2N Mixer",
"Right Output Switch",
"Right Output PGA" },
1115 {
"LINEOUT2P Mixer",
"Right Output Switch",
"Right Output PGA" },
1117 {
"LINEOUT2N Driver",
NULL,
"LINEOUT2N Mixer" },
1118 {
"LINEOUT2P Driver",
NULL,
"LINEOUT2P Mixer" },
1164 int lineout1_diff,
int lineout2_diff)
1166 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
1179 lineout1_diff_routes,
1188 lineout2_diff_routes,
1200 int lineout1_diff,
int lineout2_diff,
1201 int lineout1fb,
int lineout2fb,
1202 int jd_scthr,
int jd_thr,
1203 int micbias1_delay,
int micbias2_delay,
1204 int micbias1_lvl,
int micbias2_lvl)
1206 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
1222 if (!lineout1_diff && !lineout2_diff)
1249 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
1266 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);