aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2012-08-18 07:58:33 +1000
committerDenis 'GNUtoo' Carikli <GNUtoo@no-log.org>2013-03-09 15:43:02 +0100
commit9db3215c88e39b3c5a5aa5497603798b55831e2c (patch)
tree1b97a447659cba8f5cec03434bbc1da65e9e769d
parent22f08d1e684704adb171dea52554177bb64e6e22 (diff)
downloadkernel_goldelico_gta04-9db3215c88e39b3c5a5aa5497603798b55831e2c.zip
kernel_goldelico_gta04-9db3215c88e39b3c5a5aa5497603798b55831e2c.tar.gz
kernel_goldelico_gta04-9db3215c88e39b3c5a5aa5497603798b55831e2c.tar.bz2
GTA04: add simple headset-jack detection support.
As headset-insert doesn't generate an interrupt we need to poll the MICSENSE line to see if a headset is present. We do this every 500ms. It takes nearly that long to physically insert a jack, so much faster wouldn't help and would impact power drain more. As detection is done by polling, a jack-insert or removal event cannot wake the device from suspend. Events are only detected while device is awake. We keep the HSMIC bias enabled whenever the 'input' device is open, except during suspend so that we can poll reliably. Turning it off and on seems to interfere with reliable measurements. Currently a reading below 100 is 'nothing plugged in' while a reading above that is 'mic and headphone plugged in'. I measure between 19 and 26 when nothing is plugged in, and between 804 and 811 when a headset is plugged in. Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r--sound/soc/omap/gta04-audio.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/sound/soc/omap/gta04-audio.c b/sound/soc/omap/gta04-audio.c
index d998aae..b5cbe37 100644
--- a/sound/soc/omap/gta04-audio.c
+++ b/sound/soc/omap/gta04-audio.c
@@ -23,8 +23,10 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/module.h>
+#include <linux/input.h>
#include <sound/core.h>
#include <sound/pcm.h>
+#include <sound/jack.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -32,6 +34,8 @@
#include <mach/hardware.h>
#include <mach/gpio.h>
+#include <linux/i2c/twl4030-madc.h>
+
#include "omap-mcbsp.h"
#include "omap-pcm.h"
#include "../codecs/twl4030.h"
@@ -135,6 +139,62 @@ static const struct snd_soc_dapm_route audio_map[] = {
*/
};
+static struct {
+ struct snd_soc_jack hs_jack;
+ struct delayed_work jack_work;
+ struct snd_soc_codec *codec;
+ int open;
+} jack;
+
+static void gta04_audio_jack_work(struct work_struct *work)
+{
+ long val;
+
+ val = twl4030_get_madc_conversion(7);
+ if (val < 100)
+ snd_soc_jack_report(&jack.hs_jack, 0, SND_JACK_HEADSET);
+ else
+ snd_soc_jack_report(&jack.hs_jack, SND_JACK_HEADSET,
+ SND_JACK_HEADSET);
+ if (jack.open)
+ schedule_delayed_work(&jack.jack_work, msecs_to_jiffies(500));
+}
+
+static int gta04_audio_suspend(struct snd_soc_card *card)
+{
+ if (jack.codec) {
+ snd_soc_dapm_disable_pin(&jack.codec->dapm, "Headset Mic Bias");
+ snd_soc_dapm_sync(&jack.codec->dapm);
+ }
+ return 0;
+}
+
+static int gta04_audio_resume(struct snd_soc_card *card)
+{
+ if (jack.codec && jack.open) {
+ snd_soc_dapm_force_enable_pin(&jack.codec->dapm, "Headset Mic Bias");
+ snd_soc_dapm_sync(&jack.codec->dapm);
+ }
+ return 0;
+}
+
+static int gta04_jack_open(struct input_dev *dev)
+{
+ snd_soc_dapm_force_enable_pin(&jack.codec->dapm, "Headset Mic Bias");
+ snd_soc_dapm_sync(&jack.codec->dapm);
+ jack.open = 1;
+ schedule_delayed_work(&jack.jack_work, msecs_to_jiffies(100));
+ return 0;
+}
+
+static void gta04_jack_close(struct input_dev *dev)
+{
+ jack.open = 0;
+ cancel_delayed_work_sync(&jack.jack_work);
+ snd_soc_dapm_disable_pin(&jack.codec->dapm, "Headset Mic Bias");
+ snd_soc_dapm_sync(&jack.codec->dapm);
+}
+
static int omap3gta04_init(struct snd_soc_pcm_runtime *runtime)
{
int ret;
@@ -171,6 +231,18 @@ static int omap3gta04_init(struct snd_soc_pcm_runtime *runtime)
// snd_soc_dapm_nc_pin(codec, "HSMIC");
snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
+
+ /* We can detect when something is plugged in,
+ * but we need to poll :-(
+ */
+ ret = snd_soc_jack_new(codec, "Headset Jack",
+ SND_JACK_HEADSET, &jack.hs_jack);
+ if (ret)
+ return ret;
+ INIT_DELAYED_WORK(&jack.jack_work, gta04_audio_jack_work);
+ jack.codec = codec;
+ jack.hs_jack.jack->input_dev->open = gta04_jack_open;
+ jack.hs_jack.jack->input_dev->close = gta04_jack_close;
return snd_soc_dapm_sync(dapm);
}
@@ -199,6 +271,8 @@ static struct snd_soc_card snd_soc_omap3gta04 = {
.owner = THIS_MODULE,
.dai_link = &omap3gta04_dai,
.num_links = 1,
+ .suspend_pre = gta04_audio_suspend,
+ .resume_post = gta04_audio_resume,
};
static struct platform_device *omap3gta04_snd_device;