diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-11-30 15:32:05 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-12-01 09:21:55 -0500 |
commit | af6b6fe41c4bc9e7933d66bbbf5106e0e7e6e484 (patch) | |
tree | a77dfb3341cffbf084986bdf53bd1503e2389ebc | |
parent | 157a75e664f8c811c660de1d1b9abb16a1f72579 (diff) |
ASoC: Implement support for WM1811A jack detection
The WM1811A features an advanced low power accessory detection subsystem
which allows the device to be maintained in a very low power state while
the system is idle without sacrificing any accessory detection features.
Implement software support for this, automatically managing the power
configuration of the device depending on the detected accessory.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | include/linux/mfd/wm8994/registers.h | 16 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994.c | 264 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994.h | 3 |
3 files changed, 264 insertions, 19 deletions
diff --git a/include/linux/mfd/wm8994/registers.h b/include/linux/mfd/wm8994/registers.h index 83a9caec0e43..ebfc92fdcd77 100644 --- a/include/linux/mfd/wm8994/registers.h +++ b/include/linux/mfd/wm8994/registers.h | |||
@@ -242,6 +242,7 @@ | |||
242 | #define WM8994_GPIO_4 0x703 | 242 | #define WM8994_GPIO_4 0x703 |
243 | #define WM8994_GPIO_5 0x704 | 243 | #define WM8994_GPIO_5 0x704 |
244 | #define WM8994_GPIO_6 0x705 | 244 | #define WM8994_GPIO_6 0x705 |
245 | #define WM1811_JACKDET_CTRL 0x705 | ||
245 | #define WM8994_GPIO_7 0x706 | 246 | #define WM8994_GPIO_7 0x706 |
246 | #define WM8994_GPIO_8 0x707 | 247 | #define WM8994_GPIO_8 0x707 |
247 | #define WM8994_GPIO_9 0x708 | 248 | #define WM8994_GPIO_9 0x708 |
@@ -1852,6 +1853,9 @@ | |||
1852 | /* | 1853 | /* |
1853 | * R57 (0x39) - AntiPOP (2) | 1854 | * R57 (0x39) - AntiPOP (2) |
1854 | */ | 1855 | */ |
1856 | #define WM1811_JACKDET_MODE_MASK 0x0180 /* JACKDET_MODE - [8:7] */ | ||
1857 | #define WM1811_JACKDET_MODE_SHIFT 7 /* JACKDET_MODE - [8:7] */ | ||
1858 | #define WM1811_JACKDET_MODE_WIDTH 2 /* JACKDET_MODE - [8:7] */ | ||
1855 | #define WM8994_MICB2_DISCH 0x0100 /* MICB2_DISCH */ | 1859 | #define WM8994_MICB2_DISCH 0x0100 /* MICB2_DISCH */ |
1856 | #define WM8994_MICB2_DISCH_MASK 0x0100 /* MICB2_DISCH */ | 1860 | #define WM8994_MICB2_DISCH_MASK 0x0100 /* MICB2_DISCH */ |
1857 | #define WM8994_MICB2_DISCH_SHIFT 8 /* MICB2_DISCH */ | 1861 | #define WM8994_MICB2_DISCH_SHIFT 8 /* MICB2_DISCH */ |
@@ -4187,6 +4191,18 @@ | |||
4187 | #define WM8994_STL_SEL_WIDTH 1 /* STL_SEL */ | 4191 | #define WM8994_STL_SEL_WIDTH 1 /* STL_SEL */ |
4188 | 4192 | ||
4189 | /* | 4193 | /* |
4194 | * R1797 (0x705) - JACKDET Ctrl | ||
4195 | */ | ||
4196 | #define WM1811_JACKDET_DB 0x0100 /* JACKDET_DB */ | ||
4197 | #define WM1811_JACKDET_DB_MASK 0x0100 /* JACKDET_DB */ | ||
4198 | #define WM1811_JACKDET_DB_SHIFT 8 /* JACKDET_DB */ | ||
4199 | #define WM1811_JACKDET_DB_WIDTH 1 /* JACKDET_DB */ | ||
4200 | #define WM1811_JACKDET_LVL 0x0040 /* JACKDET_LVL */ | ||
4201 | #define WM1811_JACKDET_LVL_MASK 0x0040 /* JACKDET_LVL */ | ||
4202 | #define WM1811_JACKDET_LVL_SHIFT 6 /* JACKDET_LVL */ | ||
4203 | #define WM1811_JACKDET_LVL_WIDTH 1 /* JACKDET_LVL */ | ||
4204 | |||
4205 | /* | ||
4190 | * R1824 (0x720) - Pull Control (1) | 4206 | * R1824 (0x720) - Pull Control (1) |
4191 | */ | 4207 | */ |
4192 | #define WM8994_DMICDAT2_PU 0x0800 /* DMICDAT2_PU */ | 4208 | #define WM8994_DMICDAT2_PU 0x0800 /* DMICDAT2_PU */ |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index e65745bc1003..2e28f472b963 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -38,6 +38,11 @@ | |||
38 | #include "wm8994.h" | 38 | #include "wm8994.h" |
39 | #include "wm_hubs.h" | 39 | #include "wm_hubs.h" |
40 | 40 | ||
41 | #define WM1811_JACKDET_MODE_NONE 0x0000 | ||
42 | #define WM1811_JACKDET_MODE_JACK 0x0100 | ||
43 | #define WM1811_JACKDET_MODE_MIC 0x0080 | ||
44 | #define WM1811_JACKDET_MODE_AUDIO 0x0180 | ||
45 | |||
41 | #define WM8994_NUM_DRC 3 | 46 | #define WM8994_NUM_DRC 3 |
42 | #define WM8994_NUM_EQ 3 | 47 | #define WM8994_NUM_EQ 3 |
43 | 48 | ||
@@ -55,23 +60,34 @@ static int wm8994_retune_mobile_base[] = { | |||
55 | 60 | ||
56 | static void wm8958_default_micdet(u16 status, void *data); | 61 | static void wm8958_default_micdet(u16 status, void *data); |
57 | 62 | ||
58 | static const struct { | 63 | struct wm8958_micd_rate { |
59 | int sysclk; | 64 | int sysclk; |
60 | bool idle; | 65 | bool idle; |
61 | int start; | 66 | int start; |
62 | int rate; | 67 | int rate; |
63 | } wm8958_micd_rates[] = { | 68 | }; |
69 | |||
70 | static const struct wm8958_micd_rate micdet_rates[] = { | ||
64 | { 32768, true, 1, 4 }, | 71 | { 32768, true, 1, 4 }, |
65 | { 32768, false, 1, 1 }, | 72 | { 32768, false, 1, 1 }, |
66 | { 44100 * 256, true, 7, 10 }, | 73 | { 44100 * 256, true, 7, 10 }, |
67 | { 44100 * 256, false, 7, 10 }, | 74 | { 44100 * 256, false, 7, 10 }, |
68 | }; | 75 | }; |
69 | 76 | ||
77 | static const struct wm8958_micd_rate jackdet_rates[] = { | ||
78 | { 32768, true, 0, 1 }, | ||
79 | { 32768, false, 0, 1 }, | ||
80 | { 44100 * 256, true, 7, 10 }, | ||
81 | { 44100 * 256, false, 7, 10 }, | ||
82 | }; | ||
83 | |||
70 | static void wm8958_micd_set_rate(struct snd_soc_codec *codec) | 84 | static void wm8958_micd_set_rate(struct snd_soc_codec *codec) |
71 | { | 85 | { |
72 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 86 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
73 | int best, i, sysclk, val; | 87 | int best, i, sysclk, val; |
74 | bool idle; | 88 | bool idle; |
89 | const struct wm8958_micd_rate *rates; | ||
90 | int num_rates; | ||
75 | 91 | ||
76 | if (wm8994->jack_cb != wm8958_default_micdet) | 92 | if (wm8994->jack_cb != wm8958_default_micdet) |
77 | return; | 93 | return; |
@@ -84,19 +100,27 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec) | |||
84 | else | 100 | else |
85 | sysclk = wm8994->aifclk[0]; | 101 | sysclk = wm8994->aifclk[0]; |
86 | 102 | ||
103 | if (wm8994->jackdet) { | ||
104 | rates = jackdet_rates; | ||
105 | num_rates = ARRAY_SIZE(jackdet_rates); | ||
106 | } else { | ||
107 | rates = micdet_rates; | ||
108 | num_rates = ARRAY_SIZE(micdet_rates); | ||
109 | } | ||
110 | |||
87 | best = 0; | 111 | best = 0; |
88 | for (i = 0; i < ARRAY_SIZE(wm8958_micd_rates); i++) { | 112 | for (i = 0; i < num_rates; i++) { |
89 | if (wm8958_micd_rates[i].idle != idle) | 113 | if (rates[i].idle != idle) |
90 | continue; | 114 | continue; |
91 | if (abs(wm8958_micd_rates[i].sysclk - sysclk) < | 115 | if (abs(rates[i].sysclk - sysclk) < |
92 | abs(wm8958_micd_rates[best].sysclk - sysclk)) | 116 | abs(rates[best].sysclk - sysclk)) |
93 | best = i; | 117 | best = i; |
94 | else if (wm8958_micd_rates[best].idle != idle) | 118 | else if (rates[best].idle != idle) |
95 | best = i; | 119 | best = i; |
96 | } | 120 | } |
97 | 121 | ||
98 | val = wm8958_micd_rates[best].start << WM8958_MICD_BIAS_STARTTIME_SHIFT | 122 | val = rates[best].start << WM8958_MICD_BIAS_STARTTIME_SHIFT |
99 | | wm8958_micd_rates[best].rate << WM8958_MICD_RATE_SHIFT; | 123 | | rates[best].rate << WM8958_MICD_RATE_SHIFT; |
100 | 124 | ||
101 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | 125 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, |
102 | WM8958_MICD_BIAS_STARTTIME_MASK | | 126 | WM8958_MICD_BIAS_STARTTIME_MASK | |
@@ -762,6 +786,74 @@ SOC_SINGLE_TLV("MIXINL IN1RP Boost Volume", WM8994_INPUT_MIXER_1, 8, 1, 0, | |||
762 | mixin_boost_tlv), | 786 | mixin_boost_tlv), |
763 | }; | 787 | }; |
764 | 788 | ||
789 | /* We run all mode setting through a function to enforce audio mode */ | ||
790 | static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode) | ||
791 | { | ||
792 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
793 | |||
794 | if (wm8994->active_refcount) | ||
795 | mode = WM1811_JACKDET_MODE_AUDIO; | ||
796 | |||
797 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
798 | WM1811_JACKDET_MODE_MASK, mode); | ||
799 | |||
800 | if (mode == WM1811_JACKDET_MODE_MIC) | ||
801 | msleep(2); | ||
802 | } | ||
803 | |||
804 | static void active_reference(struct snd_soc_codec *codec) | ||
805 | { | ||
806 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
807 | |||
808 | mutex_lock(&wm8994->accdet_lock); | ||
809 | |||
810 | wm8994->active_refcount++; | ||
811 | |||
812 | dev_dbg(codec->dev, "Active refcount incremented, now %d\n", | ||
813 | wm8994->active_refcount); | ||
814 | |||
815 | if (wm8994->active_refcount == 1) { | ||
816 | /* If we're using jack detection go into audio mode */ | ||
817 | if (wm8994->jackdet && wm8994->jack_cb) { | ||
818 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
819 | WM1811_JACKDET_MODE_MASK, | ||
820 | WM1811_JACKDET_MODE_AUDIO); | ||
821 | msleep(2); | ||
822 | } | ||
823 | } | ||
824 | |||
825 | mutex_unlock(&wm8994->accdet_lock); | ||
826 | } | ||
827 | |||
828 | static void active_dereference(struct snd_soc_codec *codec) | ||
829 | { | ||
830 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
831 | u16 mode; | ||
832 | |||
833 | mutex_lock(&wm8994->accdet_lock); | ||
834 | |||
835 | wm8994->active_refcount--; | ||
836 | |||
837 | dev_dbg(codec->dev, "Active refcount decremented, now %d\n", | ||
838 | wm8994->active_refcount); | ||
839 | |||
840 | if (wm8994->active_refcount == 0) { | ||
841 | /* Go into appropriate detection only mode */ | ||
842 | if (wm8994->jackdet && wm8994->jack_cb) { | ||
843 | if (wm8994->jack_mic || wm8994->mic_detecting) | ||
844 | mode = WM1811_JACKDET_MODE_MIC; | ||
845 | else | ||
846 | mode = WM1811_JACKDET_MODE_JACK; | ||
847 | |||
848 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
849 | WM1811_JACKDET_MODE_MASK, | ||
850 | mode); | ||
851 | } | ||
852 | } | ||
853 | |||
854 | mutex_unlock(&wm8994->accdet_lock); | ||
855 | } | ||
856 | |||
765 | static int clk_sys_event(struct snd_soc_dapm_widget *w, | 857 | static int clk_sys_event(struct snd_soc_dapm_widget *w, |
766 | struct snd_kcontrol *kcontrol, int event) | 858 | struct snd_kcontrol *kcontrol, int event) |
767 | { | 859 | { |
@@ -1919,6 +2011,8 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
1919 | if (freq_out) { | 2011 | if (freq_out) { |
1920 | /* Enable VMID if we need it */ | 2012 | /* Enable VMID if we need it */ |
1921 | if (!was_enabled) { | 2013 | if (!was_enabled) { |
2014 | active_reference(codec); | ||
2015 | |||
1922 | switch (control->type) { | 2016 | switch (control->type) { |
1923 | case WM8994: | 2017 | case WM8994: |
1924 | vmid_reference(codec); | 2018 | vmid_reference(codec); |
@@ -1962,6 +2056,8 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
1962 | default: | 2056 | default: |
1963 | break; | 2057 | break; |
1964 | } | 2058 | } |
2059 | |||
2060 | active_dereference(codec); | ||
1965 | } | 2061 | } |
1966 | } | 2062 | } |
1967 | 2063 | ||
@@ -2091,6 +2187,9 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
2091 | default: | 2187 | default: |
2092 | break; | 2188 | break; |
2093 | } | 2189 | } |
2190 | |||
2191 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) | ||
2192 | active_reference(codec); | ||
2094 | break; | 2193 | break; |
2095 | 2194 | ||
2096 | case SND_SOC_BIAS_STANDBY: | 2195 | case SND_SOC_BIAS_STANDBY: |
@@ -2143,6 +2242,9 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
2143 | WM8994_LINEOUT2_DISCH); | 2242 | WM8994_LINEOUT2_DISCH); |
2144 | } | 2243 | } |
2145 | 2244 | ||
2245 | if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) | ||
2246 | active_dereference(codec); | ||
2247 | |||
2146 | /* MICBIAS into bypass mode on newer devices */ | 2248 | /* MICBIAS into bypass mode on newer devices */ |
2147 | switch (control->type) { | 2249 | switch (control->type) { |
2148 | case WM8958: | 2250 | case WM8958: |
@@ -2168,6 +2270,7 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
2168 | break; | 2270 | break; |
2169 | } | 2271 | } |
2170 | codec->dapm.bias_level = level; | 2272 | codec->dapm.bias_level = level; |
2273 | |||
2171 | return 0; | 2274 | return 0; |
2172 | } | 2275 | } |
2173 | 2276 | ||
@@ -2715,6 +2818,9 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state) | |||
2715 | snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0); | 2818 | snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0); |
2716 | break; | 2819 | break; |
2717 | case WM1811: | 2820 | case WM1811: |
2821 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
2822 | WM1811_JACKDET_MODE_MASK, 0); | ||
2823 | /* Fall through */ | ||
2718 | case WM8958: | 2824 | case WM8958: |
2719 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | 2825 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, |
2720 | WM8958_MICD_ENA, 0); | 2826 | WM8958_MICD_ENA, 0); |
@@ -2784,6 +2890,13 @@ static int wm8994_resume(struct snd_soc_codec *codec) | |||
2784 | WM8994_MICD_ENA, WM8994_MICD_ENA); | 2890 | WM8994_MICD_ENA, WM8994_MICD_ENA); |
2785 | break; | 2891 | break; |
2786 | case WM1811: | 2892 | case WM1811: |
2893 | if (wm8994->jackdet && wm8994->jack_cb) { | ||
2894 | /* Restart from idle */ | ||
2895 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
2896 | WM1811_JACKDET_MODE_MASK, | ||
2897 | WM1811_JACKDET_MODE_JACK); | ||
2898 | break; | ||
2899 | } | ||
2787 | case WM8958: | 2900 | case WM8958: |
2788 | if (wm8994->jack_cb) | 2901 | if (wm8994->jack_cb) |
2789 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | 2902 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, |
@@ -3047,17 +3160,20 @@ static void wm8958_default_micdet(u16 status, void *data) | |||
3047 | 3160 | ||
3048 | dev_dbg(codec->dev, "MICDET %x\n", status); | 3161 | dev_dbg(codec->dev, "MICDET %x\n", status); |
3049 | 3162 | ||
3050 | /* If nothing present then clear our statuses */ | 3163 | /* Either nothing present or just starting detection */ |
3051 | if (!(status & WM8958_MICD_STS)) { | 3164 | if (!(status & WM8958_MICD_STS)) { |
3052 | dev_dbg(codec->dev, "Detected open circuit\n"); | 3165 | if (!wm8994->jackdet) { |
3053 | wm8994->jack_mic = false; | 3166 | /* If nothing present then clear our statuses */ |
3054 | wm8994->mic_detecting = true; | 3167 | dev_dbg(codec->dev, "Detected open circuit\n"); |
3168 | wm8994->jack_mic = false; | ||
3169 | wm8994->mic_detecting = true; | ||
3055 | 3170 | ||
3056 | wm8958_micd_set_rate(codec); | 3171 | wm8958_micd_set_rate(codec); |
3057 | |||
3058 | snd_soc_jack_report(wm8994->micdet[0].jack, 0, | ||
3059 | wm8994->btn_mask | SND_JACK_HEADSET); | ||
3060 | 3172 | ||
3173 | snd_soc_jack_report(wm8994->micdet[0].jack, 0, | ||
3174 | wm8994->btn_mask | | ||
3175 | SND_JACK_HEADSET); | ||
3176 | } | ||
3061 | return; | 3177 | return; |
3062 | } | 3178 | } |
3063 | 3179 | ||
@@ -3085,6 +3201,15 @@ static void wm8958_default_micdet(u16 status, void *data) | |||
3085 | 3201 | ||
3086 | snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE, | 3202 | snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE, |
3087 | SND_JACK_HEADSET); | 3203 | SND_JACK_HEADSET); |
3204 | |||
3205 | /* If we have jackdet that will detect removal */ | ||
3206 | if (wm8994->jackdet) { | ||
3207 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | ||
3208 | WM8958_MICD_ENA, 0); | ||
3209 | |||
3210 | wm1811_jackdet_set_mode(codec, | ||
3211 | WM1811_JACKDET_MODE_JACK); | ||
3212 | } | ||
3088 | } | 3213 | } |
3089 | 3214 | ||
3090 | /* Report short circuit as a button */ | 3215 | /* Report short circuit as a button */ |
@@ -3113,6 +3238,56 @@ static void wm8958_default_micdet(u16 status, void *data) | |||
3113 | } | 3238 | } |
3114 | } | 3239 | } |
3115 | 3240 | ||
3241 | static irqreturn_t wm1811_jackdet_irq(int irq, void *data) | ||
3242 | { | ||
3243 | struct wm8994_priv *wm8994 = data; | ||
3244 | struct snd_soc_codec *codec = wm8994->codec; | ||
3245 | int reg; | ||
3246 | |||
3247 | mutex_lock(&wm8994->accdet_lock); | ||
3248 | |||
3249 | reg = snd_soc_read(codec, WM1811_JACKDET_CTRL); | ||
3250 | if (reg < 0) { | ||
3251 | dev_err(codec->dev, "Failed to read jack status: %d\n", reg); | ||
3252 | mutex_unlock(&wm8994->accdet_lock); | ||
3253 | return IRQ_NONE; | ||
3254 | } | ||
3255 | |||
3256 | dev_dbg(codec->dev, "JACKDET %x\n", reg); | ||
3257 | |||
3258 | if (reg & WM1811_JACKDET_LVL) { | ||
3259 | dev_dbg(codec->dev, "Jack detected\n"); | ||
3260 | |||
3261 | snd_soc_jack_report(wm8994->micdet[0].jack, | ||
3262 | SND_JACK_MECHANICAL, SND_JACK_MECHANICAL); | ||
3263 | |||
3264 | /* | ||
3265 | * Start off measument of microphone impedence to find | ||
3266 | * out what's actually there. | ||
3267 | */ | ||
3268 | wm8994->mic_detecting = true; | ||
3269 | wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_MIC); | ||
3270 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | ||
3271 | WM8958_MICD_ENA, WM8958_MICD_ENA); | ||
3272 | } else { | ||
3273 | dev_dbg(codec->dev, "Jack not detected\n"); | ||
3274 | |||
3275 | snd_soc_jack_report(wm8994->micdet[0].jack, 0, | ||
3276 | SND_JACK_MECHANICAL | SND_JACK_HEADSET | | ||
3277 | wm8994->btn_mask); | ||
3278 | |||
3279 | wm8994->mic_detecting = false; | ||
3280 | wm8994->jack_mic = false; | ||
3281 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | ||
3282 | WM8958_MICD_ENA, 0); | ||
3283 | wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK); | ||
3284 | } | ||
3285 | |||
3286 | mutex_unlock(&wm8994->accdet_lock); | ||
3287 | |||
3288 | return IRQ_HANDLED; | ||
3289 | } | ||
3290 | |||
3116 | /** | 3291 | /** |
3117 | * wm8958_mic_detect - Enable microphone detection via the WM8958 IRQ | 3292 | * wm8958_mic_detect - Enable microphone detection via the WM8958 IRQ |
3118 | * | 3293 | * |
@@ -3175,8 +3350,22 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | |||
3175 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_2, | 3350 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_2, |
3176 | WM8958_MICD_LVL_SEL_MASK, micd_lvl_sel); | 3351 | WM8958_MICD_LVL_SEL_MASK, micd_lvl_sel); |
3177 | 3352 | ||
3178 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | 3353 | WARN_ON(codec->dapm.bias_level > SND_SOC_BIAS_STANDBY); |
3179 | WM8958_MICD_ENA, WM8958_MICD_ENA); | 3354 | |
3355 | /* | ||
3356 | * If we can use jack detection start off with that, | ||
3357 | * otherwise jump straight to microphone detection. | ||
3358 | */ | ||
3359 | if (wm8994->jackdet) { | ||
3360 | snd_soc_update_bits(codec, WM8994_LDO_1, | ||
3361 | WM8994_LDO1_DISCH, 0); | ||
3362 | wm1811_jackdet_set_mode(codec, | ||
3363 | WM1811_JACKDET_MODE_JACK); | ||
3364 | } else { | ||
3365 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | ||
3366 | WM8958_MICD_ENA, WM8958_MICD_ENA); | ||
3367 | } | ||
3368 | |||
3180 | } else { | 3369 | } else { |
3181 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | 3370 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, |
3182 | WM8958_MICD_ENA, 0); | 3371 | WM8958_MICD_ENA, 0); |
@@ -3193,6 +3382,18 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) | |||
3193 | struct snd_soc_codec *codec = wm8994->codec; | 3382 | struct snd_soc_codec *codec = wm8994->codec; |
3194 | int reg, count; | 3383 | int reg, count; |
3195 | 3384 | ||
3385 | mutex_lock(&wm8994->accdet_lock); | ||
3386 | |||
3387 | /* | ||
3388 | * Jack detection may have detected a removal simulataneously | ||
3389 | * with an update of the MICDET status; if so it will have | ||
3390 | * stopped detection and we can ignore this interrupt. | ||
3391 | */ | ||
3392 | if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA)) { | ||
3393 | mutex_unlock(&wm8994->accdet_lock); | ||
3394 | return IRQ_HANDLED; | ||
3395 | } | ||
3396 | |||
3196 | /* We may occasionally read a detection without an impedence | 3397 | /* We may occasionally read a detection without an impedence |
3197 | * range being provided - if that happens loop again. | 3398 | * range being provided - if that happens loop again. |
3198 | */ | 3399 | */ |
@@ -3200,6 +3401,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) | |||
3200 | do { | 3401 | do { |
3201 | reg = snd_soc_read(codec, WM8958_MIC_DETECT_3); | 3402 | reg = snd_soc_read(codec, WM8958_MIC_DETECT_3); |
3202 | if (reg < 0) { | 3403 | if (reg < 0) { |
3404 | mutex_unlock(&wm8994->accdet_lock); | ||
3203 | dev_err(codec->dev, | 3405 | dev_err(codec->dev, |
3204 | "Failed to read mic detect status: %d\n", | 3406 | "Failed to read mic detect status: %d\n", |
3205 | reg); | 3407 | reg); |
@@ -3230,6 +3432,8 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) | |||
3230 | dev_warn(codec->dev, "Accessory detection with no callback\n"); | 3432 | dev_warn(codec->dev, "Accessory detection with no callback\n"); |
3231 | 3433 | ||
3232 | out: | 3434 | out: |
3435 | mutex_unlock(&wm8994->accdet_lock); | ||
3436 | |||
3233 | return IRQ_HANDLED; | 3437 | return IRQ_HANDLED; |
3234 | } | 3438 | } |
3235 | 3439 | ||
@@ -3280,6 +3484,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3280 | wm8994->pdata = dev_get_platdata(codec->dev->parent); | 3484 | wm8994->pdata = dev_get_platdata(codec->dev->parent); |
3281 | wm8994->codec = codec; | 3485 | wm8994->codec = codec; |
3282 | 3486 | ||
3487 | mutex_init(&wm8994->accdet_lock); | ||
3488 | |||
3283 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) | 3489 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) |
3284 | init_completion(&wm8994->fll_locked[i]); | 3490 | init_completion(&wm8994->fll_locked[i]); |
3285 | 3491 | ||
@@ -3428,6 +3634,21 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3428 | } | 3634 | } |
3429 | } | 3635 | } |
3430 | 3636 | ||
3637 | switch (control->type) { | ||
3638 | case WM1811: | ||
3639 | if (wm8994->revision > 1) { | ||
3640 | ret = wm8994_request_irq(wm8994->wm8994, | ||
3641 | WM8994_IRQ_GPIO(6), | ||
3642 | wm1811_jackdet_irq, "JACKDET", | ||
3643 | wm8994); | ||
3644 | if (ret == 0) | ||
3645 | wm8994->jackdet = true; | ||
3646 | } | ||
3647 | break; | ||
3648 | default: | ||
3649 | break; | ||
3650 | } | ||
3651 | |||
3431 | wm8994->fll_locked_irq = true; | 3652 | wm8994->fll_locked_irq = true; |
3432 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) { | 3653 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) { |
3433 | ret = wm8994_request_irq(wm8994->wm8994, | 3654 | ret = wm8994_request_irq(wm8994->wm8994, |
@@ -3650,6 +3871,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3650 | return 0; | 3871 | return 0; |
3651 | 3872 | ||
3652 | err_irq: | 3873 | err_irq: |
3874 | if (wm8994->jackdet) | ||
3875 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_GPIO(6), wm8994); | ||
3653 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC2_SHRT, wm8994); | 3876 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC2_SHRT, wm8994); |
3654 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC2_DET, wm8994); | 3877 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC2_DET, wm8994); |
3655 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC1_SHRT, wm8994); | 3878 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC1_SHRT, wm8994); |
@@ -3688,6 +3911,9 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) | |||
3688 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT, codec); | 3911 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT, codec); |
3689 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN, codec); | 3912 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN, codec); |
3690 | 3913 | ||
3914 | if (wm8994->jackdet) | ||
3915 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_GPIO(6), wm8994); | ||
3916 | |||
3691 | switch (control->type) { | 3917 | switch (control->type) { |
3692 | case WM8994: | 3918 | case WM8994: |
3693 | if (wm8994->micdet_irq) | 3919 | if (wm8994->micdet_irq) |
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 8622bc4db2fe..6ef3f11878c6 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h | |||
@@ -85,6 +85,7 @@ struct wm8994_priv { | |||
85 | bool fll_locked_irq; | 85 | bool fll_locked_irq; |
86 | 86 | ||
87 | int vmid_refcount; | 87 | int vmid_refcount; |
88 | int active_refcount; | ||
88 | 89 | ||
89 | int dac_rates[2]; | 90 | int dac_rates[2]; |
90 | int lrclk_shared[2]; | 91 | int lrclk_shared[2]; |
@@ -126,10 +127,12 @@ struct wm8994_priv { | |||
126 | const char **enh_eq_texts; | 127 | const char **enh_eq_texts; |
127 | struct soc_enum enh_eq_enum; | 128 | struct soc_enum enh_eq_enum; |
128 | 129 | ||
130 | struct mutex accdet_lock; | ||
129 | struct wm8994_micdet micdet[2]; | 131 | struct wm8994_micdet micdet[2]; |
130 | bool mic_detecting; | 132 | bool mic_detecting; |
131 | bool jack_mic; | 133 | bool jack_mic; |
132 | int btn_mask; | 134 | int btn_mask; |
135 | bool jackdet; | ||
133 | 136 | ||
134 | wm8958_micdet_cb jack_cb; | 137 | wm8958_micdet_cb jack_cb; |
135 | void *jack_cb_data; | 138 | void *jack_cb_data; |