aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm5100.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm5100.c')
-rw-r--r--sound/soc/codecs/wm5100.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 8d90ba9c1f5f..02c011d7512e 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -26,6 +26,7 @@
26#include <sound/pcm.h> 26#include <sound/pcm.h>
27#include <sound/pcm_params.h> 27#include <sound/pcm_params.h>
28#include <sound/soc.h> 28#include <sound/soc.h>
29#include <sound/jack.h>
29#include <sound/initval.h> 30#include <sound/initval.h>
30#include <sound/tlv.h> 31#include <sound/tlv.h>
31#include <sound/wm5100.h> 32#include <sound/wm5100.h>
@@ -68,6 +69,11 @@ struct wm5100_priv {
68 69
69 bool out_ena[2]; 70 bool out_ena[2];
70 71
72 struct snd_soc_jack *jack;
73 bool jack_detecting;
74 bool jack_mic;
75 int jack_mode;
76
71 struct wm5100_fll fll[2]; 77 struct wm5100_fll fll[2];
72 78
73 struct wm5100_pdata pdata; 79 struct wm5100_pdata pdata;
@@ -2113,6 +2119,159 @@ static int wm5100_dig_vu[] = {
2113 WM5100_DAC_DIGITAL_VOLUME_6R, 2119 WM5100_DAC_DIGITAL_VOLUME_6R,
2114}; 2120};
2115 2121
2122static void wm5100_set_detect_mode(struct snd_soc_codec *codec, int the_mode)
2123{
2124 struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
2125 struct wm5100_jack_mode *mode = &wm5100->pdata.jack_modes[the_mode];
2126
2127 BUG_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes));
2128
2129 gpio_set_value_cansleep(wm5100->pdata.hp_pol, mode->hp_pol);
2130 snd_soc_update_bits(codec, WM5100_ACCESSORY_DETECT_MODE_1,
2131 WM5100_ACCDET_BIAS_SRC_MASK |
2132 WM5100_ACCDET_SRC,
2133 (mode->bias << WM5100_ACCDET_BIAS_SRC_SHIFT) |
2134 mode->micd_src << WM5100_ACCDET_SRC_SHIFT);
2135
2136 wm5100->jack_mode = the_mode;
2137
2138 dev_dbg(codec->dev, "Set microphone polarity to %d\n",
2139 wm5100->jack_mode);
2140}
2141
2142static void wm5100_micd_irq(struct snd_soc_codec *codec)
2143{
2144 struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
2145 int val;
2146
2147 val = snd_soc_read(codec, WM5100_MIC_DETECT_3);
2148
2149 dev_dbg(codec->dev, "Microphone event: %x\n", val);
2150
2151 if (!(val & WM5100_ACCDET_VALID)) {
2152 dev_warn(codec->dev, "Microphone detection state invalid\n");
2153 return;
2154 }
2155
2156 /* No accessory, reset everything and report removal */
2157 if (!(val & WM5100_ACCDET_STS)) {
2158 dev_dbg(codec->dev, "Jack removal detected\n");
2159 wm5100->jack_mic = false;
2160 wm5100->jack_detecting = true;
2161 snd_soc_jack_report(wm5100->jack, 0,
2162 SND_JACK_LINEOUT | SND_JACK_HEADSET |
2163 SND_JACK_BTN_0);
2164
2165 snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
2166 WM5100_ACCDET_RATE_MASK,
2167 WM5100_ACCDET_RATE_MASK);
2168 return;
2169 }
2170
2171 /* If the measurement is very high we've got a microphone,
2172 * either we just detected one or if we already reported then
2173 * we've got a button release event.
2174 */
2175 if (val & 0x400) {
2176 if (wm5100->jack_detecting) {
2177 dev_dbg(codec->dev, "Microphone detected\n");
2178 wm5100->jack_mic = true;
2179 snd_soc_jack_report(wm5100->jack,
2180 SND_JACK_HEADSET,
2181 SND_JACK_HEADSET | SND_JACK_BTN_0);
2182
2183 /* Increase poll rate to give better responsiveness
2184 * for buttons */
2185 snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
2186 WM5100_ACCDET_RATE_MASK,
2187 5 << WM5100_ACCDET_RATE_SHIFT);
2188 } else {
2189 dev_dbg(codec->dev, "Mic button up\n");
2190 snd_soc_jack_report(wm5100->jack, 0, SND_JACK_BTN_0);
2191 }
2192
2193 return;
2194 }
2195
2196 /* If we detected a lower impedence during initial startup
2197 * then we probably have the wrong polarity, flip it. Don't
2198 * do this for the lowest impedences to speed up detection of
2199 * plain headphones.
2200 */
2201 if (wm5100->jack_detecting && (val & 0x3f8)) {
2202 wm5100_set_detect_mode(codec, !wm5100->jack_mode);
2203
2204 return;
2205 }
2206
2207 /* Don't distinguish between buttons, just report any low
2208 * impedence as BTN_0.
2209 */
2210 if (val & 0x3fc) {
2211 if (wm5100->jack_mic) {
2212 dev_dbg(codec->dev, "Mic button detected\n");
2213 snd_soc_jack_report(wm5100->jack, SND_JACK_BTN_0,
2214 SND_JACK_BTN_0);
2215 } else if (wm5100->jack_detecting) {
2216 dev_dbg(codec->dev, "Headphone detected\n");
2217 snd_soc_jack_report(wm5100->jack, SND_JACK_HEADPHONE,
2218 SND_JACK_HEADPHONE);
2219
2220 /* Increase the detection rate a bit for
2221 * responsiveness.
2222 */
2223 snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
2224 WM5100_ACCDET_RATE_MASK,
2225 7 << WM5100_ACCDET_RATE_SHIFT);
2226 }
2227 }
2228}
2229
2230int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
2231{
2232 struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
2233
2234 if (jack) {
2235 wm5100->jack = jack;
2236 wm5100->jack_detecting = true;
2237
2238 wm5100_set_detect_mode(codec, 0);
2239
2240 /* Slowest detection rate, gives debounce for initial
2241 * detection */
2242 snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
2243 WM5100_ACCDET_BIAS_STARTTIME_MASK |
2244 WM5100_ACCDET_RATE_MASK,
2245 (7 << WM5100_ACCDET_BIAS_STARTTIME_SHIFT) |
2246 WM5100_ACCDET_RATE_MASK);
2247
2248 /* We need the charge pump to power MICBIAS */
2249 snd_soc_dapm_force_enable_pin(&codec->dapm, "CP2");
2250 snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
2251 snd_soc_dapm_sync(&codec->dapm);
2252
2253 /* We start off just enabling microphone detection - even a
2254 * plain headphone will trigger detection.
2255 */
2256 snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
2257 WM5100_ACCDET_ENA, WM5100_ACCDET_ENA);
2258
2259 snd_soc_update_bits(codec, WM5100_INTERRUPT_STATUS_3_MASK,
2260 WM5100_IM_ACCDET_EINT, 0);
2261 } else {
2262 snd_soc_update_bits(codec, WM5100_INTERRUPT_STATUS_3_MASK,
2263 WM5100_IM_HPDET_EINT |
2264 WM5100_IM_ACCDET_EINT,
2265 WM5100_IM_HPDET_EINT |
2266 WM5100_IM_ACCDET_EINT);
2267 snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
2268 WM5100_ACCDET_ENA, 0);
2269 wm5100->jack = NULL;
2270 }
2271
2272 return 0;
2273}
2274
2116static irqreturn_t wm5100_irq(int irq, void *data) 2275static irqreturn_t wm5100_irq(int irq, void *data)
2117{ 2276{
2118 struct snd_soc_codec *codec = data; 2277 struct snd_soc_codec *codec = data;
@@ -2144,6 +2303,9 @@ static irqreturn_t wm5100_irq(int irq, void *data)
2144 complete(&wm5100->fll[1].lock); 2303 complete(&wm5100->fll[1].lock);
2145 } 2304 }
2146 2305
2306 if (irq_val & WM5100_ACCDET_EINT)
2307 wm5100_micd_irq(codec);
2308
2147 irq_val = snd_soc_read(codec, WM5100_INTERRUPT_STATUS_4); 2309 irq_val = snd_soc_read(codec, WM5100_INTERRUPT_STATUS_4);
2148 if (irq_val < 0) { 2310 if (irq_val < 0) {
2149 dev_err(codec->dev, "Failed to read IRQ status 4: %d\n", 2311 dev_err(codec->dev, "Failed to read IRQ status 4: %d\n",