msm_serial_hs: Add ioctl support for UART Clock on/off request

This change adds support for ioctl implementation in HSUART
driver. UART Client application (e.g. Bluetooth) can make
request for UART Clock on/off using the ioctl mechanism.
UART Clock status also can be queried using this mechanism.

CRs-Fixed: 496245
Change-Id: I9531cf2f9eda487082b9719341c5ad84c15ad5f7
Signed-off-by: Saket Saurabh <ssaurabh@codeaurora.org>
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 4d464c1..7f669d8 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -245,6 +245,48 @@
 #define UARTDM_TO_MSM(uart_port) \
 	container_of((uart_port), struct msm_hs_port, uport)
 
+
+static int msm_hs_ioctl(struct uart_port *uport, unsigned int cmd,
+						unsigned long arg)
+{
+	int ret = 0, state = 1;
+	enum msm_hs_clk_states_e clk_state;
+	unsigned long flags;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	switch (cmd) {
+	case MSM_ENABLE_UART_CLOCK: {
+		pr_debug("%s():ENABLE UART CLOCK: cmd=%d\n", __func__, cmd);
+		msm_hs_request_clock_on(&msm_uport->uport);
+		break;
+	}
+	case MSM_DISABLE_UART_CLOCK: {
+		pr_debug("%s():DISABLE UART CLOCK: cmd=%d\n", __func__, cmd);
+		msm_hs_request_clock_off(&msm_uport->uport);
+		break;
+	}
+	case MSM_GET_UART_CLOCK_STATUS: {
+		/* Return value 0 - UART CLOCK is OFF
+		 * Return value 1 - UART CLOCK is ON */
+		pr_debug("%s():GET UART CLOCK STATUS: cmd=%d\n", __func__, cmd);
+		spin_lock_irqsave(&msm_uport->uport.lock, flags);
+		clk_state = msm_uport->clk_state;
+		spin_unlock_irqrestore(&msm_uport->uport.lock, flags);
+		if (clk_state <= MSM_HS_CLK_OFF)
+			state = 0;
+		ret = state;
+		break;
+	}
+	default: {
+		pr_debug("%s():Unknown cmd specified: cmd=%d\n", __func__, cmd);
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+	}
+
+	return ret;
+}
+
 static ssize_t show_clock(struct device *dev, struct device_attribute *attr,
 			  char *buf)
 {
@@ -3307,6 +3349,7 @@
 	.release_port = msm_hs_release_port,
 	.request_port = msm_hs_request_port,
 	.flush_buffer = msm_hs_flush_buffer,
+	.ioctl = msm_hs_ioctl,
 };
 
 module_init(msm_serial_hs_init);
diff --git a/drivers/tty/serial/msm_serial_hs_hwreg.h b/drivers/tty/serial/msm_serial_hs_hwreg.h
index cdd0450..cd24f23 100644
--- a/drivers/tty/serial/msm_serial_hs_hwreg.h
+++ b/drivers/tty/serial/msm_serial_hs_hwreg.h
@@ -32,6 +32,10 @@
 #define ADM1_CRCI_GSBI6_RX_SEL         0x800
 #define ADM1_CRCI_GSBI6_TX_SEL         0x400
 
+#define MSM_ENABLE_UART_CLOCK 13
+#define MSM_DISABLE_UART_CLOCK 14
+#define MSM_GET_UART_CLOCK_STATUS 15
+
 enum msm_hsl_regs {
 	UARTDM_MR1,
 	UARTDM_MR2,