thermal: tsens: Add suspend/resume for TSENS

TSENS does not operate reliably during VDD_CX minimization.
Incorrect temperature readings are reported on some instances
when Apps processor comes out of suspend. This leads the
TSENS interrupt being triggered in critical temperature zone.

Thermal sys takes drastic action of shutting down the phone
which is not desired. Hence remove updating the thermal sys
on temperature changes as its not required.

CRs-Fixed: 309855
Change-Id: Id6186b2a6032150273bc0d74d91c72db5a077ac7
Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org>
diff --git a/drivers/thermal/msm_tsens.c b/drivers/thermal/msm_tsens.c
index f4e094e..d9a6efc 100644
--- a/drivers/thermal/msm_tsens.c
+++ b/drivers/thermal/msm_tsens.c
@@ -24,6 +24,7 @@
 
 #include <linux/io.h>
 #include <mach/msm_iomap.h>
+#include <linux/pm.h>
 
 /* Trips: from very hot to very cold */
 enum tsens_trip_type {
@@ -88,6 +89,7 @@
 	bool prev_reading_avail;
 	int offset;
 	struct work_struct work;
+	uint32_t pm_tsens_thr_data;
 };
 
 struct tsens_tm_device *tmdev;
@@ -471,9 +473,6 @@
 			if (lower_th_x)
 				mask |= TSENS_LOWER_STATUS_CLR;
 			if (upper_th_x || lower_th_x) {
-				thermal_zone_device_update(
-							tm->sensor[i].tz_dev);
-
 				/* Notify user space */
 				schedule_work(&tm->work);
 				adc_code = readl(TSENS_S0_STATUS_ADDR
@@ -490,6 +489,53 @@
 	return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_PM
+static int tsens_suspend(struct device *dev)
+{
+	unsigned int reg;
+
+	tmdev->pm_tsens_thr_data = readl_relaxed(TSENS_THRESHOLD_ADDR);
+	reg = readl_relaxed(TSENS_CNTL_ADDR);
+	writel_relaxed(reg & ~(TSENS_SLP_CLK_ENA | TSENS_EN), TSENS_CNTL_ADDR);
+	tmdev->prev_reading_avail = 0;
+
+	disable_irq_nosync(TSENS_UPPER_LOWER_INT);
+	mb();
+	return 0;
+}
+
+static int tsens_resume(struct device *dev)
+{
+	unsigned int reg;
+
+	reg = readl_relaxed(TSENS_CNTL_ADDR);
+	writel_relaxed(reg | TSENS_SW_RST, TSENS_CNTL_ADDR);
+	reg |= TSENS_SLP_CLK_ENA | TSENS_EN | (TSENS_MEASURE_PERIOD << 16) |
+		TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
+		TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
+		(((1 << TSENS_NUM_SENSORS) - 1) << 3);
+
+	reg = (reg & ~TSENS_CONFIG_MASK) | (TSENS_CONFIG << TSENS_CONFIG_SHIFT);
+	writel_relaxed(reg, TSENS_CNTL_ADDR);
+
+	if (tmdev->sensor->mode == THERMAL_DEVICE_DISABLED) {
+		writel_relaxed(reg & ~((((1 << TSENS_NUM_SENSORS) - 1) << 3)
+			| TSENS_SLP_CLK_ENA | TSENS_EN), TSENS_CNTL_ADDR);
+	}
+
+	writel_relaxed(tmdev->pm_tsens_thr_data, TSENS_THRESHOLD_ADDR);
+
+	enable_irq(TSENS_UPPER_LOWER_INT);
+	mb();
+	return 0;
+}
+
+static const struct dev_pm_ops tsens_pm_ops = {
+	.suspend	= tsens_suspend,
+	.resume		= tsens_resume,
+};
+#endif
+
 static int __devinit tsens_tm_probe(struct platform_device *pdev)
 {
 	unsigned int reg, i, calib_data, calib_data_backup;
@@ -555,7 +601,6 @@
 			return -ENODEV;
 		}
 		tmdev->sensor[i].sensor_num = i;
-		thermal_zone_device_update(tmdev->sensor[i].tz_dev);
 		tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
 	}
 
@@ -596,6 +641,9 @@
 	.driver	= {
 		.name = "tsens-tm",
 		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &tsens_pm_ops,
+#endif
 	},
 };