aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8994.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-11-26 10:21:09 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-11-27 05:32:13 -0500
commit821edd2fb5b289b84d715fb744106019fa2e1920 (patch)
tree22a51de4e306c7616ce43b182db9827f2a077b4c /sound/soc/codecs/wm8994.c
parentd6addcc9d88aeac4a0cc63a06d36baef04f5dc3b (diff)
ASoC: Add WM8958 microphone detection support
The WM8958 contains an advanced accessory detection feature which allows detection of up to seven different impedence levels on the microphone bias output, including detection of video outputs. Since some of the more involved accessory interfaces may involve noticable interactions with external components a simple detection scheme is provided by default with the option to provide custom handling of accessory detect. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/codecs/wm8994.c')
-rw-r--r--sound/soc/codecs/wm8994.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index b30b2dd3f1f4..948677b581b1 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -21,6 +21,7 @@
21#include <linux/regulator/consumer.h> 21#include <linux/regulator/consumer.h>
22#include <linux/slab.h> 22#include <linux/slab.h>
23#include <sound/core.h> 23#include <sound/core.h>
24#include <sound/jack.h>
24#include <sound/pcm.h> 25#include <sound/pcm.h>
25#include <sound/pcm_params.h> 26#include <sound/pcm_params.h>
26#include <sound/soc.h> 27#include <sound/soc.h>
@@ -95,6 +96,11 @@ struct wm8994_priv {
95 96
96 struct wm8994_micdet micdet[2]; 97 struct wm8994_micdet micdet[2];
97 98
99 wm8958_micdet_cb jack_cb;
100 void *jack_cb_data;
101 bool jack_is_mic;
102 bool jack_is_video;
103
98 int revision; 104 int revision;
99 struct wm8994_pdata *pdata; 105 struct wm8994_pdata *pdata;
100}; 106};
@@ -140,6 +146,7 @@ static int wm8994_volatile(unsigned int reg)
140 case WM8994_LDO_1: 146 case WM8994_LDO_1:
141 case WM8994_LDO_2: 147 case WM8994_LDO_2:
142 case WM8958_DSP2_EXECCONTROL: 148 case WM8958_DSP2_EXECCONTROL:
149 case WM8958_MIC_DETECT_3:
143 return 1; 150 return 1;
144 default: 151 default:
145 return 0; 152 return 0;
@@ -2633,6 +2640,133 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
2633 return IRQ_HANDLED; 2640 return IRQ_HANDLED;
2634} 2641}
2635 2642
2643/* Default microphone detection handler for WM8958 - the user can
2644 * override this if they wish.
2645 */
2646static void wm8958_default_micdet(u16 status, void *data)
2647{
2648 struct snd_soc_codec *codec = data;
2649 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
2650 int report = 0;
2651
2652 /* If nothing present then clear our statuses */
2653 if (!(status & WM8958_MICD_STS)) {
2654 wm8994->jack_is_video = false;
2655 wm8994->jack_is_mic = false;
2656 goto done;
2657 }
2658
2659 /* Assume anything over 475 ohms is a microphone and remember
2660 * that we've seen one (since buttons override it) */
2661 if (status & 0x600)
2662 wm8994->jack_is_mic = true;
2663 if (wm8994->jack_is_mic)
2664 report |= SND_JACK_MICROPHONE;
2665
2666 /* Video has an impedence of approximately 75 ohms; assume
2667 * this isn't used as a button and remember it since buttons
2668 * override it. */
2669 if (status & 0x40)
2670 wm8994->jack_is_video = true;
2671 if (wm8994->jack_is_video)
2672 report |= SND_JACK_VIDEOOUT;
2673
2674 /* Everything else is buttons; just assign slots */
2675 if (status & 0x4)
2676 report |= SND_JACK_BTN_0;
2677 if (status & 0x8)
2678 report |= SND_JACK_BTN_1;
2679 if (status & 0x10)
2680 report |= SND_JACK_BTN_2;
2681 if (status & 0x20)
2682 report |= SND_JACK_BTN_3;
2683 if (status & 0x80)
2684 report |= SND_JACK_BTN_4;
2685 if (status & 0x100)
2686 report |= SND_JACK_BTN_5;
2687
2688done:
2689 snd_soc_jack_report(wm8994->micdet[0].jack,
2690 SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
2691 SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5 |
2692 SND_JACK_MICROPHONE | SND_JACK_VIDEOOUT,
2693 report);
2694}
2695
2696/**
2697 * wm8958_mic_detect - Enable microphone detection via the WM8958 IRQ
2698 *
2699 * @codec: WM8958 codec
2700 * @jack: jack to report detection events on
2701 *
2702 * Enable microphone detection functionality for the WM8958. By
2703 * default simple detection which supports the detection of up to 6
2704 * buttons plus video and microphone functionality is supported.
2705 *
2706 * The WM8958 has an advanced jack detection facility which is able to
2707 * support complex accessory detection, especially when used in
2708 * conjunction with external circuitry. In order to provide maximum
2709 * flexiblity a callback is provided which allows a completely custom
2710 * detection algorithm.
2711 */
2712int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
2713 wm8958_micdet_cb cb, void *cb_data)
2714{
2715 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
2716 struct wm8994 *control = codec->control_data;
2717
2718 if (control->type != WM8958)
2719 return -EINVAL;
2720
2721 if (jack) {
2722 if (!cb) {
2723 dev_dbg(codec->dev, "Using default micdet callback\n");
2724 cb = wm8958_default_micdet;
2725 cb_data = codec;
2726 }
2727
2728 wm8994->micdet[0].jack = jack;
2729 wm8994->jack_cb = cb;
2730 wm8994->jack_cb_data = cb_data;
2731
2732 snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
2733 WM8958_MICD_ENA, WM8958_MICD_ENA);
2734 } else {
2735 snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
2736 WM8958_MICD_ENA, 0);
2737 }
2738
2739 return 0;
2740}
2741EXPORT_SYMBOL_GPL(wm8958_mic_detect);
2742
2743static irqreturn_t wm8958_mic_irq(int irq, void *data)
2744{
2745 struct wm8994_priv *wm8994 = data;
2746 struct snd_soc_codec *codec = wm8994->codec;
2747 int reg;
2748
2749 reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
2750 if (reg < 0) {
2751 dev_err(codec->dev, "Failed to read mic detect status: %d\n",
2752 reg);
2753 return IRQ_NONE;
2754 }
2755
2756 if (!(reg & WM8958_MICD_VALID)) {
2757 dev_dbg(codec->dev, "Mic detect data not valid\n");
2758 goto out;
2759 }
2760
2761 if (wm8994->jack_cb)
2762 wm8994->jack_cb(reg, wm8994->jack_cb_data);
2763 else
2764 dev_warn(codec->dev, "Accessory detection with no callback\n");
2765
2766out:
2767 return IRQ_HANDLED;
2768}
2769
2636static int wm8994_codec_probe(struct snd_soc_codec *codec) 2770static int wm8994_codec_probe(struct snd_soc_codec *codec)
2637{ 2771{
2638 struct wm8994 *control; 2772 struct wm8994 *control;
@@ -2732,6 +2866,17 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
2732 "Failed to request Mic2 short IRQ: %d\n", 2866 "Failed to request Mic2 short IRQ: %d\n",
2733 ret); 2867 ret);
2734 break; 2868 break;
2869
2870 case WM8958:
2871 ret = wm8994_request_irq(codec->control_data,
2872 WM8994_IRQ_MIC1_DET,
2873 wm8958_mic_irq, "Mic detect",
2874 wm8994);
2875 if (ret != 0)
2876 dev_warn(codec->dev,
2877 "Failed to request Mic detect IRQ: %d\n",
2878 ret);
2879 break;
2735 } 2880 }
2736 2881
2737 /* Remember if AIFnLRCLK is configured as a GPIO. This should be 2882 /* Remember if AIFnLRCLK is configured as a GPIO. This should be
@@ -2866,6 +3011,11 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
2866 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, 3011 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
2867 wm8994); 3012 wm8994);
2868 break; 3013 break;
3014
3015 case WM8958:
3016 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
3017 wm8994);
3018 break;
2869 } 3019 }
2870 kfree(wm8994->retune_mobile_texts); 3020 kfree(wm8994->retune_mobile_texts);
2871 kfree(wm8994->drc_texts); 3021 kfree(wm8994->drc_texts);