thermal: tsens: Add calibration support for MSM8909

Add efuse reads to compute slope and offset used to convert final
temperature readings. Add all efuse related TSENS reads for 1xxx
controller across different targets in a common file for calibration.

Change-Id: I85bf5864230c60d796c4a32963fe896da5f9a095
Signed-off-by: Chinkit Kumar,Kirti Kumar Parmar <parma@codeaurora.org>
diff --git a/drivers/thermal/tsens_calib.c b/drivers/thermal/tsens_calib.c
new file mode 100644
index 0000000..04dd5c5
--- /dev/null
+++ b/drivers/thermal/tsens_calib.c
@@ -0,0 +1,285 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include "tsens.h"
+
+/* eeprom layout data for 8937 */
+#define BASE0_MASK_8937				0x000000ff
+#define BASE1_MASK_8937				0xff000000
+#define BASE1_SHIFT_8937			24
+
+#define S0_P1_MASK_8937				0x000001f8
+#define S1_P1_MASK_8937				0x001f8000
+#define S2_P1_MASK_0_4_8937			0xf8000000
+#define S2_P1_MASK_5_8937			0x00000001
+#define S3_P1_MASK_8937				0x00001f80
+#define S4_P1_MASK_8937				0x01f80000
+#define S5_P1_MASK_8937				0x00003f00
+#define S6_P1_MASK_8937				0x03f00000
+#define S7_P1_MASK_8937				0x0000003f
+#define S8_P1_MASK_8937				0x0003f000
+#define S9_P1_MASK_8937				0x0000003f
+#define S10_P1_MASK_8937			0x0003f000
+
+#define S0_P2_MASK_8937				0x00007e00
+#define S1_P2_MASK_8937				0x07e00000
+#define S2_P2_MASK_8937				0x0000007e
+#define S3_P2_MASK_8937				0x0007e000
+#define S4_P2_MASK_8937				0x7e000000
+#define S5_P2_MASK_8937				0x000fc000
+#define S6_P2_MASK_8937				0xfc000000
+#define S7_P2_MASK_8937				0x00000fc0
+#define S8_P2_MASK_8937				0x00fc0000
+#define S9_P2_MASK_8937				0x00000fc0
+#define S10_P2_MASK_8937			0x00fc0000
+
+#define S0_P1_SHIFT_8937			3
+#define S1_P1_SHIFT_8937			15
+#define S2_P1_SHIFT_0_4_8937			27
+#define S2_P1_SHIFT_5_8937			5
+#define S3_P1_SHIFT_8937			7
+#define S4_P1_SHIFT_8937			19
+#define S5_P1_SHIFT_8937			8
+#define S6_P1_SHIFT_8937			20
+#define S8_P1_SHIFT_8937			12
+#define S10_P1_SHIFT_8937			12
+
+#define S0_P2_SHIFT_8937			9
+#define S1_P2_SHIFT_8937			21
+#define S2_P2_SHIFT_8937			1
+#define S3_P2_SHIFT_8937			13
+#define S4_P2_SHIFT_8937			25
+#define S5_P2_SHIFT_8937			14
+#define S6_P2_SHIFT_8937			26
+#define S7_P2_SHIFT_8937			6
+#define S8_P2_SHIFT_8937			18
+#define S9_P2_SHIFT_8937			6
+#define S10_P2_SHIFT_8937			18
+
+#define CAL_SEL_MASK_8937			0x00000007
+
+/* eeprom layout for 8909 */
+#define TSENS_EEPROM(n)				((n) + 0xa0)
+#define BASE0_MASK_8909				0x000000ff
+#define BASE1_MASK_8909				0x0000ff00
+
+#define S0_P1_MASK_8909				0x0000003f
+#define S1_P1_MASK_8909				0x0003f000
+#define S2_P1_MASK_8909				0x3f000000
+#define S3_P1_MASK_8909				0x000003f0
+#define S4_P1_MASK_8909				0x003f0000
+
+#define S0_P2_MASK_8909				0x00000fc0
+#define S1_P2_MASK_8909				0x00fc0000
+#define S2_P2_MASK_0_1_8909				0xc0000000
+#define S2_P2_MASK_2_5_8909				0x0000000f
+#define S3_P2_MASK_8909				0x0000fc00
+#define S4_P2_MASK_8909				0x0fc00000
+
+#define TSENS_CAL_SEL_8909				0x00070000
+#define CAL_SEL_SHIFT_8909				16
+#define BASE1_SHIFT_8909				8
+
+#define S1_P1_SHIFT_8909				12
+#define S2_P1_SHIFT_8909				24
+#define S3_P1_SHIFT_8909				4
+#define S4_P1_SHIFT_8909				16
+
+#define S0_P2_SHIFT_8909				6
+#define S1_P2_SHIFT_8909				18
+#define S2_P2_SHIFT_0_1_8909				30
+#define S2_P2_SHIFT_2_5_8909				2
+#define S3_P2_SHIFT_8909				10
+#define S4_P2_SHIFT_8909				22
+
+#define CAL_DEGC_PT1				30
+#define CAL_DEGC_PT2				120
+/*
+ * Use this function on devices where slope and offset calculations
+ * depend on calibration data read from qfprom. On others the slope
+ * and offset values are derived from tz->tzp->slope and tz->tzp->offset
+ * resp.
+ */
+static void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1,
+	u32 *p2, u32 mode)
+{
+	int i;
+	int num, den;
+
+	for (i = 0; i < tmdev->ctrl_data->num_sensors; i++) {
+		pr_debug(
+			"sensor%d - data_point1:%#x data_point2:%#x\n",
+			i, p1[i], p2[i]);
+
+		tmdev->sensor[i].slope = SLOPE_DEFAULT;
+		if (mode == TWO_PT_CALIB) {
+			/*
+			 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
+			 *	temp_120_degc - temp_30_degc (x2 - x1)
+			 */
+			num = p2[i] - p1[i];
+			num *= SLOPE_FACTOR;
+			den = CAL_DEGC_PT2 - CAL_DEGC_PT1;
+			tmdev->sensor[i].slope = num / den;
+		}
+
+		tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) -
+			(CAL_DEGC_PT1 *
+			tmdev->sensor[i].slope);
+		pr_debug("offset:%d\n", tmdev->sensor[i].offset);
+	}
+}
+
+int calibrate_8937(struct tsens_device *tmdev)
+{
+	int base0 = 0, base1 = 0, i;
+	u32 p1[TSENS_NUM_SENSORS_8937], p2[TSENS_NUM_SENSORS_8937];
+	int mode = 0, tmp = 0;
+	u32 qfprom_cdata[5] = {0, 0, 0, 0, 0};
+
+	qfprom_cdata[0] = readl_relaxed(tmdev->tsens_calib_addr + 0x1D8);
+	qfprom_cdata[1] = readl_relaxed(tmdev->tsens_calib_addr + 0x1DC);
+	qfprom_cdata[2] = readl_relaxed(tmdev->tsens_calib_addr + 0x210);
+	qfprom_cdata[3] = readl_relaxed(tmdev->tsens_calib_addr + 0x214);
+	qfprom_cdata[4] = readl_relaxed(tmdev->tsens_calib_addr + 0x230);
+
+	mode = (qfprom_cdata[2] & CAL_SEL_MASK_8937);
+	pr_debug("calibration mode is %d\n", mode);
+
+	switch (mode) {
+	case TWO_PT_CALIB:
+		base1 = (qfprom_cdata[1] &
+				BASE1_MASK_8937) >> BASE1_SHIFT_8937;
+		p2[0] = (qfprom_cdata[2] &
+				S0_P2_MASK_8937) >> S0_P2_SHIFT_8937;
+		p2[1] = (qfprom_cdata[2] &
+				S1_P2_MASK_8937) >> S1_P2_SHIFT_8937;
+		p2[2] = (qfprom_cdata[3] &
+				S2_P2_MASK_8937) >> S2_P2_SHIFT_8937;
+		p2[3] = (qfprom_cdata[3] &
+				S3_P2_MASK_8937) >> S3_P2_SHIFT_8937;
+		p2[4] = (qfprom_cdata[3] &
+				S4_P2_MASK_8937) >> S4_P2_SHIFT_8937;
+		p2[5] = (qfprom_cdata[0] &
+				S5_P2_MASK_8937) >> S5_P2_SHIFT_8937;
+		p2[6] = (qfprom_cdata[0] &
+				S6_P2_MASK_8937) >> S6_P2_SHIFT_8937;
+		p2[7] = (qfprom_cdata[1] &
+				S7_P2_MASK_8937) >> S7_P2_SHIFT_8937;
+		p2[8] = (qfprom_cdata[1] &
+				S8_P2_MASK_8937) >> S8_P2_SHIFT_8937;
+		p2[9] = (qfprom_cdata[4] &
+				S9_P2_MASK_8937) >> S9_P2_SHIFT_8937;
+		p2[10] = (qfprom_cdata[4] &
+				S10_P2_MASK_8937) >> S10_P2_SHIFT_8937;
+
+		for (i = 0; i < TSENS_NUM_SENSORS_8937; i++)
+			p2[i] = ((base1 + p2[i]) << 2);
+		/* Fall through */
+	case ONE_PT_CALIB2:
+		base0 = (qfprom_cdata[0] & BASE0_MASK_8937);
+		p1[0] = (qfprom_cdata[2] &
+				S0_P1_MASK_8937) >> S0_P1_SHIFT_8937;
+		p1[1] = (qfprom_cdata[2] &
+				S1_P1_MASK_8937) >> S1_P1_SHIFT_8937;
+		p1[2] = (qfprom_cdata[2] &
+				S2_P1_MASK_0_4_8937) >> S2_P1_SHIFT_0_4_8937;
+		tmp = (qfprom_cdata[3] &
+				S2_P1_MASK_5_8937) << S2_P1_SHIFT_5_8937;
+		p1[2] |= tmp;
+		p1[3] = (qfprom_cdata[3] &
+				S3_P1_MASK_8937) >> S3_P1_SHIFT_8937;
+		p1[4] = (qfprom_cdata[3] &
+				S4_P1_MASK_8937) >> S4_P1_SHIFT_8937;
+		p1[5] = (qfprom_cdata[0] &
+				S5_P1_MASK_8937) >> S5_P1_SHIFT_8937;
+		p1[6] = (qfprom_cdata[0] &
+				S6_P1_MASK_8937) >> S6_P1_SHIFT_8937;
+		p1[7] = (qfprom_cdata[1] & S7_P1_MASK_8937);
+		p1[8] = (qfprom_cdata[1] &
+				S8_P1_MASK_8937) >> S8_P1_SHIFT_8937;
+		p1[9] = (qfprom_cdata[4] & S9_P1_MASK_8937);
+		p1[10] = (qfprom_cdata[4] &
+				S10_P1_MASK_8937) >> S10_P1_SHIFT_8937;
+
+		for (i = 0; i < TSENS_NUM_SENSORS_8937; i++)
+			p1[i] = (((base0) + p1[i]) << 2);
+		break;
+	default:
+		for (i = 0; i < TSENS_NUM_SENSORS_8937; i++) {
+			p1[i] = 500;
+			p2[i] = 780;
+		}
+		break;
+	}
+
+	compute_intercept_slope(tmdev, p1, p2, mode);
+
+	return 0;
+}
+
+int calibrate_8909(struct tsens_device *tmdev)
+{
+	int i, base0 = 0, base1 = 0;
+	u32 p1[TSENS_NUM_SENSORS_8909], p2[TSENS_NUM_SENSORS_8909];
+	int mode = 0, temp = 0;
+	uint32_t calib_data[3] = {0, 0, 0};
+
+	calib_data[0] = readl_relaxed(
+		TSENS_EEPROM(tmdev->tsens_calib_addr));
+	calib_data[1] = readl_relaxed(
+		(TSENS_EEPROM(tmdev->tsens_calib_addr) + 0x4));
+	calib_data[2] = readl_relaxed(
+		(TSENS_EEPROM(tmdev->tsens_calib_addr) + 0x3c));
+	mode = (calib_data[2] & TSENS_CAL_SEL_8909) >> CAL_SEL_SHIFT_8909;
+
+	pr_debug("calib mode is %d\n", mode);
+
+	switch (mode) {
+	case TWO_PT_CALIB:
+		base1 = (calib_data[2] & BASE1_MASK_8909) >> BASE1_SHIFT_8909;
+		p2[0] = (calib_data[0] & S0_P2_MASK_8909) >> S0_P2_SHIFT_8909;
+		p2[1] = (calib_data[0] & S1_P2_MASK_8909) >> S1_P2_SHIFT_8909;
+		p2[2] = (calib_data[0] &
+				S2_P2_MASK_0_1_8909) >> S2_P2_SHIFT_0_1_8909;
+		temp  = (calib_data[1] &
+				S2_P2_MASK_2_5_8909) << S2_P2_SHIFT_2_5_8909;
+		p2[2] |= temp;
+		p2[3] = (calib_data[1] & S3_P2_MASK_8909) >> S3_P2_SHIFT_8909;
+		p2[4] = (calib_data[1] & S4_P2_MASK_8909) >> S4_P2_SHIFT_8909;
+
+		for (i = 0; i < TSENS_NUM_SENSORS_8909; i++)
+			p2[i] = ((base1 + p2[i]) << 2);
+	/* Fall through */
+	case ONE_PT_CALIB2:
+		base0 = (calib_data[2] & BASE0_MASK_8909);
+		p1[0] = (calib_data[0] & S0_P1_MASK_8909);
+		p1[1] = (calib_data[0] & S1_P1_MASK_8909) >> S1_P1_SHIFT_8909;
+		p1[2] = (calib_data[0] & S2_P1_MASK_8909) >> S2_P1_SHIFT_8909;
+		p1[3] = (calib_data[1] & S3_P1_MASK_8909) >> S3_P1_SHIFT_8909;
+		p1[4] = (calib_data[1] & S4_P1_MASK_8909) >> S4_P1_SHIFT_8909;
+		for (i = 0; i < TSENS_NUM_SENSORS_8909; i++)
+			p1[i] = (((base0) + p1[i]) << 2);
+		break;
+	default:
+		for (i = 0; i < TSENS_NUM_SENSORS_8909; i++) {
+			p1[i] = 500;
+			p2[i] = 780;
+		}
+		break;
+	}
+
+	compute_intercept_slope(tmdev, p1, p2, mode);
+	return 0;
+}