diff options
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/wm8994.c | 150 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994.h | 4 |
2 files changed, 154 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 | */ | ||
2646 | static 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 | |||
2688 | done: | ||
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 | */ | ||
2712 | int 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 | } | ||
2741 | EXPORT_SYMBOL_GPL(wm8958_mic_detect); | ||
2742 | |||
2743 | static 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 | |||
2766 | out: | ||
2767 | return IRQ_HANDLED; | ||
2768 | } | ||
2769 | |||
2636 | static int wm8994_codec_probe(struct snd_soc_codec *codec) | 2770 | static 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); |
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index b8b3166e1f03..455cae6b4356 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h | |||
@@ -28,8 +28,12 @@ | |||
28 | #define WM8994_FLL_SRC_LRCLK 3 | 28 | #define WM8994_FLL_SRC_LRCLK 3 |
29 | #define WM8994_FLL_SRC_BCLK 4 | 29 | #define WM8994_FLL_SRC_BCLK 4 |
30 | 30 | ||
31 | typedef void (*wm8958_micdet_cb)(u16 status, void *data); | ||
32 | |||
31 | int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | 33 | int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, |
32 | int micbias, int det, int shrt); | 34 | int micbias, int det, int shrt); |
35 | int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | ||
36 | wm8958_micdet_cb cb, void *cb_data); | ||
33 | 37 | ||
34 | #define WM8994_CACHE_SIZE 1570 | 38 | #define WM8994_CACHE_SIZE 1570 |
35 | 39 | ||