Merge "thermal: tsens8974 : Add 8x26 calibration mask"
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
index 0682cd1..67a986b 100644
--- a/Documentation/devicetree/bindings/thermal/tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -29,6 +29,11 @@
sensor used to compute the offset. Slope is represented
as ADC code/DegC and the value is multipled by a factor
of 1000.
+- qcom,calib-mode : Calibration masks to use to abstract the offset data from efuse.
+ Select from the following strings.
+ "fuse_map1" : Used for 8974/9x25 fuse calibration map.
+ "fuse_map2" : Used for 8x26 fuse calibration map.
+ "fuse_map3" : Used for 8x10 fuse calibration map.
Optional properties:
- qcom,calibration-less-mode : If present the pre-characterized data for offsets
@@ -45,6 +50,7 @@
interrupts = <0 184 0>;
qcom,calibration-less-mode;
qcom,sensors = <11>;
- qcom,slope = <1134 1122 1142 1123 1176 1176 1176 1186 1176
- 1176>;
+ qcom,slope = <3200 3200 3200 3200 3200 3200 3200 3200 3200
+ 3200>;
+ qcom,calib-mode = "fuse_map1";
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 8113187..1ef376f 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1043,6 +1043,7 @@
qcom,sensors = <11>;
qcom,slope = <3200 3200 3200 3200 3200 3200 3200 3200 3200
3200 3200>;
+ qcom,calib-mode = "fuse_map1";
};
qcom,msm-rtb {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 2bdd9fd..d5a33ee 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -379,6 +379,7 @@
interrupts = <0 184 0>;
qcom,sensors = <5>;
qcom,slope = <3200 3200 3200 3200 3200>;
+ qcom,calib-mode = "fuse_map1";
};
qcom,msm-rng@f9bff000 {
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index c2e1731..92ca357 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -69,6 +69,10 @@
#define TSENS_MAIN_CALIB_ADDR_RANGE 6
#define TSENS_BACKUP_CALIB_ADDR_RANGE 4
+#define TSENS_EEPROM_8X26_1(n) ((n) + 0x1c0)
+#define TSENS_EEPROM_8X26_2(n) ((n) + 0x444)
+#define TSENS_8X26_MAIN_CALIB_ADDR_RANGE 4
+
/* TSENS calibration Mask data */
#define TSENS_BASE1_MASK 0xff
#define TSENS0_POINT1_MASK 0x3f00
@@ -151,6 +155,41 @@
#define TSENS10_POINT2_MASK 0xfc0000
#define TSENS10_POINT2_BACKUP_MASK 0x3f000000
+#define TSENS_8X26_BASE0_MASK 0x1fe000
+#define TSENS0_8X26_POINT1_MASK 0x7f00000
+#define TSENS1_8X26_POINT1_MASK 0x3f
+#define TSENS2_8X26_POINT1_MASK 0xfc0
+#define TSENS3_8X26_POINT1_MASK 0x3f000
+#define TSENS4_8X26_POINT1_MASK 0xfc0000
+#define TSENS5_8X26_POINT1_MASK 0x3f000000
+#define TSENS6_8X26_POINT1_MASK 0x3f00000
+#define TSENS_8X26_TSENS_CAL_SEL 0xe0000000
+#define TSENS_8X26_BASE1_MASK 0xff
+#define TSENS0_8X26_POINT2_MASK 0x3f00
+#define TSENS1_8X26_POINT2_MASK 0xfc00
+#define TSENS2_8X26_POINT2_MASK 0x3f00000
+#define TSENS3_8X26_POINT2_MASK 0xfc000000
+#define TSENS4_8X26_POINT2_MASK 0xfc000000
+#define TSENS5_8X26_POINT2_MASK 0x3f00000
+#define TSENS6_8X26_POINT2_MASK 0x7e0000
+
+#define TSENS_8X26_CAL_SEL_SHIFT 29
+#define TSENS_8X26_BASE0_SHIFT 13
+#define TSENS0_8X26_POINT1_SHIFT 21
+#define TSENS2_8X26_POINT1_SHIFT 6
+#define TSENS3_8X26_POINT1_SHIFT 12
+#define TSENS4_8X26_POINT1_SHIFT 18
+#define TSENS5_8X26_POINT1_SHIFT 24
+#define TSENS6_8X26_POINT1_SHIFT 20
+
+#define TSENS0_8X26_POINT2_SHIFT 8
+#define TSENS1_8X26_POINT2_SHIFT 14
+#define TSENS2_8X26_POINT2_SHIFT 20
+#define TSENS3_8X26_POINT2_SHIFT 26
+#define TSENS4_8X26_POINT2_SHIFT 20
+#define TSENS5_8X26_POINT2_SHIFT 26
+#define TSENS6_8X26_POINT2_SHIFT 17
+
#define TSENS_BIT_APPEND 0x3
#define TSENS_CAL_DEGC_POINT1 30
#define TSENS_CAL_DEGC_POINT2 120
@@ -171,6 +210,13 @@
#define TSENS_QFPROM_BACKUP_REDUN_SEL 0xe0000000
#define TSENS_QFPROM_BACKUP_REDUN_SHIFT 29
+enum tsens_calib_fuse_map_type {
+ TSENS_CALIB_FUSE_MAP_8974 = 0,
+ TSENS_CALIB_FUSE_MAP_8X26,
+ TSENS_CALIB_FUSE_MAP_8X10,
+ TSENS_CALIB_FUSE_MAP_NUM,
+};
+
/* Trips: warm and cool */
enum tsens_trip_type {
TSENS_TRIP_WARM = 0,
@@ -203,6 +249,7 @@
struct resource *res_tsens_mem;
struct resource *res_calib_mem;
struct work_struct tsens_work;
+ uint32_t calib_mode;
struct tsens_tm_device_sensor sensor[0];
};
@@ -546,7 +593,162 @@
TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
}
-static int tsens_calib_sensors(void)
+static int tsens_calib_8x26_sensors(void)
+{
+ int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
+ int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
+ int tsens5_point1 = 0, tsens6_point1 = 0, tsens6_point2 = 0;
+ int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
+ int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
+ int tsens_base1_data = 0, tsens_calibration_mode = 0;
+ uint32_t calib_data[6];
+ uint32_t calib_tsens_point1_data[7], calib_tsens_point2_data[7];
+
+ if (tmdev->calibration_less_mode)
+ goto calibration_less_mode;
+
+ for (i = 0; i < TSENS_8X26_MAIN_CALIB_ADDR_RANGE; i++)
+ calib_data[i] = readl_relaxed(
+ (TSENS_EEPROM_8X26_1(tmdev->tsens_calib_addr))
+ + (i * TSENS_SN_ADDR_OFFSET));
+ calib_data[4] = readl_relaxed(
+ (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)));
+ calib_data[5] = readl_relaxed(
+ (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)) + 0x8);
+
+ tsens_calibration_mode = calib_data[5] & TSENS_8X26_TSENS_CAL_SEL;
+
+ if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
+ (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
+ pr_debug("backup one point calibrationless mode\n");
+ tsens_base0_data = (calib_data[0] & TSENS_8X26_BASE0_MASK)
+ >> TSENS_8X26_BASE0_SHIFT;
+ tsens0_point1 = (calib_data[0] & TSENS0_8X26_POINT1_MASK) >>
+ TSENS0_8X26_POINT1_SHIFT;
+ tsens1_point1 = calib_data[1] & TSENS1_8X26_POINT1_MASK;
+ tsens2_point1 = (calib_data[1] & TSENS2_8X26_POINT1_MASK) >>
+ TSENS2_8X26_POINT1_SHIFT;
+ tsens3_point1 = (calib_data[1] & TSENS3_8X26_POINT1_MASK) >>
+ TSENS3_8X26_POINT1_SHIFT;
+ tsens4_point1 = (calib_data[1] & TSENS4_8X26_POINT1_MASK) >>
+ TSENS4_8X26_POINT1_SHIFT;
+ tsens5_point1 = (calib_data[1] & TSENS5_8X26_POINT1_MASK) >>
+ TSENS5_8X26_POINT1_SHIFT;
+ tsens6_point1 = (calib_data[2] & TSENS6_8X26_POINT1_MASK) >>
+ TSENS6_8X26_POINT1_SHIFT;
+ } else
+ goto calibration_less_mode;
+
+ if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+ pr_debug("backup two point calibrationless mode\n");
+ tsens_base1_data = (calib_data[3] & TSENS_8X26_BASE1_MASK);
+ tsens0_point2 = (calib_data[3] & TSENS0_8X26_POINT2_MASK) >>
+ TSENS0_8X26_POINT2_SHIFT;
+ tsens1_point2 = (calib_data[3] & TSENS1_8X26_POINT2_MASK) >>
+ TSENS1_8X26_POINT2_SHIFT;
+ tsens2_point2 = (calib_data[3] & TSENS2_8X26_POINT2_MASK) >>
+ TSENS2_8X26_POINT2_SHIFT;
+ tsens3_point2 = (calib_data[3] & TSENS3_8X26_POINT2_MASK) >>
+ TSENS3_8X26_POINT2_SHIFT;
+ tsens4_point2 = (calib_data[4] & TSENS4_8X26_POINT2_MASK) >>
+ TSENS4_8X26_POINT2_SHIFT;
+ tsens5_point2 = (calib_data[4] & TSENS5_8X26_POINT2_MASK) >>
+ TSENS5_8X26_POINT2_SHIFT;
+ tsens6_point2 = (calib_data[5] & TSENS6_8X26_POINT2_MASK) >>
+ TSENS6_8X26_POINT2_SHIFT;
+ }
+
+ if (tsens_calibration_mode == 0) {
+calibration_less_mode:
+ pr_debug("TSENS is calibrationless mode\n");
+ for (i = 0; i < tmdev->tsens_num_sensor; i++)
+ calib_tsens_point2_data[i] = 780;
+ calib_tsens_point1_data[0] = 502;
+ calib_tsens_point1_data[1] = 509;
+ calib_tsens_point1_data[2] = 503;
+ calib_tsens_point1_data[3] = 509;
+ calib_tsens_point1_data[4] = 505;
+ calib_tsens_point1_data[5] = 509;
+ calib_tsens_point1_data[6] = 507;
+ goto compute_intercept_slope;
+ }
+
+ if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
+ (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
+ pr_debug("one and two point calibration calculation\n");
+ calib_tsens_point1_data[0] =
+ ((((tsens_base0_data) + tsens0_point1) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point1_data[1] =
+ ((((tsens_base0_data) + tsens1_point1) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point1_data[2] =
+ ((((tsens_base0_data) + tsens2_point1) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point1_data[3] =
+ ((((tsens_base0_data) + tsens3_point1) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point1_data[4] =
+ ((((tsens_base0_data) + tsens4_point1) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point1_data[5] =
+ ((((tsens_base0_data) + tsens5_point1) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point1_data[6] =
+ ((((tsens_base0_data) + tsens6_point1) << 2) |
+ TSENS_BIT_APPEND);
+ }
+
+ if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+ pr_debug("two point calibration calculation\n");
+ calib_tsens_point2_data[0] =
+ (((tsens_base1_data + tsens0_point2) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point2_data[1] =
+ (((tsens_base1_data + tsens1_point2) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point2_data[2] =
+ (((tsens_base1_data + tsens2_point2) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point2_data[3] =
+ (((tsens_base1_data + tsens3_point2) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point2_data[4] =
+ (((tsens_base1_data + tsens4_point2) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point2_data[5] =
+ (((tsens_base1_data + tsens5_point2) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point2_data[6] =
+ (((tsens_base1_data + tsens6_point2) << 2) |
+ TSENS_BIT_APPEND);
+ }
+
+compute_intercept_slope:
+ for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+ int32_t num = 0, den = 0;
+ tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
+ tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
+ if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+ /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
+ temp_120_degc - temp_30_degc (x2 - x1) */
+ num = tmdev->sensor[i].calib_data_point2 -
+ tmdev->sensor[i].calib_data_point1;
+ num *= tmdev->tsens_factor;
+ den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
+ tmdev->sensor[i].slope_mul_tsens_factor = num/den;
+ }
+ tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
+ tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
+ tmdev->sensor[i].slope_mul_tsens_factor);
+ INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
+ tmdev->prev_reading_avail = false;
+ }
+
+ return 0;
+}
+
+static int tsens_calib_8974_sensors(void)
{
int i, tsens_base1_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
@@ -877,12 +1079,30 @@
return 0;
}
+static int tsens_calib_sensors(void)
+{
+ int rc = 0;
+
+ if (!tmdev)
+ return -ENODEV;
+
+ if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8974)
+ rc = tsens_calib_8974_sensors();
+ else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X26)
+ rc = tsens_calib_8x26_sensors();
+ else
+ rc = -ENODEV;
+
+ return rc;
+}
+
static int get_device_tree_data(struct platform_device *pdev)
{
const struct device_node *of_node = pdev->dev.of_node;
struct resource *res_mem = NULL;
u32 *tsens_slope_data;
- u32 rc = 0, i, tsens_num_sensors;
+ u32 rc = 0, i, tsens_num_sensors, calib_type;
+ const char *tsens_calib_mode;
rc = of_property_read_u32(of_node,
"qcom,sensors", &tsens_num_sensors);
@@ -905,6 +1125,19 @@
return rc;
};
+ tsens_calib_mode = of_get_property(of_node,
+ "qcom,calib-mode", NULL);
+ if (!strncmp(tsens_calib_mode, "fuse_map1", 9))
+ calib_type = TSENS_CALIB_FUSE_MAP_8974;
+ else if (!strncmp(tsens_calib_mode, "fuse_map2", 9))
+ calib_type = TSENS_CALIB_FUSE_MAP_8X26;
+ else if (!strncmp(tsens_calib_mode, "fuse_map3", 9))
+ calib_type = TSENS_CALIB_FUSE_MAP_8X10;
+ else {
+ pr_err("%s: Invalid calibration property\n", __func__);
+ return -EINVAL;
+ }
+
tmdev = devm_kzalloc(&pdev->dev,
sizeof(struct tsens_tm_device) +
tsens_num_sensors *
@@ -921,6 +1154,7 @@
tmdev->tsens_num_sensor = tsens_num_sensors;
tmdev->calibration_less_mode = of_property_read_bool(of_node,
"qcom,calibration-less-mode");
+ tmdev->calib_mode = calib_type;
tmdev->tsens_irq = platform_get_irq(pdev, 0);
if (tmdev->tsens_irq < 0) {