diff options
author | Siddartha Mohanadoss <smohanad@codeaurora.org> | 2015-04-29 09:51:50 -0700 |
---|---|---|
committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 11:08:16 -0700 |
commit | 9b7489584281df171c56ea3ae37c1e3710dd2095 (patch) | |
tree | 6b6d197ce4ea6e5ceede89d500b38aa77a8e2374 /drivers | |
parent | 5950e6010fba47ecf1d3366fedce81e8a02ed5cc (diff) |
thermal: tsens: TSENS driver fixups
Add TSENS Thermal driver. Include support to activate
a trip type and mode.
This snapshot is taken as of msm-3.14 commit 3bc54cf86b
(Merge "msm: camera: Add dummy sub module in sensor pipeline")
Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org>
Conflicts:
drivers/thermal/Kconfig
drivers/thermal/Makefile
include/linux/thermal.h
Change-Id: Ie8a089afc0cf9e45ac000dff425a3e6206c1b9b1
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/thermal/Kconfig | 10 | ||||
-rw-r--r-- | drivers/thermal/Makefile | 1 | ||||
-rw-r--r-- | drivers/thermal/msm8974-tsens.c | 3905 |
3 files changed, 3916 insertions, 0 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 5407b49ccf62..bc155401728d 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -183,6 +183,16 @@ config HISI_THERMAL thermal framework. cpufreq is used as the cooling device to throttle CPUs when the passive trip is crossed. +config THERMAL_TSENS8974 + tristate "Qualcomm 8974 TSENS Temperature driver" + depends on THERMAL + help + This enables the thermal sysfs driver for the TSENS device. It shows + up in Sysfs as a thermal zone with multiple trip points. Also able + to set threshold temperature for both warm and cool and update + thermal userspace client when a threshold is reached. Warm/Cool + temperature thresholds can be set independently for each sensor. + config IMX_THERMAL tristate "Temperature sensor driver for Freescale i.MX SoCs" depends on CPU_THERMAL diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 950d43f3bcc8..53186c885f8d 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -50,3 +50,4 @@ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra_soctherm.o obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o obj-$(CONFIG_THERMAL_QPNP) += qpnp-temp-alarm.o obj-$(CONFIG_THERMAL_QPNP_ADC_TM) += qpnp-adc-tm.o +obj-$(CONFIG_THERMAL_TSENS8974) += msm8974-tsens.o diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c new file mode 100644 index 000000000000..d5cfedca6336 --- /dev/null +++ b/drivers/thermal/msm8974-tsens.c @@ -0,0 +1,3905 @@ +/* Copyright (c) 2012-2015, 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. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/thermal.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/msm_tsens.h> +#include <linux/err.h> +#include <linux/of.h> + +#define CREATE_TRACE_POINTS +#include <trace/trace_thermal.h> + +#define TSENS_DRIVER_NAME "msm-tsens" +/* TSENS register info */ +#define TSENS_UPPER_LOWER_INTERRUPT_CTRL(n) ((n) + 0x1000) +#define TSENS_INTERRUPT_EN BIT(0) + +#define TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(n) ((n) + 0x1004) +#define TSENS_UPPER_STATUS_CLR BIT(21) +#define TSENS_LOWER_STATUS_CLR BIT(20) +#define TSENS_UPPER_THRESHOLD_MASK 0xffc00 +#define TSENS_LOWER_THRESHOLD_MASK 0x3ff +#define TSENS_UPPER_THRESHOLD_SHIFT 10 + +#define TSENS_S0_STATUS_ADDR(n) ((n) + 0x1030) +#define TSENS_SN_ADDR_OFFSET 0x4 +#define TSENS_SN_STATUS_TEMP_MASK 0x3ff +#define TSENS_SN_STATUS_LOWER_STATUS BIT(11) +#define TSENS_SN_STATUS_UPPER_STATUS BIT(12) +#define TSENS_STATUS_ADDR_OFFSET 2 + +#define TSENS_TRDY_ADDR(n) ((n) + 0x105c) +#define TSENS_TRDY_MASK BIT(0) + +#define TSENS2_SN_STATUS_ADDR(n) ((n) + 0x1044) +#define TSENS2_SN_STATUS_VALID BIT(14) +#define TSENS2_SN_STATUS_VALID_MASK 0x4000 +#define TSENS2_TRDY_ADDR(n) ((n) + 0x84) + +/* TSENS_TM registers for 8996 */ +#define TSENS_TM_INT_EN(n) ((n) + 0x1004) +#define TSENS_TM_CRITICAL_INT_EN BIT(2) +#define TSENS_TM_UPPER_INT_EN BIT(1) +#define TSENS_TM_LOWER_INT_EN BIT(0) + +#define TSENS_TM_UPPER_INT_MASK(n) (((n) & 0xffff0000) >> 16) +#define TSENS_TM_LOWER_INT_MASK(n) ((n) & 0xffff) +#define TSENS_TM_UPPER_LOWER_INT_STATUS(n) ((n) + 0x1008) +#define TSENS_TM_UPPER_LOWER_INT_CLEAR(n) ((n) + 0x100c) +#define TSENS_TM_UPPER_LOWER_INT_MASK(n) ((n) + 0x1010) +#define TSENS_TM_UPPER_INT_SET(n) (1 << (n + 16)) + +#define TSENS_TM_CRITICAL_INT_STATUS(n) ((n) + 0x1014) +#define TSENS_TM_CRITICAL_INT_CLEAR(n) ((n) + 0x1018) +#define TSENS_TM_CRITICAL_INT_MASK(n) ((n) + 0x101c) + +#define TSENS_TM_UPPER_LOWER_THRESHOLD(n) ((n) + 0x1020) +#define TSENS_TM_UPPER_THRESHOLD_SET(n) ((n) << 12) +#define TSENS_TM_UPPER_THRESHOLD_VALUE_SHIFT(n) ((n) >> 12) +#define TSENS_TM_LOWER_THRESHOLD_VALUE(n) ((n) & 0xfff) +#define TSENS_TM_UPPER_THRESHOLD_VALUE(n) (((n) & 0xfff000) >> 12) +#define TSENS_TM_UPPER_THRESHOLD_MASK 0xfff000 +#define TSENS_TM_LOWER_THRESHOLD_MASK 0xfff +#define TSENS_TM_UPPER_THRESHOLD_SHIFT 12 + +#define TSENS_TM_SN_CRITICAL_THRESHOLD_MASK 0xfff +#define TSENS_TM_SN_CRITICAL_THRESHOLD(n) ((n) + 0x1060) +#define TSENS_TM_SN_STATUS(n) ((n) + 0x10a0) +#define TSENS_TM_SN_STATUS_VALID_BIT BIT(21) +#define TSENS_TM_SN_STATUS_CRITICAL_STATUS BIT(19) +#define TSENS_TM_SN_STATUS_UPPER_STATUS BIT(18) +#define TSENS_TM_SN_STATUS_LOWER_STATUS BIT(17) +#define TSENS_TM_SN_LAST_TEMP_MASK 0xfff + +#define TSENS_TM_TRDY(n) ((n) + 0x10e4) +#define TSENS_TM_CODE_BIT_MASK 0xfff +#define TSENS_TM_CODE_SIGN_BIT 0x800 + +/* End TSENS_TM registers for 8996 */ + +#define TSENS_CTRL_ADDR(n) (n) +#define TSENS_EN BIT(0) +#define TSENS_SW_RST BIT(1) +#define TSENS_ADC_CLK_SEL BIT(2) +#define TSENS_SENSOR0_SHIFT 3 +#define TSENS_62_5_MS_MEAS_PERIOD 1 +#define TSENS_312_5_MS_MEAS_PERIOD 2 +#define TSENS_MEAS_PERIOD_SHIFT 18 + +#define TSENS_GLOBAL_CONFIG(n) ((n) + 0x34) +#define TSENS_S0_MAIN_CONFIG(n) ((n) + 0x38) +#define TSENS_SN_REMOTE_CONFIG(n) ((n) + 0x3c) + +#define TSENS_EEPROM(n) ((n) + 0xd0) +#define TSENS_EEPROM_REDUNDANCY_SEL(n) ((n) + 0x444) +#define TSENS_EEPROM_BACKUP_REGION(n) ((n) + 0x440) + +#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 + +#define TSENS_EEPROM_8X10_1(n) ((n) + 0x1a4) +#define TSENS_EEPROM_8X10_1_OFFSET 8 +#define TSENS_EEPROM_8X10_2(n) ((n) + 0x1a8) +#define TSENS_EEPROM_8X10_SPARE_1(n) ((n) + 0xd8) +#define TSENS_EEPROM_8X10_SPARE_2(n) ((n) + 0xdc) + +#define TSENS_9900_EEPROM(n) ((n) + 0xd0) +#define TSENS_9900_EEPROM_REDUNDANCY_SEL(n) ((n) + 0x1c4) +#define TSENS_9900_EEPROM_BACKUP_REGION(n) ((n) + 0x450) +#define TSENS_9900_CALIB_ADDR_RANGE 4 + +#define TSENS_8939_EEPROM(n) ((n) + 0xa0) + +#define TSENS_8994_EEPROM(n) ((n) + 0xd0) +#define TSENS_8994_EEPROM_REDUN_SEL(n) ((n) + 0x464) +#define TSENS_REDUN_REGION1_EEPROM(n) ((n) + 0x1c0) +#define TSENS_REDUN_REGION2_EEPROM(n) ((n) + 0x1c4) +#define TSENS_REDUN_REGION3_EEPROM(n) ((n) + 0x1cc) +#define TSENS_REDUN_REGION4_EEPROM(n) ((n) + 0x440) +#define TSENS_REDUN_REGION5_EEPROM(n) ((n) + 0x444) + +/* TSENS calibration Mask data */ +#define TSENS_BASE1_MASK 0xff +#define TSENS0_POINT1_MASK 0x3f00 +#define TSENS1_POINT1_MASK 0xfc000 +#define TSENS2_POINT1_MASK 0x3f00000 +#define TSENS3_POINT1_MASK 0xfc000000 +#define TSENS4_POINT1_MASK 0x3f +#define TSENS5_POINT1_MASK 0xfc0 +#define TSENS6_POINT1_MASK 0x3f000 +#define TSENS7_POINT1_MASK 0xfc0000 +#define TSENS8_POINT1_MASK 0x3f000000 +#define TSENS8_POINT1_MASK_BACKUP 0x3f +#define TSENS9_POINT1_MASK 0x3f +#define TSENS9_POINT1_MASK_BACKUP 0xfc0 +#define TSENS10_POINT1_MASK 0xfc0 +#define TSENS10_POINT1_MASK_BACKUP 0x3f000 +#define TSENS_CAL_SEL_0_1 0xc0000000 +#define TSENS_CAL_SEL_2 0x40000000 +#define TSENS_CAL_SEL_SHIFT 30 +#define TSENS_CAL_SEL_SHIFT_2 28 +#define TSENS_ONE_POINT_CALIB 0x1 +#define TSENS_ONE_POINT_CALIB_OPTION_2 0x2 +#define TSENS_TWO_POINT_CALIB 0x3 + +#define TSENS0_POINT1_SHIFT 8 +#define TSENS1_POINT1_SHIFT 14 +#define TSENS2_POINT1_SHIFT 20 +#define TSENS3_POINT1_SHIFT 26 +#define TSENS5_POINT1_SHIFT 6 +#define TSENS6_POINT1_SHIFT 12 +#define TSENS7_POINT1_SHIFT 18 +#define TSENS8_POINT1_SHIFT 24 +#define TSENS9_POINT1_BACKUP_SHIFT 6 +#define TSENS10_POINT1_SHIFT 6 +#define TSENS10_POINT1_BACKUP_SHIFT 12 + +#define TSENS_POINT2_BASE_SHIFT 12 +#define TSENS_POINT2_BASE_BACKUP_SHIFT 18 +#define TSENS0_POINT2_SHIFT 20 +#define TSENS0_POINT2_BACKUP_SHIFT 26 +#define TSENS1_POINT2_SHIFT 26 +#define TSENS2_POINT2_BACKUP_SHIFT 6 +#define TSENS3_POINT2_SHIFT 6 +#define TSENS3_POINT2_BACKUP_SHIFT 12 +#define TSENS4_POINT2_SHIFT 12 +#define TSENS4_POINT2_BACKUP_SHIFT 18 +#define TSENS5_POINT2_SHIFT 18 +#define TSENS5_POINT2_BACKUP_SHIFT 24 +#define TSENS6_POINT2_SHIFT 24 +#define TSENS7_POINT2_BACKUP_SHIFT 6 +#define TSENS8_POINT2_SHIFT 6 +#define TSENS8_POINT2_BACKUP_SHIFT 12 +#define TSENS9_POINT2_SHIFT 12 +#define TSENS9_POINT2_BACKUP_SHIFT 18 +#define TSENS10_POINT2_SHIFT 18 +#define TSENS10_POINT2_BACKUP_SHIFT 24 + +#define TSENS_BASE2_MASK 0xff000 +#define TSENS_BASE2_BACKUP_MASK 0xfc0000 +#define TSENS0_POINT2_MASK 0x3f00000 +#define TSENS0_POINT2_BACKUP_MASK 0xfc000000 +#define TSENS1_POINT2_MASK 0xfc000000 +#define TSENS1_POINT2_BACKUP_MASK 0x3f +#define TSENS2_POINT2_MASK 0x3f +#define TSENS2_POINT2_BACKUP_MASK 0xfc0 +#define TSENS3_POINT2_MASK 0xfc0 +#define TSENS3_POINT2_BACKUP_MASK 0x3f000 +#define TSENS4_POINT2_MASK 0x3f000 +#define TSENS4_POINT2_BACKUP_MASK 0xfc0000 +#define TSENS5_POINT2_MASK 0xfc0000 +#define TSENS5_POINT2_BACKUP_MASK 0x3f000000 +#define TSENS6_POINT2_MASK 0x3f000000 +#define TSENS6_POINT2_BACKUP_MASK 0x3f +#define TSENS7_POINT2_MASK 0x3f +#define TSENS7_POINT2_BACKUP_MASK 0xfc0 +#define TSENS8_POINT2_MASK 0xfc0 +#define TSENS8_POINT2_BACKUP_MASK 0x3f000 +#define TSENS9_POINT2_MASK 0x3f000 +#define TSENS9_POINT2_BACKUP_MASK 0xfc0000 +#define TSENS10_POINT2_MASK 0xfc0000 +#define TSENS10_POINT2_BACKUP_MASK 0x3f000000 + +#define TSENS_8X26_BASE0_MASK 0x1fe000 +#define TSENS0_8X26_POINT1_MASK 0x7e00000 +#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 0xfc000 +#define TSENS2_8X26_POINT2_MASK 0x3f00000 +#define TSENS3_8X26_POINT2_MASK 0xfc000000 +#define TSENS4_8X26_POINT2_MASK 0x3f00000 +#define TSENS5_8X26_POINT2_MASK 0xfc000000 +#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_8X10_CAL_SEL_SHIFT 28 +#define TSENS_8X10_BASE1_SHIFT 8 +#define TSENS0_8X10_POINT1_SHIFT 16 +#define TSENS0_8X10_POINT2_SHIFT 22 +#define TSENS1_8X10_POINT2_SHIFT 6 +#define TSENS_8X10_BASE0_MASK 0xff +#define TSENS_8X10_BASE1_MASK 0xff00 +#define TSENS0_8X10_POINT1_MASK 0x3f0000 +#define TSENS0_8X10_POINT2_MASK 0xfc00000 +#define TSENS_8X10_TSENS_CAL_SEL 0x70000000 +#define TSENS1_8X10_POINT1_MASK 0x3f +#define TSENS1_8X10_POINT2_MASK 0xfc0 +#define TSENS_8X10_REDUN_SEL_MASK 0x6000000 +#define TSENS_8X10_REDUN_SEL_SHIFT 25 + +#define TSENS0_9900_POINT1_SHIFT 19 +#define TSENS2_9900_POINT1_SHIFT 12 +#define TSENS3_9900_POINT1_SHIFT 24 +#define TSENS4_9900_POINT1_SHIFT 6 +#define TSENS5_9900_POINT1_SHIFT 18 +#define TSENS_9900_BASE1_MASK 0xff +#define TSENS0_9900_POINT1_MASK 0x1f80000 +#define TSENS1_9900_POINT1_MASK 0x3f +#define TSENS2_9900_POINT1_MASK 0x3f000 +#define TSENS3_9900_POINT1_MASK 0x3f000000 +#define TSENS4_9900_POINT1_MASK 0xfc0 +#define TSENS5_9900_POINT1_MASK 0xfc0000 +#define TSENS6_9900_POINT1_MASK 0x3f + +#define TSENS_9900_BASE2_SHIFT 8 +#define TSENS0_9900_POINT2_SHIFT 25 +#define TSENS1_9900_POINT2_SHIFT 6 +#define TSENS2_9900_POINT2_SHIFT 18 +#define TSENS4_9900_POINT2_SHIFT 12 +#define TSENS5_9900_POINT2_SHIFT 24 +#define TSENS6_9900_POINT2_SHIFT 6 +#define TSENS_9900_BASE2_MASK 0xff00 +#define TSENS0_9900_POINT2_MASK 0x7e000000 +#define TSENS1_9900_POINT2_MASK 0xfc0 +#define TSENS2_9900_POINT2_MASK 0xfc0000 +#define TSENS3_9900_POINT2_MASK 0x3f +#define TSENS4_9900_POINT2_MASK 0x3f000 +#define TSENS5_9900_POINT2_MASK 0x3f000000 +#define TSENS6_9900_POINT2_MASK 0xfc0 + +#define TSENS_9900_CAL_SEL_SHIFT 16 +#define TSENS_9900_TSENS_CAL_SEL 0x00070000 + +#define TSENS_BIT_APPEND 0x3 +#define TSENS_CAL_DEGC_POINT1 30 +#define TSENS_CAL_DEGC_POINT2 120 +#define TSENS_SLOPE_FACTOR 1000 + +/* TSENS register data */ +#define TSENS_TRDY_RDY_MIN_TIME 2000 +#define TSENS_TRDY_RDY_MAX_TIME 2100 +#define TSENS_THRESHOLD_MAX_CODE 0x3ff +#define TSENS_THRESHOLD_MIN_CODE 0x0 + +#define TSENS_GLOBAL_INIT_DATA 0x302f16c +#define TSENS_S0_MAIN_CFG_INIT_DATA 0x1c3 +#define TSENS_SN_REMOTE_CFG_DATA 0x11c3 + +#define TSENS_QFPROM_BACKUP_SEL 0x3 +#define TSENS_QFPROM_BACKUP_REDUN_SEL 0xe0000000 +#define TSENS_QFPROM_BACKUP_REDUN_SHIFT 29 + +#define TSENS_QFPROM_BACKUP_9900_REDUN_SEL 0x07000000 +#define TSENS_QFPROM_BACKUP_9900_REDUN_SHIFT 24 + +#define TSENS_TORINO_BASE0 0x3ff +#define TSENS_TORINO_BASE1 0xffc00 +#define TSENS_TORINO_POINT0 0xf00000 +#define TSENS_TORINO_POINT1 0xf0000000 +#define TSENS_TORINO_POINT2 0xf0 +#define TSENS_TORINO_POINT3 0xf000 +#define TSENS_TORINO_POINT4 0xf00000 +#define TSENS_TORINO_CALIB_PT 0x70000000 + +#define TSENS_TORINO_BASE1_SHIFT 10 +#define TSENS_TORINO_POINT0_SHIFT 20 +#define TSENS_TORINO_POINT1_SHIFT 28 +#define TSENS_TORINO_POINT2_SHIFT 4 +#define TSENS_TORINO_POINT3_SHIFT 12 +#define TSENS_TORINO_POINT4_SHIFT 20 +#define TSENS_TORINO_CALIB_SHIFT 28 + +#define TSENS_TYPE0 0 +#define TSENS_TYPE2 2 +#define TSENS_TYPE3 3 + +#define TSENS_8916_BASE0_MASK 0x0000007f +#define TSENS_8916_BASE1_MASK 0xfe000000 + +#define TSENS0_8916_POINT1_MASK 0x00000f80 +#define TSENS1_8916_POINT1_MASK 0x003e0000 +#define TSENS2_8916_POINT1_MASK 0xf8000000 +#define TSENS3_8916_POINT1_MASK 0x000003e0 +#define TSENS4_8916_POINT1_MASK 0x000f8000 + +#define TSENS0_8916_POINT2_MASK 0x0001f000 +#define TSENS1_8916_POINT2_MASK 0x07c00000 +#define TSENS2_8916_POINT2_MASK 0x0000001f +#define TSENS3_8916_POINT2_MASK 0x00007c00 +#define TSENS4_8916_POINT2_MASK 0x01f00000 + +#define TSENS_8916_TSENS_CAL_SEL 0xe0000000 + +#define TSENS_8916_CAL_SEL_SHIFT 29 +#define TSENS_8916_BASE1_SHIFT 25 + +#define TSENS0_8916_POINT1_SHIFT 7 +#define TSENS1_8916_POINT1_SHIFT 17 +#define TSENS2_8916_POINT1_SHIFT 27 +#define TSENS3_8916_POINT1_SHIFT 5 +#define TSENS4_8916_POINT1_SHIFT 15 + +#define TSENS0_8916_POINT2_SHIFT 12 +#define TSENS1_8916_POINT2_SHIFT 22 +#define TSENS3_8916_POINT2_SHIFT 10 +#define TSENS4_8916_POINT2_SHIFT 20 +#define TSENS_VALID_CNT_2 2 + +#define TSENS_8939_BASE0_MASK 0x000000ff +#define TSENS_8939_BASE1_MASK 0xff000000 + +#define TSENS0_8939_POINT1_MASK 0x000001f8 +#define TSENS1_8939_POINT1_MASK 0x001f8000 +#define TSENS2_8939_POINT1_MASK_0_4 0xf8000000 +#define TSENS2_8939_POINT1_MASK_5 0x00000001 +#define TSENS3_8939_POINT1_MASK 0x00001f80 +#define TSENS4_8939_POINT1_MASK 0x01f80000 +#define TSENS5_8939_POINT1_MASK 0x00003f00 +#define TSENS6_8939_POINT1_MASK 0x03f00000 +#define TSENS7_8939_POINT1_MASK 0x0000003f +#define TSENS8_8939_POINT1_MASK 0x0003f000 + +#define TSENS0_8939_POINT2_MASK 0x00007e00 +#define TSENS1_8939_POINT2_MASK 0x07e00000 +#define TSENS2_8939_POINT2_MASK 0x0000007e +#define TSENS3_8939_POINT2_MASK 0x0007e000 +#define TSENS4_8939_POINT2_MASK 0x7e000000 +#define TSENS5_8939_POINT2_MASK 0x000fc000 +#define TSENS6_8939_POINT2_MASK 0xfc000000 +#define TSENS7_8939_POINT2_MASK 0x00000fc0 +#define TSENS8_8939_POINT2_MASK 0x00fc0000 + +#define TSENS_8939_TSENS_CAL_SEL 0x7 +#define TSENS_8939_CAL_SEL_SHIFT 0 +#define TSENS_8939_BASE1_SHIFT 24 + +#define TSENS0_8939_POINT1_SHIFT 3 +#define TSENS1_8939_POINT1_SHIFT 15 +#define TSENS2_8939_POINT1_SHIFT_0_4 27 +#define TSENS2_8939_POINT1_SHIFT_5 5 +#define TSENS3_8939_POINT1_SHIFT 7 +#define TSENS4_8939_POINT1_SHIFT 19 +#define TSENS5_8939_POINT1_SHIFT 8 +#define TSENS6_8939_POINT1_SHIFT 20 +#define TSENS8_8939_POINT1_SHIFT 12 + +#define TSENS0_8939_POINT2_SHIFT 9 +#define TSENS1_8939_POINT2_SHIFT 21 +#define TSENS2_8939_POINT2_SHIFT 1 +#define TSENS3_8939_POINT2_SHIFT 13 +#define TSENS4_8939_POINT2_SHIFT 25 +#define TSENS5_8939_POINT2_SHIFT 14 +#define TSENS6_8939_POINT2_SHIFT 26 +#define TSENS7_8939_POINT2_SHIFT 6 +#define TSENS8_8939_POINT2_SHIFT 18 + +#define TSENS_BASE0_8994_MASK 0x3ff +#define TSENS_BASE1_8994_MASK 0xffc00 +#define TSENS_BASE1_8994_SHIFT 10 +#define TSENS0_OFFSET_8994_MASK 0xf00000 +#define TSENS0_OFFSET_8994_SHIFT 20 +#define TSENS1_OFFSET_8994_MASK 0xf000000 +#define TSENS1_OFFSET_8994_SHIFT 24 +#define TSENS2_OFFSET_8994_MASK 0xf0000000 +#define TSENS2_OFFSET_8994_SHIFT 28 +#define TSENS3_OFFSET_8994_MASK 0xf +#define TSENS4_OFFSET_8994_MASK 0xf0 +#define TSENS4_OFFSET_8994_SHIFT 4 +#define TSENS5_OFFSET_8994_MASK 0xf00 +#define TSENS5_OFFSET_8994_SHIFT 8 +#define TSENS6_OFFSET_8994_MASK 0xf000 +#define TSENS6_OFFSET_8994_SHIFT 12 +#define TSENS7_OFFSET_8994_MASK 0xf0000 +#define TSENS7_OFFSET_8994_SHIFT 16 +#define TSENS8_OFFSET_8994_MASK 0xf00000 +#define TSENS8_OFFSET_8994_SHIFT 20 +#define TSENS9_OFFSET_8994_MASK 0xf000000 +#define TSENS9_OFFSET_8994_SHIFT 24 +#define TSENS10_OFFSET_8994_MASK 0xf0000000 +#define TSENS10_OFFSET_8994_SHIFT 28 +#define TSENS11_OFFSET_8994_MASK 0xf +#define TSENS12_OFFSET_8994_MASK 0xf0 +#define TSENS12_OFFSET_8994_SHIFT 4 +#define TSENS13_OFFSET_8994_MASK 0xf00 +#define TSENS13_OFFSET_8994_SHIFT 8 +#define TSENS14_OFFSET_8994_MASK 0xf000 +#define TSENS14_OFFSET_8994_SHIFT 12 +#define TSENS15_OFFSET_8994_MASK 0xf0000 +#define TSENS15_OFFSET_8994_SHIFT 16 +#define TSENS_8994_CAL_SEL_MASK 0x700000 +#define TSENS_8994_CAL_SEL_SHIFT 20 + +#define TSENS_BASE0_8994_REDUN_MASK 0x7fe00000 +#define TSENS_BASE0_8994_REDUN_MASK_SHIFT 21 +#define TSENS_BASE1_BIT0_8994_REDUN_MASK 0x80000000 +#define TSENS_BASE1_BIT0_SHIFT_COMPUTE 31 +#define TSENS_BASE1_BIT1_9_8994_REDUN_MASK 0x1ff +#define TSENS0_OFFSET_8994_REDUN_MASK 0x1e00 +#define TSENS0_OFFSET_8994_REDUN_SHIFT 9 +#define TSENS1_OFFSET_8994_REDUN_MASK 0x1e000 +#define TSENS1_OFFSET_8994_REDUN_SHIFT 13 +#define TSENS2_OFFSET_8994_REDUN_MASK 0x1e0000 +#define TSENS2_OFFSET_8994_REDUN_SHIFT 17 +#define TSENS3_OFFSET_8994_REDUN_MASK 0x1e00000 +#define TSENS3_OFFSET_8994_REDUN_SHIFT 21 +#define TSENS4_OFFSET_8994_REDUN_MASK 0x1e000000 +#define TSENS4_OFFSET_8994_REDUN_SHIFT 25 +#define TSENS5_OFFSET_8994_REDUN_MASK_BIT0_2 0xe0000000 +#define TSENS5_OFFSET_8994_REDUN_SHIFT_BIT0_2 29 +#define TSENS5_OFFSET_8994_REDUN_MASK_BIT3 0x800000 +#define TSENS5_OFFSET_8994_REDUN_SHIFT_BIT3 23 +#define TSENS6_OFFSET_8994_REDUN_MASK 0xf000000 +#define TSENS6_OFFSET_8994_REDUN_SHIFT 24 +#define TSENS7_OFFSET_8994_REDUN_MASK 0xf0000000 +#define TSENS7_OFFSET_8994_REDUN_SHIFT 28 +#define TSENS8_OFFSET_8994_REDUN_MASK 0xf +#define TSENS9_OFFSET_8994_REDUN_MASK 0xf0 +#define TSENS9_OFFSET_8994_REDUN_SHIFT 4 +#define TSENS10_OFFSET_8994_REDUN_MASK 0xf00 +#define TSENS10_OFFSET_8994_REDUN_SHIFT 8 +#define TSENS11_OFFSET_8994_REDUN_MASK 0xf000 +#define TSENS11_OFFSET_8994_REDUN_SHIFT 12 +#define TSENS12_OFFSET_8994_REDUN_MASK 0xf0000 +#define TSENS12_OFFSET_8994_REDUN_SHIFT 16 +#define TSENS13_OFFSET_8994_REDUN_MASK 0xf00000 +#define TSENS13_OFFSET_8994_REDUN_SHIFT 20 +#define TSENS14_OFFSET_8994_REDUN_MASK 0xf000000 +#define TSENS14_OFFSET_8994_REDUN_SHIFT 24 +#define TSENS15_OFFSET_8994_REDUN_MASK 0xf0000000 +#define TSENS15_OFFSET_8994_REDUN_SHIFT 28 +#define TSENS_8994_REDUN_SEL_MASK 0x7 +#define TSENS_8994_CAL_SEL_REDUN_MASK 0xe0000000 +#define TSENS_8994_CAL_SEL_REDUN_SHIFT 29 + +#define TSENS_MSM8909_BASE0_MASK 0x000000ff +#define TSENS_MSM8909_BASE1_MASK 0x0000ff00 + +#define TSENS0_MSM8909_POINT1_MASK 0x0000003f +#define TSENS1_MSM8909_POINT1_MASK 0x0003f000 +#define TSENS2_MSM8909_POINT1_MASK 0x3f000000 +#define TSENS3_MSM8909_POINT1_MASK 0x000003f0 +#define TSENS4_MSM8909_POINT1_MASK 0x003f0000 + +#define TSENS0_MSM8909_POINT2_MASK 0x00000fc0 +#define TSENS1_MSM8909_POINT2_MASK 0x00fc0000 +#define TSENS2_MSM8909_POINT2_MASK_0_1 0xc0000000 +#define TSENS2_MSM8909_POINT2_MASK_2_5 0x0000000f +#define TSENS3_MSM8909_POINT2_MASK 0x0000fc00 +#define TSENS4_MSM8909_POINT2_MASK 0x0fc00000 + +#define TSENS_MSM8909_TSENS_CAL_SEL 0x00070000 +#define TSENS_MSM8909_CAL_SEL_SHIFT 16 +#define TSENS_MSM8909_BASE1_SHIFT 8 + +#define TSENS1_MSM8909_POINT1_SHIFT 12 +#define TSENS2_MSM8909_POINT1_SHIFT 24 +#define TSENS3_MSM8909_POINT1_SHIFT 4 +#define TSENS4_MSM8909_POINT1_SHIFT 16 + +#define TSENS0_MSM8909_POINT2_SHIFT 6 +#define TSENS1_MSM8909_POINT2_SHIFT 18 +#define TSENS2_MSM8909_POINT2_SHIFT_0_1 30 +#define TSENS2_MSM8909_POINT2_SHIFT_2_5 2 +#define TSENS3_MSM8909_POINT2_SHIFT 10 +#define TSENS4_MSM8909_POINT2_SHIFT 22 + +#define TSENS_ZIRC_CAL_SEL 0x700 +#define TSENS_ZIRC_CAL_SEL_SHIFT 8 +#define TSENS_BASE0_ZIRC_MASK 0x3ff +#define TSENS_BASE1_ZIRC_MASK 0xffc00 +#define TSENS_BASE1_ZIRC_SHIFT 10 +#define TSENS0_OFFSET_ZIRC_MASK 0xf00000 +#define TSENS0_OFFSET_ZIRC_SHIFT 20 +#define TSENS1_OFFSET_ZIRC_MASK 0xf000000 +#define TSENS1_OFFSET_ZIRC_SHIFT 24 +#define TSENS2_OFFSET_ZIRC_MASK 0xf0000000 +#define TSENS2_OFFSET_ZIRC_SHIFT 28 +#define TSENS3_OFFSET_ZIRC_MASK 0xf +#define TSENS4_OFFSET_ZIRC_MASK 0xf0 +#define TSENS4_OFFSET_ZIRC_SHIFT 4 + +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_9900, + TSENS_CALIB_FUSE_MAP_9630, + TSENS_CALIB_FUSE_MAP_8916, + TSENS_CALIB_FUSE_MAP_8939, + TSENS_CALIB_FUSE_MAP_8994, + TSENS_CALIB_FUSE_MAP_MSM8909, + TSENS_CALIB_FUSE_MAP_MSMZIRC, + TSENS_CALIB_FUSE_MAP_NONE, + TSENS_CALIB_FUSE_MAP_8992, + TSENS_CALIB_FUSE_MAP_NUM, +}; + +/* Trips: warm and cool */ +enum tsens_trip_type { + TSENS_TRIP_WARM = 0, + TSENS_TRIP_COOL, + TSENS_TRIP_NUM, +}; + +enum tsens_tm_trip_type { + TSENS_TM_TRIP_CRITICAL = 0, + TSENS_TM_TRIP_WARM, + TSENS_TM_TRIP_COOL, + TSENS_TM_TRIP_NUM, +}; + +#define TSENS_WRITABLE_TRIPS_MASK ((1 << TSENS_TRIP_NUM) - 1) +#define TSENS_TM_WRITABLE_TRIPS_MASK ((1 << TSENS_TM_TRIP_NUM) - 1) + +struct tsens_tm_device_sensor { + struct thermal_zone_device *tz_dev; + enum thermal_device_mode mode; + /* Physical HW sensor number */ + unsigned int sensor_hw_num; + /* Software index. This is keep track of the HW/SW + * sensor_ID mapping */ + unsigned int sensor_sw_id; + int offset; + int calib_data_point1; + int calib_data_point2; + uint32_t slope_mul_tsens_factor; +}; + +struct tsens_dbg_counter { + uint32_t dbg_count[10]; + uint32_t idx; + unsigned long long time_stmp[10]; +}; + +struct tsens_sensor_dbg_info { + unsigned long temp[10]; + uint32_t idx; + unsigned long long time_stmp[10]; +}; + +struct tsens_tm_device { + struct platform_device *pdev; + struct workqueue_struct *tsens_critical_wq; + bool is_ready; + bool prev_reading_avail; + bool calibration_less_mode; + bool tsens_local_init; + int tsens_factor; + uint32_t tsens_num_sensor; + int tsens_irq; + int tsens_critical_irq; + void *tsens_addr; + void *tsens_calib_addr; + int tsens_len; + int calib_len; + struct resource *res_tsens_mem; + struct resource *res_calib_mem; + uint32_t calib_mode; + uint32_t tsens_type; + bool tsens_valid_status_check; + struct tsens_dbg_counter tsens_thread_iq_dbg; + struct tsens_sensor_dbg_info sensor_dbg_info[16]; + struct tsens_tm_device_sensor sensor[0]; +}; + +struct tsens_tm_device *tmdev; + +int tsens_is_ready() +{ + if (!tmdev) + return -EPROBE_DEFER; + else + return tmdev->is_ready; +} +EXPORT_SYMBOL(tsens_is_ready); + +int tsens_get_sw_id_mapping(int sensor_hw_num, int *sensor_sw_idx) +{ + int i = 0; + bool id_found = false; + + if (tsens_is_ready() <= 0) { + pr_debug("TSENS early init not done\n"); + return -EPROBE_DEFER; + } + + while (i < tmdev->tsens_num_sensor && !id_found) { + if (sensor_hw_num == tmdev->sensor[i].sensor_hw_num) { + *sensor_sw_idx = tmdev->sensor[i].sensor_sw_id; + id_found = true; + } + i++; + } + + if (!id_found) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(tsens_get_sw_id_mapping); + +int tsens_get_hw_id_mapping(int sensor_sw_id, int *sensor_hw_num) +{ + int i = 0; + bool id_found = false; + + if (tsens_is_ready() <= 0) { + pr_debug("TSENS early init not done\n"); + return -EPROBE_DEFER; + } + + while (i < tmdev->tsens_num_sensor && !id_found) { + if (sensor_sw_id == tmdev->sensor[i].sensor_sw_id) { + *sensor_hw_num = tmdev->sensor[i].sensor_hw_num; + id_found = true; + } + i++; + } + + if (!id_found) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(tsens_get_hw_id_mapping); + +static int tsens_tz_code_to_degc(int adc_code, int sensor_sw_id) +{ + int degc, num, den, idx; + + idx = sensor_sw_id; + num = ((adc_code * tmdev->tsens_factor) - + tmdev->sensor[idx].offset); + den = (int) tmdev->sensor[idx].slope_mul_tsens_factor; + + if (num > 0) + degc = ((num + (den/2))/den); + else if (num < 0) + degc = ((num - (den/2))/den); + else + degc = num/den; + + pr_debug("raw_code:0x%x, sensor_num:%d, degc:%d, offset:%d\n", + adc_code, idx, degc, tmdev->sensor[idx].offset); + + return degc; +} + +static int tsens_tz_degc_to_code(int degc, int idx) +{ + int code = ((degc * tmdev->sensor[idx].slope_mul_tsens_factor) + + tmdev->sensor[idx].offset)/tmdev->tsens_factor; + + if (code > TSENS_THRESHOLD_MAX_CODE) + code = TSENS_THRESHOLD_MAX_CODE; + else if (code < TSENS_THRESHOLD_MIN_CODE) + code = TSENS_THRESHOLD_MIN_CODE; + pr_debug("raw_code:0x%x, sensor_num:%d, degc:%d\n", + code, idx, degc); + return code; +} + +static void msm_tsens_get_temp(int sensor_hw_num, unsigned long *temp) +{ + unsigned int code; + void __iomem *sensor_addr; + void __iomem *trdy_addr; + int sensor_sw_id = -EINVAL, rc = 0, last_temp = 0, last_temp2 = 0; + int last_temp3 = 0, last_temp_mask, valid_status_mask, code_mask = 0; + bool last_temp_valid = false, last_temp2_valid = false; + bool last_temp3_valid = false; + + if (tmdev->tsens_type == TSENS_TYPE2) { + trdy_addr = TSENS2_TRDY_ADDR(tmdev->tsens_addr); + sensor_addr = TSENS2_SN_STATUS_ADDR(tmdev->tsens_addr); + } else if (tmdev->tsens_type == TSENS_TYPE3) { + trdy_addr = TSENS_TM_TRDY(tmdev->tsens_addr); + sensor_addr = TSENS_TM_SN_STATUS(tmdev->tsens_addr); + } else { + trdy_addr = TSENS_TRDY_ADDR(tmdev->tsens_addr); + sensor_addr = TSENS_S0_STATUS_ADDR(tmdev->tsens_addr); + } + + if ((!tmdev->prev_reading_avail) && !tmdev->tsens_valid_status_check) { + while (!((readl_relaxed(trdy_addr)) & TSENS_TRDY_MASK)) + usleep_range(TSENS_TRDY_RDY_MIN_TIME, + TSENS_TRDY_RDY_MAX_TIME); + tmdev->prev_reading_avail = true; + } + + if (tmdev->tsens_type == TSENS_TYPE3) + last_temp_mask = TSENS_TM_SN_LAST_TEMP_MASK; + else + last_temp_mask = TSENS_SN_STATUS_TEMP_MASK; + + code = readl_relaxed(sensor_addr + + (sensor_hw_num << TSENS_STATUS_ADDR_OFFSET)); + last_temp = code & last_temp_mask; + + if (tmdev->tsens_valid_status_check) { + if (tmdev->tsens_type == TSENS_TYPE3) + valid_status_mask = TSENS_TM_SN_STATUS_VALID_BIT; + else + valid_status_mask = TSENS2_SN_STATUS_VALID; + if (code & valid_status_mask) + last_temp_valid = true; + else { + code = readl_relaxed(sensor_addr + + (sensor_hw_num << TSENS_STATUS_ADDR_OFFSET)); + last_temp2 = code & last_temp_mask; + if (code & valid_status_mask) { + last_temp = last_temp2; + last_temp2_valid = true; + } else { + code = readl_relaxed(sensor_addr + + (sensor_hw_num << + TSENS_STATUS_ADDR_OFFSET)); + last_temp3 = code & last_temp_mask; + if (code & valid_status_mask) { + last_temp = last_temp3; + last_temp3_valid = true; + } + } + } + } + + if ((tmdev->tsens_valid_status_check) && + (!last_temp_valid && !last_temp2_valid && !last_temp3_valid)) { + if (last_temp == last_temp2) + last_temp = last_temp2; + else if (last_temp2 == last_temp3) + last_temp = last_temp3; + } + + if (tmdev->tsens_type != TSENS_TYPE3) { + /* Obtain SW index to map the corresponding thermal zone's + * offset and slope for code to degc conversion. */ + rc = tsens_get_sw_id_mapping(sensor_hw_num, &sensor_sw_id); + if (rc < 0) { + pr_err("tsens mapping index not found\n"); + return; + } + + *temp = tsens_tz_code_to_degc(last_temp, sensor_sw_id); + } else { + if (last_temp & TSENS_TM_CODE_SIGN_BIT) { + /* Sign extension for negative value */ + code_mask = ~TSENS_TM_CODE_BIT_MASK; + last_temp |= code_mask; + } + *temp = last_temp; + } + + trace_tsens_read(*temp, sensor_hw_num); +} + +static int tsens_tz_get_temp(struct thermal_zone_device *thermal, + unsigned long *temp) +{ + struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; + uint32_t idx = 0; + + if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp) + return -EINVAL; + + msm_tsens_get_temp(tm_sensor->sensor_hw_num, temp); + + idx = tmdev->sensor_dbg_info[tm_sensor->sensor_hw_num].idx; + tmdev->sensor_dbg_info[tm_sensor->sensor_hw_num].temp[idx%10] = *temp; + tmdev->sensor_dbg_info[tm_sensor->sensor_hw_num].time_stmp[idx%10] = + sched_clock(); + idx++; + tmdev->sensor_dbg_info[tm_sensor->sensor_hw_num].idx = idx; + + return 0; +} + +int tsens_get_temp(struct tsens_device *device, unsigned long *temp) +{ + if (tsens_is_ready() <= 0) { + pr_debug("TSENS early init not done\n"); + return -EPROBE_DEFER; + } + + msm_tsens_get_temp(device->sensor_num, temp); + + return 0; +} +EXPORT_SYMBOL(tsens_get_temp); + +int tsens_get_max_sensor_num(uint32_t *tsens_num_sensors) +{ + if (tsens_is_ready() <= 0) { + pr_debug("TSENS early init not done\n"); + return -EPROBE_DEFER; + } + + *tsens_num_sensors = tmdev->tsens_num_sensor; + + return 0; +} +EXPORT_SYMBOL(tsens_get_max_sensor_num); + +static int tsens_tz_get_mode(struct thermal_zone_device *thermal, + enum thermal_device_mode *mode) +{ + struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; + + if (!tm_sensor || !mode) + return -EINVAL; + + *mode = tm_sensor->mode; + + return 0; +} + +static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal, + int trip, enum thermal_trip_type *type) +{ + struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; + + if (!tm_sensor || trip < 0 || !type) + return -EINVAL; + + switch (trip) { + case TSENS_TRIP_WARM: + *type = THERMAL_TRIP_CONFIGURABLE_HI; + break; + case TSENS_TRIP_COOL: + *type = THERMAL_TRIP_CONFIGURABLE_LOW; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int tsens_tm_get_trip_type(struct thermal_zone_device *thermal, + int trip, enum thermal_trip_type *type) +{ + struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; + + if (!tm_sensor || trip < 0 || !type) + return -EINVAL; + + switch (trip) { + case TSENS_TM_TRIP_WARM: + *type = THERMAL_TRIP_CONFIGURABLE_HI; + break; + case TSENS_TM_TRIP_COOL: + *type = THERMAL_TRIP_CONFIGURABLE_LOW; + break; + case TSENS_TM_TRIP_CRITICAL: + *type = THERMAL_TRIP_CRITICAL; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int tsens_tm_activate_trip_type(struct thermal_zone_device *thermal, + int trip, enum thermal_trip_activation_mode mode) +{ + struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; + unsigned int reg_cntl, mask; + + /* clear the interrupt and unmask */ + if (!tm_sensor || trip < 0) + return -EINVAL; + + mask = (tm_sensor->sensor_hw_num); + switch (trip) { + case TSENS_TM_TRIP_CRITICAL: + reg_cntl = readl_relaxed(TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_addr)); + if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) + writel_relaxed(reg_cntl | (1 << mask), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_addr))); + else + writel_relaxed(reg_cntl & ~(1 << mask), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_addr))); + break; + case TSENS_TM_TRIP_WARM: + reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK + (tmdev->tsens_addr)); + if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) + writel_relaxed(reg_cntl | + (TSENS_TM_UPPER_INT_SET(mask)), + (TSENS_TM_UPPER_LOWER_INT_MASK + (tmdev->tsens_addr))); + else + writel_relaxed(reg_cntl & + ~(TSENS_TM_UPPER_INT_SET(mask)), + (TSENS_TM_UPPER_LOWER_INT_MASK + (tmdev->tsens_addr))); + break; + case TSENS_TM_TRIP_COOL: + reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK + (tmdev->tsens_addr)); + if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) + writel_relaxed(reg_cntl | (1 << mask), + (TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_addr))); + else + writel_relaxed(reg_cntl & ~(1 << mask), + (TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_addr))); + break; + default: + return -EINVAL; + } + /* Activate and enable the respective trip threshold setting */ + mb(); + return 0; +} + +static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal, + int trip, enum thermal_trip_activation_mode mode) +{ + struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; + unsigned int reg_cntl, code, hi_code, lo_code, mask; + + if (!tm_sensor || trip < 0) + return -EINVAL; + + lo_code = TSENS_THRESHOLD_MIN_CODE; + hi_code = TSENS_THRESHOLD_MAX_CODE; + + reg_cntl = readl_relaxed((TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR + (tmdev->tsens_addr) + + (tm_sensor->sensor_hw_num * + TSENS_SN_ADDR_OFFSET))); + switch (trip) { + case TSENS_TRIP_WARM: + code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK) + >> TSENS_UPPER_THRESHOLD_SHIFT; + mask = TSENS_UPPER_STATUS_CLR; + + if (!(reg_cntl & TSENS_LOWER_STATUS_CLR)) + lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK); + break; + case TSENS_TRIP_COOL: + code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK); + mask = TSENS_LOWER_STATUS_CLR; + + if (!(reg_cntl & TSENS_UPPER_STATUS_CLR)) + hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK) + >> TSENS_UPPER_THRESHOLD_SHIFT; + break; + default: + return -EINVAL; + } + + if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) + writel_relaxed(reg_cntl | mask, + (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR + (tmdev->tsens_addr) + + (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET))); + else { + writel_relaxed(reg_cntl & ~mask, + (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_addr) + + (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET))); + } + /* Enable the thresholds */ + mb(); + return 0; +} + +static int tsens_tm_get_trip_temp(struct thermal_zone_device *thermal, + int trip, unsigned long *temp) +{ + struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; + int reg_cntl, code_mask; + + if (!tm_sensor || trip < 0 || !temp) + return -EINVAL; + + switch (trip) { + case TSENS_TM_TRIP_CRITICAL: + reg_cntl = readl_relaxed((TSENS_TM_SN_CRITICAL_THRESHOLD + (tmdev->tsens_addr)) + + (tm_sensor->sensor_hw_num * + TSENS_SN_ADDR_OFFSET)); + if (reg_cntl & TSENS_TM_CODE_SIGN_BIT) { + /* Sign extension for negative value */ + code_mask = ~TSENS_TM_CODE_BIT_MASK; + reg_cntl |= code_mask; + } + break; + case TSENS_TM_TRIP_WARM: + reg_cntl = readl_relaxed((TSENS_TM_UPPER_LOWER_THRESHOLD + (tmdev->tsens_addr)) + + (tm_sensor->sensor_hw_num * + TSENS_SN_ADDR_OFFSET)); + reg_cntl = TSENS_TM_UPPER_THRESHOLD_VALUE(reg_cntl); + if (reg_cntl & TSENS_TM_CODE_SIGN_BIT) { + /* Sign extension for negative value */ + code_mask = ~TSENS_TM_CODE_BIT_MASK; + reg_cntl |= code_mask; + } + break; + case TSENS_TM_TRIP_COOL: + reg_cntl = readl_relaxed((TSENS_TM_UPPER_LOWER_THRESHOLD + (tmdev->tsens_addr)) + + (tm_sensor->sensor_hw_num * + TSENS_SN_ADDR_OFFSET)); + reg_cntl = TSENS_TM_LOWER_THRESHOLD_VALUE(reg_cntl); + if (reg_cntl & TSENS_TM_CODE_SIGN_BIT) { + /* Sign extension for negative value */ + code_mask = ~TSENS_TM_CODE_BIT_MASK; + reg_cntl |= code_mask; + } + break; + default: + return -EINVAL; + } + + *temp = reg_cntl; + + return 0; +} + +static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal, + int trip, unsigned long *temp) +{ + struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; + unsigned int reg; + int sensor_sw_id = -EINVAL, rc = 0; + + if (!tm_sensor || trip < 0 || !temp) + return -EINVAL; + + reg = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR + (tmdev->tsens_addr) + + (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET)); + switch (trip) { + case TSENS_TRIP_WARM: + reg = (reg & TSENS_UPPER_THRESHOLD_MASK) >> + TSENS_UPPER_THRESHOLD_SHIFT; + break; + case TSENS_TRIP_COOL: + reg = (reg & TSENS_LOWER_THRESHOLD_MASK); + break; + default: + return -EINVAL; + } + + rc = tsens_get_sw_id_mapping(tm_sensor->sensor_hw_num, &sensor_sw_id); + if (rc < 0) { + pr_err("tsens mapping index not found\n"); + return rc; + } + *temp = tsens_tz_code_to_degc(reg, sensor_sw_id); + + return 0; +} + +static int tsens_tz_notify(struct thermal_zone_device *thermal, + int count, enum thermal_trip_type type) +{ + /* Critical temperature threshold are enabled and will + * shutdown the device once critical thresholds are crossed. */ + pr_debug("%s debug\n", __func__); + return 1; +} + +static int tsens_tm_set_trip_temp(struct thermal_zone_device *thermal, + int trip, unsigned long temp) +{ + struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; + unsigned int reg_cntl; + + if (!tm_sensor || trip < 0) + return -EINVAL; + + switch (trip) { + case TSENS_TM_TRIP_CRITICAL: + temp &= TSENS_TM_SN_CRITICAL_THRESHOLD_MASK; + writel_relaxed(temp, + (TSENS_TM_SN_CRITICAL_THRESHOLD(tmdev->tsens_addr) + + (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET))); + break; + case TSENS_TM_TRIP_WARM: + reg_cntl = readl_relaxed((TSENS_TM_UPPER_LOWER_THRESHOLD + (tmdev->tsens_addr)) + + (tm_sensor->sensor_hw_num * + TSENS_SN_ADDR_OFFSET)); + temp = TSENS_TM_UPPER_THRESHOLD_SET(temp); + temp &= TSENS_TM_UPPER_THRESHOLD_MASK; + reg_cntl &= ~TSENS_TM_UPPER_THRESHOLD_MASK; + writel_relaxed(reg_cntl | temp, + (TSENS_TM_UPPER_LOWER_THRESHOLD(tmdev->tsens_addr) + + (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET))); + break; + case TSENS_TM_TRIP_COOL: + reg_cntl = readl_relaxed((TSENS_TM_UPPER_LOWER_THRESHOLD + (tmdev->tsens_addr)) + + (tm_sensor->sensor_hw_num * + TSENS_SN_ADDR_OFFSET)); + temp &= TSENS_TM_LOWER_THRESHOLD_MASK; + reg_cntl &= ~TSENS_TM_LOWER_THRESHOLD_MASK; + writel_relaxed(reg_cntl | temp, + (TSENS_TM_UPPER_LOWER_THRESHOLD(tmdev->tsens_addr) + + (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET))); + break; + default: + return -EINVAL; + } + + /* Set trip temperature thresholds */ + mb(); + return 0; +} + +static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal, + int trip, unsigned long temp) +{ + struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; + unsigned int reg_cntl; + int code, hi_code, lo_code, code_err_chk, sensor_sw_id = 0, rc = 0; + + if (!tm_sensor || trip < 0) + return -EINVAL; + + rc = tsens_get_sw_id_mapping(tm_sensor->sensor_hw_num, &sensor_sw_id); + if (rc < 0) { + pr_err("tsens mapping index not found\n"); + return rc; + } + code_err_chk = code = tsens_tz_degc_to_code(temp, sensor_sw_id); + if (!tm_sensor || trip < 0) + return -EINVAL; + + lo_code = TSENS_THRESHOLD_MIN_CODE; + hi_code = TSENS_THRESHOLD_MAX_CODE; + + reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR + (tmdev->tsens_addr) + (tm_sensor->sensor_hw_num * + TSENS_SN_ADDR_OFFSET)); + switch (trip) { + case TSENS_TRIP_WARM: + code <<= TSENS_UPPER_THRESHOLD_SHIFT; + reg_cntl &= ~TSENS_UPPER_THRESHOLD_MASK; + if (!(reg_cntl & TSENS_LOWER_STATUS_CLR)) + lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK); + break; + case TSENS_TRIP_COOL: + reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK; + if (!(reg_cntl & TSENS_UPPER_STATUS_CLR)) + hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK) + >> TSENS_UPPER_THRESHOLD_SHIFT; + break; + default: + return -EINVAL; + } + + writel_relaxed(reg_cntl | code, (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR + (tmdev->tsens_addr) + + (tm_sensor->sensor_hw_num * + TSENS_SN_ADDR_OFFSET))); + /* Activate the set trip temperature thresholds */ + mb(); + return 0; +} + +static struct thermal_zone_device_ops tsens_thermal_zone_ops = { + .get_temp = tsens_tz_get_temp, + .get_mode = tsens_tz_get_mode, + .get_trip_type = tsens_tz_get_trip_type, + .activate_trip_type = tsens_tz_activate_trip_type, + .get_trip_temp = tsens_tz_get_trip_temp, + .set_trip_temp = tsens_tz_set_trip_temp, + .notify = tsens_tz_notify, +}; + +/* Thermal zone ops for decidegC */ +static struct thermal_zone_device_ops tsens_tm_thermal_zone_ops = { + .get_temp = tsens_tz_get_temp, + .get_trip_type = tsens_tm_get_trip_type, + .activate_trip_type = tsens_tm_activate_trip_type, + .get_trip_temp = tsens_tm_get_trip_temp, + .set_trip_temp = tsens_tm_set_trip_temp, + .notify = tsens_tz_notify, +}; + +static irqreturn_t tsens_tm_critical_irq_thread(int irq, void *data) +{ + struct tsens_tm_device *tm = data; + unsigned int i, status, threshold; + void __iomem *sensor_status_addr; + void __iomem *sensor_int_mask_addr; + void __iomem *sensor_critical_addr; + int sensor_sw_id = -EINVAL, rc = 0; + + sensor_status_addr = TSENS_TM_SN_STATUS(tmdev->tsens_addr); + sensor_int_mask_addr = + TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_addr); + sensor_critical_addr = + TSENS_TM_SN_CRITICAL_THRESHOLD(tmdev->tsens_addr); + + for (i = 0; i < tm->tsens_num_sensor; i++) { + bool critical_thr = false; + int int_mask, int_mask_val; + uint32_t addr_offset; + + addr_offset = tm->sensor[i].sensor_hw_num * + TSENS_SN_ADDR_OFFSET; + status = readl_relaxed(sensor_status_addr + addr_offset); + if (status & TSENS_TM_SN_STATUS_CRITICAL_STATUS) { + int_mask = readl_relaxed(sensor_int_mask_addr); + int_mask_val = (1 << tm->sensor[i].sensor_hw_num); + writel_relaxed(int_mask | int_mask_val, + TSENS_TM_CRITICAL_INT_MASK( + tmdev->tsens_addr)); + critical_thr = true; + } + if (critical_thr) { + unsigned long temp; + tsens_tz_get_temp(tm->sensor[i].tz_dev, &temp); + + rc = tsens_get_sw_id_mapping( + tm->sensor[i].sensor_hw_num, + &sensor_sw_id); + if (rc < 0) + pr_err("tsens mapping index not found\n"); + pr_debug("sensor:%d trigger temp (%d degC)\n", + tm->sensor[i].sensor_hw_num, + (status & TSENS_TM_SN_LAST_TEMP_MASK)); + threshold = readl_relaxed(sensor_critical_addr + + addr_offset); + } + } + + /* Mask critical interrupt */ + mb(); + + return IRQ_HANDLED; +} + +static irqreturn_t tsens_tm_irq_thread(int irq, void *data) +{ + struct tsens_tm_device *tm = data; + unsigned int i, status, threshold; + void __iomem *sensor_status_addr; + void __iomem *sensor_int_mask_addr; + void __iomem *sensor_upper_lower_addr; + int sensor_sw_id = -EINVAL, rc = 0; + + sensor_status_addr = TSENS_TM_SN_STATUS(tmdev->tsens_addr); + sensor_int_mask_addr = + TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_addr); + sensor_upper_lower_addr = + TSENS_TM_UPPER_LOWER_THRESHOLD(tmdev->tsens_addr); + + for (i = 0; i < tm->tsens_num_sensor; i++) { + bool upper_thr = false, lower_thr = false; + int int_mask, int_mask_val; + uint32_t addr_offset; + + addr_offset = tm->sensor[i].sensor_hw_num * + TSENS_SN_ADDR_OFFSET; + status = readl_relaxed(sensor_status_addr + addr_offset); + if (status & TSENS_TM_SN_STATUS_UPPER_STATUS) { + int_mask = readl_relaxed(sensor_int_mask_addr); + int_mask_val = TSENS_TM_UPPER_INT_SET( + tm->sensor[i].sensor_hw_num); + writel_relaxed(int_mask | int_mask_val, + TSENS_TM_UPPER_LOWER_INT_MASK( + tmdev->tsens_addr)); + upper_thr = true; + } + if (status & TSENS_TM_SN_STATUS_LOWER_STATUS) { + int_mask = readl_relaxed(sensor_int_mask_addr); + int_mask_val = (1 << tm->sensor[i].sensor_hw_num); + writel_relaxed(int_mask | int_mask_val, + TSENS_TM_UPPER_LOWER_INT_MASK( + tmdev->tsens_addr)); + lower_thr = true; + } + if (upper_thr || lower_thr) { + unsigned long temp; + enum thermal_trip_type trip = + THERMAL_TRIP_CONFIGURABLE_LOW; + + if (upper_thr) + trip = THERMAL_TRIP_CONFIGURABLE_HI; + tsens_tz_get_temp(tm->sensor[i].tz_dev, &temp); + + rc = tsens_get_sw_id_mapping( + tm->sensor[i].sensor_hw_num, + &sensor_sw_id); + if (rc < 0) + pr_err("tsens mapping index not found\n"); + pr_debug("sensor:%d trigger temp (%d degC)\n", + tm->sensor[i].sensor_hw_num, + (status & TSENS_TM_SN_LAST_TEMP_MASK)); + threshold = readl_relaxed(sensor_upper_lower_addr + + addr_offset); + if (upper_thr) + trace_tsens_threshold_hit( + TSENS_TM_UPPER_THRESHOLD_VALUE( + threshold), + tm->sensor[i].sensor_hw_num); + else + trace_tsens_threshold_clear( + TSENS_TM_LOWER_THRESHOLD_VALUE( + threshold), + tm->sensor[i].sensor_hw_num); + } + } + /* Disable monitoring sensor trip threshold for triggered sensor */ + mb(); + + return IRQ_HANDLED; +} + +static irqreturn_t tsens_irq_thread(int irq, void *data) +{ + struct tsens_tm_device *tm = data; + unsigned int i, status, threshold; + void __iomem *sensor_status_addr; + void __iomem *sensor_status_ctrl_addr; + int sensor_sw_id = -EINVAL, rc = 0; + uint32_t idx = 0; + + if (tmdev->tsens_type == TSENS_TYPE2) + sensor_status_addr = TSENS2_SN_STATUS_ADDR(tmdev->tsens_addr); + else + sensor_status_addr = TSENS_S0_STATUS_ADDR(tmdev->tsens_addr); + + sensor_status_ctrl_addr = + TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_addr); + for (i = 0; i < tm->tsens_num_sensor; i++) { + bool upper_thr = false, lower_thr = false; + uint32_t addr_offset; + + addr_offset = tm->sensor[i].sensor_hw_num * + TSENS_SN_ADDR_OFFSET; + status = readl_relaxed(sensor_status_addr + addr_offset); + threshold = readl_relaxed(sensor_status_ctrl_addr + + addr_offset); + if (status & TSENS_SN_STATUS_UPPER_STATUS) { + writel_relaxed(threshold | TSENS_UPPER_STATUS_CLR, + TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR( + tmdev->tsens_addr + addr_offset)); + upper_thr = true; + } + if (status & TSENS_SN_STATUS_LOWER_STATUS) { + writel_relaxed(threshold | TSENS_LOWER_STATUS_CLR, + TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR( + tmdev->tsens_addr + addr_offset)); + lower_thr = true; + } + if (upper_thr || lower_thr) { + unsigned long temp; + enum thermal_trip_type trip = + THERMAL_TRIP_CONFIGURABLE_LOW; + + if (upper_thr) + trip = THERMAL_TRIP_CONFIGURABLE_HI; + tsens_tz_get_temp(tm->sensor[i].tz_dev, &temp); + + rc = tsens_get_sw_id_mapping( + tm->sensor[i].sensor_hw_num, + &sensor_sw_id); + if (rc < 0) + pr_err("tsens mapping index not found\n"); + pr_debug("sensor:%d trigger temp (%d degC)\n", + tm->sensor[i].sensor_hw_num, + tsens_tz_code_to_degc((status & + TSENS_SN_STATUS_TEMP_MASK), + sensor_sw_id)); + if (upper_thr) + trace_tsens_threshold_hit( + tsens_tz_code_to_degc((threshold & + TSENS_UPPER_THRESHOLD_MASK) >> + TSENS_UPPER_THRESHOLD_SHIFT, + sensor_sw_id), + tm->sensor[i].sensor_hw_num); + else + trace_tsens_threshold_clear( + tsens_tz_code_to_degc((threshold & + TSENS_LOWER_THRESHOLD_MASK), + sensor_sw_id), + tm->sensor[i].sensor_hw_num); + } + } + /* debug */ + idx = tmdev->tsens_thread_iq_dbg.idx; + tmdev->tsens_thread_iq_dbg.dbg_count[idx%10]++; + tmdev->tsens_thread_iq_dbg.time_stmp[idx%10] = sched_clock(); + tmdev->tsens_thread_iq_dbg.idx++; + + mb(); + + return IRQ_HANDLED; +} + +static void tsens_hw_init(void) +{ + if (tmdev->tsens_type == TSENS_TYPE3) + writel_relaxed(TSENS_TM_CRITICAL_INT_EN | + TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN, + TSENS_TM_INT_EN(tmdev->tsens_addr)); + else + writel_relaxed(TSENS_INTERRUPT_EN, + TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr)); +} + +static int tsens_calib_msm8909_sensors(void) +{ + int i, tsens_base0_data = 0, tsens_base1_data = 0; + int tsens0_point1 = 0, tsens0_point2 = 0; + int tsens1_point1 = 0, tsens1_point2 = 0; + int tsens2_point1 = 0, tsens2_point2 = 0; + int tsens3_point1 = 0, tsens3_point2 = 0; + int tsens4_point1 = 0, tsens4_point2 = 0; + int tsens_calibration_mode = 0, temp = 0; + uint32_t calib_data[3] = {0, 0, 0}; + uint32_t calib_tsens_point1_data[5], calib_tsens_point2_data[5]; + + if (!tmdev->calibration_less_mode) { + + calib_data[0] = readl_relaxed( + TSENS_8939_EEPROM(tmdev->tsens_calib_addr)); + calib_data[1] = readl_relaxed( + (TSENS_8939_EEPROM(tmdev->tsens_calib_addr) + 0x4)); + calib_data[2] = readl_relaxed( + (TSENS_8939_EEPROM(tmdev->tsens_calib_addr) + 0x3c)); + + tsens_calibration_mode = + (calib_data[2] & TSENS_MSM8909_TSENS_CAL_SEL) >> + TSENS_MSM8909_CAL_SEL_SHIFT; + + pr_debug("calib mode is %d\n", tsens_calibration_mode); + } + + if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) || + (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) { + tsens_base0_data = (calib_data[2] & TSENS_MSM8909_BASE0_MASK); + tsens0_point1 = (calib_data[0] & TSENS0_MSM8909_POINT1_MASK); + tsens1_point1 = (calib_data[0] & TSENS1_MSM8909_POINT1_MASK) + >> TSENS1_MSM8909_POINT1_SHIFT; + tsens2_point1 = (calib_data[0] & TSENS2_MSM8909_POINT1_MASK) + >> TSENS2_MSM8909_POINT1_SHIFT; + tsens3_point1 = (calib_data[1] & TSENS3_MSM8909_POINT1_MASK) + >> TSENS3_MSM8909_POINT1_SHIFT; + tsens4_point1 = (calib_data[1] & TSENS4_MSM8909_POINT1_MASK) + >> TSENS4_MSM8909_POINT1_SHIFT; + } + + if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) { + tsens_base1_data = (calib_data[2] & TSENS_MSM8909_BASE1_MASK) + >> TSENS_MSM8909_BASE1_SHIFT; + tsens0_point2 = (calib_data[0] & TSENS0_MSM8909_POINT2_MASK) + >> TSENS0_MSM8909_POINT2_SHIFT; + tsens1_point2 = (calib_data[0] & TSENS1_MSM8909_POINT2_MASK) + >> TSENS1_MSM8909_POINT2_SHIFT; + tsens2_point2 = + (calib_data[0] & TSENS2_MSM8909_POINT2_MASK_0_1) + >> TSENS2_MSM8909_POINT2_SHIFT_0_1; + temp = (calib_data[1] & TSENS2_MSM8909_POINT2_MASK_2_5) << + TSENS2_MSM8909_POINT2_SHIFT_2_5; + tsens2_point2 |= temp; + tsens3_point2 = (calib_data[1] & TSENS3_MSM8909_POINT2_MASK) + >> TSENS3_MSM8909_POINT2_SHIFT; + tsens4_point2 = (calib_data[1] & TSENS4_MSM8909_POINT2_MASK) + >> TSENS4_MSM8909_POINT2_SHIFT; + } + + if (tsens_calibration_mode == 0) { + 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] = 500; + calib_tsens_point1_data[1] = 500; + calib_tsens_point1_data[2] = 500; + calib_tsens_point1_data[3] = 500; + calib_tsens_point1_data[4] = 500; + } + + if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) || + (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) { + calib_tsens_point1_data[0] = + (((tsens_base0_data) + tsens0_point1) << 2); + calib_tsens_point1_data[1] = + (((tsens_base0_data) + tsens1_point1) << 2); + calib_tsens_point1_data[2] = + (((tsens_base0_data) + tsens2_point1) << 2); + calib_tsens_point1_data[3] = + (((tsens_base0_data) + tsens3_point1) << 2); + calib_tsens_point1_data[4] = + (((tsens_base0_data) + tsens4_point1) << 2); + } + + 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); + calib_tsens_point2_data[1] = + ((tsens_base1_data + tsens1_point2) << 2); + calib_tsens_point2_data[2] = + ((tsens_base1_data + tsens2_point2) << 2); + calib_tsens_point2_data[3] = + ((tsens_base1_data + tsens3_point2) << 2); + calib_tsens_point2_data[4] = + ((tsens_base1_data + tsens4_point2) << 2); + } + + 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]; + pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n", + i, tmdev->sensor[i].calib_data_point1, + tmdev->sensor[i].calib_data_point2); + 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); + pr_debug("offset:%d and slope:%d\n", tmdev->sensor[i].offset, + tmdev->sensor[i].slope_mul_tsens_factor); + tmdev->prev_reading_avail = false; + } + + return 0; +} + +static int tsens_calib_8939_sensors(void) +{ + int i, tsens_base0_data = 0, tsens_base1_data = 0; + int tsens0_point1 = 0, tsens0_point2 = 0; + int tsens1_point1 = 0, tsens1_point2 = 0; + int tsens2_point1 = 0, tsens2_point2 = 0; + int tsens3_point1 = 0, tsens3_point2 = 0; + int tsens4_point1 = 0, tsens4_point2 = 0; + int tsens5_point1 = 0, tsens5_point2 = 0; + int tsens6_point1 = 0, tsens6_point2 = 0; + int tsens7_point1 = 0, tsens7_point2 = 0; + int tsens8_point1 = 0, tsens8_point2 = 0; + int tsens_calibration_mode = 0, temp = 0; + uint32_t calib_data[4] = {0, 0, 0, 0}; + uint32_t calib_tsens_point1_data[9], calib_tsens_point2_data[9]; + + if (!tmdev->calibration_less_mode) { + + calib_data[0] = readl_relaxed( + TSENS_8939_EEPROM(tmdev->tsens_calib_addr) + 0x30); + calib_data[1] = readl_relaxed( + (TSENS_8939_EEPROM(tmdev->tsens_calib_addr) + 0x34)); + calib_data[2] = readl_relaxed( + (TSENS_8939_EEPROM(tmdev->tsens_calib_addr))); + calib_data[3] = readl_relaxed( + (TSENS_8939_EEPROM(tmdev->tsens_calib_addr) + 0x4)); + + tsens_calibration_mode = + (calib_data[0] & TSENS_8939_TSENS_CAL_SEL); + + pr_debug("calib mode is %d\n", tsens_calibration_mode); + } + + if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) || + (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) { + tsens_base0_data = (calib_data[2] & TSENS_8939_BASE0_MASK); + tsens0_point1 = (calib_data[0] & TSENS0_8939_POINT1_MASK) >> + TSENS0_8939_POINT1_SHIFT; + tsens1_point1 = (calib_data[0] & TSENS1_8939_POINT1_MASK) >> + TSENS1_8939_POINT1_SHIFT; + tsens2_point1 = (calib_data[0] & TSENS2_8939_POINT1_MASK_0_4) + >> TSENS2_8939_POINT1_SHIFT_0_4; + temp = (calib_data[1] & TSENS2_8939_POINT1_MASK_5) << + TSENS2_8939_POINT1_SHIFT_5; + tsens2_point1 |= temp; + tsens3_point1 = (calib_data[1] & TSENS3_8939_POINT1_MASK) >> + TSENS3_8939_POINT1_SHIFT; + tsens4_point1 = (calib_data[1] & TSENS4_8939_POINT1_MASK) >> + TSENS4_8939_POINT1_SHIFT; + tsens5_point1 = (calib_data[2] & TSENS5_8939_POINT1_MASK) >> + TSENS5_8939_POINT1_SHIFT; + tsens6_point1 = (calib_data[2] & TSENS6_8939_POINT1_MASK) >> + TSENS6_8939_POINT1_SHIFT; + tsens7_point1 = (calib_data[3] & TSENS7_8939_POINT1_MASK); + tsens8_point1 = (calib_data[3] & TSENS8_8939_POINT1_MASK) >> + TSENS8_8939_POINT1_SHIFT; + } + + if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) { + tsens_base1_data = (calib_data[3] & TSENS_8939_BASE1_MASK) >> + TSENS_8939_BASE1_SHIFT; + tsens0_point2 = (calib_data[0] & TSENS0_8939_POINT2_MASK) >> + TSENS0_8939_POINT2_SHIFT; + tsens1_point2 = (calib_data[0] & TSENS1_8939_POINT2_MASK) >> + TSENS1_8939_POINT2_SHIFT; + tsens2_point2 = (calib_data[1] & TSENS2_8939_POINT2_MASK) >> + TSENS2_8939_POINT2_SHIFT; + tsens3_point2 = (calib_data[1] & TSENS3_8939_POINT2_MASK) >> + TSENS3_8939_POINT2_SHIFT; + tsens4_point2 = (calib_data[1] & TSENS4_8939_POINT2_MASK) >> + TSENS4_8939_POINT2_SHIFT; + tsens5_point2 = (calib_data[2] & TSENS5_8939_POINT2_MASK) >> + TSENS5_8939_POINT2_SHIFT; + tsens6_point2 = (calib_data[2] & TSENS6_8939_POINT2_MASK) >> + TSENS6_8939_POINT2_SHIFT; + tsens7_point2 = (calib_data[3] & TSENS7_8939_POINT2_MASK) >> + TSENS7_8939_POINT2_SHIFT; + tsens8_point2 = (calib_data[3] & TSENS8_8939_POINT2_MASK) >> + TSENS8_8939_POINT2_SHIFT; + } + + if (tsens_calibration_mode == 0) { + 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] = 500; + calib_tsens_point1_data[1] = 500; + calib_tsens_point1_data[2] = 500; + calib_tsens_point1_data[3] = 500; + calib_tsens_point1_data[4] = 500; + calib_tsens_point1_data[5] = 500; + calib_tsens_point1_data[6] = 500; + calib_tsens_point1_data[7] = 500; + calib_tsens_point1_data[8] = 500; + } + + if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) || + (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) { + calib_tsens_point1_data[0] = + (((tsens_base0_data) + tsens0_point1) << 2); + calib_tsens_point1_data[1] = + (((tsens_base0_data) + tsens1_point1) << 2); + calib_tsens_point1_data[2] = + (((tsens_base0_data) + tsens2_point1) << 2); + calib_tsens_point1_data[3] = + (((tsens_base0_data) + tsens3_point1) << 2); + calib_tsens_point1_data[4] = + (((tsens_base0_data) + tsens4_point1) << 2); + calib_tsens_point1_data[5] = + (((tsens_base0_data) + tsens5_point1) << 2); + calib_tsens_point1_data[6] = + (((tsens_base0_data) + tsens6_point1) << 2); + calib_tsens_point1_data[7] = + (((tsens_base0_data) + tsens7_point1) << 2); + calib_tsens_point1_data[8] = + (((tsens_base0_data) + tsens8_point1) << 2); + } + + 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); + calib_tsens_point2_data[1] = + ((tsens_base1_data + tsens1_point2) << 2); + calib_tsens_point2_data[2] = + ((tsens_base1_data + tsens2_point2) << 2); + calib_tsens_point2_data[3] = + ((tsens_base1_data + tsens3_point2) << 2); + calib_tsens_point2_data[4] = + ((tsens_base1_data + tsens4_point2) << 2); + calib_tsens_point2_data[5] = + ((tsens_base1_data + tsens5_point2) << 2); + calib_tsens_point2_data[6] = + ((tsens_base1_data + tsens6_point2) << 2); + calib_tsens_point2_data[7] = + ((tsens_base1_data + tsens7_point2) << 2); + calib_tsens_point2_data[8] = + ((tsens_base1_data + tsens8_point2) << 2); + } + + 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]; + pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n", + i, tmdev->sensor[i].calib_data_point1, + tmdev->sensor[i].calib_data_point2); + 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); + pr_debug("offset:%d and slope:%d\n", tmdev->sensor[i].offset, + tmdev->sensor[i].slope_mul_tsens_factor); + tmdev->prev_reading_avail = false; + } + + return 0; +} + +static int tsens_calib_8916_sensors(void) +{ + int i, tsens_base0_data = 0, tsens_base1_data = 0; + int tsens0_point1 = 0, tsens0_point2 = 0; + int tsens1_point1 = 0, tsens1_point2 = 0; + int tsens2_point1 = 0, tsens2_point2 = 0; + int tsens3_point1 = 0, tsens3_point2 = 0; + int tsens4_point1 = 0, tsens4_point2 = 0; + int tsens_calibration_mode = 0; + uint32_t calib_data[3] = {0, 0, 0}; + uint32_t calib_tsens_point1_data[5], calib_tsens_point2_data[5]; + + if (!tmdev->calibration_less_mode) { + + 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) + 0x1c)); + + tsens_calibration_mode = + (calib_data[2] & TSENS_8916_TSENS_CAL_SEL) >> + TSENS_8916_CAL_SEL_SHIFT; + + pr_debug("calib mode is %d\n", tsens_calibration_mode); + } + + if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) || + (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) { + tsens_base0_data = (calib_data[0] & TSENS_8916_BASE0_MASK); + tsens0_point1 = (calib_data[0] & TSENS0_8916_POINT1_MASK) >> + TSENS0_8916_POINT1_SHIFT; + tsens1_point1 = (calib_data[0] & TSENS1_8916_POINT1_MASK) >> + TSENS1_8916_POINT1_SHIFT; + tsens2_point1 = (calib_data[0] & TSENS2_8916_POINT1_MASK) >> + TSENS2_8916_POINT1_SHIFT; + tsens3_point1 = (calib_data[1] & TSENS3_8916_POINT1_MASK) >> + TSENS3_8916_POINT1_SHIFT; + tsens4_point1 = (calib_data[1] & TSENS4_8916_POINT1_MASK) >> + TSENS4_8916_POINT1_SHIFT; + } + + if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) { + tsens_base1_data = (calib_data[1] & TSENS_8916_BASE1_MASK) >> + TSENS_8916_BASE1_SHIFT; + tsens0_point2 = (calib_data[0] & TSENS0_8916_POINT2_MASK) >> + TSENS0_8916_POINT2_SHIFT; + tsens1_point2 = (calib_data[0] & TSENS1_8916_POINT2_MASK) >> + TSENS1_8916_POINT2_SHIFT; + tsens2_point2 = (calib_data[1] & TSENS2_8916_POINT2_MASK); + tsens3_point2 = (calib_data[1] & TSENS3_8916_POINT2_MASK) >> + TSENS3_8916_POINT2_SHIFT; + tsens4_point2 = (calib_data[1] & TSENS4_8916_POINT2_MASK) >> + TSENS4_8916_POINT2_SHIFT; + } + + if (tsens_calibration_mode == 0) { + 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] = 500; + calib_tsens_point1_data[1] = 500; + calib_tsens_point1_data[2] = 500; + calib_tsens_point1_data[3] = 500; + calib_tsens_point1_data[4] = 500; + } + + if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) || + (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) { + calib_tsens_point1_data[0] = + (((tsens_base0_data) + tsens0_point1) << 3); + calib_tsens_point1_data[1] = + (((tsens_base0_data) + tsens1_point1) << 3); + calib_tsens_point1_data[2] = + (((tsens_base0_data) + tsens2_point1) << 3); + calib_tsens_point1_data[3] = + (((tsens_base0_data) + tsens3_point1) << 3); + calib_tsens_point1_data[4] = + (((tsens_base0_data) + tsens4_point1) << 3); + } + + 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) << 3); + calib_tsens_point2_data[1] = + ((tsens_base1_data + tsens1_point2) << 3); + calib_tsens_point2_data[2] = + ((tsens_base1_data + tsens2_point2) << 3); + calib_tsens_point2_data[3] = + ((tsens_base1_data + tsens3_point2) << 3); + calib_tsens_point2_data[4] = + ((tsens_base1_data + tsens4_point2) << 3); + } + + 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]; + pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n", + i, tmdev->sensor[i].calib_data_point1, + tmdev->sensor[i].calib_data_point2); + 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); + pr_debug("offset:%d and slope:%d\n", tmdev->sensor[i].offset, + tmdev->sensor[i].slope_mul_tsens_factor); + tmdev->prev_reading_avail = false; + } + + return 0; +} + +static int tsens_calib_9630_sensors(void) +{ + int i, tsens_base0_data = 0, tsens0_point = 0, tsens1_point = 0; + int tsens2_point = 0, tsens3_point = 0, tsens4_point = 0; + int tsens_base1_data = 0, tsens_calibration_mode = 0, calib_mode = 0; + uint32_t calib_data[2], calib_tsens_point_data[5]; + + if (tmdev->calibration_less_mode) + goto calibration_less_mode; + + calib_data[0] = readl_relaxed( + TSENS_EEPROM(tmdev->tsens_calib_addr)); + calib_data[1] = readl_relaxed( + (TSENS_EEPROM(tmdev->tsens_calib_addr) + 0x4)); + + calib_mode = (calib_data[1] & TSENS_TORINO_CALIB_PT) >> + TSENS_TORINO_CALIB_SHIFT; + pr_debug("calib mode is %d\n", calib_mode); + if (calib_mode == TSENS_TWO_POINT_CALIB) { + tsens_base0_data = (calib_data[0] & TSENS_TORINO_BASE0); + tsens_base1_data = (calib_data[0] & TSENS_TORINO_BASE1) >> + TSENS_TORINO_BASE1_SHIFT; + tsens0_point = (calib_data[0] & TSENS_TORINO_POINT0) >> + TSENS_TORINO_POINT0_SHIFT; + tsens1_point = (calib_data[0] & TSENS_TORINO_POINT1) >> + TSENS_TORINO_POINT1_SHIFT; + tsens2_point = (calib_data[0] & TSENS_TORINO_POINT2) >> + TSENS_TORINO_POINT2_SHIFT; + tsens3_point = (calib_data[0] & TSENS_TORINO_POINT3) >> + TSENS_TORINO_POINT3_SHIFT; + tsens4_point = (calib_data[0] & TSENS_TORINO_POINT4) >> + TSENS_TORINO_POINT4_SHIFT; + calib_tsens_point_data[0] = tsens0_point; + calib_tsens_point_data[1] = tsens1_point; + calib_tsens_point_data[2] = tsens2_point; + calib_tsens_point_data[3] = tsens3_point; + calib_tsens_point_data[4] = tsens4_point; + } + + if (calib_mode == 0) { +calibration_less_mode: + pr_debug("TSENS is calibrationless mode\n"); + calib_tsens_point_data[0] = 532; + calib_tsens_point_data[1] = 532; + calib_tsens_point_data[2] = 532; + calib_tsens_point_data[3] = 532; + calib_tsens_point_data[4] = 532; + goto compute_intercept_slope; + } + +compute_intercept_slope: + for (i = 0; i < tmdev->tsens_num_sensor; i++) { + int32_t num = 0, den = 0, adc_code_of_tempx = 0; + tmdev->sensor[i].calib_data_point2 = tsens_base1_data; + tmdev->sensor[i].calib_data_point1 = tsens_base0_data; + pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n", + i, tmdev->sensor[i].calib_data_point1, + tmdev->sensor[i].calib_data_point2); + 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; + } + adc_code_of_tempx = + tsens_base0_data + calib_tsens_point_data[i]; + pr_debug("offset_adc_code_of_tempx:0x%x\n", + adc_code_of_tempx); + tmdev->sensor[i].offset = (adc_code_of_tempx * + tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 * + tmdev->sensor[i].slope_mul_tsens_factor); + pr_debug("offset:%d and slope:%d\n", tmdev->sensor[i].offset, + tmdev->sensor[i].slope_mul_tsens_factor); + tmdev->prev_reading_avail = false; + } + + return 0; +} + +static int tsens_calib_8994_sensors(void) +{ + int i, tsens_base0_data = 0, tsens0_point = 0, tsens1_point = 0; + int tsens2_point = 0, tsens3_point = 0, tsens4_point = 0; + int tsens5_point = 0, tsens6_point = 0, tsens7_point = 0; + int tsens8_point = 0, tsens9_point = 0, tsens10_point = 0; + int tsens11_point = 0, tsens12_point = 0, tsens13_point = 0; + int tsens14_point = 0, tsens15_point = 0; + int tsens_base1_data = 0, calib_mode = 0; + uint32_t calib_data[6], calib_tsens_point_data[16], calib_redun_sel; + + if (tmdev->calibration_less_mode) + goto calibration_less_mode; + + calib_redun_sel = readl_relaxed( + TSENS_8994_EEPROM_REDUN_SEL(tmdev->tsens_calib_addr)); + calib_redun_sel = calib_redun_sel & TSENS_8994_CAL_SEL_REDUN_MASK; + calib_redun_sel >>= TSENS_8994_CAL_SEL_REDUN_SHIFT; + + if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) { + calib_data[0] = readl_relaxed( + TSENS_REDUN_REGION1_EEPROM(tmdev->tsens_calib_addr)); + calib_data[1] = readl_relaxed( + TSENS_REDUN_REGION2_EEPROM(tmdev->tsens_calib_addr)); + calib_data[2] = readl_relaxed( + TSENS_REDUN_REGION3_EEPROM(tmdev->tsens_calib_addr)); + calib_data[3] = readl_relaxed( + TSENS_REDUN_REGION4_EEPROM(tmdev->tsens_calib_addr)); + calib_data[4] = readl_relaxed( + TSENS_REDUN_REGION5_EEPROM(tmdev->tsens_calib_addr)); + + calib_mode = (calib_data[4] & TSENS_8994_REDUN_SEL_MASK); + pr_debug("calib mode is %d\n", calib_mode); + if (calib_mode == TSENS_TWO_POINT_CALIB) { + tsens_base0_data = (calib_data[0] & + TSENS_BASE0_8994_REDUN_MASK) >> + TSENS_BASE0_8994_REDUN_MASK_SHIFT; + tsens_base1_data = (calib_data[0] & + TSENS_BASE1_BIT0_8994_REDUN_MASK) >> + TSENS_BASE1_BIT0_SHIFT_COMPUTE; + tsens_base1_data |= (calib_data[1] & + TSENS_BASE1_BIT1_9_8994_REDUN_MASK); + tsens0_point = (calib_data[1] & + TSENS0_OFFSET_8994_REDUN_MASK) >> + TSENS0_OFFSET_8994_REDUN_SHIFT; + tsens1_point = (calib_data[1] & + TSENS1_OFFSET_8994_REDUN_MASK) >> + TSENS1_OFFSET_8994_REDUN_SHIFT; + tsens2_point = (calib_data[1] & + TSENS2_OFFSET_8994_REDUN_MASK) >> + TSENS2_OFFSET_8994_REDUN_SHIFT; + tsens3_point = (calib_data[1] & + TSENS3_OFFSET_8994_REDUN_MASK) >> + TSENS3_OFFSET_8994_REDUN_SHIFT; + tsens4_point = (calib_data[1] & + TSENS4_OFFSET_8994_REDUN_MASK) >> + TSENS4_OFFSET_8994_REDUN_SHIFT; + tsens5_point = (calib_data[1] & + TSENS5_OFFSET_8994_REDUN_MASK_BIT0_2) >> + TSENS5_OFFSET_8994_REDUN_SHIFT_BIT0_2; + tsens5_point |= ((calib_data[2] & + TSENS5_OFFSET_8994_REDUN_MASK_BIT3) >> + TSENS5_OFFSET_8994_REDUN_SHIFT_BIT3); + tsens6_point = (calib_data[2] & + TSENS6_OFFSET_8994_REDUN_MASK) >> + TSENS6_OFFSET_8994_REDUN_SHIFT; + tsens7_point = (calib_data[2] & + TSENS7_OFFSET_8994_REDUN_MASK) >> + TSENS7_OFFSET_8994_REDUN_SHIFT; + tsens8_point = (calib_data[3] & + TSENS8_OFFSET_8994_REDUN_MASK); + tsens9_point = (calib_data[3] & + TSENS9_OFFSET_8994_REDUN_MASK) >> + TSENS9_OFFSET_8994_REDUN_SHIFT; + tsens10_point = (calib_data[3] & + TSENS10_OFFSET_8994_REDUN_MASK) >> + TSENS10_OFFSET_8994_REDUN_SHIFT; + tsens11_point = (calib_data[3] & + TSENS11_OFFSET_8994_REDUN_MASK) >> + TSENS11_OFFSET_8994_REDUN_SHIFT; + tsens12_point = (calib_data[3] & + TSENS12_OFFSET_8994_REDUN_MASK) >> + TSENS12_OFFSET_8994_REDUN_SHIFT; + tsens13_point = (calib_data[3] & + TSENS13_OFFSET_8994_REDUN_MASK) >> + TSENS13_OFFSET_8994_REDUN_SHIFT; + tsens14_point = (calib_data[3] & + TSENS14_OFFSET_8994_REDUN_MASK) >> + TSENS14_OFFSET_8994_REDUN_SHIFT; + tsens15_point = (calib_data[3] & + TSENS15_OFFSET_8994_REDUN_MASK) >> + TSENS15_OFFSET_8994_REDUN_SHIFT; + calib_tsens_point_data[0] = tsens0_point; + calib_tsens_point_data[1] = tsens1_point; + calib_tsens_point_data[2] = tsens2_point; + calib_tsens_point_data[3] = tsens3_point; + calib_tsens_point_data[4] = tsens4_point; + calib_tsens_point_data[5] = tsens5_point; + calib_tsens_point_data[6] = tsens6_point; + calib_tsens_point_data[7] = tsens7_point; + calib_tsens_point_data[8] = tsens8_point; + calib_tsens_point_data[9] = tsens9_point; + calib_tsens_point_data[10] = tsens10_point; + calib_tsens_point_data[11] = tsens11_point; + calib_tsens_point_data[12] = tsens12_point; + calib_tsens_point_data[13] = tsens13_point; + calib_tsens_point_data[14] = tsens14_point; + calib_tsens_point_data[15] = tsens15_point; + } else + goto calibration_less_mode; + } else { + calib_data[0] = readl_relaxed( + TSENS_8994_EEPROM(tmdev->tsens_calib_addr)); + calib_data[1] = readl_relaxed( + (TSENS_8994_EEPROM(tmdev->tsens_calib_addr) + 0x4)); + calib_data[2] = readl_relaxed( + (TSENS_8994_EEPROM(tmdev->tsens_calib_addr) + 0x8)); + + calib_mode = (calib_data[2] & TSENS_8994_CAL_SEL_MASK) >> + TSENS_8994_CAL_SEL_SHIFT; + pr_debug("calib mode is %d\n", calib_mode); + if (calib_mode == TSENS_TWO_POINT_CALIB) { + tsens_base0_data = (calib_data[0] & + TSENS_BASE0_8994_MASK); + tsens_base1_data = (calib_data[0] & + TSENS_BASE1_8994_MASK) >> + TSENS_BASE1_8994_SHIFT; + tsens0_point = (calib_data[0] & + TSENS0_OFFSET_8994_MASK) >> + TSENS0_OFFSET_8994_SHIFT; + tsens1_point = (calib_data[0] & + TSENS1_OFFSET_8994_MASK) >> + TSENS1_OFFSET_8994_SHIFT; + tsens2_point = (calib_data[0] & + TSENS2_OFFSET_8994_MASK) >> + TSENS2_OFFSET_8994_SHIFT; + tsens3_point = (calib_data[1] & + TSENS3_OFFSET_8994_MASK); + tsens4_point = (calib_data[1] & + TSENS4_OFFSET_8994_MASK) >> + TSENS4_OFFSET_8994_SHIFT; + tsens5_point = (calib_data[1] & + TSENS5_OFFSET_8994_MASK) >> + TSENS5_OFFSET_8994_SHIFT; + tsens6_point = (calib_data[1] & + TSENS6_OFFSET_8994_MASK) >> + TSENS6_OFFSET_8994_SHIFT; + tsens7_point = (calib_data[1] & + TSENS7_OFFSET_8994_MASK) >> + TSENS7_OFFSET_8994_SHIFT; + tsens8_point = (calib_data[1] & + TSENS8_OFFSET_8994_MASK) >> + TSENS8_OFFSET_8994_SHIFT; + tsens9_point = (calib_data[1] & + TSENS9_OFFSET_8994_MASK) >> + TSENS9_OFFSET_8994_SHIFT; + tsens10_point = (calib_data[1] & + TSENS10_OFFSET_8994_MASK) >> + TSENS10_OFFSET_8994_SHIFT; + tsens11_point = (calib_data[2] & + TSENS11_OFFSET_8994_MASK); + tsens12_point = (calib_data[2] & + TSENS12_OFFSET_8994_MASK) >> + TSENS12_OFFSET_8994_SHIFT; + tsens13_point = (calib_data[2] & + TSENS13_OFFSET_8994_MASK) >> + TSENS13_OFFSET_8994_SHIFT; + tsens14_point = (calib_data[2] & + TSENS14_OFFSET_8994_MASK) >> + TSENS14_OFFSET_8994_SHIFT; + tsens15_point = (calib_data[2] & + TSENS15_OFFSET_8994_MASK) >> + TSENS15_OFFSET_8994_SHIFT; + calib_tsens_point_data[0] = tsens0_point; + calib_tsens_point_data[1] = tsens1_point; + calib_tsens_point_data[2] = tsens2_point; + calib_tsens_point_data[3] = tsens3_point; + calib_tsens_point_data[4] = tsens4_point; + calib_tsens_point_data[5] = tsens5_point; + calib_tsens_point_data[6] = tsens6_point; + calib_tsens_point_data[7] = tsens7_point; + calib_tsens_point_data[8] = tsens8_point; + calib_tsens_point_data[9] = tsens9_point; + calib_tsens_point_data[10] = tsens10_point; + calib_tsens_point_data[11] = tsens11_point; + calib_tsens_point_data[12] = tsens12_point; + calib_tsens_point_data[13] = tsens13_point; + calib_tsens_point_data[14] = tsens14_point; + calib_tsens_point_data[15] = tsens15_point; + } else { +calibration_less_mode: + pr_debug("TSENS is calibrationless mode\n"); + calib_tsens_point_data[0] = 532; + calib_tsens_point_data[1] = 532; + calib_tsens_point_data[2] = 532; + calib_tsens_point_data[3] = 532; + calib_tsens_point_data[4] = 532; + calib_tsens_point_data[5] = 532; + calib_tsens_point_data[6] = 532; + calib_tsens_point_data[7] = 532; + calib_tsens_point_data[8] = 532; + calib_tsens_point_data[9] = 532; + calib_tsens_point_data[10] = 532; + calib_tsens_point_data[11] = 532; + calib_tsens_point_data[12] = 532; + calib_tsens_point_data[13] = 532; + calib_tsens_point_data[14] = 532; + calib_tsens_point_data[15] = 532; + } + } + + for (i = 0; i < tmdev->tsens_num_sensor; i++) { + int32_t num = 0, den = 0, adc_code_of_tempx = 0; + tmdev->sensor[i].calib_data_point2 = tsens_base1_data; + tmdev->sensor[i].calib_data_point1 = tsens_base0_data; + pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n", + i, tmdev->sensor[i].calib_data_point1, + tmdev->sensor[i].calib_data_point2); + if (calib_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; + } + adc_code_of_tempx = + tsens_base0_data + calib_tsens_point_data[i]; + pr_debug("offset_adc_code_of_tempx:0x%x\n", + adc_code_of_tempx); + tmdev->sensor[i].offset = (adc_code_of_tempx * + tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 * + tmdev->sensor[i].slope_mul_tsens_factor); + pr_debug("offset:%d and slope:%d\n", tmdev->sensor[i].offset, + tmdev->sensor[i].slope_mul_tsens_factor); + tmdev->prev_reading_avail = false; + } + + return 0; +} + +static int tsens_calib_8992_sensors(void) +{ + int i, tsens_base0_data = 0, tsens0_point = 0, tsens1_point = 0; + int tsens2_point = 0, tsens3_point = 0, tsens4_point = 0; + int tsens5_point = 0, tsens6_point = 0, tsens7_point = 0; + int tsens8_point = 0, tsens9_point = 0, tsens10_point = 0; + int tsens11_point = 0, tsens12_point = 0, tsens13_point = 0; + int tsens14_point = 0, tsens15_point = 0; + int tsens_base1_data = 0, calib_mode = 0; + uint32_t calib_data[6], calib_tsens_point_data[16], calib_redun_sel; + + if (tmdev->calibration_less_mode) + goto calibration_less_mode; + + calib_redun_sel = readl_relaxed( + TSENS_8994_EEPROM_REDUN_SEL(tmdev->tsens_calib_addr)); + calib_redun_sel = calib_redun_sel & TSENS_8994_CAL_SEL_REDUN_MASK; + calib_redun_sel >>= TSENS_8994_CAL_SEL_REDUN_SHIFT; + + if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) { + calib_data[0] = readl_relaxed( + TSENS_REDUN_REGION1_EEPROM(tmdev->tsens_calib_addr)); + calib_data[1] = readl_relaxed( + TSENS_REDUN_REGION2_EEPROM(tmdev->tsens_calib_addr)); + calib_data[2] = readl_relaxed( + TSENS_REDUN_REGION3_EEPROM(tmdev->tsens_calib_addr)); + calib_data[3] = readl_relaxed( + TSENS_REDUN_REGION4_EEPROM(tmdev->tsens_calib_addr)); + calib_data[4] = readl_relaxed( + TSENS_REDUN_REGION5_EEPROM(tmdev->tsens_calib_addr)); + + calib_mode = (calib_data[4] & TSENS_8994_REDUN_SEL_MASK); + pr_debug("calib mode is %d\n", calib_mode); + if (calib_mode == TSENS_TWO_POINT_CALIB) { + tsens_base0_data = (calib_data[0] & + TSENS_BASE0_8994_REDUN_MASK) >> + TSENS_BASE0_8994_REDUN_MASK_SHIFT; + tsens_base1_data = (calib_data[0] & + TSENS_BASE1_BIT0_8994_REDUN_MASK) >> + TSENS_BASE1_BIT0_SHIFT_COMPUTE; + tsens_base1_data |= (calib_data[1] & + TSENS_BASE1_BIT1_9_8994_REDUN_MASK); + tsens0_point = (calib_data[1] & + TSENS0_OFFSET_8994_REDUN_MASK) >> + TSENS0_OFFSET_8994_REDUN_SHIFT; + tsens1_point = (calib_data[1] & + TSENS1_OFFSET_8994_REDUN_MASK) >> + TSENS1_OFFSET_8994_REDUN_SHIFT; + tsens2_point = (calib_data[1] & + TSENS2_OFFSET_8994_REDUN_MASK) >> + TSENS2_OFFSET_8994_REDUN_SHIFT; + tsens3_point = (calib_data[1] & + TSENS3_OFFSET_8994_REDUN_MASK) >> + TSENS3_OFFSET_8994_REDUN_SHIFT; + tsens4_point = (calib_data[1] & + TSENS4_OFFSET_8994_REDUN_MASK) >> + TSENS4_OFFSET_8994_REDUN_SHIFT; + tsens5_point = (calib_data[1] & + TSENS5_OFFSET_8994_REDUN_MASK_BIT0_2) >> + TSENS5_OFFSET_8994_REDUN_SHIFT_BIT0_2; + tsens5_point |= ((calib_data[2] & + TSENS5_OFFSET_8994_REDUN_MASK_BIT3) >> + TSENS5_OFFSET_8994_REDUN_SHIFT_BIT3); + tsens6_point = (calib_data[2] & + TSENS6_OFFSET_8994_REDUN_MASK) >> + TSENS6_OFFSET_8994_REDUN_SHIFT; + tsens7_point = (calib_data[2] & + TSENS7_OFFSET_8994_REDUN_MASK) >> + TSENS7_OFFSET_8994_REDUN_SHIFT; + tsens8_point = (calib_data[3] & + TSENS8_OFFSET_8994_REDUN_MASK); + tsens9_point = (calib_data[3] & + TSENS9_OFFSET_8994_REDUN_MASK) >> + TSENS9_OFFSET_8994_REDUN_SHIFT; + tsens10_point = (calib_data[3] & + TSENS10_OFFSET_8994_REDUN_MASK) >> + TSENS10_OFFSET_8994_REDUN_SHIFT; + tsens11_point = (calib_data[3] & + TSENS11_OFFSET_8994_REDUN_MASK) >> + TSENS11_OFFSET_8994_REDUN_SHIFT; + tsens12_point = (calib_data[3] & + TSENS12_OFFSET_8994_REDUN_MASK) >> + TSENS12_OFFSET_8994_REDUN_SHIFT; + tsens13_point = (calib_data[3] & + TSENS13_OFFSET_8994_REDUN_MASK) >> + TSENS13_OFFSET_8994_REDUN_SHIFT; + tsens14_point = (calib_data[3] & + TSENS14_OFFSET_8994_REDUN_MASK) >> + TSENS14_OFFSET_8994_REDUN_SHIFT; + tsens15_point = (calib_data[3] & + TSENS15_OFFSET_8994_REDUN_MASK) >> + TSENS15_OFFSET_8994_REDUN_SHIFT; + calib_tsens_point_data[0] = tsens0_point; + calib_tsens_point_data[1] = tsens1_point; + calib_tsens_point_data[2] = tsens2_point; + calib_tsens_point_data[3] = tsens3_point; + calib_tsens_point_data[4] = tsens4_point; + calib_tsens_point_data[5] = tsens5_point; + calib_tsens_point_data[6] = tsens7_point; + calib_tsens_point_data[7] = tsens9_point; + calib_tsens_point_data[8] = tsens10_point; + calib_tsens_point_data[9] = tsens11_point; + calib_tsens_point_data[10] = tsens12_point; + calib_tsens_point_data[11] = tsens13_point; + calib_tsens_point_data[12] = tsens14_point; + } else + goto calibration_less_mode; + } else { + calib_data[0] = readl_relaxed( + TSENS_8994_EEPROM(tmdev->tsens_calib_addr)); + calib_data[1] = readl_relaxed( + (TSENS_8994_EEPROM(tmdev->tsens_calib_addr) + 0x4)); + calib_data[2] = readl_relaxed( + (TSENS_8994_EEPROM(tmdev->tsens_calib_addr) + 0x8)); + + calib_mode = (calib_data[2] & TSENS_8994_CAL_SEL_MASK) >> + TSENS_8994_CAL_SEL_SHIFT; + pr_debug("calib mode is %d\n", calib_mode); + if (calib_mode == TSENS_TWO_POINT_CALIB) { + tsens_base0_data = (calib_data[0] & + TSENS_BASE0_8994_MASK); + tsens_base1_data = (calib_data[0] & + TSENS_BASE1_8994_MASK) >> + TSENS_BASE1_8994_SHIFT; + tsens0_point = (calib_data[0] & + TSENS0_OFFSET_8994_MASK) >> + TSENS0_OFFSET_8994_SHIFT; + tsens1_point = (calib_data[0] & + TSENS1_OFFSET_8994_MASK) >> + TSENS1_OFFSET_8994_SHIFT; + tsens2_point = (calib_data[0] & + TSENS2_OFFSET_8994_MASK) >> + TSENS2_OFFSET_8994_SHIFT; + tsens3_point = (calib_data[1] & + TSENS3_OFFSET_8994_MASK); + tsens4_point = (calib_data[1] & + TSENS4_OFFSET_8994_MASK) >> + TSENS4_OFFSET_8994_SHIFT; + tsens5_point = (calib_data[1] & + TSENS5_OFFSET_8994_MASK) >> + TSENS5_OFFSET_8994_SHIFT; + tsens7_point = (calib_data[1] & + TSENS6_OFFSET_8994_MASK) >> + TSENS6_OFFSET_8994_SHIFT; + tsens9_point = (calib_data[1] & + TSENS7_OFFSET_8994_MASK) >> + TSENS7_OFFSET_8994_SHIFT; + tsens10_point = (calib_data[1] & + TSENS8_OFFSET_8994_MASK) >> + TSENS8_OFFSET_8994_SHIFT; + tsens11_point = (calib_data[1] & + TSENS9_OFFSET_8994_MASK) >> + TSENS9_OFFSET_8994_SHIFT; + tsens12_point = (calib_data[1] & + TSENS10_OFFSET_8994_MASK) >> + TSENS10_OFFSET_8994_SHIFT; + tsens13_point = (calib_data[2] & + TSENS11_OFFSET_8994_MASK); + tsens14_point = (calib_data[2] & + TSENS12_OFFSET_8994_MASK) >> + TSENS12_OFFSET_8994_SHIFT; + calib_tsens_point_data[0] = tsens0_point; + calib_tsens_point_data[1] = tsens1_point; + calib_tsens_point_data[2] = tsens2_point; + calib_tsens_point_data[3] = tsens3_point; + calib_tsens_point_data[4] = tsens4_point; + calib_tsens_point_data[5] = tsens5_point; + calib_tsens_point_data[6] = tsens7_point; + calib_tsens_point_data[7] = tsens9_point; + calib_tsens_point_data[8] = tsens10_point; + calib_tsens_point_data[9] = tsens11_point; + calib_tsens_point_data[10] = tsens12_point; + calib_tsens_point_data[11] = tsens13_point; + calib_tsens_point_data[12] = tsens14_point; + } else { +calibration_less_mode: + pr_debug("TSENS is calibrationless mode\n"); + calib_tsens_point_data[0] = 532; + calib_tsens_point_data[1] = 532; + calib_tsens_point_data[2] = 532; + calib_tsens_point_data[3] = 532; + calib_tsens_point_data[4] = 532; + calib_tsens_point_data[5] = 532; + calib_tsens_point_data[6] = 532; + calib_tsens_point_data[7] = 532; + calib_tsens_point_data[8] = 532; + calib_tsens_point_data[9] = 532; + calib_tsens_point_data[10] = 532; + calib_tsens_point_data[11] = 532; + calib_tsens_point_data[12] = 532; + calib_tsens_point_data[13] = 532; + calib_tsens_point_data[14] = 532; + calib_tsens_point_data[15] = 532; + } + } + + for (i = 0; i < tmdev->tsens_num_sensor; i++) { + int32_t num = 0, den = 0, adc_code_of_tempx = 0; + tmdev->sensor[i].calib_data_point2 = tsens_base1_data; + tmdev->sensor[i].calib_data_point1 = tsens_base0_data; + pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n", + i, tmdev->sensor[i].calib_data_point1, + tmdev->sensor[i].calib_data_point2); + if (calib_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; + } + adc_code_of_tempx = + tsens_base0_data + calib_tsens_point_data[i]; + pr_debug("offset_adc_code_of_tempx:0x%x\n", + adc_code_of_tempx); + tmdev->sensor[i].offset = (adc_code_of_tempx * + tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 * + tmdev->sensor[i].slope_mul_tsens_factor); + pr_debug("offset:%d and slope:%d\n", tmdev->sensor[i].offset, + tmdev->sensor[i].slope_mul_tsens_factor); + tmdev->prev_reading_avail = false; + } + + return 0; +} + +static int tsens_calib_8x10_sensors(void) +{ + int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0; + int tsens0_point2 = 0, tsens1_point2 = 0; + int tsens_base1_data = 0, tsens_calibration_mode = 0; + uint32_t calib_data[2], calib_redun_sel; + uint32_t calib_tsens_point1_data[2], calib_tsens_point2_data[2]; + + if (tmdev->calibration_less_mode) + goto calibration_less_mode; + + calib_redun_sel = readl_relaxed( + TSENS_EEPROM_8X10_2(tmdev->tsens_calib_addr)); + calib_redun_sel = calib_redun_sel & TSENS_8X10_REDUN_SEL_MASK; + calib_redun_sel >>= TSENS_8X10_REDUN_SEL_SHIFT; + pr_debug("calib_redun_sel:%x\n", calib_redun_sel); + + if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) { + calib_data[0] = readl_relaxed( + TSENS_EEPROM_8X10_SPARE_1(tmdev->tsens_calib_addr)); + calib_data[1] = readl_relaxed( + TSENS_EEPROM_8X10_SPARE_2(tmdev->tsens_calib_addr)); + } else { + calib_data[0] = readl_relaxed( + TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr)); + calib_data[1] = readl_relaxed( + (TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr) + + TSENS_EEPROM_8X10_1_OFFSET)); + } + + tsens_calibration_mode = (calib_data[0] & TSENS_8X10_TSENS_CAL_SEL) + >> TSENS_8X10_CAL_SEL_SHIFT; + pr_debug("calib mode scheme:%x\n", tsens_calibration_mode); + + if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) || + (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) { + tsens_base0_data = (calib_data[0] & TSENS_8X10_BASE0_MASK); + tsens0_point1 = (calib_data[0] & TSENS0_8X10_POINT1_MASK) >> + TSENS0_8X10_POINT1_SHIFT; + tsens1_point1 = calib_data[1] & TSENS1_8X10_POINT1_MASK; + } else + goto calibration_less_mode; + + if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) { + tsens_base1_data = (calib_data[0] & TSENS_8X10_BASE1_MASK) >> + TSENS_8X10_BASE1_SHIFT; + tsens0_point2 = (calib_data[0] & TSENS0_8X10_POINT2_MASK) >> + TSENS0_8X10_POINT2_SHIFT; + tsens1_point2 = (calib_data[1] & TSENS1_8X10_POINT2_MASK) >> + TSENS1_8X10_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] = 595; + calib_tsens_point1_data[1] = 629; + goto compute_intercept_slope; + } + + if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) || + (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) { + 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); + } + + 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); + } + +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]; + pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n", + i, tmdev->sensor[i].calib_data_point1, + tmdev->sensor[i].calib_data_point2); + 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); + tmdev->prev_reading_avail = false; + } + + return 0; +} + +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) + >> TSENS_8X26_CAL_SEL_SHIFT; + pr_debug("calib mode scheme:%x\n", tsens_calibration_mode); + + if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) || + (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) { + 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) { + 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] = 595; + calib_tsens_point1_data[1] = 625; + calib_tsens_point1_data[2] = 553; + calib_tsens_point1_data[3] = 578; + 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)) { + 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]; + pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n", + i, tmdev->sensor[i].calib_data_point1, + tmdev->sensor[i].calib_data_point2); + 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); + 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; + int tsens5_point1 = 0, tsens6_point1 = 0, tsens7_point1 = 0; + int tsens8_point1 = 0, tsens9_point1 = 0, tsens10_point1 = 0; + int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0; + int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0; + int tsens6_point2 = 0, tsens7_point2 = 0, tsens8_point2 = 0; + int tsens9_point2 = 0, tsens10_point2 = 0; + int tsens_base2_data = 0, tsens_calibration_mode = 0, temp = 0; + uint32_t calib_data[6], calib_redun_sel, calib_data_backup[4]; + uint32_t calib_tsens_point1_data[11], calib_tsens_point2_data[11]; + + if (tmdev->calibration_less_mode) + goto calibration_less_mode; + + calib_redun_sel = readl_relaxed( + TSENS_EEPROM_REDUNDANCY_SEL(tmdev->tsens_calib_addr)); + calib_redun_sel = calib_redun_sel & TSENS_QFPROM_BACKUP_REDUN_SEL; + calib_redun_sel >>= TSENS_QFPROM_BACKUP_REDUN_SHIFT; + pr_debug("calib_redun_sel:%x\n", calib_redun_sel); + + for (i = 0; i < TSENS_MAIN_CALIB_ADDR_RANGE; i++) { + calib_data[i] = readl_relaxed( + (TSENS_EEPROM(tmdev->tsens_calib_addr)) + + (i * TSENS_SN_ADDR_OFFSET)); + pr_debug("calib raw data row%d:0x%x\n", i, calib_data[i]); + } + + if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) { + tsens_calibration_mode = (calib_data[4] & TSENS_CAL_SEL_0_1) + >> TSENS_CAL_SEL_SHIFT; + temp = (calib_data[5] & TSENS_CAL_SEL_2) + >> TSENS_CAL_SEL_SHIFT_2; + tsens_calibration_mode |= temp; + pr_debug("backup calib mode:%x\n", calib_redun_sel); + + for (i = 0; i < TSENS_BACKUP_CALIB_ADDR_RANGE; i++) + calib_data_backup[i] = readl_relaxed( + (TSENS_EEPROM_BACKUP_REGION( + tmdev->tsens_calib_addr)) + + (i * TSENS_SN_ADDR_OFFSET)); + + if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB) + || (tsens_calibration_mode == + TSENS_TWO_POINT_CALIB) || + (tsens_calibration_mode == + TSENS_ONE_POINT_CALIB_OPTION_2)) { + tsens_base1_data = (calib_data_backup[0] & + TSENS_BASE1_MASK); + tsens0_point1 = (calib_data_backup[0] & + TSENS0_POINT1_MASK) >> + TSENS0_POINT1_SHIFT; + tsens1_point1 = (calib_data_backup[0] & + TSENS1_POINT1_MASK) >> TSENS1_POINT1_SHIFT; + tsens2_point1 = (calib_data_backup[0] & + TSENS2_POINT1_MASK) >> TSENS2_POINT1_SHIFT; + tsens3_point1 = (calib_data_backup[0] & + TSENS3_POINT1_MASK) >> TSENS3_POINT1_SHIFT; + tsens4_point1 = (calib_data_backup[1] & + TSENS4_POINT1_MASK); + tsens5_point1 = (calib_data_backup[1] & + TSENS5_POINT1_MASK) >> TSENS5_POINT1_SHIFT; + tsens6_point1 = (calib_data_backup[1] & + TSENS6_POINT1_MASK) >> TSENS6_POINT1_SHIFT; + tsens7_point1 = (calib_data_backup[1] & + TSENS7_POINT1_MASK) >> TSENS7_POINT1_SHIFT; + tsens8_point1 = (calib_data_backup[2] & + TSENS8_POINT1_MASK_BACKUP) >> + TSENS8_POINT1_SHIFT; + tsens9_point1 = (calib_data_backup[2] & + TSENS9_POINT1_MASK_BACKUP) >> + TSENS9_POINT1_BACKUP_SHIFT; + tsens10_point1 = (calib_data_backup[2] & + TSENS10_POINT1_MASK_BACKUP) >> + TSENS10_POINT1_BACKUP_SHIFT; + } else + goto calibration_less_mode; + + if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) { + tsens_base2_data = (calib_data_backup[2] & + TSENS_BASE2_BACKUP_MASK) >> + TSENS_POINT2_BASE_BACKUP_SHIFT; + tsens0_point2 = (calib_data_backup[2] & + TSENS0_POINT2_BACKUP_MASK) >> + TSENS0_POINT2_BACKUP_SHIFT; + tsens1_point2 = (calib_data_backup[3] & + TSENS1_POINT2_BACKUP_MASK); + tsens2_point2 = (calib_data_backup[3] & + TSENS2_POINT2_BACKUP_MASK) >> + TSENS2_POINT2_BACKUP_SHIFT; + tsens3_point2 = (calib_data_backup[3] & + TSENS3_POINT2_BACKUP_MASK) >> + TSENS3_POINT2_BACKUP_SHIFT; + tsens4_point2 = (calib_data_backup[3] & + TSENS4_POINT2_BACKUP_MASK) >> + TSENS4_POINT2_BACKUP_SHIFT; + tsens5_point2 = (calib_data[4] & + TSENS5_POINT2_BACKUP_MASK) >> + TSENS5_POINT2_BACKUP_SHIFT; + tsens6_point2 = (calib_data[5] & + TSENS6_POINT2_BACKUP_MASK); + tsens7_point2 = (calib_data[5] & + TSENS7_POINT2_BACKUP_MASK) >> + TSENS7_POINT2_BACKUP_SHIFT; + tsens8_point2 = (calib_data[5] & + TSENS8_POINT2_BACKUP_MASK) >> + TSENS8_POINT2_BACKUP_SHIFT; + tsens9_point2 = (calib_data[5] & + TSENS9_POINT2_BACKUP_MASK) >> + TSENS9_POINT2_BACKUP_SHIFT; + tsens10_point2 = (calib_data[5] & + TSENS10_POINT2_BACKUP_MASK) + >> TSENS10_POINT2_BACKUP_SHIFT; + } + } else { + tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1) + >> TSENS_CAL_SEL_SHIFT; + temp = (calib_data[3] & TSENS_CAL_SEL_2) + >> TSENS_CAL_SEL_SHIFT_2; + tsens_calibration_mode |= temp; + pr_debug("calib mode scheme:%x\n", tsens_calibration_mode); + if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB) || + (tsens_calibration_mode == + TSENS_ONE_POINT_CALIB_OPTION_2) || + (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) { + tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK); + tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >> + TSENS0_POINT1_SHIFT; + tsens1_point1 = (calib_data[0] & TSENS1_POINT1_MASK) >> + TSENS1_POINT1_SHIFT; + tsens2_point1 = (calib_data[0] & TSENS2_POINT1_MASK) >> + TSENS2_POINT1_SHIFT; + tsens3_point1 = (calib_data[0] & TSENS3_POINT1_MASK) >> + TSENS3_POINT1_SHIFT; + tsens4_point1 = (calib_data[1] & TSENS4_POINT1_MASK); + tsens5_point1 = (calib_data[1] & TSENS5_POINT1_MASK) >> + TSENS5_POINT1_SHIFT; + tsens6_point1 = (calib_data[1] & TSENS6_POINT1_MASK) >> + TSENS6_POINT1_SHIFT; + tsens7_point1 = (calib_data[1] & TSENS7_POINT1_MASK) >> + TSENS7_POINT1_SHIFT; + tsens8_point1 = (calib_data[1] & TSENS8_POINT1_MASK) >> + TSENS8_POINT1_SHIFT; + tsens9_point1 = (calib_data[2] & TSENS9_POINT1_MASK); + tsens10_point1 = (calib_data[2] & TSENS10_POINT1_MASK) + >> TSENS10_POINT1_SHIFT; + } else + goto calibration_less_mode; + + if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) { + tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >> + TSENS_POINT2_BASE_SHIFT; + tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >> + TSENS0_POINT2_SHIFT; + tsens1_point2 = (calib_data[2] & TSENS1_POINT2_MASK) >> + TSENS1_POINT2_SHIFT; + tsens2_point2 = (calib_data[3] & TSENS2_POINT2_MASK); + tsens3_point2 = (calib_data[3] & TSENS3_POINT2_MASK) >> + TSENS3_POINT2_SHIFT; + tsens4_point2 = (calib_data[3] & TSENS4_POINT2_MASK) >> + TSENS4_POINT2_SHIFT; + tsens5_point2 = (calib_data[3] & TSENS5_POINT2_MASK) >> + TSENS5_POINT2_SHIFT; + tsens6_point2 = (calib_data[3] & TSENS6_POINT2_MASK) >> + TSENS6_POINT2_SHIFT; + tsens7_point2 = (calib_data[4] & TSENS7_POINT2_MASK); + tsens8_point2 = (calib_data[4] & TSENS8_POINT2_MASK) >> + TSENS8_POINT2_SHIFT; + tsens9_point2 = (calib_data[4] & TSENS9_POINT2_MASK) >> + TSENS9_POINT2_SHIFT; + tsens10_point2 = (calib_data[4] & TSENS10_POINT2_MASK) + >> TSENS10_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; + calib_tsens_point1_data[7] = 510; + calib_tsens_point1_data[8] = 508; + calib_tsens_point1_data[9] = 509; + calib_tsens_point1_data[10] = 508; + goto compute_intercept_slope; + } + } + + if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) { + calib_tsens_point1_data[0] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens0_point1; + calib_tsens_point1_data[1] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens1_point1; + calib_tsens_point1_data[2] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens2_point1; + calib_tsens_point1_data[3] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens3_point1; + calib_tsens_point1_data[4] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens4_point1; + calib_tsens_point1_data[5] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens5_point1; + calib_tsens_point1_data[6] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens6_point1; + calib_tsens_point1_data[7] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens7_point1; + calib_tsens_point1_data[8] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens8_point1; + calib_tsens_point1_data[9] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens9_point1; + calib_tsens_point1_data[10] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens10_point1; + } + + if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) || + (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) { + pr_debug("one point calibration calculation\n"); + calib_tsens_point1_data[0] = + ((((tsens_base1_data) + tsens0_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[1] = + ((((tsens_base1_data) + tsens1_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[2] = + ((((tsens_base1_data) + tsens2_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[3] = + ((((tsens_base1_data) + tsens3_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[4] = + ((((tsens_base1_data) + tsens4_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[5] = + ((((tsens_base1_data) + tsens5_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[6] = + ((((tsens_base1_data) + tsens6_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[7] = + ((((tsens_base1_data) + tsens7_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[8] = + ((((tsens_base1_data) + tsens8_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[9] = + ((((tsens_base1_data) + tsens9_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[10] = + ((((tsens_base1_data) + tsens10_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_base2_data + tsens0_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[1] = + (((tsens_base2_data + tsens1_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[2] = + (((tsens_base2_data + tsens2_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[3] = + (((tsens_base2_data + tsens3_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[4] = + (((tsens_base2_data + tsens4_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[5] = + (((tsens_base2_data + tsens5_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[6] = + (((tsens_base2_data + tsens6_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[7] = + (((tsens_base2_data + tsens7_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[8] = + (((tsens_base2_data + tsens8_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[9] = + (((tsens_base2_data + tsens9_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[10] = + (((tsens_base2_data + tsens10_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]; + pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n", + i, tmdev->sensor[i].calib_data_point1, + tmdev->sensor[i].calib_data_point2); + 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); + pr_debug("offset:%d\n", tmdev->sensor[i].offset); + tmdev->prev_reading_avail = false; + } + + return 0; +} + +static int tsens_calib_9900_sensors(void) +{ + int i, tsens_base1_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, tsens0_point2 = 0; + int tsens1_point2 = 0, tsens2_point2 = 0, tsens3_point2 = 0; + int tsens4_point2 = 0, tsens5_point2 = 0, tsens6_point2 = 0; + int tsens_base2_data = 0, tsens_calibration_mode = 0; + uint32_t calib_data[4], calib_redun_sel, calib_data_backup[4]; + uint32_t calib_tsens_point1_data[7], calib_tsens_point2_data[7]; + + if (tmdev->calibration_less_mode) + goto calibration_less_mode; + + calib_redun_sel = readl_relaxed( + TSENS_9900_EEPROM_REDUNDANCY_SEL(tmdev->tsens_calib_addr)); + calib_redun_sel = calib_redun_sel & TSENS_QFPROM_BACKUP_9900_REDUN_SEL; + calib_redun_sel >>= TSENS_QFPROM_BACKUP_9900_REDUN_SHIFT; + pr_debug("calib_redun_sel:%x\n", calib_redun_sel); + + if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) { + for (i = 0; i < TSENS_9900_CALIB_ADDR_RANGE; i++) { + calib_data_backup[i] = readl_relaxed( + (TSENS_9900_EEPROM_BACKUP_REGION( + tmdev->tsens_calib_addr)) + + (i * TSENS_SN_ADDR_OFFSET)); + pr_debug("backup calib raw data row%d:0x%x\n", + i, calib_data_backup[i]); + } + + tsens_calibration_mode = (calib_data_backup[0] & + TSENS_9900_TSENS_CAL_SEL) >> TSENS_9900_CAL_SEL_SHIFT; + pr_debug("backup calib mode:%x\n", tsens_calibration_mode); + + if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB) + || (tsens_calibration_mode == + TSENS_TWO_POINT_CALIB) || + (tsens_calibration_mode == + TSENS_ONE_POINT_CALIB_OPTION_2)) { + tsens_base1_data = (calib_data_backup[0] & + TSENS_9900_BASE1_MASK); + tsens0_point1 = (calib_data_backup[0] & + TSENS0_9900_POINT1_MASK) >> + TSENS0_9900_POINT1_SHIFT; + tsens1_point1 = (calib_data_backup[1] & + TSENS1_9900_POINT1_MASK); + tsens2_point1 = (calib_data_backup[1] & + TSENS2_9900_POINT1_MASK) >> + TSENS2_9900_POINT1_SHIFT; + tsens3_point1 = (calib_data_backup[1] & + TSENS3_9900_POINT1_MASK) >> + TSENS3_9900_POINT1_SHIFT; + tsens4_point1 = (calib_data_backup[2] & + TSENS4_9900_POINT1_MASK) >> + TSENS4_9900_POINT1_SHIFT; + tsens5_point1 = (calib_data_backup[2] & + TSENS5_9900_POINT1_MASK) >> + TSENS5_9900_POINT1_SHIFT; + tsens6_point1 = (calib_data_backup[3] & + TSENS6_9900_POINT1_MASK); + } else + goto calibration_less_mode; + + if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) { + tsens_base2_data = (calib_data_backup[0] & + TSENS_9900_BASE2_MASK) >> + TSENS_9900_BASE2_SHIFT; + tsens0_point2 = (calib_data_backup[0] & + TSENS0_9900_POINT2_MASK) >> + TSENS0_9900_POINT2_SHIFT; + tsens1_point2 = (calib_data_backup[1] & + TSENS1_9900_POINT2_MASK)>> + TSENS1_9900_POINT2_SHIFT; + tsens2_point2 = (calib_data_backup[1] & + TSENS2_9900_POINT2_MASK) >> + TSENS2_9900_POINT2_SHIFT; + tsens3_point2 = (calib_data_backup[2] & + TSENS3_9900_POINT2_MASK); + tsens4_point2 = (calib_data_backup[2] & + TSENS4_9900_POINT2_MASK) >> + TSENS4_9900_POINT2_SHIFT; + tsens5_point2 = (calib_data_backup[2] & + TSENS5_9900_POINT2_MASK) >> + TSENS5_9900_POINT2_SHIFT; + tsens6_point2 = (calib_data_backup[3] & + TSENS6_9900_POINT2_MASK) >> + TSENS6_9900_POINT2_SHIFT; + } + } else { + for (i = 0; i < TSENS_9900_CALIB_ADDR_RANGE; i++) { + calib_data[i] = readl_relaxed( + (TSENS_9900_EEPROM(tmdev->tsens_calib_addr)) + + (i * TSENS_SN_ADDR_OFFSET)); + pr_debug("calib raw data row%d:0x%x\n", i , calib_data[i]); + } + + tsens_calibration_mode = (calib_data[0] & + TSENS_9900_TSENS_CAL_SEL) >> TSENS_9900_CAL_SEL_SHIFT; + pr_debug("calib mode:%x\n", tsens_calibration_mode); + + if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB) || + (tsens_calibration_mode == + TSENS_ONE_POINT_CALIB_OPTION_2) || + (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) { + tsens_base1_data = (calib_data[0] & + TSENS_9900_BASE1_MASK); + tsens0_point1 = (calib_data[0] & + TSENS0_9900_POINT1_MASK) >> + TSENS0_9900_POINT1_SHIFT; + tsens1_point1 = (calib_data[1] & + TSENS1_9900_POINT1_MASK); + tsens2_point1 = (calib_data[1] & + TSENS2_9900_POINT1_MASK) >> + TSENS2_9900_POINT1_SHIFT; + tsens3_point1 = (calib_data[1] & + TSENS3_9900_POINT1_MASK) >> + TSENS3_9900_POINT1_SHIFT; + tsens4_point1 = (calib_data[2] & + TSENS4_9900_POINT1_MASK) >> + TSENS4_9900_POINT1_SHIFT; + tsens5_point1 = (calib_data[2] & + TSENS5_9900_POINT1_MASK) >> + TSENS5_9900_POINT1_SHIFT; + tsens6_point1 = (calib_data[3] & + TSENS6_9900_POINT1_MASK); + } else + goto calibration_less_mode; + + if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) { + tsens_base2_data = (calib_data[0] & + TSENS_9900_BASE2_MASK) >> + TSENS_9900_BASE2_SHIFT; + tsens0_point2 = (calib_data[0] & + TSENS0_9900_POINT2_MASK) >> + TSENS0_9900_POINT2_SHIFT; + tsens1_point2 = (calib_data[1] & + TSENS1_9900_POINT2_MASK) >> + TSENS1_9900_POINT2_SHIFT; + tsens2_point2 = (calib_data[1] & + TSENS2_9900_POINT2_MASK)>> + TSENS2_9900_POINT2_SHIFT; + tsens3_point2 = (calib_data[2] & + TSENS3_9900_POINT2_MASK); + tsens4_point2 = (calib_data[2] & + TSENS4_9900_POINT2_MASK) >> + TSENS4_9900_POINT2_SHIFT; + tsens5_point2 = (calib_data[2] & + TSENS5_9900_POINT2_MASK) >> + TSENS5_9900_POINT2_SHIFT; + tsens6_point2 = (calib_data[3] & + TSENS6_9900_POINT2_MASK) >> + TSENS6_9900_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) { + calib_tsens_point1_data[0] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens0_point1; + calib_tsens_point1_data[1] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens1_point1; + calib_tsens_point1_data[2] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens2_point1; + calib_tsens_point1_data[3] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens3_point1; + calib_tsens_point1_data[4] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens4_point1; + calib_tsens_point1_data[5] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens5_point1; + calib_tsens_point1_data[6] = + (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + + tsens6_point1; + } + + if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) || + (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) { + pr_debug("one point calibration calculation\n"); + calib_tsens_point1_data[0] = + ((((tsens_base1_data) + tsens0_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[1] = + ((((tsens_base1_data) + tsens1_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[2] = + ((((tsens_base1_data) + tsens2_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[3] = + ((((tsens_base1_data) + tsens3_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[4] = + ((((tsens_base1_data) + tsens4_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[5] = + ((((tsens_base1_data) + tsens5_point1) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point1_data[6] = + ((((tsens_base1_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_base2_data + tsens0_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[1] = + (((tsens_base2_data + tsens1_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[2] = + (((tsens_base2_data + tsens2_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[3] = + (((tsens_base2_data + tsens3_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[4] = + (((tsens_base2_data + tsens4_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[5] = + (((tsens_base2_data + tsens5_point2) << 2) | + TSENS_BIT_APPEND); + calib_tsens_point2_data[6] = + (((tsens_base2_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]; + pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n", + i, tmdev->sensor[i].calib_data_point1, + tmdev->sensor[i].calib_data_point2); + 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); + pr_debug("offset:%d\n", tmdev->sensor[i].offset); + tmdev->prev_reading_avail = false; + } + + return 0; +} + +static int tsens_calib_msmzirc_sensors(void) +{ + int i = 0, tsens_base0_data = 0, tsens_base1_data = 0; + int tsens0_point = 0, tsens1_point = 0, tsens2_point = 0; + int tsens3_point = 0, tsens4_point = 0; + int tsens_calibration_mode = 0; + uint32_t calib_data[2] = {0, 0}; + uint32_t calib_tsens_point_data[5]; + + if (!tmdev->calibration_less_mode) { + calib_data[0] = readl_relaxed( + TSENS_EEPROM(tmdev->tsens_calib_addr)); + calib_data[1] = readl_relaxed( + (TSENS_EEPROM(tmdev->tsens_calib_addr) + 0x4)); + + tsens_calibration_mode = + (calib_data[1] & TSENS_ZIRC_CAL_SEL) >> + TSENS_ZIRC_CAL_SEL_SHIFT; + pr_debug("calib mode is %d\n", tsens_calibration_mode); + } + + if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) { + tsens_base0_data = (calib_data[0] & TSENS_BASE0_ZIRC_MASK); + tsens_base1_data = (calib_data[0] & TSENS_BASE1_ZIRC_MASK) >> + TSENS_BASE1_ZIRC_SHIFT; + tsens0_point = (calib_data[0] & TSENS0_OFFSET_ZIRC_MASK) >> + TSENS0_OFFSET_ZIRC_SHIFT; + tsens1_point = (calib_data[0] & TSENS1_OFFSET_ZIRC_MASK) >> + TSENS1_OFFSET_ZIRC_SHIFT; + tsens2_point = (calib_data[0] & TSENS2_OFFSET_ZIRC_MASK) >> + TSENS2_OFFSET_ZIRC_SHIFT; + tsens3_point = (calib_data[1] & TSENS3_OFFSET_ZIRC_MASK); + tsens4_point = (calib_data[1] & TSENS4_OFFSET_ZIRC_MASK) >> + TSENS4_OFFSET_ZIRC_SHIFT; + calib_tsens_point_data[0] = tsens0_point; + calib_tsens_point_data[1] = tsens1_point; + calib_tsens_point_data[2] = tsens2_point; + calib_tsens_point_data[3] = tsens3_point; + calib_tsens_point_data[4] = tsens4_point; + } else { + if (tsens_calibration_mode == 0) { + pr_debug("TSENS is calibrationless mode\n"); + calib_tsens_point_data[0] = 532; + calib_tsens_point_data[1] = 532; + calib_tsens_point_data[2] = 532; + calib_tsens_point_data[3] = 532; + calib_tsens_point_data[4] = 532; + } + } + + for (i = 0; i < tmdev->tsens_num_sensor; i++) { + int32_t num = 0, den = 0, adc_code_of_tempx = 0; + tmdev->sensor[i].calib_data_point2 = tsens_base1_data; + tmdev->sensor[i].calib_data_point1 = tsens_base0_data; + pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n", + i, tmdev->sensor[i].calib_data_point1, + tmdev->sensor[i].calib_data_point2); + 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; + } + adc_code_of_tempx = + tsens_base0_data + calib_tsens_point_data[i]; + pr_debug("offset_adc_code_of_tempx:0x%x\n", + adc_code_of_tempx); + tmdev->sensor[i].offset = (adc_code_of_tempx * + tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 * + tmdev->sensor[i].slope_mul_tsens_factor); + pr_debug("offset:%d and slope:%d\n", tmdev->sensor[i].offset, + tmdev->sensor[i].slope_mul_tsens_factor); + tmdev->prev_reading_avail = false; + } + + 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 if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X10) + rc = tsens_calib_8x10_sensors(); + else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_9900) + rc = tsens_calib_9900_sensors(); + else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_9630) + rc = tsens_calib_9630_sensors(); + else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8916) + rc = tsens_calib_8916_sensors(); + else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8939) + rc = tsens_calib_8939_sensors(); + else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8994) + rc = tsens_calib_8994_sensors(); + else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_MSM8909) + rc = tsens_calib_msm8909_sensors(); + else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_MSMZIRC) + rc = tsens_calib_msmzirc_sensors(); + else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8992) + rc = tsens_calib_8992_sensors(); + else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_NONE) { + pr_debug("Fuse map info not required\n"); + rc = 0; + } else { + pr_err("TSENS Calib fuse not found\n"); + rc = -ENODEV; + } + + return rc; +} + +static struct of_device_id tsens_match[] = { + { .compatible = "qcom,msm-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_8974, + }, + { .compatible = "qcom,msm8x26-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_8X26, + }, + { .compatible = "qcom,msm8x10-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_8X10, + }, + { .compatible = "qcom,fsm9900-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_9900, + }, + { .compatible = "qcom,mdm9630-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_9630, + }, + { .compatible = "qcom,msm8916-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_8916, + }, + { .compatible = "qcom,msm8939-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_8939, + }, + { .compatible = "qcom,msm8994-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_8994, + }, + { .compatible = "qcom,msm8909-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_MSM8909, + }, + { .compatible = "qcom,msmzirc-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_MSMZIRC, + }, + { .compatible = "qcom,msm8996-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_NONE, + }, + { .compatible = "qcom,msm8992-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_8992, + }, + {} +}; + +static int get_device_tree_data(struct platform_device *pdev) +{ + struct device_node *of_node = pdev->dev.of_node; + struct resource *res_mem = NULL; + u32 *tsens_slope_data, *sensor_id; + u32 rc = 0, i, tsens_num_sensors; + const struct of_device_id *id; + + rc = of_property_read_u32(of_node, + "qcom,sensors", &tsens_num_sensors); + if (rc) { + dev_err(&pdev->dev, "missing sensor number\n"); + return -ENODEV; + } + + tsens_slope_data = devm_kzalloc(&pdev->dev, + tsens_num_sensors * sizeof(u32), GFP_KERNEL); + if (!tsens_slope_data) { + dev_err(&pdev->dev, "can not allocate slope data\n"); + return -ENOMEM; + } + + rc = of_property_read_u32_array(of_node, + "qcom,slope", tsens_slope_data, tsens_num_sensors); + if (rc) { + dev_err(&pdev->dev, "invalid or missing property: tsens-slope\n"); + return rc; + }; + + if (!of_match_node(tsens_match, of_node)) { + pr_err("Need to read SoC specific fuse map\n"); + return -ENODEV; + } else { + id = of_match_node(tsens_match, of_node); + if (id == NULL) { + pr_err("can not find tsens_match of_node\n"); + return -ENODEV; + } + } + + tmdev = devm_kzalloc(&pdev->dev, + sizeof(struct tsens_tm_device) + + tsens_num_sensors * + sizeof(struct tsens_tm_device_sensor), + GFP_KERNEL); + if (tmdev == NULL) { + pr_err("%s: kzalloc() failed.\n", __func__); + return -ENOMEM; + } + + for (i = 0; i < tsens_num_sensors; i++) + tmdev->sensor[i].slope_mul_tsens_factor = tsens_slope_data[i]; + tmdev->tsens_factor = TSENS_SLOPE_FACTOR; + tmdev->tsens_num_sensor = tsens_num_sensors; + tmdev->calibration_less_mode = of_property_read_bool(of_node, + "qcom,calibration-less-mode"); + tmdev->tsens_local_init = of_property_read_bool(of_node, + "qcom,tsens-local-init"); + tmdev->calib_mode = (u32)(uintptr_t) id->data; + + sensor_id = devm_kzalloc(&pdev->dev, + tsens_num_sensors * sizeof(u32), GFP_KERNEL); + if (!sensor_id) { + dev_err(&pdev->dev, "can not allocate sensor id\n"); + return -ENOMEM; + } + + rc = of_property_read_u32_array(of_node, + "qcom,sensor-id", sensor_id, tsens_num_sensors); + if (rc) { + pr_debug("Default sensor id mapping\n"); + for (i = 0; i < tsens_num_sensors; i++) { + tmdev->sensor[i].sensor_hw_num = i; + tmdev->sensor[i].sensor_sw_id = i; + } + } else { + pr_debug("Use specified sensor id mapping\n"); + for (i = 0; i < tsens_num_sensors; i++) { + tmdev->sensor[i].sensor_hw_num = sensor_id[i]; + tmdev->sensor[i].sensor_sw_id = i; + } + } + + if (!strcmp(id->compatible, "qcom,mdm9630-tsens") || + (!strcmp(id->compatible, "qcom,msmzirc-tsens")) || + (!strcmp(id->compatible, "qcom,msm8994-tsens")) || + (!strcmp(id->compatible, "qcom,msm8992-tsens"))) + tmdev->tsens_type = TSENS_TYPE2; + else if (!strcmp(id->compatible, "qcom,msm8996-tsens")) + tmdev->tsens_type = TSENS_TYPE3; + else + tmdev->tsens_type = TSENS_TYPE0; + + if (!strcmp(id->compatible, "qcom,msm8994-tsens") || + (!strcmp(id->compatible, "qcom,msmzirc-tsens")) || + (!strcmp(id->compatible, "qcom,msm8992-tsens")) || + (!strcmp(id->compatible, "qcom,msm8996-tsens"))) + tmdev->tsens_valid_status_check = true; + else + tmdev->tsens_valid_status_check = false; + + tmdev->tsens_irq = platform_get_irq_byname(pdev, + "tsens-upper-lower"); + if (tmdev->tsens_irq < 0) { + pr_err("Invalid Upper/Lower get irq\n"); + rc = tmdev->tsens_irq; + goto fail_tmdev; + } + + if (!strcmp(id->compatible, "qcom,msm8996-tsens")) { + tmdev->tsens_critical_irq = + platform_get_irq_byname(pdev, + "tsens-critical"); + if (tmdev->tsens_critical_irq < 0) { + pr_err("Invalid Critical get irq\n"); + rc = tmdev->tsens_critical_irq; + goto fail_tmdev; + } + } + + /* TSENS register region */ + tmdev->res_tsens_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "tsens_physical"); + if (!tmdev->res_tsens_mem) { + pr_err("Could not get tsens physical address resource\n"); + rc = -EINVAL; + goto fail_tmdev; + } + + tmdev->tsens_len = tmdev->res_tsens_mem->end - + tmdev->res_tsens_mem->start + 1; + + res_mem = request_mem_region(tmdev->res_tsens_mem->start, + tmdev->tsens_len, tmdev->res_tsens_mem->name); + if (!res_mem) { + pr_err("Request tsens physical memory region failed\n"); + rc = -EINVAL; + goto fail_tmdev; + } + + tmdev->tsens_addr = ioremap(res_mem->start, tmdev->tsens_len); + if (!tmdev->tsens_addr) { + pr_err("Failed to IO map TSENS registers.\n"); + rc = -EINVAL; + goto fail_unmap_tsens_region; + } + + /* TSENS calibration region */ + tmdev->res_calib_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "tsens_eeprom_physical"); + if (!tmdev->res_calib_mem) { + pr_err("Could not get qfprom physical address resource\n"); + rc = -EINVAL; + goto fail_unmap_tsens; + } + + tmdev->calib_len = tmdev->res_calib_mem->end - + tmdev->res_calib_mem->start + 1; + + res_mem = request_mem_region(tmdev->res_calib_mem->start, + tmdev->calib_len, tmdev->res_calib_mem->name); + if (!res_mem) { + pr_err("Request calibration memory region failed\n"); + rc = -EINVAL; + goto fail_unmap_tsens; + } + + tmdev->tsens_calib_addr = ioremap(res_mem->start, + tmdev->calib_len); + if (!tmdev->tsens_calib_addr) { + pr_err("Failed to IO map EEPROM registers.\n"); + rc = -EINVAL; + goto fail_unmap_calib_region; + } + + return 0; + +fail_unmap_calib_region: + if (tmdev->res_calib_mem) + release_mem_region(tmdev->res_calib_mem->start, + tmdev->calib_len); +fail_unmap_tsens: + if (tmdev->tsens_addr) + iounmap(tmdev->tsens_addr); +fail_unmap_tsens_region: + if (tmdev->res_tsens_mem) + release_mem_region(tmdev->res_tsens_mem->start, + tmdev->tsens_len); +fail_tmdev: + tmdev = NULL; + return rc; +} + +static int tsens_tm_probe(struct platform_device *pdev) +{ + int rc, i; + + if (tmdev) { + pr_err("TSENS device already in use\n"); + return -EBUSY; + } + + if (pdev->dev.of_node) { + rc = get_device_tree_data(pdev); + if (rc) { + pr_err("Error reading TSENS DT\n"); + return rc; + } + } else + return -ENODEV; + + tmdev->pdev = pdev; + + tmdev->tsens_critical_wq = alloc_workqueue("tsens_critical_wq", + WQ_HIGHPRI, 0); + if (!tmdev->tsens_critical_wq) { + rc = -ENOMEM; + goto fail; + } + + rc = tsens_calib_sensors(); + if (rc < 0) { + pr_err("Calibration failed\n"); + goto fail; + } + + tsens_hw_init(); + + tmdev->prev_reading_avail = true; + + for (i = 0; i < 16; i++) + tmdev->sensor_dbg_info[i].idx = 0; + + tmdev->is_ready = true; + + platform_set_drvdata(pdev, tmdev); + + return 0; +fail: + if (tmdev->tsens_critical_wq) + destroy_workqueue(tmdev->tsens_critical_wq); + if (tmdev->tsens_calib_addr) + iounmap(tmdev->tsens_calib_addr); + if (tmdev->res_calib_mem) + release_mem_region(tmdev->res_calib_mem->start, + tmdev->calib_len); + if (tmdev->tsens_addr) + iounmap(tmdev->tsens_addr); + if (tmdev->res_tsens_mem) + release_mem_region(tmdev->res_tsens_mem->start, + tmdev->tsens_len); + tmdev = NULL; + + return rc; +} + +static int _tsens_register_thermal(void) +{ + struct platform_device *pdev; + int rc, i; + + if (tsens_is_ready() <= 0) { + pr_err("%s: TSENS early init not done\n", __func__); + return -ENODEV; + } + + pdev = tmdev->pdev; + + for (i = 0; i < tmdev->tsens_num_sensor; i++) { + char name[18]; + snprintf(name, sizeof(name), "tsens_tz_sensor%d", + tmdev->sensor[i].sensor_hw_num); + tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED; + if (tmdev->tsens_type == TSENS_TYPE3) { + tmdev->sensor[i].tz_dev = + thermal_zone_device_register(name, + TSENS_TM_TRIP_NUM, + TSENS_TM_WRITABLE_TRIPS_MASK, + &tmdev->sensor[i], + &tsens_tm_thermal_zone_ops, + NULL, 0, 0); + if (IS_ERR(tmdev->sensor[i].tz_dev)) { + pr_err("%s: thermal_zone_device_register() failed.\n", + __func__); + rc = -ENODEV; + goto fail; + } + } else { + tmdev->sensor[i].tz_dev = + thermal_zone_device_register(name, + TSENS_TRIP_NUM, + TSENS_WRITABLE_TRIPS_MASK, + &tmdev->sensor[i], + &tsens_thermal_zone_ops, + NULL, 0, 0); + if (IS_ERR(tmdev->sensor[i].tz_dev)) { + pr_err("%s: thermal_zone_device_register() failed.\n", + __func__); + rc = -ENODEV; + goto fail; + } + } + } + + if (tmdev->tsens_type == TSENS_TYPE3) { + rc = request_threaded_irq(tmdev->tsens_irq, NULL, + tsens_tm_irq_thread, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "tsens_interrupt", tmdev); + if (rc < 0) { + pr_err("%s: request_irq FAIL: %d\n", __func__, rc); + for (i = 0; i < tmdev->tsens_num_sensor; i++) + thermal_zone_device_unregister( + tmdev->sensor[i].tz_dev); + goto fail; + } else { + enable_irq_wake(tmdev->tsens_irq); + } + + rc = request_threaded_irq(tmdev->tsens_critical_irq, NULL, + tsens_tm_critical_irq_thread, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "tsens_critical_interrupt", tmdev); + if (rc < 0) { + pr_err("%s: request_irq FAIL: %d\n", __func__, rc); + for (i = 0; i < tmdev->tsens_num_sensor; i++) + thermal_zone_device_unregister( + tmdev->sensor[i].tz_dev); + goto fail; + } else { + enable_irq_wake(tmdev->tsens_critical_irq); + } + } else { + rc = request_threaded_irq(tmdev->tsens_irq, NULL, + tsens_irq_thread, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "tsens_interrupt", + tmdev); + if (rc < 0) { + pr_err("%s: request_irq FAIL: %d\n", __func__, rc); + for (i = 0; i < tmdev->tsens_num_sensor; i++) + thermal_zone_device_unregister( + tmdev->sensor[i].tz_dev); + goto fail; + } else { + enable_irq_wake(tmdev->tsens_irq); + } + } + + platform_set_drvdata(pdev, tmdev); + + return 0; +fail: + if (tmdev->tsens_calib_addr) + iounmap(tmdev->tsens_calib_addr); + if (tmdev->res_calib_mem) + release_mem_region(tmdev->res_calib_mem->start, + tmdev->calib_len); + if (tmdev->tsens_addr) + iounmap(tmdev->tsens_addr); + if (tmdev->res_tsens_mem) + release_mem_region(tmdev->res_tsens_mem->start, + tmdev->tsens_len); + return rc; +} + +static int tsens_tm_remove(struct platform_device *pdev) +{ + struct tsens_tm_device *tmdev = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < tmdev->tsens_num_sensor; i++) + thermal_zone_device_unregister(tmdev->sensor[i].tz_dev); + if (tmdev->tsens_calib_addr) + iounmap(tmdev->tsens_calib_addr); + if (tmdev->res_calib_mem) + release_mem_region(tmdev->res_calib_mem->start, + tmdev->calib_len); + if (tmdev->tsens_addr) + iounmap(tmdev->tsens_addr); + if (tmdev->res_tsens_mem) + release_mem_region(tmdev->res_tsens_mem->start, + tmdev->tsens_len); + if (tmdev->tsens_critical_wq) + destroy_workqueue(tmdev->tsens_critical_wq); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver tsens_tm_driver = { + .probe = tsens_tm_probe, + .remove = tsens_tm_remove, + .driver = { + .name = "msm-tsens", + .owner = THIS_MODULE, + .of_match_table = tsens_match, + }, +}; + +int __init tsens_tm_init_driver(void) +{ + return platform_driver_register(&tsens_tm_driver); +} +arch_initcall(tsens_tm_init_driver); + +static int __init tsens_thermal_register(void) +{ + return _tsens_register_thermal(); +} +module_init(tsens_thermal_register); + +static void __exit _tsens_tm_remove(void) +{ + platform_driver_unregister(&tsens_tm_driver); +} +module_exit(_tsens_tm_remove); + +MODULE_ALIAS("platform:" TSENS_DRIVER_NAME); +MODULE_LICENSE("GPL v2"); |