mako: add the earjack debugger trigger

Only enable the uart console when detected earjack debugger.
Uart signal interferes audio signal. you might listen to noise via
headset. So this patch fixes this issue.

Change-Id: I9174f0f243043138304aced16b49c70ce317a2de
diff --git a/arch/arm/mach-msm/lge/mako/Makefile b/arch/arm/mach-msm/lge/mako/Makefile
index 77c00cc..f8f995f 100644
--- a/arch/arm/mach-msm/lge/mako/Makefile
+++ b/arch/arm/mach-msm/lge/mako/Makefile
@@ -9,6 +9,7 @@
 	board-mako-misc.o \
 	board-mako-sound.o \
 	board-mako-storage.o \
-	board-mako-nfc.o
+	board-mako-nfc.o \
+	board-mako-earjack-debugger.o
 
-CFLAGS_board-mako-display.o += -Idrivers/video
\ No newline at end of file
+CFLAGS_board-mako-display.o += -Idrivers/video
diff --git a/arch/arm/mach-msm/lge/mako/board-mako-earjack-debugger.c b/arch/arm/mach-msm/lge/mako/board-mako-earjack-debugger.c
new file mode 100644
index 0000000..2dec2ca
--- /dev/null
+++ b/arch/arm/mach-msm/lge/mako/board-mako-earjack-debugger.c
@@ -0,0 +1,240 @@
+/*
+ * earjack debugger trigger
+ *
+ * Copyright (C) 2012 LGE, Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+
+#include <mach/gpiomux.h>
+
+#include "board-mako.h"
+#include "board-mako-earjack-debugger.h"
+
+#define MAKO_UART_TX_GPIO	10
+#define MAKO_UART_RX_GPIO	11
+
+static struct gpiomux_setting gsbi4_uart = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi4_gpio = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static bool mako_uart_initialized = false;
+
+struct earjack_debugger_device {
+	int gpio;
+	int irq;
+	int saved_detect;
+	void (*set_uart_console)(int enable);
+};
+
+static void earjack_debugger_set_gpiomux_uart(int enable)
+{
+	if (enable) {
+		msm_gpiomux_write(MAKO_UART_TX_GPIO, GPIOMUX_ACTIVE,
+				&gsbi4_uart, NULL);
+		msm_gpiomux_write(MAKO_UART_TX_GPIO, GPIOMUX_SUSPENDED,
+				&gsbi4_uart, NULL);
+		msm_gpiomux_write(MAKO_UART_RX_GPIO, GPIOMUX_ACTIVE,
+				&gsbi4_uart, NULL);
+		msm_gpiomux_write(MAKO_UART_RX_GPIO, GPIOMUX_SUSPENDED,
+				&gsbi4_uart, NULL);
+	} else {
+		msm_gpiomux_write(MAKO_UART_TX_GPIO, GPIOMUX_ACTIVE,
+				&gsbi4_gpio, NULL);
+		msm_gpiomux_write(MAKO_UART_TX_GPIO, GPIOMUX_SUSPENDED,
+				&gsbi4_gpio, NULL);
+		msm_gpiomux_write(MAKO_UART_RX_GPIO, GPIOMUX_ACTIVE,
+				&gsbi4_gpio, NULL);
+		msm_gpiomux_write(MAKO_UART_RX_GPIO, GPIOMUX_SUSPENDED,
+				&gsbi4_gpio, NULL);
+	}
+}
+
+static int earjack_debugger_detected(void *dev)
+{
+	struct earjack_debugger_device *adev = dev;
+
+	return !!gpio_get_value(adev->gpio);
+}
+
+static void earjack_debugger_set_console(void *dev)
+{
+	struct earjack_debugger_device *adev = dev;
+
+	if (earjack_debugger_detected(adev)) {
+		if (!mako_uart_initialized) {
+			mako_uart_initialized = true;
+			earjack_debugger_set_gpiomux_uart(1);
+			mdelay(1);
+		}
+		adev->set_uart_console(1);
+	} else {
+		adev->set_uart_console(0);
+	}
+}
+
+static irqreturn_t earjack_debugger_irq_handler(int irq, void *_dev)
+{
+	struct earjack_debugger_device *adev = _dev;
+
+	earjack_debugger_set_console(adev);
+
+	return IRQ_HANDLED;
+}
+
+static int earjack_debugger_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct earjack_debugger_device *adev;
+	struct earjack_debugger_platform_data *pdata =
+		pdev->dev.platform_data;
+
+	if (!pdata) {
+		pr_err("%s: no pdata\n", __func__);
+		return -ENODEV;
+	}
+
+	adev = kzalloc(sizeof(struct earjack_debugger_device), GFP_KERNEL);
+	if (!adev) {
+		pr_err("%s: no memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	adev->gpio = pdata->gpio_trigger;
+	adev->irq = gpio_to_irq(pdata->gpio_trigger);
+	adev->set_uart_console = pdata->set_uart_console;
+
+	platform_set_drvdata(pdev, adev);
+
+	ret = gpio_request_one(adev->gpio, GPIOF_IN,
+			"gpio_earjack_debugger");
+	if (ret < 0) {
+		pr_err("%s: failed to request gpio %d\n", __func__,
+				adev->gpio);
+		goto err_gpio_request;
+	}
+
+	ret = request_threaded_irq(adev->irq, NULL, earjack_debugger_irq_handler,
+			IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,
+			"earjack_debugger_trigger", adev);
+	if (ret < 0) {
+		pr_err("%s: failed to request irq\n", __func__);
+		goto err_request_irq;
+	}
+
+	if (earjack_debugger_detected(adev)) {
+		if (adev->set_uart_console) {
+			mako_uart_initialized = true;
+			earjack_debugger_set_gpiomux_uart(1);
+			adev->set_uart_console(1);
+		}
+	} else {
+		earjack_debugger_set_gpiomux_uart(0);
+	}
+
+	pr_info("earjack debugger probed\n");
+
+	return ret;
+
+err_request_irq:
+	gpio_free(adev->gpio);
+err_gpio_request:
+	kfree(adev);
+
+	return ret;
+}
+
+static int earjack_debugger_remove(struct platform_device *pdev)
+{
+	struct earjack_debugger_device *adev = platform_get_drvdata(pdev);
+
+	free_irq(adev->irq, adev);
+	gpio_free(adev->gpio);
+	kfree(adev);
+
+	return 0;
+}
+
+static void earjack_debugger_shutdown(struct platform_device *pdev)
+{
+	struct earjack_debugger_device *adev = platform_get_drvdata(pdev);
+
+	disable_irq(adev->irq);
+}
+
+static int earjack_debugger_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct earjack_debugger_device *adev = platform_get_drvdata(pdev);
+
+	disable_irq(adev->irq);
+	adev->saved_detect = earjack_debugger_detected(adev);
+
+	return 0;
+}
+
+static int earjack_debugger_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct earjack_debugger_device *adev = platform_get_drvdata(pdev);
+	int detect = 0;
+
+	detect = earjack_debugger_detected(adev);
+	if (detect != adev->saved_detect)
+		earjack_debugger_set_console(adev);
+	enable_irq(adev->irq);
+
+	return 0;
+}
+
+static const struct dev_pm_ops earjack_debugger_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(earjack_debugger_suspend,
+			earjack_debugger_resume)
+};
+
+static struct platform_driver earjack_debugger_driver = {
+	.probe = earjack_debugger_probe,
+	.remove = earjack_debugger_remove,
+	.shutdown = earjack_debugger_shutdown,
+	.driver = {
+		.name = "earjack-debugger-trigger",
+		.pm = &earjack_debugger_pm_ops,
+	},
+};
+
+static int __init earjack_debugger_init(void)
+{
+	return platform_driver_register(&earjack_debugger_driver);
+}
+
+subsys_initcall_sync(earjack_debugger_init);
diff --git a/arch/arm/mach-msm/lge/mako/board-mako-earjack-debugger.h b/arch/arm/mach-msm/lge/mako/board-mako-earjack-debugger.h
new file mode 100644
index 0000000..7048a25
--- /dev/null
+++ b/arch/arm/mach-msm/lge/mako/board-mako-earjack-debugger.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2012 LGE, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __EARJACK_DEBUGGER_H
+#define __EARJACK_DEBUGGER_H
+
+struct earjack_debugger_platform_data {
+	int gpio_trigger;
+	void (*set_uart_console)(int enable);
+};
+
+#endif
diff --git a/arch/arm/mach-msm/lge/mako/board-mako-pmic.c b/arch/arm/mach-msm/lge/mako/board-mako-pmic.c
index 996a249..ad35ef7 100644
--- a/arch/arm/mach-msm/lge/mako/board-mako-pmic.c
+++ b/arch/arm/mach-msm/lge/mako/board-mako-pmic.c
@@ -119,6 +119,7 @@
 
 /* Initial PM8921 GPIO configurations */
 static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
+	PM8921_GPIO_INPUT(13, PM_GPIO_PULL_DN), /* EARJACK_DEBUGGER */
 	PM8921_GPIO_INPUT(14, PM_GPIO_PULL_DN), /* SLIMPORT_CBL_DET */
 	PM8921_GPIO_OUTPUT(15, 0, HIGH), /* ANX_P_DWN_CTL */
 	PM8921_GPIO_OUTPUT(16, 0, HIGH), /* ANX_AVDD33_EN */
diff --git a/arch/arm/mach-msm/lge/mako/board-mako-sound.c b/arch/arm/mach-msm/lge/mako/board-mako-sound.c
index 825336a..64fee27 100644
--- a/arch/arm/mach-msm/lge/mako/board-mako-sound.c
+++ b/arch/arm/mach-msm/lge/mako/board-mako-sound.c
@@ -26,6 +26,7 @@
 #endif
 
 #include "board-mako.h"
+#include "board-mako-earjack-debugger.h"
 
 
 #define TPA2028D_ADDRESS (0xB0>>1)
@@ -170,10 +171,12 @@
 	return !console_enabled;
 }
 
-static void fsa8008_set_uart_console(int enable)
+static void set_uart_console(int enable)
 {
 	static struct console *uart_con = NULL;
 
+	console_enabled = enable;
+
 	if (!uart_con) {
 		struct console *con;
 		for_each_console(con) {
@@ -189,7 +192,6 @@
 		return;
 	}
 
-	console_enabled = enable;
 	if (enable)
 		console_start(uart_con);
 	else
@@ -210,7 +212,7 @@
 
 	.latency_for_detection = 75,
 	.set_headset_mic_bias = enable_external_mic_bias,
-	.set_uart_console = fsa8008_set_uart_console,
+	.set_uart_console = set_uart_console,
 };
 
 static struct platform_device lge_hsd_device = {
@@ -221,14 +223,27 @@
 	},
 };
 
-static int __init lge_hsd_fsa8008_init(void)
-{
-	printk(KERN_INFO "lge_hsd_fsa8008_init\n");
-	return platform_device_register(&lge_hsd_device);
-}
+#define GPIO_EARJACK_DEBUGGER_TRIGGER       PM8921_GPIO_PM_TO_SYS(13)
+static struct earjack_debugger_platform_data earjack_debugger_pdata = {
+	.gpio_trigger = GPIO_EARJACK_DEBUGGER_TRIGGER,
+	.set_uart_console = set_uart_console,
+};
+
+static struct platform_device earjack_debugger_device = {
+	.name = "earjack-debugger-trigger",
+	.id = -1,
+	.dev = {
+		.platform_data = &earjack_debugger_pdata,
+	},
+};
+
+static struct platform_device *sound_devices[] __initdata = {
+	&lge_hsd_device,
+	&earjack_debugger_device,
+};
 
 void __init lge_add_sound_devices(void)
 {
 	lge_add_i2c_tpa2028d_devices();
-	lge_hsd_fsa8008_init();
+	platform_add_devices(sound_devices, ARRAY_SIZE(sound_devices));
 }