summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorChao Jiang <chaoj@nvidia.com>2011-03-08 16:02:20 +0900
committerVarun Colbert <vcolbert@nvidia.com>2011-03-14 17:38:41 -0800
commitf7ccf6cae50ef4fa40ff4a8fa93d290c86c67a8c (patch)
treeee3ed63e3caf0119f5772b0b4ea55cf41b911091 /sound
parentac6c67d1089a31107cc5838ea766497dfa968914 (diff)
[tegra ALSA] Enable mic jack detection
Added support on Mic jack detection on Tegra. - External mic jack detection could be probed by trigger an interrupt via specific gpio or pull-up a generic gpio pin. The patch enabled the later option. - Tegra reference boards have gpio to switch external mic and internal mic. The switching is done in the patch automatically once jack happened. fixes bug 766757 Change-Id: If530f237d4564d1de6c019b206910f2a0ffe4163 Reviewed-on: http://git-master/r/22033 Reviewed-by: Chao Jiang <chaoj@nvidia.com> Tested-by: Chao Jiang <chaoj@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com> Reviewed-by: Scott Peterson <speterson@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/tegra/tegra_soc.h1
-rw-r--r--sound/soc/tegra/tegra_soc_controls.c41
-rw-r--r--sound/soc/tegra/tegra_wired_jack.c132
3 files changed, 142 insertions, 32 deletions
diff --git a/sound/soc/tegra/tegra_soc.h b/sound/soc/tegra/tegra_soc.h
index ea3bf4a786d1..92f621bf87d0 100644
--- a/sound/soc/tegra/tegra_soc.h
+++ b/sound/soc/tegra/tegra_soc.h
@@ -108,6 +108,7 @@ struct wired_jack_conf {
int hp_det_n;
int en_mic_int;
int en_mic_ext;
+ int cdc_irq;
int en_spkr;
};
diff --git a/sound/soc/tegra/tegra_soc_controls.c b/sound/soc/tegra/tegra_soc_controls.c
index 4371130e1081..eb22a85af493 100644
--- a/sound/soc/tegra/tegra_soc_controls.c
+++ b/sound/soc/tegra/tegra_soc_controls.c
@@ -164,10 +164,39 @@ static int tegra_dapm_event_int_spk(struct snd_soc_dapm_widget* w,
return 0;
}
+static int tegra_dapm_event_int_mic(struct snd_soc_dapm_widget* w,
+ struct snd_kcontrol* k, int event)
+{
+ if (tegra_wired_jack_conf.en_mic_int != -1)
+ gpio_set_value_cansleep(tegra_wired_jack_conf.en_mic_int,
+ SND_SOC_DAPM_EVENT_ON(event));
+
+ if (tegra_wired_jack_conf.en_mic_ext != -1)
+ gpio_set_value_cansleep(tegra_wired_jack_conf.en_mic_ext,
+ !(SND_SOC_DAPM_EVENT_ON(event)));
+
+ return 0;
+}
+
+static int tegra_dapm_event_ext_mic(struct snd_soc_dapm_widget* w,
+ struct snd_kcontrol* k, int event)
+{
+ if (tegra_wired_jack_conf.en_mic_ext != -1)
+ gpio_set_value_cansleep(tegra_wired_jack_conf.en_mic_ext,
+ SND_SOC_DAPM_EVENT_ON(event));
+
+ if (tegra_wired_jack_conf.en_mic_int != -1)
+ gpio_set_value_cansleep(tegra_wired_jack_conf.en_mic_int,
+ !(SND_SOC_DAPM_EVENT_ON(event)));
+
+ return 0;
+}
+
/*tegra machine dapm widgets */
static const struct snd_soc_dapm_widget tegra_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", tegra_dapm_event_ext_mic),
+ SND_SOC_DAPM_MIC("Int Mic", tegra_dapm_event_int_mic),
SND_SOC_DAPM_SPK("Lineout", NULL),
SND_SOC_DAPM_SPK("Int Spk", tegra_dapm_event_int_spk),
SND_SOC_DAPM_LINE("Line Jack", NULL),
@@ -193,11 +222,15 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Lineout", NULL, "LINEOUTR"},
{"Lineout", NULL, "LINEOUTL"},
- /* mic is connected to MICIN (via right channel of headphone jack) */
+ /* external mic is stero */
{"IN1L", NULL, "Mic Jack"},
+ {"IN1R", NULL, "Mic Jack"},
+
+ /* internal mic is mono */
+ {"IN1R", NULL, "Int Mic"},
- /* Same as the above but no mic bias for line signals */
- {"IN2L", NULL, "Line Jack"},
+ {"IN3L", NULL, "Line Jack"},
+ {"IN3R", NULL, "Line Jack"},
};
static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
diff --git a/sound/soc/tegra/tegra_wired_jack.c b/sound/soc/tegra/tegra_wired_jack.c
index 10fb237ce64a..b846fa003c62 100644
--- a/sound/soc/tegra/tegra_wired_jack.c
+++ b/sound/soc/tegra/tegra_wired_jack.c
@@ -29,6 +29,7 @@
#include "tegra_soc.h"
#define HEAD_DET_GPIO 0
+#define MIC_DET_GPIO 1
struct wired_jack_conf tegra_wired_jack_conf = {
-1, -1, -1, -1
@@ -37,7 +38,7 @@ struct wired_jack_conf tegra_wired_jack_conf = {
/* jack */
static struct snd_soc_jack *tegra_wired_jack;
-static struct snd_soc_jack_pin hs_jack_pins[] = {
+static struct snd_soc_jack_pin wired_jack_pins[] = {
{
.pin = "Headset Jack",
.mask = SND_JACK_HEADSET,
@@ -52,7 +53,7 @@ static struct snd_soc_jack_pin hs_jack_pins[] = {
},
};
-static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+static struct snd_soc_jack_gpio wired_jack_gpios[] = {
{
/* gpio pin depends on board traits */
.name = "headphone-detect-gpio",
@@ -60,6 +61,13 @@ static struct snd_soc_jack_gpio hs_jack_gpios[] = {
.invert = 1,
.debounce_time = 200,
},
+ {
+ /* gpio pin depens on board traits */
+ .name = "mic-detect-gpio",
+ .report = SND_JACK_MICROPHONE,
+ .invert = 1,
+ .debounce_time = 200,
+ },
};
static struct switch_dev wired_switch_dev = {
@@ -76,16 +84,49 @@ static int wired_swith_notify(struct notifier_block *self,
unsigned long action, void* dev)
{
int state = 0;
+ int flag = 0;
+ int hp_gpio = -1;
+ int mic_gpio = -1;;
+
+ /* hp_det_n is low active pin */
+ if (tegra_wired_jack_conf.hp_det_n != -1)
+ hp_gpio = gpio_get_value(tegra_wired_jack_conf.hp_det_n);
+ if (tegra_wired_jack_conf.cdc_irq != -1)
+ mic_gpio = gpio_get_value(tegra_wired_jack_conf.cdc_irq);
+
+ flag = (hp_gpio << 4) | mic_gpio;
switch (action) {
case SND_JACK_HEADSET:
state = 1;
break;
case SND_JACK_HEADPHONE:
- state = 2;
+ if (mic_gpio)
+ state = 1;
+ else
+ state = 2;
+ break;
+ case SND_JACK_MICROPHONE:
+ if (!hp_gpio) /* low = hp */
+ state = 1;
break;
default:
- state = 0;
+ switch (flag) {
+ case 0x010:
+ state = 0;
+ break;
+ case 0x01:
+ state = 1;
+ break;
+ case 0x11:
+ /* mic: would not report */
+ break;
+ case 0x00:
+ state = 2;
+ break;
+ default:
+ state = 0;
+ }
}
tegra_switch_set_state(state);
@@ -101,30 +142,55 @@ static struct notifier_block wired_switch_nb = {
static int tegra_wired_jack_probe(struct platform_device *pdev)
{
int ret;
- int hp_det_n;
+ int hp_det_n, cdc_irq;
+ int en_mic_int, en_mic_ext;
int en_spkr;
struct tegra_wired_jack_conf *pdata;
pdata = (struct tegra_wired_jack_conf *)pdev->dev.platform_data;
- if (!pdata || !pdata->hp_det_n || !pdata->en_spkr) {
+ if (!pdata || !pdata->hp_det_n || !pdata->en_spkr ||
+ !pdata->cdc_irq || !pdata->en_mic_int || !pdata->en_mic_ext) {
pr_err("Please set up gpio pins for jack.\n");
return -EBUSY;
}
hp_det_n = pdata->hp_det_n;
- hs_jack_gpios[HEAD_DET_GPIO].gpio = hp_det_n;
+ wired_jack_gpios[HEAD_DET_GPIO].gpio = hp_det_n;
+
+ cdc_irq = pdata->cdc_irq;
+ wired_jack_gpios[MIC_DET_GPIO].gpio = cdc_irq;
ret = snd_soc_jack_add_gpios(tegra_wired_jack,
- ARRAY_SIZE(hs_jack_gpios),
- hs_jack_gpios);
+ ARRAY_SIZE(wired_jack_gpios),
+ wired_jack_gpios);
if (ret) {
pr_err("Could NOT set up gpio pins for jack.\n");
snd_soc_jack_free_gpios(tegra_wired_jack,
- ARRAY_SIZE(hs_jack_gpios),
- hs_jack_gpios);
+ ARRAY_SIZE(wired_jack_gpios),
+ wired_jack_gpios);
return ret;
}
+ /* Mic switch controlling pins */
+ en_mic_int = pdata->en_mic_int;
+ en_mic_ext = pdata->en_mic_ext;
+
+ ret = gpio_request(en_mic_int, "en_mic_int");
+ if (ret) {
+ pr_err("Could NOT get gpio for internal mic controlling.\n");
+ gpio_free(en_mic_int);
+ }
+ gpio_direction_output(en_mic_int, 0);
+ gpio_export(en_mic_int, false);
+
+ ret = gpio_request(en_mic_ext, "en_mic_ext");
+ if (ret) {
+ pr_err("Could NOT get gpio for external mic controlling.\n");
+ gpio_free(en_mic_ext);
+ }
+ gpio_direction_output(en_mic_ext, 0);
+ gpio_export(en_mic_ext, false);
+
en_spkr = pdata->en_spkr;
ret = gpio_request(en_spkr, "en_spkr");
if (ret) {
@@ -136,23 +202,44 @@ static int tegra_wired_jack_probe(struct platform_device *pdev)
/* restore configuration of these pins */
tegra_wired_jack_conf.hp_det_n = hp_det_n;
+ tegra_wired_jack_conf.en_mic_int = en_mic_int;
+ tegra_wired_jack_conf.en_mic_ext = en_mic_ext;
+ tegra_wired_jack_conf.cdc_irq = cdc_irq;
tegra_wired_jack_conf.en_spkr = en_spkr;
+ /* Addd h2w swith class support */
+ ret = switch_dev_register(&wired_switch_dev);
+ if (ret < 0)
+ goto switch_dev_failed;
+
+ snd_soc_jack_notifier_register(tegra_wired_jack,
+ &wired_switch_nb);
+
return 0;
+
+switch_dev_failed:
+ switch_dev_unregister(&wired_switch_dev);
+ return ret;
}
static int tegra_wired_jack_remove(struct platform_device *pdev)
{
snd_soc_jack_free_gpios(tegra_wired_jack,
- ARRAY_SIZE(hs_jack_gpios),
- hs_jack_gpios);
+ ARRAY_SIZE(wired_jack_gpios),
+ wired_jack_gpios);
+
+ gpio_free(tegra_wired_jack_conf.en_mic_int);
+ gpio_free(tegra_wired_jack_conf.en_mic_ext);
+ gpio_free(tegra_wired_jack_conf.en_spkr);
+
+ switch_dev_unregister(&wired_switch_dev);
return 0;
}
static struct platform_driver tegra_wired_jack_driver = {
.probe = tegra_wired_jack_probe,
- .remove = __devexit_p(tegra_wired_jack_remove),
+ .remove = tegra_wired_jack_remove,
.driver = {
.name = "tegra_wired_jack",
.owner = THIS_MODULE,
@@ -174,33 +261,23 @@ int tegra_jack_init(struct snd_soc_codec *codec)
}
/* Add jack detection */
- ret = snd_soc_jack_new(codec->socdev->card, "Headset Jack",
+ ret = snd_soc_jack_new(codec->socdev->card, "Wired Accessory Jack",
SND_JACK_HEADSET, tegra_wired_jack);
if (ret < 0)
goto failed;
ret = snd_soc_jack_add_pins(tegra_wired_jack,
- ARRAY_SIZE(hs_jack_pins),
- hs_jack_pins);
+ ARRAY_SIZE(wired_jack_pins),
+ wired_jack_pins);
if (ret < 0)
goto failed;
- /* Addd h2w swith class support */
- ret = switch_dev_register(&wired_switch_dev);
- if (ret < 0)
- goto switch_dev_failed;
-
- snd_soc_jack_notifier_register(tegra_wired_jack,
- &wired_switch_nb);
-
ret = platform_driver_register(&tegra_wired_jack_driver);
if (ret < 0)
goto platform_dev_failed;
return 0;
-switch_dev_failed:
- switch_dev_unregister(&wired_switch_dev);
platform_dev_failed:
platform_driver_unregister(&tegra_wired_jack_driver);
failed:
@@ -213,7 +290,6 @@ failed:
void tegra_jack_exit(void)
{
- switch_dev_unregister(&wired_switch_dev);
platform_driver_unregister(&tegra_wired_jack_driver);
if (tegra_wired_jack) {