thermal: tsens: Enable monitoring watchdog

Handle watchdog interrupt from the temperature
sensor (TSENS) controller. Log the TSENS debug
ID and data dump if the TSENS watchdog has reset
the controller. The data dump provides the state
of the controller for debug purpose.

Change-Id: Id415d2cea5087cb612ad9b918b91b4b8ad2f9f66
Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org>
diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c
index 13b183d..55be2f9 100644
--- a/drivers/thermal/tsens2xxx.c
+++ b/drivers/thermal/tsens2xxx.c
@@ -57,6 +57,8 @@
 #define TSENS_TM_CODE_BIT_MASK			0xfff
 #define TSENS_TM_CODE_SIGN_BIT			0x800
 #define TSENS_TM_SCALE_DECI_MILLIDEG		100
+#define TSENS_DEBUG_WDOG_TRIGGER_COUNT		5
+#define TSENS_TM_WATCHDOG_LOG(n)		((n) + 0x13c)
 
 #define TSENS_EN				BIT(0)
 
@@ -296,13 +298,11 @@
 static irqreturn_t tsens_tm_critical_irq_thread(int irq, void *data)
 {
 	struct tsens_device *tm = data;
-	unsigned int i, status;
+	unsigned int i, status, wd_log, wd_mask;
 	unsigned long flags;
-	void __iomem *sensor_status_addr;
-	void __iomem *sensor_int_mask_addr;
+	void __iomem *sensor_status_addr, *sensor_int_mask_addr;
 	void __iomem *sensor_critical_addr;
-	void __iomem *wd_critical_addr;
-	int wd_mask;
+	void __iomem *wd_critical_addr, *wd_log_addr;
 
 	sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_tm_addr);
 	sensor_int_mask_addr =
@@ -311,6 +311,7 @@
 		TSENS_TM_SN_CRITICAL_THRESHOLD(tm->tsens_tm_addr);
 	wd_critical_addr =
 		TSENS_TM_CRITICAL_INT_STATUS(tm->tsens_tm_addr);
+	wd_log_addr = TSENS_TM_WATCHDOG_LOG(tm->tsens_tm_addr);
 
 	if (tm->ctrl_data->wd_bark) {
 		wd_mask = readl_relaxed(wd_critical_addr);
@@ -325,7 +326,15 @@
 			writel_relaxed(wd_mask & ~(TSENS_TM_CRITICAL_WD_BARK),
 				(TSENS_TM_CRITICAL_INT_CLEAR
 				(tm->tsens_tm_addr)));
-			tm->tsens_dbg.tsens_critical_wd_cnt++;
+			wd_log = readl_relaxed(wd_log_addr);
+			if (wd_log >= TSENS_DEBUG_WDOG_TRIGGER_COUNT) {
+				pr_err("Watchdog count:%d\n", wd_log);
+				if (tm->ops->dbg)
+					tm->ops->dbg(tm, 0,
+					TSENS_DBG_LOG_BUS_ID_DATA, NULL);
+				BUG();
+			}
+
 			return IRQ_HANDLED;
 		}
 	}
@@ -494,8 +503,7 @@
 {
 	void __iomem *srot_addr;
 	void __iomem *sensor_int_mask_addr;
-	unsigned int srot_val;
-	int crit_mask;
+	unsigned int srot_val, crit_mask, crit_val;
 
 	srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
 	srot_val = readl_relaxed(srot_addr);
@@ -508,13 +516,36 @@
 		sensor_int_mask_addr =
 			TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr);
 		crit_mask = readl_relaxed(sensor_int_mask_addr);
-		writel_relaxed(
-			crit_mask | tmdev->ctrl_data->cycle_compltn_monitor_val,
-			(TSENS_TM_CRITICAL_INT_MASK
-			(tmdev->tsens_tm_addr)));
+		crit_val = TSENS_TM_CRITICAL_CYCLE_MONITOR;
+		if (tmdev->ctrl_data->cycle_compltn_monitor_mask)
+			writel_relaxed((crit_mask | crit_val),
+				(TSENS_TM_CRITICAL_INT_MASK
+				(tmdev->tsens_tm_addr)));
+		else
+			writel_relaxed((crit_mask & ~crit_val),
+				(TSENS_TM_CRITICAL_INT_MASK
+				(tmdev->tsens_tm_addr)));
 		/*Update critical cycle monitoring*/
 		mb();
 	}
+
+	if (tmdev->ctrl_data->wd_bark) {
+		sensor_int_mask_addr =
+			TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr);
+		crit_mask = readl_relaxed(sensor_int_mask_addr);
+		crit_val = TSENS_TM_CRITICAL_WD_BARK;
+		if (tmdev->ctrl_data->wd_bark_mask)
+			writel_relaxed((crit_mask | crit_val),
+			(TSENS_TM_CRITICAL_INT_MASK
+			(tmdev->tsens_tm_addr)));
+		else
+			writel_relaxed((crit_mask & ~crit_val),
+			(TSENS_TM_CRITICAL_INT_MASK
+			(tmdev->tsens_tm_addr)));
+		/*Update watchdog monitoring*/
+		mb();
+	}
+
 	writel_relaxed(TSENS_TM_CRITICAL_INT_EN |
 		TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN,
 		TSENS_TM_INT_EN(tmdev->tsens_tm_addr));
@@ -575,24 +606,25 @@
 
 const struct tsens_data data_tsens2xxx = {
 	.cycle_monitor			= false,
-	.cycle_compltn_monitor_val	= 0,
+	.cycle_compltn_monitor_mask	= 1,
 	.wd_bark			= false,
-	.wd_bark_val			= 0,
+	.wd_bark_mask			= 1,
 	.ops				= &ops_tsens2xxx,
 };
 
 const struct tsens_data data_tsens23xx = {
 	.cycle_monitor			= true,
-	.cycle_compltn_monitor_val	= 0,
+	.cycle_compltn_monitor_mask	= 1,
 	.wd_bark			= true,
-	.wd_bark_val			= 0,
+	.wd_bark_mask			= 1,
 	.ops				= &ops_tsens2xxx,
 };
 
 const struct tsens_data data_tsens24xx = {
 	.cycle_monitor			= true,
-	.cycle_compltn_monitor_val	= 0,
+	.cycle_compltn_monitor_mask	= 1,
 	.wd_bark			= true,
-	.wd_bark_val			= 1,
+	/* Enable Watchdog monitoring by unmasking */
+	.wd_bark_mask			= 0,
 	.ops				= &ops_tsens2xxx,
 };