summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorScottPeterson <speterson@nvidia.com>2012-12-05 16:21:44 -0800
committerSimone Willett <swillett@nvidia.com>2013-01-08 18:34:30 -0800
commit11888c116fa2d1ab86076d0d1682bdda124798b9 (patch)
tree61dab61c5a47828c93a1eb5f2207a9cef77c80d6 /sound
parent5a87677fcb235d9b20b84aadb2fa321373f61bbf (diff)
tegra: asoc: Enable AIC3262 HP detect
Enable Headphone detection for AIC3262 audio codec. For bug 1179798 Change-Id: I4107c02d4463ea1d1ac71add7519a946af34ddc6 Signed-off-by: ScottPeterson <speterson@nvidia.com> Signed-off-by: Vijay Mali <vmali@nvidia.com> Reviewed-on: http://git-master/r/189114 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/tegra/tegra_aic326x.c112
1 files changed, 108 insertions, 4 deletions
diff --git a/sound/soc/tegra/tegra_aic326x.c b/sound/soc/tegra/tegra_aic326x.c
index 096f75fe628c..6eefc6fcbd36 100644
--- a/sound/soc/tegra/tegra_aic326x.c
+++ b/sound/soc/tegra/tegra_aic326x.c
@@ -60,6 +60,7 @@
#define GPIO_HP_MUTE BIT(1)
#define GPIO_INT_MIC_EN BIT(2)
#define GPIO_EXT_MIC_EN BIT(3)
+#define GPIO_HP_DET BIT(4)
#define DAI_LINK_HIFI 0
#define DAI_LINK_SPDIF 1
@@ -94,7 +95,9 @@ struct tegra_aic326x {
struct regulator *dmic_reg;
struct regulator *dmic_1v8_reg;
struct regulator *hmic_reg;
+ enum snd_soc_bias_level bias_level;
#endif
+ int clock_enabled;
};
static int tegra_aic326x_call_mode_info(struct snd_kcontrol *kcontrol,
@@ -893,6 +896,14 @@ static struct switch_dev aic326x_wired_switch_dev = {
.name = "h2w",
};
+/* Headset jack detection gpios */
+static struct snd_soc_jack_gpio tegra_aic326x_hp_jack_gpio = {
+ .name = "headphone detect",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 150,
+ .invert = 1,
+};
+
/* These values are copied from WiredAccessoryObserver */
enum headset_state {
BIT_NO_HEADSET = 0,
@@ -1144,14 +1155,26 @@ static int tegra_aic326x_init(struct snd_soc_pcm_runtime *rtd)
if (ret < 0)
return ret;
-#ifdef CONFIG_SWITCH
- snd_soc_jack_notifier_register(&tegra_aic326x_hp_jack,
- &aic326x_headset_switch_nb);
-#else /*gpio based headset detection*/
+ if (gpio_is_valid(pdata->gpio_hp_det)) {
+ /* Headphone detection */
+ tegra_aic326x_hp_jack_gpio.gpio = pdata->gpio_hp_det;
+ snd_soc_jack_new(codec, "Headphone Jack",
+ SND_JACK_HEADSET, &tegra_aic326x_hp_jack);
+
+#ifndef CONFIG_SWITCH
snd_soc_jack_add_pins(&tegra_aic326x_hp_jack,
ARRAY_SIZE(tegra_aic326x_hp_jack_pins),
tegra_aic326x_hp_jack_pins);
+#else
+ snd_soc_jack_notifier_register(&tegra_aic326x_hp_jack,
+ &aic326x_headset_switch_nb);
#endif
+ snd_soc_jack_add_gpios(&tegra_aic326x_hp_jack,
+ 1,
+ &tegra_aic326x_hp_jack_gpio);
+
+ machine->gpio_requested |= GPIO_HP_DET;
+ }
/* update jack status during boot */
aic3262_hs_jack_detect(codec, &tegra_aic326x_hp_jack,
@@ -1237,11 +1260,87 @@ static struct snd_soc_dai_link tegra_aic326x_dai[] = {
},
};
+static int tegra_aic326x_suspend_post(struct snd_soc_card *card)
+{
+ struct snd_soc_jack_gpio *gpio = &tegra_aic326x_hp_jack_gpio;
+ struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card);
+
+ if (gpio_is_valid(gpio->gpio))
+ disable_irq(gpio_to_irq(gpio->gpio));
+
+ if (machine->clock_enabled) {
+ machine->clock_enabled = 0;
+ tegra_asoc_utils_clk_disable(&machine->util_data);
+ }
+
+
+ return 0;
+}
+
+static int tegra_aic326x_resume_pre(struct snd_soc_card *card)
+{
+ int val;
+ struct snd_soc_jack_gpio *gpio = &tegra_aic326x_hp_jack_gpio;
+ struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card);
+
+ if (gpio_is_valid(gpio->gpio)) {
+ val = gpio_get_value(gpio->gpio);
+ val = gpio->invert ? !val : val;
+ snd_soc_jack_report(gpio->jack, val, gpio->report);
+ enable_irq(gpio_to_irq(gpio->gpio));
+ }
+
+ if (!machine->clock_enabled) {
+ machine->clock_enabled = 1;
+ tegra_asoc_utils_clk_enable(&machine->util_data);
+ }
+
+ return 0;
+}
+
+
+static int tegra_aic326x_set_bias_level(struct snd_soc_card *card,
+ struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
+{
+ struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card);
+
+ if (machine->bias_level == SND_SOC_BIAS_OFF &&
+ level != SND_SOC_BIAS_OFF && (!machine->clock_enabled)) {
+ machine->clock_enabled = 1;
+ tegra_asoc_utils_clk_enable(&machine->util_data);
+ machine->bias_level = level;
+ }
+
+ return 0;
+}
+
+static int tegra_aic326x_set_bias_level_post(struct snd_soc_card *card,
+ struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
+{
+ struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card);
+
+ if (machine->bias_level != SND_SOC_BIAS_OFF &&
+ level == SND_SOC_BIAS_OFF && machine->clock_enabled) {
+ machine->clock_enabled = 0;
+ tegra_asoc_utils_clk_disable(&machine->util_data);
+ }
+
+ machine->bias_level = level;
+
+ return 0 ;
+}
+
+
+
static struct snd_soc_card snd_soc_tegra_aic326x = {
.name = "tegra-aic326x",
.owner = THIS_MODULE,
.dai_link = tegra_aic326x_dai,
.num_links = ARRAY_SIZE(tegra_aic326x_dai),
+ .set_bias_level = tegra_aic326x_set_bias_level,
+ .set_bias_level_post = tegra_aic326x_set_bias_level_post,
+ .suspend_post = tegra_aic326x_suspend_post,
+ .resume_pre = tegra_aic326x_resume_pre,
};
static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev)
@@ -1381,6 +1480,11 @@ static int __devexit tegra_aic326x_driver_remove(struct platform_device *pdev)
struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card);
struct tegra_asoc_platform_data *pdata = machine->pdata;
+ if (machine->gpio_requested & GPIO_HP_DET)
+ snd_soc_jack_free_gpios(&tegra_aic326x_hp_jack,
+ 1,
+ &tegra_aic326x_hp_jack_gpio);
+
snd_soc_unregister_card(card);
#ifdef CONFIG_SWITCH