aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-04-12 03:00:36 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-04-13 13:02:06 -0400
commit68688e78ed4bc8d1a811ca29e2f8681561706db3 (patch)
tree1dabf09546d81a792b19e1b6b3874539afae06a2
parentea3e98e75a6f38522450b66e22e34267977915ef (diff)
ASoC: Add Speyside headset jack detection support
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>
-rw-r--r--sound/soc/samsung/speyside.c78
1 files changed, 77 insertions, 1 deletions
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index 0adaf7fe6814..612a39e0e108 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -11,10 +11,14 @@
11 11
12#include <sound/soc.h> 12#include <sound/soc.h>
13#include <sound/soc-dapm.h> 13#include <sound/soc-dapm.h>
14#include <sound/jack.h>
15#include <linux/gpio.h>
14 16
15#include "../codecs/wm8915.h" 17#include "../codecs/wm8915.h"
16#include "../codecs/wm9081.h" 18#include "../codecs/wm9081.h"
17 19
20#define WM8915_HPSEL_GPIO 214
21
18static int speyside_set_bias_level(struct snd_soc_card *card, 22static int speyside_set_bias_level(struct snd_soc_card *card,
19 enum snd_soc_bias_level level) 23 enum snd_soc_bias_level level)
20{ 24{
@@ -79,11 +83,74 @@ static struct snd_soc_ops speyside_ops = {
79 .hw_params = speyside_hw_params, 83 .hw_params = speyside_hw_params,
80}; 84};
81 85
86static struct snd_soc_jack speyside_headset;
87
88/* Headset jack detection DAPM pins */
89static struct snd_soc_jack_pin speyside_headset_pins[] = {
90 {
91 .pin = "Headset Mic",
92 .mask = SND_JACK_MICROPHONE,
93 },
94 {
95 .pin = "Headphone",
96 .mask = SND_JACK_HEADPHONE,
97 },
98};
99
100/* Default the headphone selection to active high */
101static int speyside_jack_polarity;
102
103static int speyside_get_micbias(struct snd_soc_dapm_widget *source,
104 struct snd_soc_dapm_widget *sink)
105{
106 if (speyside_jack_polarity && (strcmp(source->name, "MICB1") == 0))
107 return 1;
108 if (!speyside_jack_polarity && (strcmp(source->name, "MICB2") == 0))
109 return 1;
110
111 return 0;
112}
113
114static void speyside_set_polarity(struct snd_soc_codec *codec,
115 int polarity)
116{
117 speyside_jack_polarity = !polarity;
118 gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
119
120 /* Re-run DAPM to make sure we're using the correct mic bias */
121 snd_soc_dapm_sync(&codec->dapm);
122}
123
82static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd) 124static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd)
83{ 125{
84 struct snd_soc_dai *dai = rtd->codec_dai; 126 struct snd_soc_dai *dai = rtd->codec_dai;
127 struct snd_soc_codec *codec = rtd->codec;
128 int ret;
129
130 ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0);
131 if (ret < 0)
132 return ret;
133
134 ret = gpio_request(WM8915_HPSEL_GPIO, "HP_SEL");
135 if (ret != 0)
136 pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
137 gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
85 138
86 return snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0); 139 ret = snd_soc_jack_new(codec, "Headset",
140 SND_JACK_HEADSET | SND_JACK_BTN_0,
141 &speyside_headset);
142 if (ret)
143 return ret;
144
145 ret = snd_soc_jack_add_pins(&speyside_headset,
146 ARRAY_SIZE(speyside_headset_pins),
147 speyside_headset_pins);
148 if (ret)
149 return ret;
150
151 wm8915_detect(codec, &speyside_headset, speyside_set_polarity);
152
153 return 0;
87} 154}
88 155
89static struct snd_soc_dai_link speyside_dai[] = { 156static struct snd_soc_dai_link speyside_dai[] = {
@@ -125,6 +192,7 @@ static struct snd_soc_codec_conf speyside_codec_conf[] = {
125 192
126static struct snd_soc_dapm_widget widgets[] = { 193static struct snd_soc_dapm_widget widgets[] = {
127 SND_SOC_DAPM_HP("Headphone", NULL), 194 SND_SOC_DAPM_HP("Headphone", NULL),
195 SND_SOC_DAPM_MIC("Headset Mic", NULL),
128 196
129 SND_SOC_DAPM_SPK("Main Speaker", NULL), 197 SND_SOC_DAPM_SPK("Main Speaker", NULL),
130 198
@@ -133,7 +201,15 @@ static struct snd_soc_dapm_widget widgets[] = {
133}; 201};
134 202
135static struct snd_soc_dapm_route audio_paths[] = { 203static struct snd_soc_dapm_route audio_paths[] = {
204 { "IN1RN", NULL, "MICB1" },
205 { "IN1RP", NULL, "MICB1" },
206 { "IN1RN", NULL, "MICB2" },
207 { "IN1RP", NULL, "MICB2" },
208 { "MICB1", NULL, "Headset Mic", speyside_get_micbias },
209 { "MICB2", NULL, "Headset Mic", speyside_get_micbias },
210
136 { "IN1LP", NULL, "MICB2" }, 211 { "IN1LP", NULL, "MICB2" },
212 { "IN1RN", NULL, "MICB1" },
137 { "MICB2", NULL, "Main AMIC" }, 213 { "MICB2", NULL, "Main AMIC" },
138 214
139 { "DMIC1DAT", NULL, "MICB1" }, 215 { "DMIC1DAT", NULL, "MICB1" },