diff options
Diffstat (limited to 'sound/soc/codecs/wm8994.c')
-rw-r--r-- | sound/soc/codecs/wm8994.c | 270 |
1 files changed, 213 insertions, 57 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index b393f9fac97a..e5372675123d 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -107,6 +107,7 @@ static int wm8994_volatile(struct snd_soc_codec *codec, unsigned int reg) | |||
107 | case WM8994_LDO_2: | 107 | case WM8994_LDO_2: |
108 | case WM8958_DSP2_EXECCONTROL: | 108 | case WM8958_DSP2_EXECCONTROL: |
109 | case WM8958_MIC_DETECT_3: | 109 | case WM8958_MIC_DETECT_3: |
110 | case WM8994_DC_SERVO_4E: | ||
110 | return 1; | 111 | return 1; |
111 | default: | 112 | default: |
112 | return 0; | 113 | return 0; |
@@ -281,6 +282,7 @@ static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); | |||
281 | static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0); | 282 | static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0); |
282 | static const DECLARE_TLV_DB_SCALE(wm8994_3d_tlv, -1600, 183, 0); | 283 | static const DECLARE_TLV_DB_SCALE(wm8994_3d_tlv, -1600, 183, 0); |
283 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | 284 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); |
285 | static const DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); | ||
284 | 286 | ||
285 | #define WM8994_DRC_SWITCH(xname, reg, shift) \ | 287 | #define WM8994_DRC_SWITCH(xname, reg, shift) \ |
286 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 288 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
@@ -660,8 +662,45 @@ SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0, | |||
660 | eq_tlv), | 662 | eq_tlv), |
661 | }; | 663 | }; |
662 | 664 | ||
665 | static const char *wm8958_ng_text[] = { | ||
666 | "30ms", "125ms", "250ms", "500ms", | ||
667 | }; | ||
668 | |||
669 | static const struct soc_enum wm8958_aif1dac1_ng_hold = | ||
670 | SOC_ENUM_SINGLE(WM8958_AIF1_DAC1_NOISE_GATE, | ||
671 | WM8958_AIF1DAC1_NG_THR_SHIFT, 4, wm8958_ng_text); | ||
672 | |||
673 | static const struct soc_enum wm8958_aif1dac2_ng_hold = | ||
674 | SOC_ENUM_SINGLE(WM8958_AIF1_DAC2_NOISE_GATE, | ||
675 | WM8958_AIF1DAC2_NG_THR_SHIFT, 4, wm8958_ng_text); | ||
676 | |||
677 | static const struct soc_enum wm8958_aif2dac_ng_hold = | ||
678 | SOC_ENUM_SINGLE(WM8958_AIF2_DAC_NOISE_GATE, | ||
679 | WM8958_AIF2DAC_NG_THR_SHIFT, 4, wm8958_ng_text); | ||
680 | |||
663 | static const struct snd_kcontrol_new wm8958_snd_controls[] = { | 681 | static const struct snd_kcontrol_new wm8958_snd_controls[] = { |
664 | SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv), | 682 | SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv), |
683 | |||
684 | SOC_SINGLE("AIF1DAC1 Noise Gate Switch", WM8958_AIF1_DAC1_NOISE_GATE, | ||
685 | WM8958_AIF1DAC1_NG_ENA_SHIFT, 1, 0), | ||
686 | SOC_ENUM("AIF1DAC1 Noise Gate Hold Time", wm8958_aif1dac1_ng_hold), | ||
687 | SOC_SINGLE_TLV("AIF1DAC1 Noise Gate Threshold Volume", | ||
688 | WM8958_AIF1_DAC1_NOISE_GATE, WM8958_AIF1DAC1_NG_THR_SHIFT, | ||
689 | 7, 1, ng_tlv), | ||
690 | |||
691 | SOC_SINGLE("AIF1DAC2 Noise Gate Switch", WM8958_AIF1_DAC2_NOISE_GATE, | ||
692 | WM8958_AIF1DAC2_NG_ENA_SHIFT, 1, 0), | ||
693 | SOC_ENUM("AIF1DAC2 Noise Gate Hold Time", wm8958_aif1dac2_ng_hold), | ||
694 | SOC_SINGLE_TLV("AIF1DAC2 Noise Gate Threshold Volume", | ||
695 | WM8958_AIF1_DAC2_NOISE_GATE, WM8958_AIF1DAC2_NG_THR_SHIFT, | ||
696 | 7, 1, ng_tlv), | ||
697 | |||
698 | SOC_SINGLE("AIF2DAC Noise Gate Switch", WM8958_AIF2_DAC_NOISE_GATE, | ||
699 | WM8958_AIF2DAC_NG_ENA_SHIFT, 1, 0), | ||
700 | SOC_ENUM("AIF2DAC Noise Gate Hold Time", wm8958_aif2dac_ng_hold), | ||
701 | SOC_SINGLE_TLV("AIF2DAC Noise Gate Threshold Volume", | ||
702 | WM8958_AIF2_DAC_NOISE_GATE, WM8958_AIF2DAC_NG_THR_SHIFT, | ||
703 | 7, 1, ng_tlv), | ||
665 | }; | 704 | }; |
666 | 705 | ||
667 | static int clk_sys_event(struct snd_soc_dapm_widget *w, | 706 | static int clk_sys_event(struct snd_soc_dapm_widget *w, |
@@ -681,6 +720,97 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w, | |||
681 | return 0; | 720 | return 0; |
682 | } | 721 | } |
683 | 722 | ||
723 | static void vmid_reference(struct snd_soc_codec *codec) | ||
724 | { | ||
725 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
726 | |||
727 | wm8994->vmid_refcount++; | ||
728 | |||
729 | dev_dbg(codec->dev, "Referencing VMID, refcount is now %d\n", | ||
730 | wm8994->vmid_refcount); | ||
731 | |||
732 | if (wm8994->vmid_refcount == 1) { | ||
733 | /* Startup bias, VMID ramp & buffer */ | ||
734 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
735 | WM8994_STARTUP_BIAS_ENA | | ||
736 | WM8994_VMID_BUF_ENA | | ||
737 | WM8994_VMID_RAMP_MASK, | ||
738 | WM8994_STARTUP_BIAS_ENA | | ||
739 | WM8994_VMID_BUF_ENA | | ||
740 | (0x11 << WM8994_VMID_RAMP_SHIFT)); | ||
741 | |||
742 | /* Main bias enable, VMID=2x40k */ | ||
743 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | ||
744 | WM8994_BIAS_ENA | | ||
745 | WM8994_VMID_SEL_MASK, | ||
746 | WM8994_BIAS_ENA | 0x2); | ||
747 | |||
748 | msleep(20); | ||
749 | } | ||
750 | } | ||
751 | |||
752 | static void vmid_dereference(struct snd_soc_codec *codec) | ||
753 | { | ||
754 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
755 | |||
756 | wm8994->vmid_refcount--; | ||
757 | |||
758 | dev_dbg(codec->dev, "Dereferencing VMID, refcount is now %d\n", | ||
759 | wm8994->vmid_refcount); | ||
760 | |||
761 | if (wm8994->vmid_refcount == 0) { | ||
762 | /* Switch over to startup biases */ | ||
763 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
764 | WM8994_BIAS_SRC | | ||
765 | WM8994_STARTUP_BIAS_ENA | | ||
766 | WM8994_VMID_BUF_ENA | | ||
767 | WM8994_VMID_RAMP_MASK, | ||
768 | WM8994_BIAS_SRC | | ||
769 | WM8994_STARTUP_BIAS_ENA | | ||
770 | WM8994_VMID_BUF_ENA | | ||
771 | (1 << WM8994_VMID_RAMP_SHIFT)); | ||
772 | |||
773 | /* Disable main biases */ | ||
774 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | ||
775 | WM8994_BIAS_ENA | | ||
776 | WM8994_VMID_SEL_MASK, 0); | ||
777 | |||
778 | /* Discharge line */ | ||
779 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, | ||
780 | WM8994_LINEOUT1_DISCH | | ||
781 | WM8994_LINEOUT2_DISCH, | ||
782 | WM8994_LINEOUT1_DISCH | | ||
783 | WM8994_LINEOUT2_DISCH); | ||
784 | |||
785 | msleep(5); | ||
786 | |||
787 | /* Switch off startup biases */ | ||
788 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
789 | WM8994_BIAS_SRC | | ||
790 | WM8994_STARTUP_BIAS_ENA | | ||
791 | WM8994_VMID_BUF_ENA | | ||
792 | WM8994_VMID_RAMP_MASK, 0); | ||
793 | } | ||
794 | } | ||
795 | |||
796 | static int vmid_event(struct snd_soc_dapm_widget *w, | ||
797 | struct snd_kcontrol *kcontrol, int event) | ||
798 | { | ||
799 | struct snd_soc_codec *codec = w->codec; | ||
800 | |||
801 | switch (event) { | ||
802 | case SND_SOC_DAPM_PRE_PMU: | ||
803 | vmid_reference(codec); | ||
804 | break; | ||
805 | |||
806 | case SND_SOC_DAPM_POST_PMD: | ||
807 | vmid_dereference(codec); | ||
808 | break; | ||
809 | } | ||
810 | |||
811 | return 0; | ||
812 | } | ||
813 | |||
684 | static void wm8994_update_class_w(struct snd_soc_codec *codec) | 814 | static void wm8994_update_class_w(struct snd_soc_codec *codec) |
685 | { | 815 | { |
686 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 816 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
@@ -1208,6 +1338,8 @@ SND_SOC_DAPM_INPUT("Clock"), | |||
1208 | 1338 | ||
1209 | SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev, | 1339 | SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev, |
1210 | SND_SOC_DAPM_PRE_PMU), | 1340 | SND_SOC_DAPM_PRE_PMU), |
1341 | SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, vmid_event, | ||
1342 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
1211 | 1343 | ||
1212 | SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, | 1344 | SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, |
1213 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | 1345 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
@@ -1525,6 +1657,8 @@ static const struct snd_soc_dapm_route wm8994_revd_intercon[] = { | |||
1525 | static const struct snd_soc_dapm_route wm8994_intercon[] = { | 1657 | static const struct snd_soc_dapm_route wm8994_intercon[] = { |
1526 | { "AIF2DACL", NULL, "AIF2DAC Mux" }, | 1658 | { "AIF2DACL", NULL, "AIF2DAC Mux" }, |
1527 | { "AIF2DACR", NULL, "AIF2DAC Mux" }, | 1659 | { "AIF2DACR", NULL, "AIF2DAC Mux" }, |
1660 | { "MICBIAS1", NULL, "VMID" }, | ||
1661 | { "MICBIAS2", NULL, "VMID" }, | ||
1528 | }; | 1662 | }; |
1529 | 1663 | ||
1530 | static const struct snd_soc_dapm_route wm8958_intercon[] = { | 1664 | static const struct snd_soc_dapm_route wm8958_intercon[] = { |
@@ -1629,10 +1763,12 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
1629 | unsigned int freq_in, unsigned int freq_out) | 1763 | unsigned int freq_in, unsigned int freq_out) |
1630 | { | 1764 | { |
1631 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 1765 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
1766 | struct wm8994 *control = codec->control_data; | ||
1632 | int reg_offset, ret; | 1767 | int reg_offset, ret; |
1633 | struct fll_div fll; | 1768 | struct fll_div fll; |
1634 | u16 reg, aif1, aif2; | 1769 | u16 reg, aif1, aif2; |
1635 | unsigned long timeout; | 1770 | unsigned long timeout; |
1771 | bool was_enabled; | ||
1636 | 1772 | ||
1637 | aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) | 1773 | aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) |
1638 | & WM8994_AIF1CLK_ENA; | 1774 | & WM8994_AIF1CLK_ENA; |
@@ -1653,6 +1789,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
1653 | return -EINVAL; | 1789 | return -EINVAL; |
1654 | } | 1790 | } |
1655 | 1791 | ||
1792 | reg = snd_soc_read(codec, WM8994_FLL1_CONTROL_1 + reg_offset); | ||
1793 | was_enabled = reg & WM8994_FLL1_ENA; | ||
1794 | |||
1656 | switch (src) { | 1795 | switch (src) { |
1657 | case 0: | 1796 | case 0: |
1658 | /* Allow no source specification when stopping */ | 1797 | /* Allow no source specification when stopping */ |
@@ -1719,6 +1858,21 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
1719 | 1858 | ||
1720 | /* Enable (with fractional mode if required) */ | 1859 | /* Enable (with fractional mode if required) */ |
1721 | if (freq_out) { | 1860 | if (freq_out) { |
1861 | /* Enable VMID if we need it */ | ||
1862 | if (!was_enabled) { | ||
1863 | switch (control->type) { | ||
1864 | case WM8994: | ||
1865 | vmid_reference(codec); | ||
1866 | break; | ||
1867 | case WM8958: | ||
1868 | if (wm8994->revision < 1) | ||
1869 | vmid_reference(codec); | ||
1870 | break; | ||
1871 | default: | ||
1872 | break; | ||
1873 | } | ||
1874 | } | ||
1875 | |||
1722 | if (fll.k) | 1876 | if (fll.k) |
1723 | reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC; | 1877 | reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC; |
1724 | else | 1878 | else |
@@ -1736,6 +1890,20 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
1736 | } else { | 1890 | } else { |
1737 | msleep(5); | 1891 | msleep(5); |
1738 | } | 1892 | } |
1893 | } else { | ||
1894 | if (was_enabled) { | ||
1895 | switch (control->type) { | ||
1896 | case WM8994: | ||
1897 | vmid_dereference(codec); | ||
1898 | break; | ||
1899 | case WM8958: | ||
1900 | if (wm8994->revision < 1) | ||
1901 | vmid_dereference(codec); | ||
1902 | break; | ||
1903 | default: | ||
1904 | break; | ||
1905 | } | ||
1906 | } | ||
1739 | } | 1907 | } |
1740 | 1908 | ||
1741 | wm8994->fll[id].in = freq_in; | 1909 | wm8994->fll[id].in = freq_in; |
@@ -1852,9 +2020,6 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
1852 | break; | 2020 | break; |
1853 | 2021 | ||
1854 | case SND_SOC_BIAS_PREPARE: | 2022 | case SND_SOC_BIAS_PREPARE: |
1855 | /* VMID=2x40k */ | ||
1856 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | ||
1857 | WM8994_VMID_SEL_MASK, 0x2); | ||
1858 | break; | 2023 | break; |
1859 | 2024 | ||
1860 | case SND_SOC_BIAS_STANDBY: | 2025 | case SND_SOC_BIAS_STANDBY: |
@@ -1896,65 +2061,13 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
1896 | WM8994_LINEOUT2_DISCH, | 2061 | WM8994_LINEOUT2_DISCH, |
1897 | WM8994_LINEOUT1_DISCH | | 2062 | WM8994_LINEOUT1_DISCH | |
1898 | WM8994_LINEOUT2_DISCH); | 2063 | WM8994_LINEOUT2_DISCH); |
1899 | |||
1900 | /* Startup bias, VMID ramp & buffer */ | ||
1901 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
1902 | WM8994_STARTUP_BIAS_ENA | | ||
1903 | WM8994_VMID_BUF_ENA | | ||
1904 | WM8994_VMID_RAMP_MASK, | ||
1905 | WM8994_STARTUP_BIAS_ENA | | ||
1906 | WM8994_VMID_BUF_ENA | | ||
1907 | (0x11 << WM8994_VMID_RAMP_SHIFT)); | ||
1908 | |||
1909 | /* Main bias enable, VMID=2x40k */ | ||
1910 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | ||
1911 | WM8994_BIAS_ENA | | ||
1912 | WM8994_VMID_SEL_MASK, | ||
1913 | WM8994_BIAS_ENA | 0x2); | ||
1914 | |||
1915 | msleep(20); | ||
1916 | } | 2064 | } |
1917 | 2065 | ||
1918 | /* VMID=2x500k */ | ||
1919 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | ||
1920 | WM8994_VMID_SEL_MASK, 0x4); | ||
1921 | 2066 | ||
1922 | break; | 2067 | break; |
1923 | 2068 | ||
1924 | case SND_SOC_BIAS_OFF: | 2069 | case SND_SOC_BIAS_OFF: |
1925 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { | 2070 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { |
1926 | /* Switch over to startup biases */ | ||
1927 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
1928 | WM8994_BIAS_SRC | | ||
1929 | WM8994_STARTUP_BIAS_ENA | | ||
1930 | WM8994_VMID_BUF_ENA | | ||
1931 | WM8994_VMID_RAMP_MASK, | ||
1932 | WM8994_BIAS_SRC | | ||
1933 | WM8994_STARTUP_BIAS_ENA | | ||
1934 | WM8994_VMID_BUF_ENA | | ||
1935 | (1 << WM8994_VMID_RAMP_SHIFT)); | ||
1936 | |||
1937 | /* Disable main biases */ | ||
1938 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | ||
1939 | WM8994_BIAS_ENA | | ||
1940 | WM8994_VMID_SEL_MASK, 0); | ||
1941 | |||
1942 | /* Discharge line */ | ||
1943 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, | ||
1944 | WM8994_LINEOUT1_DISCH | | ||
1945 | WM8994_LINEOUT2_DISCH, | ||
1946 | WM8994_LINEOUT1_DISCH | | ||
1947 | WM8994_LINEOUT2_DISCH); | ||
1948 | |||
1949 | msleep(5); | ||
1950 | |||
1951 | /* Switch off startup biases */ | ||
1952 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
1953 | WM8994_BIAS_SRC | | ||
1954 | WM8994_STARTUP_BIAS_ENA | | ||
1955 | WM8994_VMID_BUF_ENA | | ||
1956 | WM8994_VMID_RAMP_MASK, 0); | ||
1957 | |||
1958 | wm8994->cur_fw = NULL; | 2071 | wm8994->cur_fw = NULL; |
1959 | 2072 | ||
1960 | pm_runtime_put(codec->dev); | 2073 | pm_runtime_put(codec->dev); |
@@ -2384,6 +2497,21 @@ static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate) | |||
2384 | return snd_soc_update_bits(codec, reg, mask, val); | 2497 | return snd_soc_update_bits(codec, reg, mask, val); |
2385 | } | 2498 | } |
2386 | 2499 | ||
2500 | static int wm8994_aif2_probe(struct snd_soc_dai *dai) | ||
2501 | { | ||
2502 | struct snd_soc_codec *codec = dai->codec; | ||
2503 | |||
2504 | /* Disable the pulls on the AIF if we're using it to save power. */ | ||
2505 | snd_soc_update_bits(codec, WM8994_GPIO_3, | ||
2506 | WM8994_GPN_PU | WM8994_GPN_PD, 0); | ||
2507 | snd_soc_update_bits(codec, WM8994_GPIO_4, | ||
2508 | WM8994_GPN_PU | WM8994_GPN_PD, 0); | ||
2509 | snd_soc_update_bits(codec, WM8994_GPIO_5, | ||
2510 | WM8994_GPN_PU | WM8994_GPN_PD, 0); | ||
2511 | |||
2512 | return 0; | ||
2513 | } | ||
2514 | |||
2387 | #define WM8994_RATES SNDRV_PCM_RATE_8000_96000 | 2515 | #define WM8994_RATES SNDRV_PCM_RATE_8000_96000 |
2388 | 2516 | ||
2389 | #define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 2517 | #define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
@@ -2451,6 +2579,7 @@ static struct snd_soc_dai_driver wm8994_dai[] = { | |||
2451 | .rates = WM8994_RATES, | 2579 | .rates = WM8994_RATES, |
2452 | .formats = WM8994_FORMATS, | 2580 | .formats = WM8994_FORMATS, |
2453 | }, | 2581 | }, |
2582 | .probe = wm8994_aif2_probe, | ||
2454 | .ops = &wm8994_aif2_dai_ops, | 2583 | .ops = &wm8994_aif2_dai_ops, |
2455 | }, | 2584 | }, |
2456 | { | 2585 | { |
@@ -2916,6 +3045,24 @@ static irqreturn_t wm8994_fifo_error(int irq, void *data) | |||
2916 | return IRQ_HANDLED; | 3045 | return IRQ_HANDLED; |
2917 | } | 3046 | } |
2918 | 3047 | ||
3048 | static irqreturn_t wm8994_temp_warn(int irq, void *data) | ||
3049 | { | ||
3050 | struct snd_soc_codec *codec = data; | ||
3051 | |||
3052 | dev_err(codec->dev, "Thermal warning\n"); | ||
3053 | |||
3054 | return IRQ_HANDLED; | ||
3055 | } | ||
3056 | |||
3057 | static irqreturn_t wm8994_temp_shut(int irq, void *data) | ||
3058 | { | ||
3059 | struct snd_soc_codec *codec = data; | ||
3060 | |||
3061 | dev_crit(codec->dev, "Thermal shutdown\n"); | ||
3062 | |||
3063 | return IRQ_HANDLED; | ||
3064 | } | ||
3065 | |||
2919 | static int wm8994_codec_probe(struct snd_soc_codec *codec) | 3066 | static int wm8994_codec_probe(struct snd_soc_codec *codec) |
2920 | { | 3067 | { |
2921 | struct wm8994 *control; | 3068 | struct wm8994 *control; |
@@ -2972,13 +3119,14 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
2972 | switch (wm8994->revision) { | 3119 | switch (wm8994->revision) { |
2973 | case 2: | 3120 | case 2: |
2974 | case 3: | 3121 | case 3: |
2975 | wm8994->hubs.dcs_codes = -5; | 3122 | wm8994->hubs.dcs_codes_l = -5; |
3123 | wm8994->hubs.dcs_codes_r = -5; | ||
2976 | wm8994->hubs.hp_startup_mode = 1; | 3124 | wm8994->hubs.hp_startup_mode = 1; |
2977 | wm8994->hubs.dcs_readback_mode = 1; | 3125 | wm8994->hubs.dcs_readback_mode = 1; |
2978 | wm8994->hubs.series_startup = 1; | 3126 | wm8994->hubs.series_startup = 1; |
2979 | break; | 3127 | break; |
2980 | default: | 3128 | default: |
2981 | wm8994->hubs.dcs_readback_mode = 1; | 3129 | wm8994->hubs.dcs_readback_mode = 2; |
2982 | break; | 3130 | break; |
2983 | } | 3131 | } |
2984 | break; | 3132 | break; |
@@ -2993,6 +3141,10 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
2993 | 3141 | ||
2994 | wm8994_request_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, | 3142 | wm8994_request_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, |
2995 | wm8994_fifo_error, "FIFO error", codec); | 3143 | wm8994_fifo_error, "FIFO error", codec); |
3144 | wm8994_request_irq(wm8994->control_data, WM8994_IRQ_TEMP_WARN, | ||
3145 | wm8994_temp_warn, "Thermal warning", codec); | ||
3146 | wm8994_request_irq(wm8994->control_data, WM8994_IRQ_TEMP_SHUT, | ||
3147 | wm8994_temp_shut, "Thermal shutdown", codec); | ||
2996 | 3148 | ||
2997 | ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_DCS_DONE, | 3149 | ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_DCS_DONE, |
2998 | wm_hubs_dcs_done, "DC servo done", | 3150 | wm_hubs_dcs_done, "DC servo done", |
@@ -3257,6 +3409,8 @@ err_irq: | |||
3257 | wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE, | 3409 | wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE, |
3258 | &wm8994->hubs); | 3410 | &wm8994->hubs); |
3259 | wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec); | 3411 | wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec); |
3412 | wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_SHUT, codec); | ||
3413 | wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_WARN, codec); | ||
3260 | err: | 3414 | err: |
3261 | kfree(wm8994); | 3415 | kfree(wm8994); |
3262 | return ret; | 3416 | return ret; |
@@ -3279,6 +3433,8 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) | |||
3279 | wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE, | 3433 | wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE, |
3280 | &wm8994->hubs); | 3434 | &wm8994->hubs); |
3281 | wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec); | 3435 | wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec); |
3436 | wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_SHUT, codec); | ||
3437 | wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_WARN, codec); | ||
3282 | 3438 | ||
3283 | switch (control->type) { | 3439 | switch (control->type) { |
3284 | case WM8994: | 3440 | case WM8994: |