aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-03-29 15:57:12 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-04-05 14:18:12 -0400
commit8876698406147986a9a7748586a54c4b14514c0e (patch)
tree6353c911b3d62ffb67c44d1459436fd434992546 /sound/soc/codecs
parentddf438cf2a6de9aa47783a45907e1188b9437ff7 (diff)
ASoC: Implement interrupt based WM8994 microphone detection
Support interrupt based microphone bias detection. The WM8994 has two microphone bias supplies, with detection supported on both. Detection using GPIOs together with the standard GPIO based jack framework is already supported via the platform data for the WM8994 core driver. Note that as well as the microphone bias itself the system clock and whichever AIF clock is supplying the system clock will need to be enabled for detection to function. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/wm8994.c137
-rw-r--r--sound/soc/codecs/wm8994.h3
2 files changed, 137 insertions, 3 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index bdda0936a404..fc3dce814924 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -61,6 +61,12 @@ static int wm8994_retune_mobile_base[] = {
61 61
62#define WM8994_REG_CACHE_SIZE 0x621 62#define WM8994_REG_CACHE_SIZE 0x621
63 63
64struct wm8994_micdet {
65 struct snd_soc_jack *jack;
66 int det;
67 int shrt;
68};
69
64/* codec private data */ 70/* codec private data */
65struct wm8994_priv { 71struct wm8994_priv {
66 struct wm_hubs_data hubs; 72 struct wm_hubs_data hubs;
@@ -86,6 +92,8 @@ struct wm8994_priv {
86 int retune_mobile_cfg[WM8994_NUM_EQ]; 92 int retune_mobile_cfg[WM8994_NUM_EQ];
87 struct soc_enum retune_mobile_enum; 93 struct soc_enum retune_mobile_enum;
88 94
95 struct wm8994_micdet micdet[2];
96
89 struct wm8994_pdata *pdata; 97 struct wm8994_pdata *pdata;
90}; 98};
91 99
@@ -3702,6 +3710,96 @@ struct snd_soc_codec_device soc_codec_dev_wm8994 = {
3702}; 3710};
3703EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994); 3711EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994);
3704 3712
3713/**
3714 * wm8994_mic_detect - Enable microphone detection via the WM8994 IRQ
3715 *
3716 * @codec: WM8994 codec
3717 * @jack: jack to report detection events on
3718 * @micbias: microphone bias to detect on
3719 * @det: value to report for presence detection
3720 * @shrt: value to report for short detection
3721 *
3722 * Enable microphone detection via IRQ on the WM8994. If GPIOs are
3723 * being used to bring out signals to the processor then only platform
3724 * data configuration is needed for WM8903 and processor GPIOs should
3725 * be configured using snd_soc_jack_add_gpios() instead.
3726 *
3727 * Configuration of detection levels is available via the micbias1_lvl
3728 * and micbias2_lvl platform data members.
3729 */
3730int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
3731 int micbias, int det, int shrt)
3732{
3733 struct wm8994_priv *wm8994 = codec->private_data;
3734 struct wm8994_micdet *micdet;
3735 int reg;
3736
3737 switch (micbias) {
3738 case 1:
3739 micdet = &wm8994->micdet[0];
3740 break;
3741 case 2:
3742 micdet = &wm8994->micdet[1];
3743 break;
3744 default:
3745 return -EINVAL;
3746 }
3747
3748 dev_dbg(codec->dev, "Configuring microphone detection on %d: %x %x\n",
3749 micbias, det, shrt);
3750
3751 /* Store the configuration */
3752 micdet->jack = jack;
3753 micdet->det = det;
3754 micdet->shrt = shrt;
3755
3756 /* If either of the jacks is set up then enable detection */
3757 if (wm8994->micdet[0].jack || wm8994->micdet[1].jack)
3758 reg = WM8994_MICD_ENA;
3759 else
3760 reg = 0;
3761
3762 snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg);
3763
3764 return 0;
3765}
3766EXPORT_SYMBOL_GPL(wm8994_mic_detect);
3767
3768static irqreturn_t wm8994_mic_irq(int irq, void *data)
3769{
3770 struct wm8994_priv *priv = data;
3771 struct snd_soc_codec *codec = &priv->codec;
3772 int reg;
3773 int report;
3774
3775 reg = snd_soc_read(codec, WM8994_INTERRUPT_RAW_STATUS_2);
3776 if (reg < 0) {
3777 dev_err(codec->dev, "Failed to read microphone status: %d\n",
3778 reg);
3779 return IRQ_HANDLED;
3780 }
3781
3782 dev_dbg(codec->dev, "Microphone status: %x\n", reg);
3783
3784 report = 0;
3785 if (reg & WM8994_MIC1_DET_STS)
3786 report |= priv->micdet[0].det;
3787 if (reg & WM8994_MIC1_SHRT_STS)
3788 report |= priv->micdet[0].shrt;
3789 snd_soc_jack_report(priv->micdet[0].jack, report,
3790 priv->micdet[0].det | priv->micdet[0].shrt);
3791
3792 report = 0;
3793 if (reg & WM8994_MIC2_DET_STS)
3794 report |= priv->micdet[1].det;
3795 if (reg & WM8994_MIC2_SHRT_STS)
3796 report |= priv->micdet[1].shrt;
3797 snd_soc_jack_report(priv->micdet[1].jack, report,
3798 priv->micdet[1].det | priv->micdet[1].shrt);
3799
3800 return IRQ_HANDLED;
3801}
3802
3705static int wm8994_codec_probe(struct platform_device *pdev) 3803static int wm8994_codec_probe(struct platform_device *pdev)
3706{ 3804{
3707 int ret; 3805 int ret;
@@ -3774,6 +3872,30 @@ static int wm8994_codec_probe(struct platform_device *pdev)
3774 } 3872 }
3775 3873
3776 3874
3875 ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
3876 wm8994_mic_irq, "Mic 1 detect", wm8994);
3877 if (ret != 0)
3878 dev_warn(&pdev->dev,
3879 "Failed to request Mic1 detect IRQ: %d\n", ret);
3880
3881 ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT,
3882 wm8994_mic_irq, "Mic 1 short", wm8994);
3883 if (ret != 0)
3884 dev_warn(&pdev->dev,
3885 "Failed to request Mic1 short IRQ: %d\n", ret);
3886
3887 ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_DET,
3888 wm8994_mic_irq, "Mic 2 detect", wm8994);
3889 if (ret != 0)
3890 dev_warn(&pdev->dev,
3891 "Failed to request Mic2 detect IRQ: %d\n", ret);
3892
3893 ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT,
3894 wm8994_mic_irq, "Mic 2 short", wm8994);
3895 if (ret != 0)
3896 dev_warn(&pdev->dev,
3897 "Failed to request Mic2 short IRQ: %d\n", ret);
3898
3777 /* Remember if AIFnLRCLK is configured as a GPIO. This should be 3899 /* Remember if AIFnLRCLK is configured as a GPIO. This should be
3778 * configured on init - if a system wants to do this dynamically 3900 * configured on init - if a system wants to do this dynamically
3779 * at runtime we can deal with that then. 3901 * at runtime we can deal with that then.
@@ -3781,7 +3903,7 @@ static int wm8994_codec_probe(struct platform_device *pdev)
3781 ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_1); 3903 ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_1);
3782 if (ret < 0) { 3904 if (ret < 0) {
3783 dev_err(codec->dev, "Failed to read GPIO1 state: %d\n", ret); 3905 dev_err(codec->dev, "Failed to read GPIO1 state: %d\n", ret);
3784 goto err; 3906 goto err_irq;
3785 } 3907 }
3786 if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) { 3908 if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
3787 wm8994->lrclk_shared[0] = 1; 3909 wm8994->lrclk_shared[0] = 1;
@@ -3793,7 +3915,7 @@ static int wm8994_codec_probe(struct platform_device *pdev)
3793 ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_6); 3915 ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_6);
3794 if (ret < 0) { 3916 if (ret < 0) {
3795 dev_err(codec->dev, "Failed to read GPIO6 state: %d\n", ret); 3917 dev_err(codec->dev, "Failed to read GPIO6 state: %d\n", ret);
3796 goto err; 3918 goto err_irq;
3797 } 3919 }
3798 if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) { 3920 if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
3799 wm8994->lrclk_shared[1] = 1; 3921 wm8994->lrclk_shared[1] = 1;
@@ -3843,7 +3965,7 @@ static int wm8994_codec_probe(struct platform_device *pdev)
3843 ret = snd_soc_register_codec(codec); 3965 ret = snd_soc_register_codec(codec);
3844 if (ret != 0) { 3966 if (ret != 0) {
3845 dev_err(codec->dev, "Failed to register codec: %d\n", ret); 3967 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
3846 goto err; 3968 goto err_irq;
3847 } 3969 }
3848 3970
3849 ret = snd_soc_register_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai)); 3971 ret = snd_soc_register_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai));
@@ -3858,6 +3980,11 @@ static int wm8994_codec_probe(struct platform_device *pdev)
3858 3980
3859err_codec: 3981err_codec:
3860 snd_soc_unregister_codec(codec); 3982 snd_soc_unregister_codec(codec);
3983err_irq:
3984 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
3985 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
3986 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
3987 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994);
3861err: 3988err:
3862 kfree(wm8994); 3989 kfree(wm8994);
3863 return ret; 3990 return ret;
@@ -3871,6 +3998,10 @@ static int __devexit wm8994_codec_remove(struct platform_device *pdev)
3871 wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); 3998 wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
3872 snd_soc_unregister_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai)); 3999 snd_soc_unregister_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai));
3873 snd_soc_unregister_codec(&wm8994->codec); 4000 snd_soc_unregister_codec(&wm8994->codec);
4001 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
4002 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
4003 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
4004 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994);
3874 kfree(wm8994); 4005 kfree(wm8994);
3875 wm8994_codec = NULL; 4006 wm8994_codec = NULL;
3876 4007
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 0a5e1424dea0..79d5915ae4b3 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -23,4 +23,7 @@ extern struct snd_soc_dai wm8994_dai[];
23#define WM8994_FLL1 1 23#define WM8994_FLL1 1
24#define WM8994_FLL2 2 24#define WM8994_FLL2 2
25 25
26int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
27 int micbias, int det, int shrt);
28
26#endif 29#endif