summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorSumit Bhattacharya <sumitb@nvidia.com>2011-10-03 05:10:51 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:52:33 -0800
commitc333609b01af3de744bb909e0e4e57ba0ced0778 (patch)
tree00ed8b5adb3d683ce239319c40b7c764a0ded43e /sound
parentd6b7aebfafda31f58cb7854bda525840c8ae1fa0 (diff)
ASoC: Tegra: WM8903: Support switch class
Add support to convey HP and mic jack status to switch class. Bug 872652 Change-Id: I2d64c97ef8bf0ab3dfeec3c711ef0e8048bff133 Signed-off-by: Sumit Bhattacharya <sumitb@nvidia.com> Reviewed-on: http://git-master/r/55670 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: Re41027a605ed344cd0dd90c1bc41656a04afb1c1
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/tegra/tegra_wm8903.c99
1 files changed, 90 insertions, 9 deletions
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 1f27e7066794..f9b434194e82 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -35,6 +35,9 @@
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
+#ifdef CONFIG_SWITCH
+#include <linux/switch.h>
+#endif
#include <mach/tegra_wm8903_pdata.h>
@@ -67,6 +70,9 @@ struct tegra_wm8903 {
struct regulator *spk_reg;
struct regulator *dmic_reg;
int gpio_requested;
+#ifdef CONFIG_SWITCH
+ int jack_status;
+#endif
};
static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
@@ -297,13 +303,7 @@ static struct snd_soc_ops tegra_spdif_ops = {
};
static struct snd_soc_jack tegra_wm8903_hp_jack;
-
-static struct snd_soc_jack_pin tegra_wm8903_hp_jack_pins[] = {
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
-};
+static struct snd_soc_jack tegra_wm8903_mic_jack;
static struct snd_soc_jack_gpio tegra_wm8903_hp_jack_gpio = {
.name = "headphone detect",
@@ -312,7 +312,63 @@ static struct snd_soc_jack_gpio tegra_wm8903_hp_jack_gpio = {
.invert = 1,
};
-static struct snd_soc_jack tegra_wm8903_mic_jack;
+#ifdef CONFIG_SWITCH
+/* These values are copied from Android WiredAccessoryObserver */
+enum headset_state {
+ BIT_NO_HEADSET = 0,
+ BIT_HEADSET = (1 << 0),
+ BIT_HEADSET_NO_MIC = (1 << 1),
+};
+
+static struct switch_dev tegra_wm8903_headset_switch = {
+ .name = "h2w",
+};
+
+static int tegra_wm8903_jack_notifier(struct notifier_block *self,
+ unsigned long action, void *dev)
+{
+ struct snd_soc_jack *jack = dev;
+ struct snd_soc_codec *codec = jack->codec;
+ struct snd_soc_card *card = codec->card;
+ struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+ enum headset_state state = BIT_NO_HEADSET;
+
+ if (jack == &tegra_wm8903_hp_jack) {
+ machine->jack_status &= ~SND_JACK_HEADPHONE;
+ machine->jack_status |= (action & SND_JACK_HEADPHONE);
+ } else {
+ machine->jack_status &= ~SND_JACK_MICROPHONE;
+ machine->jack_status |= (action & SND_JACK_MICROPHONE);
+ }
+
+ switch (machine->jack_status) {
+ case SND_JACK_HEADPHONE:
+ state = BIT_HEADSET_NO_MIC;
+ break;
+ case SND_JACK_HEADSET:
+ state = BIT_HEADSET;
+ break;
+ case SND_JACK_MICROPHONE:
+ /* mic: would not report */
+ default:
+ state = BIT_NO_HEADSET;
+ }
+
+ switch_set_state(&tegra_wm8903_headset_switch, state);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block tegra_wm8903_jack_detect_nb = {
+ .notifier_call = tegra_wm8903_jack_notifier,
+};
+#else
+static struct snd_soc_jack_pin tegra_wm8903_hp_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+};
static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = {
{
@@ -320,6 +376,7 @@ static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = {
.mask = SND_JACK_MICROPHONE,
},
};
+#endif
static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
@@ -550,9 +607,14 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det;
snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
&tegra_wm8903_hp_jack);
+#ifndef CONFIG_SWITCH
snd_soc_jack_add_pins(&tegra_wm8903_hp_jack,
ARRAY_SIZE(tegra_wm8903_hp_jack_pins),
tegra_wm8903_hp_jack_pins);
+#else
+ snd_soc_jack_notifier_register(&tegra_wm8903_hp_jack,
+ &tegra_wm8903_jack_detect_nb);
+#endif
snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack,
1,
&tegra_wm8903_hp_jack_gpio);
@@ -561,9 +623,14 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
&tegra_wm8903_mic_jack);
+#ifndef CONFIG_SWITCH
snd_soc_jack_add_pins(&tegra_wm8903_mic_jack,
ARRAY_SIZE(tegra_wm8903_mic_jack_pins),
tegra_wm8903_mic_jack_pins);
+#else
+ snd_soc_jack_notifier_register(&tegra_wm8903_mic_jack,
+ &tegra_wm8903_jack_detect_nb);
+#endif
wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE,
0);
@@ -680,6 +747,13 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
tegra_wm8903_dai[2].cpu_dai_name = "tegra30-i2s.3";
}
+#ifdef CONFIG_SWITCH
+ /* Addd h2w swith class support */
+ ret = switch_dev_register(&tegra_wm8903_headset_switch);
+ if (ret < 0)
+ goto err_fini_utils;
+#endif
+
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
@@ -719,11 +793,15 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
ret);
- goto err_fini_utils;
+ goto err_unregister_switch;
}
return 0;
+err_unregister_switch:
+#ifdef CONFIG_SWITCH
+ switch_dev_unregister(&tegra_wm8903_headset_switch);
+#endif
err_fini_utils:
tegra_asoc_utils_fini(&machine->util_data);
err_free_machine:
@@ -760,6 +838,9 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
tegra_asoc_utils_fini(&machine->util_data);
+#ifdef CONFIG_SWITCH
+ switch_dev_unregister(&tegra_wm8903_headset_switch);
+#endif
kfree(machine);
return 0;