msm_serial_hs: Use new clock framework apis

Clock framework provides clk_prepare/clk_unprepare (callable from
non-atomic context only) and clk_enable/clk_disable (callable from
atomic/non-atomic context) APIs. Start using these new APIs.

To use these new Clock APIs below changes are done in driver.
1. wakeup irq is converted into wakeup threaded irq.
2. New mutex lock (clk_mutex) is introduced to guard the clock
off/on request and making sure that there is no race condition
exist between these two asynchronous calls.
3. current UART Tx/Rx activities and clock status is checked in
msm_hs_isr() function by calling msm_hs_check_clock_off_locked()
function. Based on the return value of it, clock off timer is
started. Now same functionality is achieved by clock_off_work and
it is used instead of explicit function call.

With these changes, HSUART_DM driver imposes below restrictions on
usage of exported Clock On/Off APIs.
1. Client driver shouldn't call msm_hs_request_clk_on() API from
atomic context. It must be called from non-atomic context.
2. Client driver can call msm_hs_requeset_clk_off() API from
both atomic / non-atomic context.

Change-Id: I75512f488bb53f4f9a08879a1d473706861f5cd4
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 0e121d1..fc665ed 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -163,6 +163,9 @@
 	struct wake_lock dma_wake_lock;  /* held while any DMA active */
 
 	struct dentry *loopback_dir;
+	struct work_struct clock_off_w; /* work for actual clock off */
+	struct workqueue_struct *hsuart_wq; /* hsuart workqueue */
+	struct mutex clk_mutex; /* mutex to guard against clock off/clock on */
 };
 
 #define MSM_UARTDM_BURST_SIZE 16   /* DM burst size (in bytes) */
@@ -307,9 +310,9 @@
 	unsigned long flags;
 	int ret = 0;
 
-	clk_enable(msm_uport->clk);
+	clk_prepare_enable(msm_uport->clk);
 	if (msm_uport->pclk)
-		clk_enable(msm_uport->pclk);
+		clk_prepare_enable(msm_uport->pclk);
 
 	if (val) {
 		spin_lock_irqsave(&uport->lock, flags);
@@ -326,9 +329,9 @@
 	}
 	/* Calling CLOCK API. Hence mb() requires here. */
 	mb();
-	clk_disable(msm_uport->clk);
+	clk_disable_unprepare(msm_uport->clk);
 	if (msm_uport->pclk)
-		clk_disable(msm_uport->pclk);
+		clk_disable_unprepare(msm_uport->pclk);
 
 	return 0;
 }
@@ -340,17 +343,17 @@
 	unsigned long flags;
 	int ret = 0;
 
-	clk_enable(msm_uport->clk);
+	clk_prepare_enable(msm_uport->clk);
 	if (msm_uport->pclk)
-		clk_enable(msm_uport->pclk);
+		clk_prepare_enable(msm_uport->pclk);
 
 	spin_lock_irqsave(&uport->lock, flags);
 	ret = msm_hs_read(&msm_uport->uport, UARTDM_MR2_ADDR);
 	spin_unlock_irqrestore(&uport->lock, flags);
 
-	clk_disable(msm_uport->clk);
+	clk_disable_unprepare(msm_uport->clk);
 	if (msm_uport->pclk)
-		clk_disable(msm_uport->pclk);
+		clk_disable_unprepare(msm_uport->pclk);
 
 	*val = (ret & UARTDM_MR2_LOOP_MODE_BMSK) ? 1 : 0;
 	return 0;
@@ -418,9 +421,13 @@
 
 	wake_lock_destroy(&msm_uport->rx.wake_lock);
 	wake_lock_destroy(&msm_uport->dma_wake_lock);
+	destroy_workqueue(msm_uport->hsuart_wq);
+	mutex_destroy(&msm_uport->clk_mutex);
 
 	uart_remove_one_port(&msm_hs_driver, &msm_uport->uport);
 	clk_put(msm_uport->clk);
+	if (msm_uport->pclk)
+		clk_put(msm_uport->pclk);
 
 	/* Free the tx resources */
 	kfree(msm_uport->tx.command_ptr);
@@ -447,15 +454,15 @@
 		return ret;
 	}
 
-	ret = clk_enable(msm_uport->clk);
+	ret = clk_prepare_enable(msm_uport->clk);
 	if (ret) {
 		printk(KERN_ERR "Error could not turn on UART clk\n");
 		return ret;
 	}
 	if (msm_uport->pclk) {
-		ret = clk_enable(msm_uport->pclk);
+		ret = clk_prepare_enable(msm_uport->pclk);
 		if (ret) {
-			clk_disable(msm_uport->clk);
+			clk_disable_unprepare(msm_uport->clk);
 			dev_err(uport->dev,
 				"Error could not turn on UART pclk\n");
 			return ret;
@@ -1250,16 +1257,16 @@
 		msm_hs_request_port(uport);
 	}
 
-	spin_lock_irqsave(&uport->lock, flags);
 	if (is_gsbi_uart(msm_uport)) {
 		if (msm_uport->pclk)
-			clk_enable(msm_uport->pclk);
+			clk_prepare_enable(msm_uport->pclk);
+		spin_lock_irqsave(&uport->lock, flags);
 		iowrite32(GSBI_PROTOCOL_UART, msm_uport->mapped_gsbi +
 			  GSBI_CONTROL_ADDR);
+		spin_unlock_irqrestore(&uport->lock, flags);
 		if (msm_uport->pclk)
-			clk_disable(msm_uport->pclk);
+			clk_disable_unprepare(msm_uport->pclk);
 	}
-	spin_unlock_irqrestore(&uport->lock, flags);
 }
 
 /*  Handle CTS changes (Called from interrupt handler) */
@@ -1280,24 +1287,33 @@
  *        -1 did not clock off, do not retry
  *         1 if we clocked off
  */
-static int msm_hs_check_clock_off_locked(struct uart_port *uport)
+static int msm_hs_check_clock_off(struct uart_port *uport)
 {
 	unsigned long sr_status;
+	unsigned long flags;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 	struct circ_buf *tx_buf = &uport->state->xmit;
 
+	mutex_lock(&msm_uport->clk_mutex);
+	spin_lock_irqsave(&uport->lock, flags);
+
 	/* Cancel if tx tty buffer is not empty, dma is in flight,
 	 * or tx fifo is not empty */
 	if (msm_uport->clk_state != MSM_HS_CLK_REQUEST_OFF ||
 	    !uart_circ_empty(tx_buf) || msm_uport->tx.dma_in_flight ||
 	    msm_uport->imr_reg & UARTDM_ISR_TXLEV_BMSK) {
+		spin_unlock_irqrestore(&uport->lock, flags);
+		mutex_unlock(&msm_uport->clk_mutex);
 		return -1;
 	}
 
 	/* Make sure the uart is finished with the last byte */
 	sr_status = msm_hs_read(uport, UARTDM_SR_ADDR);
-	if (!(sr_status & UARTDM_SR_TXEMT_BMSK))
+	if (!(sr_status & UARTDM_SR_TXEMT_BMSK)) {
+		spin_unlock_irqrestore(&uport->lock, flags);
+		mutex_unlock(&msm_uport->clk_mutex);
 		return 0;  /* retry */
+	}
 
 	/* Make sure forced RXSTALE flush complete */
 	switch (msm_uport->clk_req_off_state) {
@@ -1309,9 +1325,13 @@
 		 * Hence mb() requires here.
 		 */
 		mb();
+		spin_unlock_irqrestore(&uport->lock, flags);
+		mutex_unlock(&msm_uport->clk_mutex);
 		return 0;  /* RXSTALE flush not complete - retry */
 	case CLK_REQ_OFF_RXSTALE_ISSUED:
 	case CLK_REQ_OFF_FLUSH_ISSUED:
+		spin_unlock_irqrestore(&uport->lock, flags);
+		mutex_unlock(&msm_uport->clk_mutex);
 		return 0;  /* RXSTALE flush not complete - retry */
 	case CLK_REQ_OFF_RXSTALE_FLUSHED:
 		break;  /* continue */
@@ -1320,39 +1340,53 @@
 	if (msm_uport->rx.flush != FLUSH_SHUTDOWN) {
 		if (msm_uport->rx.flush == FLUSH_NONE)
 			msm_hs_stop_rx_locked(uport);
+
+		spin_unlock_irqrestore(&uport->lock, flags);
+		mutex_unlock(&msm_uport->clk_mutex);
 		return 0;  /* come back later to really clock off */
 	}
 
+	spin_unlock_irqrestore(&uport->lock, flags);
+
 	/* we really want to clock off */
-	clk_disable(msm_uport->clk);
+	clk_disable_unprepare(msm_uport->clk);
 	if (msm_uport->pclk)
-		clk_disable(msm_uport->pclk);
+		clk_disable_unprepare(msm_uport->pclk);
+
 	msm_uport->clk_state = MSM_HS_CLK_OFF;
+
+	spin_lock_irqsave(&uport->lock, flags);
 	if (use_low_power_wakeup(msm_uport)) {
 		msm_uport->wakeup.ignore = 1;
 		enable_irq(msm_uport->wakeup.irq);
 	}
 	wake_unlock(&msm_uport->dma_wake_lock);
+
+	spin_unlock_irqrestore(&uport->lock, flags);
+	mutex_unlock(&msm_uport->clk_mutex);
 	return 1;
 }
 
-static enum hrtimer_restart msm_hs_clk_off_retry(struct hrtimer *timer) {
-	unsigned long flags;
-	int ret = HRTIMER_NORESTART;
-	struct msm_hs_port *msm_uport = container_of(timer, struct msm_hs_port,
-						     clk_off_timer);
+static void hsuart_clock_off_work(struct work_struct *w)
+{
+	struct msm_hs_port *msm_uport = container_of(w, struct msm_hs_port,
+							clock_off_w);
 	struct uart_port *uport = &msm_uport->uport;
 
-	spin_lock_irqsave(&uport->lock, flags);
-
-	if (!msm_hs_check_clock_off_locked(uport)) {
-		hrtimer_forward_now(timer, msm_uport->clk_off_delay);
-		ret = HRTIMER_RESTART;
+	if (!msm_hs_check_clock_off(uport)) {
+		hrtimer_start(&msm_uport->clk_off_timer,
+				msm_uport->clk_off_delay,
+				HRTIMER_MODE_REL);
 	}
+}
 
-	spin_unlock_irqrestore(&uport->lock, flags);
+static enum hrtimer_restart msm_hs_clk_off_retry(struct hrtimer *timer)
+{
+	struct msm_hs_port *msm_uport = container_of(timer, struct msm_hs_port,
+							clk_off_timer);
 
-	return ret;
+	queue_work(msm_uport->hsuart_wq, &msm_uport->clock_off_w);
+	return HRTIMER_NORESTART;
 }
 
 static irqreturn_t msm_hs_isr(int irq, void *dev)
@@ -1432,10 +1466,7 @@
 		 * Hence mb() requires here.
 		 */
 		mb();
-		if (!msm_hs_check_clock_off_locked(uport))
-			hrtimer_start(&msm_uport->clk_off_timer,
-				      msm_uport->clk_off_delay,
-				      HRTIMER_MODE_REL);
+		queue_work(msm_uport->hsuart_wq, &msm_uport->clock_off_w);
 	}
 
 	/* Change in CTS interrupt */
@@ -1468,23 +1499,38 @@
 }
 EXPORT_SYMBOL(msm_hs_request_clock_off);
 
-static void msm_hs_request_clock_on_locked(struct uart_port *uport) {
+void msm_hs_request_clock_on(struct uart_port *uport)
+{
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+	unsigned long flags;
 	unsigned int data;
 	int ret = 0;
 
+	mutex_lock(&msm_uport->clk_mutex);
+	spin_lock_irqsave(&uport->lock, flags);
+
 	switch (msm_uport->clk_state) {
 	case MSM_HS_CLK_OFF:
 		wake_lock(&msm_uport->dma_wake_lock);
-		clk_enable(msm_uport->clk);
-		if (msm_uport->pclk)
-			ret = clk_enable(msm_uport->pclk);
 		disable_irq_nosync(msm_uport->wakeup.irq);
-		if (unlikely(ret)) {
+		spin_unlock_irqrestore(&uport->lock, flags);
+		ret = clk_prepare_enable(msm_uport->clk);
+		if (ret) {
 			dev_err(uport->dev, "Clock ON Failure"
-				"Stalling HSUART\n");
+			"For UART CLK Stalling HSUART\n");
 			break;
 		}
+
+		if (msm_uport->pclk) {
+			ret = clk_prepare_enable(msm_uport->pclk);
+			if (unlikely(ret)) {
+				clk_disable_unprepare(msm_uport->clk);
+				dev_err(uport->dev, "Clock ON Failure"
+				"For UART Pclk Stalling HSUART\n");
+				break;
+			}
+		}
+		spin_lock_irqsave(&uport->lock, flags);
 		/* else fall-through */
 	case MSM_HS_CLK_REQUEST_OFF:
 		if (msm_uport->rx.flush == FLUSH_STOP ||
@@ -1508,13 +1554,9 @@
 	case MSM_HS_CLK_PORT_OFF:
 		break;
 	}
-}
 
-void msm_hs_request_clock_on(struct uart_port *uport) {
-	unsigned long flags;
-	spin_lock_irqsave(&uport->lock, flags);
-	msm_hs_request_clock_on_locked(uport);
 	spin_unlock_irqrestore(&uport->lock, flags);
+	mutex_unlock(&msm_uport->clk_mutex);
 }
 EXPORT_SYMBOL(msm_hs_request_clock_on);
 
@@ -1539,7 +1581,9 @@
 	if (wakeup) {
 		/* the uart was clocked off during an rx, wake up and
 		 * optionally inject char into tty rx */
-		msm_hs_request_clock_on_locked(uport);
+		spin_unlock_irqrestore(&uport->lock, flags);
+		msm_hs_request_clock_on(uport);
+		spin_lock_irqsave(&uport->lock, flags);
 		if (msm_uport->wakeup.inject_rx) {
 			tty = uport->state->port.tty;
 			tty_insert_flip_char(tty,
@@ -1663,9 +1707,12 @@
 		goto free_wake_irq;
 	}
 	if (use_low_power_wakeup(msm_uport)) {
-		ret = request_irq(msm_uport->wakeup.irq, msm_hs_wakeup_isr,
-				  IRQF_TRIGGER_FALLING,
-				  "msm_hs_wakeup", msm_uport);
+
+		ret = request_threaded_irq(msm_uport->wakeup.irq, NULL,
+					msm_hs_wakeup_isr,
+					IRQF_TRIGGER_FALLING,
+					"msm_hs_wakeup", msm_uport);
+
 		if (unlikely(ret)) {
 			pr_err("%s():Err getting uart wakeup_irq\n", __func__);
 			goto free_uart_irq;
@@ -1690,9 +1737,9 @@
 free_wake_irq:
 	irq_set_irq_wake(msm_uport->wakeup.irq, 0);
 deinit_uart_clk:
-	clk_disable(msm_uport->clk);
+	clk_disable_unprepare(msm_uport->clk);
 	if (msm_uport->pclk)
-		clk_disable(msm_uport->pclk);
+		clk_disable_unprepare(msm_uport->pclk);
 	wake_unlock(&msm_uport->dma_wake_lock);
 
 	return ret;
@@ -1908,6 +1955,17 @@
 		return ret;
 	}
 
+	msm_uport->hsuart_wq = alloc_workqueue("k_hsuart",
+					WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+	if (!msm_uport->hsuart_wq) {
+		pr_err("%s(): Unable to create workqueue hsuart_wq\n",
+								__func__);
+		return -ENOMEM;
+	}
+
+	INIT_WORK(&msm_uport->clock_off_w, hsuart_clock_off_work);
+	mutex_init(&msm_uport->clk_mutex);
+
 	ret = uartdm_init_port(uport);
 	if (unlikely(ret))
 		return ret;
@@ -1974,7 +2032,6 @@
  */
 static void msm_hs_shutdown(struct uart_port *uport)
 {
-	unsigned long flags;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 
 	BUG_ON(msm_uport->rx.flush < FLUSH_STOP);
@@ -1983,10 +2040,11 @@
 	tasklet_kill(&msm_uport->rx.tlet);
 	cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work);
 
+	flush_workqueue(msm_uport->hsuart_wq);
 	pm_runtime_disable(uport->dev);
 	pm_runtime_set_suspended(uport->dev);
 
-	spin_lock_irqsave(&uport->lock, flags);
+	mutex_lock(&msm_uport->clk_mutex);
 	/* Disable the transmitter */
 	msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK);
 	/* Disable the receiver */
@@ -2001,9 +2059,10 @@
 	mb();
 
 	if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
-		clk_disable(msm_uport->clk);  /* to balance clk_state */
+		/* to balance clk_state */
+		clk_disable_unprepare(msm_uport->clk);
 		if (msm_uport->pclk)
-			clk_disable(msm_uport->pclk);
+			clk_disable_unprepare(msm_uport->pclk);
 		wake_unlock(&msm_uport->dma_wake_lock);
 	}
 	msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
@@ -2011,8 +2070,6 @@
 	dma_unmap_single(uport->dev, msm_uport->tx.dma_base,
 			 UART_XMIT_SIZE, DMA_TO_DEVICE);
 
-	spin_unlock_irqrestore(&uport->lock, flags);
-
 	if (use_low_power_wakeup(msm_uport))
 		irq_set_irq_wake(msm_uport->wakeup.irq, 0);
 
@@ -2020,6 +2077,8 @@
 	free_irq(uport->irq, msm_uport);
 	if (use_low_power_wakeup(msm_uport))
 		free_irq(msm_uport->wakeup.irq, msm_uport);
+	mutex_unlock(&msm_uport->clk_mutex);
+	mutex_destroy(&msm_uport->clk_mutex);
 }
 
 static void __exit msm_serial_hs_exit(void)