summaryrefslogtreecommitdiff
path: root/sound/soc/tegra/tegra_wired_jack.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/tegra/tegra_wired_jack.c')
-rw-r--r--sound/soc/tegra/tegra_wired_jack.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/sound/soc/tegra/tegra_wired_jack.c b/sound/soc/tegra/tegra_wired_jack.c
new file mode 100644
index 000000000000..23eeecbb3422
--- /dev/null
+++ b/sound/soc/tegra/tegra_wired_jack.c
@@ -0,0 +1,198 @@
+/*
+ * sound/soc/tegra/tegra_wired_jack.c
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/switch.h>
+#include <linux/notifier.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <mach/audio.h>
+
+#include "tegra_soc.h"
+
+#define HEAD_DET_GPIO 0
+
+/* jack */
+static struct snd_soc_jack *tegra_wired_jack;
+
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+ {
+ .pin = "Headset Jack",
+ .mask = SND_JACK_HEADSET,
+ },
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+ {
+ /* gpio pin depends on board traits */
+ .name = "headphone-detect-gpio",
+ .report = SND_JACK_HEADPHONE,
+ .invert = 1,
+ .debounce_time = 200,
+ },
+};
+
+static struct switch_dev wired_switch_dev = {
+ .name = "h2w",
+};
+
+static int wired_swith_notify(struct notifier_block *self,
+ unsigned long action, void* dev)
+{
+ int state = 0;
+
+ switch (action) {
+ case SND_JACK_HEADSET:
+ state = 1;
+ break;
+ case SND_JACK_HEADPHONE:
+ state = 2;
+ break;
+ default:
+ state = 0;
+ }
+
+ switch_set_state(&wired_switch_dev, state);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block wired_switch_nb = {
+ .notifier_call = wired_swith_notify,
+};
+
+/* platform driver */
+static int tegra_wired_jack_probe(struct platform_device *pdev)
+{
+ int ret;
+ int hp_det_n;
+ struct tegra_wired_jack_conf *pdata;
+
+ pdata = (struct tegra_wired_jack_conf *)pdev->dev.platform_data;
+ if (!pdata || !pdata->hp_det_n) {
+ 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;
+
+ ret = snd_soc_jack_add_gpios(tegra_wired_jack,
+ ARRAY_SIZE(hs_jack_gpios),
+ hs_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);
+ return ret;
+ }
+
+ return 0;
+}
+
+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);
+
+ return 0;
+}
+
+static struct platform_driver tegra_wired_jack_driver = {
+ .probe = tegra_wired_jack_probe,
+ .remove = __devexit_p(tegra_wired_jack_remove),
+ .driver = {
+ .name = "tegra_wired_jack",
+ .owner = THIS_MODULE,
+ },
+};
+
+
+int tegra_jack_init(struct snd_soc_codec *codec)
+{
+ int ret;
+
+ if (!codec)
+ return -1;
+
+ tegra_wired_jack = kzalloc(sizeof(*tegra_wired_jack), GFP_KERNEL);
+ if (!tegra_wired_jack) {
+ pr_err("failed to allocate tegra_wired_jack \n");
+ return -ENOMEM;
+ }
+
+ /* Add jack detection */
+ ret = snd_soc_jack_new(codec->socdev->card, "Headset 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);
+ 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:
+ if (tegra_wired_jack) {
+ kfree(tegra_wired_jack);
+ tegra_wired_jack = 0;
+ }
+ return ret;
+}
+
+void tegra_jack_exit(void)
+{
+ switch_dev_unregister(&wired_switch_dev);
+ platform_driver_unregister(&tegra_wired_jack_driver);
+
+ if (tegra_wired_jack) {
+ kfree(tegra_wired_jack);
+ tegra_wired_jack = 0;
+ }
+}