Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: wm_hubs: Improve single ended line output enable performance

The enable of the single ended line outputs on wm_hubs devices performs
better if the output is enabled prior to starting VMID. Since inactive
outputs are held at VMID anyway there is little cost to doing this for
unused outputs. Add callbacks into wm_hubs and keep track of which outputs
are really active so we can disable them once we're active.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>

+125 -8
+4
sound/soc/codecs/wm8993.c
··· 1058 1058 struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); 1059 1059 int ret; 1060 1060 1061 + wm_hubs_set_bias_level(codec, level); 1062 + 1061 1063 switch (level) { 1062 1064 case SND_SOC_BIAS_ON: 1063 1065 case SND_SOC_BIAS_PREPARE: ··· 1079 1077 1080 1078 regcache_cache_only(wm8993->regmap, false); 1081 1079 regcache_sync(wm8993->regmap); 1080 + 1081 + wm_hubs_vmid_ena(codec); 1082 1082 1083 1083 /* Bring up VMID with fast soft start */ 1084 1084 snd_soc_update_bits(codec, WM8993_ANTIPOP2,
+5
sound/soc/codecs/wm8994.c
··· 787 787 WM8994_VMID_BUF_ENA | 788 788 (0x3 << WM8994_VMID_RAMP_SHIFT)); 789 789 790 + wm_hubs_vmid_ena(codec); 791 + 790 792 /* Remove discharge for line out */ 791 793 snd_soc_update_bits(codec, WM8994_ANTIPOP_1, 792 794 WM8994_LINEOUT1_DISCH | ··· 2076 2074 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); 2077 2075 struct wm8994 *control = wm8994->wm8994; 2078 2076 2077 + wm_hubs_set_bias_level(codec, level); 2078 + 2079 2079 switch (level) { 2080 2080 case SND_SOC_BIAS_ON: 2081 2081 break; ··· 2172 2168 wm8994->cur_fw = NULL; 2173 2169 break; 2174 2170 } 2171 + 2175 2172 codec->dapm.bias_level = level; 2176 2173 2177 2174 return 0;
+105 -8
sound/soc/codecs/wm_hubs.c
··· 500 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 533 static const struct snd_kcontrol_new in1l_pga[] = { 504 534 SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0), 505 535 SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0), ··· 705 675 SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0, 706 676 line2p_mix, ARRAY_SIZE(line2p_mix)), 707 677 708 - SND_SOC_DAPM_OUT_DRV("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0, 709 - NULL, 0), 710 - SND_SOC_DAPM_OUT_DRV("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0, 711 - NULL, 0), 712 - SND_SOC_DAPM_OUT_DRV("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0, 713 - NULL, 0), 714 - SND_SOC_DAPM_OUT_DRV("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0, 715 - NULL, 0), 678 + SND_SOC_DAPM_OUT_DRV_E("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0, 679 + NULL, 0, lineout_event, 680 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 681 + SND_SOC_DAPM_OUT_DRV_E("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0, 682 + NULL, 0, lineout_event, 683 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 684 + SND_SOC_DAPM_OUT_DRV_E("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0, 685 + NULL, 0, lineout_event, 686 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 687 + SND_SOC_DAPM_OUT_DRV_E("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0, 688 + NULL, 0, lineout_event, 689 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 716 690 717 691 SND_SOC_DAPM_OUTPUT("SPKOUTLP"), 718 692 SND_SOC_DAPM_OUTPUT("SPKOUTLN"), ··· 983 949 int jd_scthr, int jd_thr, int micbias1_lvl, 984 950 int micbias2_lvl) 985 951 { 952 + struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); 953 + 954 + hubs->lineout1_se = !lineout1_diff; 955 + hubs->lineout2_se = !lineout2_diff; 956 + 986 957 if (!lineout1_diff) 987 958 snd_soc_update_bits(codec, WM8993_LINE_MIXER1, 988 959 WM8993_LINEOUT1_MODE, ··· 1016 977 return 0; 1017 978 } 1018 979 EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata); 980 + 981 + void wm_hubs_vmid_ena(struct snd_soc_codec *codec) 982 + { 983 + struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); 984 + int val = 0; 985 + 986 + if (hubs->lineout1_se) 987 + val |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA; 988 + 989 + if (hubs->lineout2_se) 990 + val |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA; 991 + 992 + /* Enable the line outputs while we power up */ 993 + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3, val, val); 994 + } 995 + EXPORT_SYMBOL_GPL(wm_hubs_vmid_ena); 996 + 997 + void wm_hubs_set_bias_level(struct snd_soc_codec *codec, 998 + enum snd_soc_bias_level level) 999 + { 1000 + struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); 1001 + int val; 1002 + 1003 + switch (level) { 1004 + case SND_SOC_BIAS_ON: 1005 + /* Turn off any unneded single ended outputs */ 1006 + val = 0; 1007 + 1008 + if (hubs->lineout1_se && hubs->lineout1n_ena) 1009 + val |= WM8993_LINEOUT1N_ENA; 1010 + 1011 + if (hubs->lineout1_se && hubs->lineout1p_ena) 1012 + val |= WM8993_LINEOUT1P_ENA; 1013 + 1014 + if (hubs->lineout2_se && hubs->lineout2n_ena) 1015 + val |= WM8993_LINEOUT2N_ENA; 1016 + 1017 + if (hubs->lineout2_se && hubs->lineout2p_ena) 1018 + val |= WM8993_LINEOUT2P_ENA; 1019 + 1020 + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3, 1021 + WM8993_LINEOUT1N_ENA | 1022 + WM8993_LINEOUT1P_ENA | 1023 + WM8993_LINEOUT2N_ENA | 1024 + WM8993_LINEOUT2P_ENA, 1025 + val); 1026 + 1027 + if (!hubs->lineout1n_ena && !hubs->lineout1p_ena && 1028 + !hubs->lineout2n_ena && !hubs->lineout2p_ena) 1029 + snd_soc_update_bits(codec, WM8993_ANTIPOP1, 1030 + WM8993_LINEOUT_VMID_BUF_ENA, 0); 1031 + break; 1032 + 1033 + default: 1034 + break; 1035 + } 1036 + } 1037 + EXPORT_SYMBOL_GPL(wm_hubs_set_bias_level); 1019 1038 1020 1039 MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); 1021 1040 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+11
sound/soc/codecs/wm_hubs.h
··· 33 33 bool class_w; 34 34 u16 class_w_dcs; 35 35 36 + bool lineout1_se; 37 + bool lineout1n_ena; 38 + bool lineout1p_ena; 39 + 40 + bool lineout2_se; 41 + bool lineout2n_ena; 42 + bool lineout2p_ena; 43 + 36 44 bool dcs_done_irq; 37 45 struct completion dcs_done; 38 46 }; ··· 54 46 int micbias1_lvl, int micbias2_lvl); 55 47 56 48 extern irqreturn_t wm_hubs_dcs_done(int irq, void *data); 49 + extern void wm_hubs_vmid_ena(struct snd_soc_codec *codec); 50 + extern void wm_hubs_set_bias_level(struct snd_soc_codec *codec, 51 + enum snd_soc_bias_level level); 57 52 58 53 #endif