tsif: use new clock preparation functions

Replace the clk_enable() with clk_prepare_enable() and replace
clk_disable() with clk_disable_unprepare() functions.
Add a new tasklet so the clocks can be turned off and
unprepared from the irq context in the case of emergency.

Change-Id: Ic63c6c25600069938b414974c5e1237943ffe2e7
Signed-off-by: Joel Nider <jnider@codeaurora.org>
diff --git a/drivers/misc/tsif.c b/drivers/misc/tsif.c
index aeda38c..7e59c98 100644
--- a/drivers/misc/tsif.c
+++ b/drivers/misc/tsif.c
@@ -169,6 +169,7 @@
 	dma_addr_t dmov_cmd_dma[2];
 	struct tsif_xfer xfer[2];
 	struct tasklet_struct dma_refill;
+	struct tasklet_struct clocks_off;
 	/* statistics */
 	u32 stat_rx;
 	u32 stat_overflow;
@@ -251,18 +252,24 @@
 {
 	if (on) {
 		if (tsif_device->tsif_clk)
-			clk_enable(tsif_device->tsif_clk);
+			clk_prepare_enable(tsif_device->tsif_clk);
 		if (tsif_device->tsif_pclk)
-			clk_enable(tsif_device->tsif_pclk);
-		clk_enable(tsif_device->tsif_ref_clk);
+			clk_prepare_enable(tsif_device->tsif_pclk);
+		clk_prepare_enable(tsif_device->tsif_ref_clk);
 	} else {
 		if (tsif_device->tsif_clk)
-			clk_disable(tsif_device->tsif_clk);
+			clk_disable_unprepare(tsif_device->tsif_clk);
 		if (tsif_device->tsif_pclk)
-			clk_disable(tsif_device->tsif_pclk);
-		clk_disable(tsif_device->tsif_ref_clk);
+			clk_disable_unprepare(tsif_device->tsif_pclk);
+		clk_disable_unprepare(tsif_device->tsif_ref_clk);
 	}
 }
+
+static void tsif_clocks_off(unsigned long data)
+{
+	struct msm_tsif_device *tsif_device = (struct msm_tsif_device *) data;
+	tsif_clock(tsif_device, 0);
+}
 /* ===clocks end=== */
 /* ===gpio begin=== */
 
@@ -605,17 +612,15 @@
 			if (tsif_device->state == tsif_state_running) {
 				tsif_stop_hw(tsif_device);
 				/*
-				 * Clocks _may_ be stopped right from IRQ
-				 * context. This is far from optimal w.r.t
-				 * latency.
-				 *
-				 * But, this branch taken only in case of
+				 * This branch is taken only in case of
 				 * severe hardware problem (I don't even know
-				 * what should happens for DMOV_RSLT_ERROR);
+				 * what should happen for DMOV_RSLT_ERROR);
 				 * thus I prefer code simplicity over
 				 * performance.
+				 * Clocks are turned off from outside the
+				 * interrupt context.
 				 */
-				tsif_clock(tsif_device, 0);
+				tasklet_schedule(&tsif_device->clocks_off);
 				tsif_device->state = tsif_state_flushing;
 			}
 		}
@@ -1313,6 +1318,8 @@
 	tsif_device->chunks_per_buf = TSIF_CHUNKS_IN_BUF_DEFAULT;
 	tasklet_init(&tsif_device->dma_refill, tsif_dma_refill,
 		     (unsigned long)tsif_device);
+	tasklet_init(&tsif_device->clocks_off, tsif_clocks_off,
+		     (unsigned long)tsif_device);
 	if (tsif_get_clocks(tsif_device))
 		goto err_clocks;
 /* map I/O memory */