aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-08-10 04:47:33 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-08-14 00:44:23 -0400
commit4b7ed83aa3c7f4b9fe363875440836e0f2aabbdf (patch)
treed25cdee15a1d0b3df46d0b071076ce508336b36c /sound/soc/codecs
parent4e04adaf87c678425b8009c5f208d9acfc1530ab (diff)
ASoC: Disable WM8994 VMID for digital only paths
On WM8994 class devices only the analogue portions of the CODEC require VMID so when running digital only paths we can leave VMID disabled. On some earlier devices the FLL uses VMID so we don't use DAPM reference counting alone, we maintain an internal reference count which is also enabled and disabled by the FLL startup. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@ti.com>
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/wm8994.c183
-rw-r--r--sound/soc/codecs/wm8994.h2
2 files changed, 129 insertions, 56 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index f57e01344adb..e5691ad8a2d3 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -682,6 +682,97 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w,
682 return 0; 682 return 0;
683} 683}
684 684
685static void vmid_reference(struct snd_soc_codec *codec)
686{
687 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
688
689 wm8994->vmid_refcount++;
690
691 dev_dbg(codec->dev, "Referencing VMID, refcount is now %d\n",
692 wm8994->vmid_refcount);
693
694 if (wm8994->vmid_refcount == 1) {
695 /* Startup bias, VMID ramp & buffer */
696 snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
697 WM8994_STARTUP_BIAS_ENA |
698 WM8994_VMID_BUF_ENA |
699 WM8994_VMID_RAMP_MASK,
700 WM8994_STARTUP_BIAS_ENA |
701 WM8994_VMID_BUF_ENA |
702 (0x11 << WM8994_VMID_RAMP_SHIFT));
703
704 /* Main bias enable, VMID=2x40k */
705 snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
706 WM8994_BIAS_ENA |
707 WM8994_VMID_SEL_MASK,
708 WM8994_BIAS_ENA | 0x2);
709
710 msleep(20);
711 }
712}
713
714static void vmid_dereference(struct snd_soc_codec *codec)
715{
716 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
717
718 wm8994->vmid_refcount--;
719
720 dev_dbg(codec->dev, "Dereferencing VMID, refcount is now %d\n",
721 wm8994->vmid_refcount);
722
723 if (wm8994->vmid_refcount == 0) {
724 /* Switch over to startup biases */
725 snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
726 WM8994_BIAS_SRC |
727 WM8994_STARTUP_BIAS_ENA |
728 WM8994_VMID_BUF_ENA |
729 WM8994_VMID_RAMP_MASK,
730 WM8994_BIAS_SRC |
731 WM8994_STARTUP_BIAS_ENA |
732 WM8994_VMID_BUF_ENA |
733 (1 << WM8994_VMID_RAMP_SHIFT));
734
735 /* Disable main biases */
736 snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
737 WM8994_BIAS_ENA |
738 WM8994_VMID_SEL_MASK, 0);
739
740 /* Discharge line */
741 snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
742 WM8994_LINEOUT1_DISCH |
743 WM8994_LINEOUT2_DISCH,
744 WM8994_LINEOUT1_DISCH |
745 WM8994_LINEOUT2_DISCH);
746
747 msleep(5);
748
749 /* Switch off startup biases */
750 snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
751 WM8994_BIAS_SRC |
752 WM8994_STARTUP_BIAS_ENA |
753 WM8994_VMID_BUF_ENA |
754 WM8994_VMID_RAMP_MASK, 0);
755 }
756}
757
758static int vmid_event(struct snd_soc_dapm_widget *w,
759 struct snd_kcontrol *kcontrol, int event)
760{
761 struct snd_soc_codec *codec = w->codec;
762
763 switch (event) {
764 case SND_SOC_DAPM_PRE_PMU:
765 vmid_reference(codec);
766 break;
767
768 case SND_SOC_DAPM_POST_PMD:
769 vmid_dereference(codec);
770 break;
771 }
772
773 return 0;
774}
775
685static void wm8994_update_class_w(struct snd_soc_codec *codec) 776static void wm8994_update_class_w(struct snd_soc_codec *codec)
686{ 777{
687 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); 778 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
@@ -1209,7 +1300,8 @@ SND_SOC_DAPM_INPUT("Clock"),
1209 1300
1210SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev, 1301SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev,
1211 SND_SOC_DAPM_PRE_PMU), 1302 SND_SOC_DAPM_PRE_PMU),
1212SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, NULL, 0), 1303SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, vmid_event,
1304 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1213 1305
1214SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, 1306SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
1215 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 1307 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -1633,10 +1725,12 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
1633 unsigned int freq_in, unsigned int freq_out) 1725 unsigned int freq_in, unsigned int freq_out)
1634{ 1726{
1635 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); 1727 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
1728 struct wm8994 *control = codec->control_data;
1636 int reg_offset, ret; 1729 int reg_offset, ret;
1637 struct fll_div fll; 1730 struct fll_div fll;
1638 u16 reg, aif1, aif2; 1731 u16 reg, aif1, aif2;
1639 unsigned long timeout; 1732 unsigned long timeout;
1733 bool was_enabled;
1640 1734
1641 aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) 1735 aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
1642 & WM8994_AIF1CLK_ENA; 1736 & WM8994_AIF1CLK_ENA;
@@ -1657,6 +1751,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
1657 return -EINVAL; 1751 return -EINVAL;
1658 } 1752 }
1659 1753
1754 reg = snd_soc_read(codec, WM8994_FLL1_CONTROL_1 + reg_offset);
1755 was_enabled = reg & WM8994_FLL1_ENA;
1756
1660 switch (src) { 1757 switch (src) {
1661 case 0: 1758 case 0:
1662 /* Allow no source specification when stopping */ 1759 /* Allow no source specification when stopping */
@@ -1723,6 +1820,21 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
1723 1820
1724 /* Enable (with fractional mode if required) */ 1821 /* Enable (with fractional mode if required) */
1725 if (freq_out) { 1822 if (freq_out) {
1823 /* Enable VMID if we need it */
1824 if (!was_enabled) {
1825 switch (control->type) {
1826 case WM8994:
1827 vmid_reference(codec);
1828 break;
1829 case WM8958:
1830 if (wm8994->revision < 1)
1831 vmid_reference(codec);
1832 break;
1833 default:
1834 break;
1835 }
1836 }
1837
1726 if (fll.k) 1838 if (fll.k)
1727 reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC; 1839 reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC;
1728 else 1840 else
@@ -1740,6 +1852,20 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
1740 } else { 1852 } else {
1741 msleep(5); 1853 msleep(5);
1742 } 1854 }
1855 } else {
1856 if (was_enabled) {
1857 switch (control->type) {
1858 case WM8994:
1859 vmid_dereference(codec);
1860 break;
1861 case WM8958:
1862 if (wm8994->revision < 1)
1863 vmid_dereference(codec);
1864 break;
1865 default:
1866 break;
1867 }
1868 }
1743 } 1869 }
1744 1870
1745 wm8994->fll[id].in = freq_in; 1871 wm8994->fll[id].in = freq_in;
@@ -1856,9 +1982,6 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
1856 break; 1982 break;
1857 1983
1858 case SND_SOC_BIAS_PREPARE: 1984 case SND_SOC_BIAS_PREPARE:
1859 /* VMID=2x40k */
1860 snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
1861 WM8994_VMID_SEL_MASK, 0x2);
1862 break; 1985 break;
1863 1986
1864 case SND_SOC_BIAS_STANDBY: 1987 case SND_SOC_BIAS_STANDBY:
@@ -1900,65 +2023,13 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
1900 WM8994_LINEOUT2_DISCH, 2023 WM8994_LINEOUT2_DISCH,
1901 WM8994_LINEOUT1_DISCH | 2024 WM8994_LINEOUT1_DISCH |
1902 WM8994_LINEOUT2_DISCH); 2025 WM8994_LINEOUT2_DISCH);
1903
1904 /* Startup bias, VMID ramp & buffer */
1905 snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
1906 WM8994_STARTUP_BIAS_ENA |
1907 WM8994_VMID_BUF_ENA |
1908 WM8994_VMID_RAMP_MASK,
1909 WM8994_STARTUP_BIAS_ENA |
1910 WM8994_VMID_BUF_ENA |
1911 (0x11 << WM8994_VMID_RAMP_SHIFT));
1912
1913 /* Main bias enable, VMID=2x40k */
1914 snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
1915 WM8994_BIAS_ENA |
1916 WM8994_VMID_SEL_MASK,
1917 WM8994_BIAS_ENA | 0x2);
1918
1919 msleep(20);
1920 } 2026 }
1921 2027
1922 /* VMID=2x500k */
1923 snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
1924 WM8994_VMID_SEL_MASK, 0x4);
1925 2028
1926 break; 2029 break;
1927 2030
1928 case SND_SOC_BIAS_OFF: 2031 case SND_SOC_BIAS_OFF:
1929 if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { 2032 if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
1930 /* Switch over to startup biases */
1931 snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
1932 WM8994_BIAS_SRC |
1933 WM8994_STARTUP_BIAS_ENA |
1934 WM8994_VMID_BUF_ENA |
1935 WM8994_VMID_RAMP_MASK,
1936 WM8994_BIAS_SRC |
1937 WM8994_STARTUP_BIAS_ENA |
1938 WM8994_VMID_BUF_ENA |
1939 (1 << WM8994_VMID_RAMP_SHIFT));
1940
1941 /* Disable main biases */
1942 snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
1943 WM8994_BIAS_ENA |
1944 WM8994_VMID_SEL_MASK, 0);
1945
1946 /* Discharge line */
1947 snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
1948 WM8994_LINEOUT1_DISCH |
1949 WM8994_LINEOUT2_DISCH,
1950 WM8994_LINEOUT1_DISCH |
1951 WM8994_LINEOUT2_DISCH);
1952
1953 msleep(5);
1954
1955 /* Switch off startup biases */
1956 snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
1957 WM8994_BIAS_SRC |
1958 WM8994_STARTUP_BIAS_ENA |
1959 WM8994_VMID_BUF_ENA |
1960 WM8994_VMID_RAMP_MASK, 0);
1961
1962 wm8994->cur_fw = NULL; 2033 wm8994->cur_fw = NULL;
1963 2034
1964 pm_runtime_put(codec->dev); 2035 pm_runtime_put(codec->dev);
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 1ab2266039f7..f4f1355efc82 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -83,6 +83,8 @@ struct wm8994_priv {
83 struct completion fll_locked[2]; 83 struct completion fll_locked[2];
84 bool fll_locked_irq; 84 bool fll_locked_irq;
85 85
86 int vmid_refcount;
87
86 int dac_rates[2]; 88 int dac_rates[2];
87 int lrclk_shared[2]; 89 int lrclk_shared[2];
88 90