Skip to content

Commit

Permalink
ASoC: Add Speyside headset jack detection support
Browse files Browse the repository at this point in the history
Speyside makes use of support the WM8915 has for detecting the polarity
of the microphone and ground connections on headsets, using a GPIO to
control the polarity of the ground connection and switching between the
two microphone bias supplies available on the device in order to do so.
As a result of this the detection support is more involved than for most
other CODECs, using a callback to configure the current polarity of the
jack and translate this into the board-specific connections required for
the current scenario.

On Android some additional work is required to hook this up to the
application layer as the Android HeadsetObserver monitors a custom
drivers/switch API rather than the standard Linux APIs.  This can be
done by either updating HeadsetObserver or modifying the ALSA core to
report via drivers/switch as well.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Jassi Brar <jassisinghbrar@gmail.com>
Acked-by: Liam Girdwood <lrg@ti.com>
  • Loading branch information
Mark Brown committed Apr 13, 2011
1 parent ea3e98e commit 68688e7
Showing 1 changed file with 77 additions and 1 deletion.
78 changes: 77 additions & 1 deletion sound/soc/samsung/speyside.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@

#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
#include <linux/gpio.h>

#include "../codecs/wm8915.h"
#include "../codecs/wm9081.h"

#define WM8915_HPSEL_GPIO 214

static int speyside_set_bias_level(struct snd_soc_card *card,
enum snd_soc_bias_level level)
{
Expand Down Expand Up @@ -79,11 +83,74 @@ static struct snd_soc_ops speyside_ops = {
.hw_params = speyside_hw_params,
};

static struct snd_soc_jack speyside_headset;

/* Headset jack detection DAPM pins */
static struct snd_soc_jack_pin speyside_headset_pins[] = {
{
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
{
.pin = "Headphone",
.mask = SND_JACK_HEADPHONE,
},
};

/* Default the headphone selection to active high */
static int speyside_jack_polarity;

static int speyside_get_micbias(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
if (speyside_jack_polarity && (strcmp(source->name, "MICB1") == 0))
return 1;
if (!speyside_jack_polarity && (strcmp(source->name, "MICB2") == 0))
return 1;

return 0;
}

static void speyside_set_polarity(struct snd_soc_codec *codec,
int polarity)
{
speyside_jack_polarity = !polarity;
gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);

/* Re-run DAPM to make sure we're using the correct mic bias */
snd_soc_dapm_sync(&codec->dapm);
}

static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *dai = rtd->codec_dai;
struct snd_soc_codec *codec = rtd->codec;
int ret;

ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0);
if (ret < 0)
return ret;

ret = gpio_request(WM8915_HPSEL_GPIO, "HP_SEL");
if (ret != 0)
pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);

return snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0);
ret = snd_soc_jack_new(codec, "Headset",
SND_JACK_HEADSET | SND_JACK_BTN_0,
&speyside_headset);
if (ret)
return ret;

ret = snd_soc_jack_add_pins(&speyside_headset,
ARRAY_SIZE(speyside_headset_pins),
speyside_headset_pins);
if (ret)
return ret;

wm8915_detect(codec, &speyside_headset, speyside_set_polarity);

return 0;
}

static struct snd_soc_dai_link speyside_dai[] = {
Expand Down Expand Up @@ -125,6 +192,7 @@ static struct snd_soc_codec_conf speyside_codec_conf[] = {

static struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),

SND_SOC_DAPM_SPK("Main Speaker", NULL),

Expand All @@ -133,7 +201,15 @@ static struct snd_soc_dapm_widget widgets[] = {
};

static struct snd_soc_dapm_route audio_paths[] = {
{ "IN1RN", NULL, "MICB1" },
{ "IN1RP", NULL, "MICB1" },
{ "IN1RN", NULL, "MICB2" },
{ "IN1RP", NULL, "MICB2" },
{ "MICB1", NULL, "Headset Mic", speyside_get_micbias },
{ "MICB2", NULL, "Headset Mic", speyside_get_micbias },

{ "IN1LP", NULL, "MICB2" },
{ "IN1RN", NULL, "MICB1" },
{ "MICB2", NULL, "Main AMIC" },

{ "DMIC1DAT", NULL, "MICB1" },
Expand Down

0 comments on commit 68688e7

Please sign in to comment.