diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt index dcbe9238328f..725bee029004 100644 --- a/Documentation/devicetree/bindings/thermal/tsens.txt +++ b/Documentation/devicetree/bindings/thermal/tsens.txt @@ -20,6 +20,15 @@ Required properties: should be "qcom,msm8994-tsens" for 8994 TSENS driver. should be "qcom,msm8996-tsens" for 8996 TSENS driver. should be "qcom,msm8992-tsens" for 8992 TSENS driver. + should be "qcom,msm8916-tsens" for 8916 TSENS driver. + should be "qcom,msm8939-tsens" for 8939 TSENS driver. + should be "qcom,msm8909-tsens" for 8909 TSENS driver. + should be "qcom,msm8952-tsens" for 8952 TSENS driver. + should be "qcom,msmzirc-tsens" for zirc TSENS driver. + should be "qcom,mdm9607-tsens" for 9607 TSENS driver. + should be "qcom,msmtitanium-tsens" for titanium TSENS driver. + should be "qcom,msm8937-tsens" for 8937 TSENS driver. + should be "qcom,msmgold-tsens" for gold TSENS driver. The compatible property is used to identify the respective fusemap to use for the corresponding SoC. - reg : offset and length of the TSENS registers. @@ -54,6 +63,19 @@ Optional properties: - qcom,sensor-id : If the flag is present map the TSENS sensors based on the remote sensors that are enabled in HW. Ensure the mapping is not more than the number of supported sensors. +- qcom,client-id : If the flag is present use it to identify the SW ID mapping + used to associate it with the controller and the physical sensor + mapping within the controller. The physical sensor mapping within + each controller is done using the qcom,sensor-id property. If the + property is not present the SW ID mapping with default from 0 to + total number of supported sensors with each controller instance. +- qcom,valid-status-check: If property is present, check the VALID bit is set + before reporting the temperature data. +- qcom,temp1-offset: If property is present, Use these offset values + to be added for 30 deg calib points. +- qcom,temp2-offset: If property is present, Use these offset values + to be added for 120 deg calib points. + Example: tsens@fc4a8000 { diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index cbfff2226bcd..22abb6a161a0 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -50,7 +50,7 @@ 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 +obj-$(CONFIG_THERMAL_TSENS8974) += msm-tsens.o obj-$(CONFIG_THERMAL_MONITOR) += msm_thermal.o msm_thermal-dev.o obj-$(CONFIG_LIMITS_MONITOR) += lmh_interface.o obj-$(CONFIG_LIMITS_LITE_HW) += lmh_lite.o diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm-tsens.c similarity index 64% rename from drivers/thermal/msm8974-tsens.c rename to drivers/thermal/msm-tsens.c index d5cfedca6336..9d7f697960bf 100644 --- a/drivers/thermal/msm8974-tsens.c +++ b/drivers/thermal/msm-tsens.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,9 @@ #include #include #include +#include +#include +#include #define CREATE_TRACE_POINTS #include @@ -55,6 +59,29 @@ #define TSENS2_SN_STATUS_VALID_MASK 0x4000 #define TSENS2_TRDY_ADDR(n) ((n) + 0x84) +#define TSENS4_TRDY_ADDR(n) ((n) + 0x1084) + +#define TSENS_MTC_ZONE0_SW_MASK_ADDR(n) ((n) + 0x10c0) +#define TSENS_TH1_MTC_IN_EFFECT BIT(0) +#define TSENS_TH2_MTC_IN_EFFECT BIT(1) +#define TSENS_MTC_IN_EFFECT 0x3 +#define TSENS_MTC_DISABLE 0x0 + +#define TSENS_MTC_ZONE0_LOG(n) ((n) + 0x10d0) +#define TSENS_LOGS_VALID_MASK 0x40000000 +#define TSENS_LOGS_VALID_SHIFT 30 +#define TSENS_LOGS_LATEST_MASK 0x0000001f +#define TSENS_LOGS_LOG1_MASK 0x000003e0 +#define TSENS_LOGS_LOG2_MASK 0x00007c00 +#define TSENS_LOGS_LOG3_MASK 0x000f8000 +#define TSENS_LOGS_LOG4_MASK 0x01f00000 +#define TSENS_LOGS_LOG5_MASK 0x3e000000 +#define TSENS_LOGS_LOG1_SHIFT 5 +#define TSENS_LOGS_LOG2_SHIFT 10 +#define TSENS_LOGS_LOG3_SHIFT 15 +#define TSENS_LOGS_LOG4_SHIFT 20 +#define TSENS_LOGS_LOG5_SHIFT 25 + /* TSENS_TM registers for 8996 */ #define TSENS_TM_INT_EN(n) ((n) + 0x1004) #define TSENS_TM_CRITICAL_INT_EN BIT(2) @@ -94,6 +121,19 @@ #define TSENS_TM_CODE_BIT_MASK 0xfff #define TSENS_TM_CODE_SIGN_BIT 0x800 +#define TSENS_CONTROLLER_ID(n) ((n) + 0x1000) +#define TSENS_DEBUG_CONTROL(n) ((n) + 0x1130) +#define TSENS_DEBUG_DATA(n) ((n) + 0x1134) +#define TSENS_TM_MTC_ZONE0_SW_MASK_ADDR(n) ((n) + 0x1140) +#define TSENS_TM_MTC_ZONE0_LOG(n) ((n) + 0x1150) +#define TSENS_TM_MTC_ZONE0_HISTORY(n) ((n) + 0x1160) +#define TSENS_RESET_HISTORY_MASK 0x4 +#define TSENS_RESET_HISTORY_SHIFT 2 +#define TSENS_PS_RED_CMD_MASK 0x3ff00000 +#define TSENS_PS_YELLOW_CMD_MASK 0x000ffc00 +#define TSENS_PS_COOL_CMD_MASK 0x000003ff +#define TSENS_PS_YELLOW_CMD_SHIFT 0xa +#define TSENS_PS_RED_CMD_SHIFT 0x14 /* End TSENS_TM registers for 8996 */ #define TSENS_CTRL_ADDR(n) (n) @@ -348,6 +388,7 @@ #define TSENS_TYPE0 0 #define TSENS_TYPE2 2 #define TSENS_TYPE3 3 +#define TSENS_TYPE4 4 #define TSENS_8916_BASE0_MASK 0x0000007f #define TSENS_8916_BASE1_MASK 0xfe000000 @@ -554,6 +595,137 @@ #define TSENS4_OFFSET_ZIRC_MASK 0xf0 #define TSENS4_OFFSET_ZIRC_SHIFT 4 +#define TSENS_CONTR_14_BASE0_MASK 0x000000ff +#define TSENS_CONTR_14_BASE1_MASK 0xff000000 + +#define TSENS0_CONTR_14_POINT1_MASK 0x000001f8 +#define TSENS1_CONTR_14_POINT1_MASK 0x001f8000 +#define TSENS2_CONTR_14_POINT1_MASK_0_4 0xf8000000 +#define TSENS2_CONTR_14_POINT1_MASK_5 0x00000001 +#define TSENS3_CONTR_14_POINT1_MASK 0x00001f80 +#define TSENS4_CONTR_14_POINT1_MASK 0x01f80000 +#define TSENS5_CONTR_14_POINT1_MASK 0x00003f00 +#define TSENS6_CONTR_14_POINT1_MASK 0x03f00000 +#define TSENS7_CONTR_14_POINT1_MASK 0x0000003f +#define TSENS8_CONTR_14_POINT1_MASK 0x0003f000 +#define TSENS9_CONTR_14_POINT1_MASK 0x0000003f +#define TSENS10_CONTR_14_POINT1_MASK 0x0003f000 + +#define TSENS0_CONTR_14_POINT2_MASK 0x00007e00 +#define TSENS1_CONTR_14_POINT2_MASK 0x07e00000 +#define TSENS2_CONTR_14_POINT2_MASK 0x0000007e +#define TSENS3_CONTR_14_POINT2_MASK 0x0007e000 +#define TSENS4_CONTR_14_POINT2_MASK 0x7e000000 +#define TSENS5_CONTR_14_POINT2_MASK 0x000fc000 +#define TSENS6_CONTR_14_POINT2_MASK 0xfc000000 +#define TSENS7_CONTR_14_POINT2_MASK 0x00000fc0 +#define TSENS8_CONTR_14_POINT2_MASK 0x00fc0000 +#define TSENS9_CONTR_14_POINT2_MASK 0x00000fc0 +#define TSENS10_CONTR_14_POINT2_MASK 0x00fc0000 + +#define TSENS_CONTR_14_TSENS_CAL_SEL 0x00000007 +#define TSENS_CONTR_14_BASE1_SHIFT 24 + +#define TSENS0_CONTR_14_POINT1_SHIFT 3 +#define TSENS1_CONTR_14_POINT1_SHIFT 15 +#define TSENS2_CONTR_14_POINT1_SHIFT_0_4 27 +#define TSENS2_CONTR_14_POINT1_SHIFT_5 5 +#define TSENS3_CONTR_14_POINT1_SHIFT 7 +#define TSENS4_CONTR_14_POINT1_SHIFT 19 +#define TSENS5_CONTR_14_POINT1_SHIFT 8 +#define TSENS6_CONTR_14_POINT1_SHIFT 20 +#define TSENS8_CONTR_14_POINT1_SHIFT 12 +#define TSENS10_CONTR_14_POINT1_SHIFT 12 + +#define TSENS0_CONTR_14_POINT2_SHIFT 9 +#define TSENS1_CONTR_14_POINT2_SHIFT 21 +#define TSENS2_CONTR_14_POINT2_SHIFT 1 +#define TSENS3_CONTR_14_POINT2_SHIFT 13 +#define TSENS4_CONTR_14_POINT2_SHIFT 25 +#define TSENS5_CONTR_14_POINT2_SHIFT 14 +#define TSENS6_CONTR_14_POINT2_SHIFT 26 +#define TSENS7_CONTR_14_POINT2_SHIFT 6 +#define TSENS8_CONTR_14_POINT2_SHIFT 18 +#define TSENS9_CONTR_14_POINT2_SHIFT 6 +#define TSENS10_CONTR_14_POINT2_SHIFT 18 + +#define TSENS_TWO_POINT_CALIB_N_WA 0x6 +#define TSENS_TWO_POINT_CALIB_N_OFFSET_WA 0x7 + +#define TSENS_MSM8952_D30_WA_S0 2 +#define TSENS_MSM8952_D30_WA_S1 4 +#define TSENS_MSM8952_D30_WA_S2 4 +#define TSENS_MSM8952_D30_WA_S3 1 +#define TSENS_MSM8952_D30_WA_S4 2 +#define TSENS_MSM8952_D30_WA_S5 1 +#define TSENS_MSM8952_D30_WA_S7 3 +#define TSENS_MSM8952_D30_WA_S8 2 +#define TSENS_MSM8952_D30_WA_S10 3 + +#define TSENS_MSM8952_D120_WA_S0 1 +#define TSENS_MSM8952_D120_WA_S1 4 +#define TSENS_MSM8952_D120_WA_S2 5 +#define TSENS_MSM8952_D120_WA_S3 1 +#define TSENS_MSM8952_D120_WA_S4 3 +#define TSENS_MSM8952_D120_WA_S5 1 +#define TSENS_MSM8952_D120_WA_S6 1 +#define TSENS_MSM8952_D120_WA_S7 4 +#define TSENS_MSM8952_D120_WA_S8 4 +#define TSENS_MSM8952_D120_WA_S10 2 + +#define TSENS_NO_CALIB_POINT1_DATA 500 +#define TSENS_NO_CALIB_POINT2_DATA 780 + +#define TSENS_MDM9607_TSENS_CAL_SEL 0x00700000 +#define TSENS_MDM9607_CAL_SEL_SHIFT 20 +#define TSENS_MDM9607_BASE1_SHIFT 12 + +#define TSENS_MDM9607_BASE0_MASK 0x000000ff +#define TSENS_MDM9607_BASE1_MASK 0x000ff000 + +#define TSENS0_MDM9607_POINT1_MASK 0x00003f00 +#define TSENS1_MDM9607_POINT1_MASK 0x03f00000 +#define TSENS2_MDM9607_POINT1_MASK 0x0000003f +#define TSENS3_MDM9607_POINT1_MASK 0x0003f000 +#define TSENS4_MDM9607_POINT1_MASK 0x0000003f + +#define TSENS0_MDM9607_POINT2_MASK 0x000fc000 +#define TSENS1_MDM9607_POINT2_MASK 0xfc000000 +#define TSENS2_MDM9607_POINT2_MASK 0x00000fc0 +#define TSENS3_MDM9607_POINT2_MASK 0x00fc0000 +#define TSENS4_MDM9607_POINT2_MASK 0x0000fc00 + +#define TSENS0_MDM9607_POINT1_SHIFT 8 +#define TSENS1_MDM9607_POINT1_SHIFT 20 +#define TSENS3_MDM9607_POINT1_SHIFT 12 + +#define TSENS0_MDM9607_POINT2_SHIFT 14 +#define TSENS1_MDM9607_POINT2_SHIFT 26 +#define TSENS2_MDM9607_POINT2_SHIFT 6 +#define TSENS3_MDM9607_POINT2_SHIFT 18 +#define TSENS4_MDM9607_POINT2_SHIFT 6 + +/* debug defines */ +#define TSENS_DBG_BUS_ID_0 0 +#define TSENS_DBG_BUS_ID_1 1 +#define TSENS_DBG_BUS_ID_15 15 +#define TSENS_DEBUG_LOOP_COUNT_ID_0 30 +#define TSENS_DEBUG_LOOP_COUNT 5 +#define TSENS_DEBUG_STATUS_REG_START 10 +#define TSENS_DEBUG_OFFSET_RANGE 16 +#define TSENS_DEBUG_OFFSET_WORD1 0x4 +#define TSENS_DEBUG_OFFSET_WORD2 0x8 +#define TSENS_DEBUG_OFFSET_WORD3 0xc +#define TSENS_DEBUG_OFFSET_ROW 0x10 +#define TSENS_DEBUG_DECIDEGC -400 +#define TSENS_DEBUG_MIN_CYCLE 63000 +#define TSENS_DEBUG_MAX_CYCLE 64000 +#define TSENS_DEBUG_ID_MASK_1_4 0xffffffe1 + +static uint32_t tsens_sec_to_msec_value = 3000; +static uint32_t tsens_completion_timeout_hz = 2 * HZ; +static uint32_t tsens_poll_check = 1; + enum tsens_calib_fuse_map_type { TSENS_CALIB_FUSE_MAP_8974 = 0, TSENS_CALIB_FUSE_MAP_8X26, @@ -567,6 +739,10 @@ enum tsens_calib_fuse_map_type { TSENS_CALIB_FUSE_MAP_MSMZIRC, TSENS_CALIB_FUSE_MAP_NONE, TSENS_CALIB_FUSE_MAP_8992, + TSENS_CALIB_FUSE_MAP_MSM8952, + TSENS_CALIB_FUSE_MAP_MDM9607, + TSENS_CALIB_FUSE_MAP_MSM8937, + TSENS_CALIB_FUSE_MAP_MSMGOLD, TSENS_CALIB_FUSE_MAP_NUM, }; @@ -587,18 +763,38 @@ enum tsens_tm_trip_type { #define TSENS_WRITABLE_TRIPS_MASK ((1 << TSENS_TRIP_NUM) - 1) #define TSENS_TM_WRITABLE_TRIPS_MASK ((1 << TSENS_TM_TRIP_NUM) - 1) +struct tsens_thrshld_state { + enum thermal_device_mode high_th_state; + enum thermal_device_mode low_th_state; + enum thermal_device_mode crit_th_state; + unsigned int high_adc_code; + unsigned int low_adc_code; + int high_temp; + int low_temp; + int crit_temp; +}; + struct tsens_tm_device_sensor { struct thermal_zone_device *tz_dev; + struct tsens_tm_device *tm; 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; + unsigned int sensor_client_id; int offset; int calib_data_point1; int calib_data_point2; uint32_t slope_mul_tsens_factor; + struct tsens_thrshld_state debug_thr_state_copy; + /* dbg_adc_code logs either the raw ADC code or temperature values in + * decidegC based on the controller settings. + */ + int dbg_adc_code; + u32 wa_temp1_calib_offset_factor; + u32 wa_temp2_calib_offset_factor; }; struct tsens_dbg_counter { @@ -611,11 +807,21 @@ struct tsens_sensor_dbg_info { unsigned long temp[10]; uint32_t idx; unsigned long long time_stmp[10]; + int adccode[10]; +}; + +struct tsens_mtc_sysfs { + uint32_t zone_log; + int zone_mtc; + int th1; + int th2; + uint32_t zone_hist; }; struct tsens_tm_device { struct platform_device *pdev; struct workqueue_struct *tsens_critical_wq; + struct list_head list; bool is_ready; bool prev_reading_avail; bool calibration_less_mode; @@ -635,13 +841,184 @@ struct tsens_tm_device { bool tsens_valid_status_check; struct tsens_dbg_counter tsens_thread_iq_dbg; struct tsens_sensor_dbg_info sensor_dbg_info[16]; + int tsens_upper_irq_cnt; + int tsens_lower_irq_cnt; + int tsens_critical_irq_cnt; + struct delayed_work tsens_critical_poll_test; + struct completion tsens_rslt_completion; + struct tsens_mtc_sysfs mtcsys; + spinlock_t tsens_crit_lock; + spinlock_t tsens_upp_low_lock; + bool crit_set; + unsigned long long crit_timestamp_last_run; + unsigned long long crit_timestamp_last_interrupt_handled; + unsigned long long crit_timestamp_last_poll_request; + u64 qtimer_val_detection_start; + u64 qtimer_val_last_detection_interrupt; + u64 qtimer_val_last_polling_check; struct tsens_tm_device_sensor sensor[0]; }; -struct tsens_tm_device *tmdev; +LIST_HEAD(tsens_device_list); -int tsens_is_ready() +static char dbg_buff[1024]; +static struct dentry *dent; +static struct dentry *dfile_stats; + +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, + }, + { .compatible = "qcom,msm8952-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_MSM8952, + }, + { .compatible = "qcom,mdm9607-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_MDM9607, + }, + { .compatible = "qcom,msmtitanium-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_NONE, + }, + { .compatible = "qcom,msm8937-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_MSM8937, + }, + { .compatible = "qcom,msmgold-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_MSMGOLD, + }, + {} +}; + +static struct tsens_tm_device *tsens_controller_is_present(void) { + struct tsens_tm_device *tmdev_chip = NULL; + + if (list_empty(&tsens_device_list)) { + pr_err("%s: TSENS controller not available\n", __func__); + return tmdev_chip; + } + + list_for_each_entry(tmdev_chip, &tsens_device_list, list) + return tmdev_chip; + + return tmdev_chip; +} + +static int32_t get_tsens_sensor_for_client_id(struct tsens_tm_device *tmdev, + uint32_t sensor_client_id) +{ + bool id_found = false; + uint32_t i = 0; + struct device_node *of_node = NULL; + const struct of_device_id *id; + + of_node = tmdev->pdev->dev.of_node; + if (of_node == NULL) { + pr_err("Invalid of_node??\n"); + return -EINVAL; + } + + if (!of_match_node(tsens_match, of_node)) { + pr_err("Need to read SoC specific fuse map\n"); + return -ENODEV; + } + + id = of_match_node(tsens_match, of_node); + if (id == NULL) { + pr_err("can not find tsens_match of_node\n"); + return -ENODEV; + } + + if (!strcmp(id->compatible, "qcom,msm8996-tsens")) { + while (i < tmdev->tsens_num_sensor && !id_found) { + if (tmdev->sensor[i].sensor_client_id == + sensor_client_id) { + id_found = true; + return tmdev->sensor[i].sensor_hw_num; + } + i++; + } + } else + return sensor_client_id; + + if (!id_found) + return -EINVAL; + + return -EINVAL; +} + +static struct tsens_tm_device *get_tsens_controller_for_client_id( + uint32_t sensor_client_id) +{ + struct tsens_tm_device *tmdev_chip = NULL; + bool id_found = false; + uint32_t i = 0; + + list_for_each_entry(tmdev_chip, &tsens_device_list, list) { + i = 0; + while (i < tmdev_chip->tsens_num_sensor && !id_found) { + if (tmdev_chip->sensor[i].sensor_client_id == + sensor_client_id) { + id_found = true; + return tmdev_chip; + } + i++; + } + } + + if (!id_found) + return NULL; + + return tmdev_chip; +} + +static struct tsens_tm_device *get_all_tsens_controller_sensor_count( + uint32_t *sensor_count) +{ + struct tsens_tm_device *tmdev_chip = NULL; + + list_for_each_entry(tmdev_chip, &tsens_device_list, list) + *sensor_count += tmdev_chip->tsens_num_sensor; + + return tmdev_chip; +} + +int tsens_is_ready(void) +{ + struct tsens_tm_device *tmdev = NULL; + + tmdev = tsens_controller_is_present(); if (!tmdev) return -EPROBE_DEFER; else @@ -649,16 +1026,14 @@ int tsens_is_ready() } EXPORT_SYMBOL(tsens_is_ready); -int tsens_get_sw_id_mapping(int sensor_hw_num, int *sensor_sw_idx) +static int tsens_get_sw_id_mapping_for_controller( + int sensor_hw_num, + int *sensor_sw_idx, + struct tsens_tm_device *tmdev) { 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; @@ -672,24 +1047,62 @@ int tsens_get_sw_id_mapping(int sensor_hw_num, int *sensor_sw_idx) return 0; } -EXPORT_SYMBOL(tsens_get_sw_id_mapping); -int tsens_get_hw_id_mapping(int sensor_sw_id, int *sensor_hw_num) +int tsens_get_hw_id_mapping(int sensor_sw_id, int *sensor_client_id) { int i = 0; bool id_found = false; + struct tsens_tm_device *tmdev = NULL; + struct device_node *of_node = NULL; + const struct of_device_id *id; - if (tsens_is_ready() <= 0) { + tmdev = get_tsens_controller_for_client_id(sensor_sw_id); + if (tmdev == NULL) { 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; + of_node = tmdev->pdev->dev.of_node; + if (of_node == NULL) { + pr_err("Invalid of_node??\n"); + return -EINVAL; + } + + if (!of_match_node(tsens_match, of_node)) { + pr_err("Need to read SoC specific fuse map\n"); + return -ENODEV; + } + + id = of_match_node(tsens_match, of_node); + if (id == NULL) { + pr_err("can not find tsens_match of_node\n"); + return -ENODEV; + } + + if (!strcmp(id->compatible, "qcom,msm8996-tsens")) { + /* Assign a client id which will be used to get the + * controller and hw_sensor details + */ + while (i < tmdev->tsens_num_sensor && !id_found) { + if (sensor_sw_id == tmdev->sensor[i].sensor_client_id) { + *sensor_client_id = + tmdev->sensor[i].sensor_client_id; + id_found = true; + } + i++; + } + } else { + /* Assign the corresponding hw sensor number which is done + * prior to support for multiple controllres + */ + while (i < tmdev->tsens_num_sensor && !id_found) { + if (sensor_sw_id == tmdev->sensor[i].sensor_client_id) { + *sensor_client_id = + tmdev->sensor[i].sensor_hw_num; + id_found = true; + } + i++; } - i++; } if (!id_found) @@ -699,7 +1112,179 @@ int tsens_get_hw_id_mapping(int sensor_sw_id, int *sensor_hw_num) } EXPORT_SYMBOL(tsens_get_hw_id_mapping); -static int tsens_tz_code_to_degc(int adc_code, int sensor_sw_id) +static ssize_t +zonemask_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct tsens_tm_device *tmdev = NULL; + + tmdev = tsens_controller_is_present(); + if (!tmdev) { + pr_err("No TSENS controller present\n"); + return -EPROBE_DEFER; + } + + return snprintf(buf, PAGE_SIZE, + "Zone =%d th1=%d th2=%d\n" , tmdev->mtcsys.zone_mtc, + tmdev->mtcsys.th1 , tmdev->mtcsys.th2); +} + +static ssize_t +zonemask_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + struct tsens_tm_device *tmdev = NULL; + + tmdev = tsens_controller_is_present(); + if (!tmdev) { + pr_err("No TSENS controller present\n"); + return -EPROBE_DEFER; + } + + ret = sscanf(buf, "%d %d %d", &tmdev->mtcsys.zone_mtc , + &tmdev->mtcsys.th1 , &tmdev->mtcsys.th2); + + if (ret != TSENS_ZONEMASK_PARAMS) { + pr_err("Invalid command line arguments\n"); + count = -EINVAL; + } else { + pr_debug("store zone_mtc=%d th1=%d th2=%d\n", + tmdev->mtcsys.zone_mtc, + tmdev->mtcsys.th1 , tmdev->mtcsys.th2); + ret = tsens_set_mtc_zone_sw_mask(tmdev->mtcsys.zone_mtc , + tmdev->mtcsys.th1 , tmdev->mtcsys.th2); + if (ret < 0) { + pr_err("Invalid command line arguments\n"); + count = -EINVAL; + } + } + + return count; +} + +static ssize_t +zonelog_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int ret, zlog[TSENS_MTC_ZONE_LOG_SIZE]; + struct tsens_tm_device *tmdev = NULL; + + tmdev = tsens_controller_is_present(); + if (!tmdev) { + pr_err("No TSENS controller present\n"); + return -EPROBE_DEFER; + } + + ret = tsens_get_mtc_zone_log(tmdev->mtcsys.zone_log , zlog); + if (ret < 0) { + pr_err("Invalid command line arguments\n"); + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, + "Log[0]=%d\nLog[1]=%d\nLog[2]=%d\nLog[3]=%d\nLog[4]=%d\nLog[5]=%d\n", + zlog[0], zlog[1], zlog[2], zlog[3], zlog[4], zlog[5]); +} + +static ssize_t +zonelog_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + struct tsens_tm_device *tmdev = NULL; + + tmdev = tsens_controller_is_present(); + if (!tmdev) { + pr_err("No TSENS controller present\n"); + return -EPROBE_DEFER; + } + + ret = kstrtou32(buf, 0, &tmdev->mtcsys.zone_log); + if (ret < 0) { + pr_err("Invalid command line arguments\n"); + return -EINVAL; + } + + return count; +} + +static ssize_t +zonehist_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int ret, zhist[TSENS_MTC_ZONE_HISTORY_SIZE]; + struct tsens_tm_device *tmdev = NULL; + + tmdev = tsens_controller_is_present(); + if (!tmdev) { + pr_err("No TSENS controller present\n"); + return -EPROBE_DEFER; + } + + ret = tsens_get_mtc_zone_history(tmdev->mtcsys.zone_hist , zhist); + if (ret < 0) { + pr_err("Invalid command line arguments\n"); + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, + "Cool = %d\nYellow = %d\nRed = %d\n", + zhist[0], zhist[1], zhist[2]); +} + +static ssize_t +zonehist_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + struct tsens_tm_device *tmdev = NULL; + + tmdev = tsens_controller_is_present(); + if (!tmdev) { + pr_err("No TSENS controller present\n"); + return -EPROBE_DEFER; + } + + ret = kstrtou32(buf, 0, &tmdev->mtcsys.zone_hist); + if (ret < 0) { + pr_err("Invalid command line arguments\n"); + return -EINVAL; + } + + return count; +} + + +static struct device_attribute tsens_mtc_dev_attr[] = { + __ATTR(zonemask, 0644, zonemask_show, zonemask_store), + __ATTR(zonelog, 0644, zonelog_show, zonelog_store), + __ATTR(zonehist, 0644, zonehist_show, zonehist_store), +}; + +static int create_tsens_mtc_sysfs(struct platform_device *pdev) +{ + int result = 0, i; + struct device_attribute *attr_ptr = NULL; + + attr_ptr = tsens_mtc_dev_attr; + + for (i = 0; i < ARRAY_SIZE(tsens_mtc_dev_attr); i++) { + result = device_create_file(&pdev->dev, &attr_ptr[i]); + if (result < 0) + goto error; + } + + pr_debug("create_tsens_mtc_sysfs success\n"); + + return result; + +error: + for (i--; i >= 0; i--) + device_remove_file(&pdev->dev, &attr_ptr[i]); + + return result; +} + +static int tsens_tz_code_to_degc(int adc_code, int sensor_sw_id, + struct tsens_tm_device *tmdev) { int degc, num, den, idx; @@ -721,7 +1306,8 @@ static int tsens_tz_code_to_degc(int adc_code, int sensor_sw_id) return degc; } -static int tsens_tz_degc_to_code(int degc, int idx) +static int tsens_tz_degc_to_code(int degc, int idx, + struct tsens_tm_device *tmdev) { int code = ((degc * tmdev->sensor[idx].slope_mul_tsens_factor) + tmdev->sensor[idx].offset)/tmdev->tsens_factor; @@ -735,7 +1321,7 @@ static int tsens_tz_degc_to_code(int degc, int idx) return code; } -static void msm_tsens_get_temp(int sensor_hw_num, unsigned long *temp) +static int msm_tsens_get_temp(int sensor_client_id, int *temp) { unsigned int code; void __iomem *sensor_addr; @@ -744,6 +1330,23 @@ static void msm_tsens_get_temp(int sensor_hw_num, unsigned long *temp) 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; + struct tsens_tm_device *tmdev = NULL; + uint32_t sensor_hw_num = 0; + + tmdev = get_tsens_controller_for_client_id(sensor_client_id); + if (tmdev == NULL) { + pr_err("TSENS early init not done\n"); + return -EPROBE_DEFER; + } + + pr_debug("sensor_client_id:%d\n", sensor_client_id); + + sensor_hw_num = get_tsens_sensor_for_client_id(tmdev, sensor_client_id); + if (sensor_hw_num < 0) { + pr_err("cannot read the temperature\n"); + return sensor_hw_num; + } + pr_debug("sensor_hw_num:%d\n", sensor_hw_num); if (tmdev->tsens_type == TSENS_TYPE2) { trdy_addr = TSENS2_TRDY_ADDR(tmdev->tsens_addr); @@ -751,6 +1354,9 @@ static void msm_tsens_get_temp(int sensor_hw_num, unsigned long *temp) } 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 if (tmdev->tsens_type == TSENS_TYPE4) { + trdy_addr = TSENS4_TRDY_ADDR(tmdev->tsens_addr); + sensor_addr = TSENS2_SN_STATUS_ADDR(tmdev->tsens_addr); } else { trdy_addr = TSENS_TRDY_ADDR(tmdev->tsens_addr); sensor_addr = TSENS_S0_STATUS_ADDR(tmdev->tsens_addr); @@ -810,13 +1416,14 @@ static void msm_tsens_get_temp(int sensor_hw_num, unsigned long *temp) 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); + rc = tsens_get_sw_id_mapping_for_controller(sensor_hw_num, + &sensor_sw_id, tmdev); if (rc < 0) { pr_err("tsens mapping index not found\n"); - return; + return rc; } - *temp = tsens_tz_code_to_degc(last_temp, sensor_sw_id); + *temp = tsens_tz_code_to_degc(last_temp, sensor_sw_id, tmdev); } else { if (last_temp & TSENS_TM_CODE_SIGN_BIT) { /* Sign extension for negative value */ @@ -826,38 +1433,56 @@ static void msm_tsens_get_temp(int sensor_hw_num, unsigned long *temp) *temp = last_temp; } - trace_tsens_read(*temp, sensor_hw_num); + tmdev->sensor[sensor_hw_num].dbg_adc_code = last_temp; + + trace_tsens_read(*temp, sensor_client_id); + + return 0; } static int tsens_tz_get_temp(struct thermal_zone_device *thermal, - unsigned long *temp) + int *temp) { struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; + struct tsens_tm_device *tmdev = NULL; uint32_t idx = 0; + int rc = 0; - if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp) + if (!tm_sensor || !temp) return -EINVAL; - msm_tsens_get_temp(tm_sensor->sensor_hw_num, temp); + tmdev = tm_sensor->tm; + if (!tmdev) + return -EINVAL; + + rc = msm_tsens_get_temp(tm_sensor->sensor_client_id, temp); + if (rc) + return rc; 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(); + tmdev->sensor_dbg_info[tm_sensor->sensor_hw_num].adccode[idx%10] = + tmdev->sensor[tm_sensor->sensor_hw_num].dbg_adc_code; 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) +int tsens_get_temp(struct tsens_device *device, int *temp) { + int rc = 0; + if (tsens_is_ready() <= 0) { pr_debug("TSENS early init not done\n"); return -EPROBE_DEFER; } - msm_tsens_get_temp(device->sensor_num, temp); + rc = msm_tsens_get_temp(device->sensor_num, temp); + if (rc) + return rc; return 0; } @@ -870,7 +1495,12 @@ int tsens_get_max_sensor_num(uint32_t *tsens_num_sensors) return -EPROBE_DEFER; } - *tsens_num_sensors = tmdev->tsens_num_sensor; + *tsens_num_sensors = 0; + + if (get_all_tsens_controller_sensor_count(tsens_num_sensors) == NULL) + return -EINVAL; + + pr_debug("%d\n", *tsens_num_sensors); return 0; } @@ -941,14 +1571,24 @@ static int tsens_tm_activate_trip_type(struct thermal_zone_device *thermal, { struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; unsigned int reg_cntl, mask; + unsigned long flags; + struct tsens_tm_device *tmdev = NULL; + int rc = 0; /* clear the interrupt and unmask */ if (!tm_sensor || trip < 0) return -EINVAL; + tmdev = tm_sensor->tm; + if (!tmdev) + return -EINVAL; + + spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags); mask = (tm_sensor->sensor_hw_num); switch (trip) { case TSENS_TM_TRIP_CRITICAL: + tmdev->sensor[tm_sensor->sensor_hw_num]. + debug_thr_state_copy.crit_th_state = mode; reg_cntl = readl_relaxed(TSENS_TM_CRITICAL_INT_MASK (tmdev->tsens_addr)); if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) @@ -961,6 +1601,8 @@ static int tsens_tm_activate_trip_type(struct thermal_zone_device *thermal, (tmdev->tsens_addr))); break; case TSENS_TM_TRIP_WARM: + tmdev->sensor[tm_sensor->sensor_hw_num]. + debug_thr_state_copy.high_th_state = mode; reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK (tmdev->tsens_addr)); if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) @@ -975,6 +1617,8 @@ static int tsens_tm_activate_trip_type(struct thermal_zone_device *thermal, (tmdev->tsens_addr))); break; case TSENS_TM_TRIP_COOL: + tmdev->sensor[tm_sensor->sensor_hw_num]. + debug_thr_state_copy.low_th_state = mode; reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK (tmdev->tsens_addr)); if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) @@ -985,11 +1629,14 @@ static int tsens_tm_activate_trip_type(struct thermal_zone_device *thermal, (TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_addr))); break; default: - return -EINVAL; + rc = -EINVAL; } + + spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags); /* Activate and enable the respective trip threshold setting */ mb(); - return 0; + + return rc; } static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal, @@ -997,10 +1644,15 @@ static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal, { struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; unsigned int reg_cntl, code, hi_code, lo_code, mask; + struct tsens_tm_device *tmdev = NULL; if (!tm_sensor || trip < 0) return -EINVAL; + tmdev = tm_sensor->tm; + if (!tmdev) + return -EINVAL; + lo_code = TSENS_THRESHOLD_MIN_CODE; hi_code = TSENS_THRESHOLD_MAX_CODE; @@ -1008,8 +1660,12 @@ static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal, (tmdev->tsens_addr) + (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET))); + switch (trip) { case TSENS_TRIP_WARM: + tmdev->sensor[tm_sensor->sensor_hw_num]. + debug_thr_state_copy.high_th_state = mode; + code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK) >> TSENS_UPPER_THRESHOLD_SHIFT; mask = TSENS_UPPER_STATUS_CLR; @@ -1018,6 +1674,9 @@ static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal, lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK); break; case TSENS_TRIP_COOL: + tmdev->sensor[tm_sensor->sensor_hw_num]. + debug_thr_state_copy.low_th_state = mode; + code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK); mask = TSENS_LOWER_STATUS_CLR; @@ -1031,32 +1690,36 @@ static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal, if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) writel_relaxed(reg_cntl | mask, - (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR - (tmdev->tsens_addr) + + (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_addr) + (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET))); - else { + + 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) + int trip, int *temp) { struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; int reg_cntl, code_mask; + struct tsens_tm_device *tmdev = NULL; if (!tm_sensor || trip < 0 || !temp) return -EINVAL; + tmdev = tm_sensor->tm; + if (!tmdev) + return -EINVAL; + switch (trip) { case TSENS_TM_TRIP_CRITICAL: reg_cntl = readl_relaxed((TSENS_TM_SN_CRITICAL_THRESHOLD - (tmdev->tsens_addr)) + + (tmdev->tsens_addr)) + (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET)); if (reg_cntl & TSENS_TM_CODE_SIGN_BIT) { @@ -1099,15 +1762,20 @@ static int tsens_tm_get_trip_temp(struct thermal_zone_device *thermal, } static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal, - int trip, unsigned long *temp) + int trip, int *temp) { struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; unsigned int reg; int sensor_sw_id = -EINVAL, rc = 0; + struct tsens_tm_device *tmdev = NULL; if (!tm_sensor || trip < 0 || !temp) return -EINVAL; + tmdev = tm_sensor->tm; + if (!tmdev) + return -EINVAL; + reg = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR (tmdev->tsens_addr) + (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET)); @@ -1123,12 +1791,13 @@ static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal, return -EINVAL; } - rc = tsens_get_sw_id_mapping(tm_sensor->sensor_hw_num, &sensor_sw_id); + rc = tsens_get_sw_id_mapping_for_controller(tm_sensor->sensor_hw_num, + &sensor_sw_id, tmdev); if (rc < 0) { pr_err("tsens mapping index not found\n"); return rc; } - *temp = tsens_tz_code_to_degc(reg, sensor_sw_id); + *temp = tsens_tz_code_to_degc(reg, sensor_sw_id, tmdev); return 0; } @@ -1143,22 +1812,34 @@ static int tsens_tz_notify(struct thermal_zone_device *thermal, } static int tsens_tm_set_trip_temp(struct thermal_zone_device *thermal, - int trip, unsigned long temp) + int trip, int temp) { struct tsens_tm_device_sensor *tm_sensor = thermal->devdata; unsigned int reg_cntl; + unsigned long flags; + struct tsens_tm_device *tmdev = NULL; + int rc = 0; if (!tm_sensor || trip < 0) return -EINVAL; + tmdev = tm_sensor->tm; + if (!tmdev) + return -EINVAL; + + spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags); switch (trip) { case TSENS_TM_TRIP_CRITICAL: + tmdev->sensor[tm_sensor->sensor_hw_num]. + debug_thr_state_copy.crit_temp = temp; 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: + tmdev->sensor[tm_sensor->sensor_hw_num]. + debug_thr_state_copy.high_temp = temp; reg_cntl = readl_relaxed((TSENS_TM_UPPER_LOWER_THRESHOLD (tmdev->tsens_addr)) + (tm_sensor->sensor_hw_num * @@ -1171,6 +1852,8 @@ static int tsens_tm_set_trip_temp(struct thermal_zone_device *thermal, (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET))); break; case TSENS_TM_TRIP_COOL: + tmdev->sensor[tm_sensor->sensor_hw_num]. + debug_thr_state_copy.low_temp = temp; reg_cntl = readl_relaxed((TSENS_TM_UPPER_LOWER_THRESHOLD (tmdev->tsens_addr)) + (tm_sensor->sensor_hw_num * @@ -1182,30 +1865,38 @@ static int tsens_tm_set_trip_temp(struct thermal_zone_device *thermal, (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET))); break; default: - return -EINVAL; + rc = -EINVAL; } + spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags); /* Set trip temperature thresholds */ mb(); - return 0; + return rc; } static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal, - int trip, unsigned long temp) + int trip, int 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; + struct tsens_tm_device *tmdev = NULL; if (!tm_sensor || trip < 0) return -EINVAL; - rc = tsens_get_sw_id_mapping(tm_sensor->sensor_hw_num, &sensor_sw_id); + tmdev = tm_sensor->tm; + if (!tmdev) + return -EINVAL; + + rc = tsens_get_sw_id_mapping_for_controller(tm_sensor->sensor_hw_num, + &sensor_sw_id, tmdev); 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); + + code_err_chk = code = tsens_tz_degc_to_code(temp, sensor_sw_id, tmdev); if (!tm_sensor || trip < 0) return -EINVAL; @@ -1217,12 +1908,20 @@ static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal, TSENS_SN_ADDR_OFFSET)); switch (trip) { case TSENS_TRIP_WARM: + tmdev->sensor[tm_sensor->sensor_hw_num]. + debug_thr_state_copy.high_adc_code = code; + tmdev->sensor[tm_sensor->sensor_hw_num]. + debug_thr_state_copy.high_temp = temp; 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: + tmdev->sensor[tm_sensor->sensor_hw_num]. + debug_thr_state_copy.low_adc_code = code; + tmdev->sensor[tm_sensor->sensor_hw_num]. + debug_thr_state_copy.low_temp = temp; reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK; if (!(reg_cntl & TSENS_UPPER_STATUS_CLR)) hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK) @@ -1241,6 +1940,369 @@ static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal, return 0; } +static void tsens_poll(struct work_struct *work) +{ + struct tsens_tm_device *tmdev = container_of(work, + struct tsens_tm_device, tsens_critical_poll_test.work); + unsigned int reg_cntl, mask, rc = 0, debug_dump, i = 0, loop = 0; + unsigned int debug_id = 0; + uint32_t r1, r2, r3, r4, offset = 0; + unsigned long temp, flags; + unsigned int status, int_mask, int_mask_val; + void __iomem *srot_addr; + void __iomem *controller_id_addr; + void __iomem *debug_id_addr; + void __iomem *debug_data_addr; + void __iomem *sensor_status_addr; + void __iomem *sensor_int_mask_addr; + void __iomem *sensor_critical_addr; + + /* Set the Critical temperature threshold to a value of 10 that should + * guarantee a threshold to trigger. Check the interrupt count if + * it did. Schedule the next round of the above test again after + * 3 seconds. + */ + + controller_id_addr = TSENS_CONTROLLER_ID(tmdev->tsens_addr); + debug_id_addr = TSENS_DEBUG_CONTROL(tmdev->tsens_addr); + debug_data_addr = TSENS_DEBUG_DATA(tmdev->tsens_addr); + srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_addr); + + temp = TSENS_DEBUG_DECIDEGC; + /* Sensor 0 on either of the controllers */ + mask = 0; + + reinit_completion(&tmdev->tsens_rslt_completion); + + temp &= TSENS_TM_SN_CRITICAL_THRESHOLD_MASK; + writel_relaxed(temp, + (TSENS_TM_SN_CRITICAL_THRESHOLD(tmdev->tsens_addr) + + (mask * TSENS_SN_ADDR_OFFSET))); + + tmdev->crit_timestamp_last_run = sched_clock(); + tmdev->qtimer_val_detection_start = arch_counter_get_cntvct(); + + spin_lock_irqsave(&tmdev->tsens_crit_lock, flags); + tmdev->crit_set = true; + reg_cntl = readl_relaxed(TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_addr)); + writel_relaxed(reg_cntl & ~(1 << mask), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_addr))); + spin_unlock_irqrestore(&tmdev->tsens_crit_lock, flags); + + rc = wait_for_completion_timeout( + &tmdev->tsens_rslt_completion, + tsens_completion_timeout_hz); + if (!rc) { + pr_debug("Switch to polling, TSENS critical interrupt failed\n"); + 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); + + spin_lock_irqsave(&tmdev->tsens_crit_lock, flags); + if (!tmdev->crit_set) { + pr_debug("Ignore this check cycle\n"); + spin_unlock_irqrestore(&tmdev->tsens_crit_lock, flags); + goto re_schedule; + } + status = readl_relaxed(sensor_status_addr); + int_mask = readl_relaxed(sensor_int_mask_addr); + tmdev->crit_set = false; + spin_unlock_irqrestore(&tmdev->tsens_crit_lock, flags); + + tmdev->crit_timestamp_last_poll_request = sched_clock(); + tmdev->qtimer_val_last_polling_check = + arch_counter_get_cntvct(); + if (status & TSENS_TM_SN_STATUS_CRITICAL_STATUS) { + + spin_lock_irqsave(&tmdev->tsens_crit_lock, flags); + int_mask = readl_relaxed(sensor_int_mask_addr); + int_mask_val = 1; + /* Mask the corresponding interrupt for the sensors */ + writel_relaxed(int_mask | int_mask_val, + TSENS_TM_CRITICAL_INT_MASK( + tmdev->tsens_addr)); + /* Clear the corresponding sensors interrupt */ + writel_relaxed(int_mask_val, + TSENS_TM_CRITICAL_INT_CLEAR(tmdev->tsens_addr)); + writel_relaxed(0, + TSENS_TM_CRITICAL_INT_CLEAR( + tmdev->tsens_addr)); + spin_unlock_irqrestore(&tmdev->tsens_crit_lock, flags); + + goto re_schedule; + } + + debug_dump = readl_relaxed(controller_id_addr); + pr_err("Controller_id: 0x%x\n", debug_dump); + + loop = 0; + i = 0; + debug_id = readl_relaxed(debug_id_addr); + writel_relaxed((debug_id | (i << 1) | 1), + TSENS_DEBUG_CONTROL(tmdev->tsens_addr)); + while (loop < TSENS_DEBUG_LOOP_COUNT_ID_0) { + debug_dump = readl_relaxed(debug_data_addr); + r1 = readl_relaxed(debug_data_addr); + r2 = readl_relaxed(debug_data_addr); + r3 = readl_relaxed(debug_data_addr); + r4 = readl_relaxed(debug_data_addr); + pr_err("bus-id:%d value:0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", + i, debug_dump, r1, r2, r3, r4); + loop++; + } + + for (i = TSENS_DBG_BUS_ID_1; i <= TSENS_DBG_BUS_ID_15; i++) { + loop = 0; + debug_id = readl_relaxed(debug_id_addr); + debug_id = debug_id & TSENS_DEBUG_ID_MASK_1_4; + writel_relaxed((debug_id | (i << 1) | 1), + TSENS_DEBUG_CONTROL(tmdev->tsens_addr)); + while (loop < TSENS_DEBUG_LOOP_COUNT) { + debug_dump = readl_relaxed(debug_data_addr); + pr_err("bus-id:%d with value: 0x%x\n", + i, debug_dump); + loop++; + } + } + + pr_err("Start of TSENS TM dump\n"); + for (i = 0; i < TSENS_DEBUG_OFFSET_RANGE; i++) { + r1 = readl_relaxed(controller_id_addr + offset); + r2 = readl_relaxed(controller_id_addr + (offset + + TSENS_DEBUG_OFFSET_WORD1)); + r3 = readl_relaxed(controller_id_addr + (offset + + TSENS_DEBUG_OFFSET_WORD2)); + r4 = readl_relaxed(controller_id_addr + (offset + + TSENS_DEBUG_OFFSET_WORD3)); + + pr_err("0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + offset, r1, r2, r3, r4); + offset += TSENS_DEBUG_OFFSET_ROW; + } + + offset = 0; + pr_err("Start of TSENS SROT dump\n"); + for (i = 0; i < TSENS_DEBUG_OFFSET_RANGE; i++) { + r1 = readl_relaxed(srot_addr + offset); + r2 = readl_relaxed(srot_addr + (offset + + TSENS_DEBUG_OFFSET_WORD1)); + r3 = readl_relaxed(srot_addr + (offset + + TSENS_DEBUG_OFFSET_WORD2)); + r4 = readl_relaxed(srot_addr + (offset + + TSENS_DEBUG_OFFSET_WORD3)); + + pr_err("0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + offset, r1, r2, r3, r4); + offset += TSENS_DEBUG_OFFSET_ROW; + } + + loop = 0; + while (loop < TSENS_DEBUG_LOOP_COUNT) { + offset = TSENS_DEBUG_OFFSET_ROW * + TSENS_DEBUG_STATUS_REG_START; + pr_err("Start of TSENS TM dump %d\n", loop); + /* Limited dump of the registers for the temperature */ + for (i = 0; i < TSENS_DEBUG_LOOP_COUNT; i++) { + r1 = readl_relaxed(controller_id_addr + offset); + r2 = readl_relaxed(controller_id_addr + + (offset + TSENS_DEBUG_OFFSET_WORD1)); + r3 = readl_relaxed(controller_id_addr + + (offset + TSENS_DEBUG_OFFSET_WORD2)); + r4 = readl_relaxed(controller_id_addr + + (offset + TSENS_DEBUG_OFFSET_WORD3)); + + pr_err("0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + offset, r1, r2, r3, r4); + offset += TSENS_DEBUG_OFFSET_ROW; + } + loop++; + usleep_range(TSENS_DEBUG_MIN_CYCLE, + TSENS_DEBUG_MAX_CYCLE); + } + + BUG(); + } + +re_schedule: + + schedule_delayed_work(&tmdev->tsens_critical_poll_test, + msecs_to_jiffies(tsens_sec_to_msec_value)); +} + +int tsens_mtc_reset_history_counter(unsigned int zone) +{ + unsigned int reg_cntl, is_valid; + void __iomem *sensor_addr; + struct tsens_tm_device *tmdev = NULL; + + if (zone > TSENS_NUM_MTC_ZONES_SUPPORT) + return -EINVAL; + + tmdev = tsens_controller_is_present(); + if (!tmdev) { + pr_err("No TSENS controller present\n"); + return -EPROBE_DEFER; + } + + sensor_addr = TSENS_TM_MTC_ZONE0_SW_MASK_ADDR(tmdev->tsens_addr); + reg_cntl = readl_relaxed((sensor_addr + + (zone * TSENS_SN_ADDR_OFFSET))); + is_valid = (reg_cntl & TSENS_RESET_HISTORY_MASK) + >> TSENS_RESET_HISTORY_SHIFT; + if (!is_valid) { + /*Enable the bit to reset counter*/ + writel_relaxed(reg_cntl | (1 << TSENS_RESET_HISTORY_SHIFT), + (sensor_addr + (zone * TSENS_SN_ADDR_OFFSET))); + reg_cntl = readl_relaxed((sensor_addr + + (zone * TSENS_SN_ADDR_OFFSET))); + pr_debug("tsens : zone =%d reg=%x\n", zone , reg_cntl); + } + + /*Disble the bit to start counter*/ + writel_relaxed(reg_cntl & ~(1 << TSENS_RESET_HISTORY_SHIFT), + (sensor_addr + (zone * TSENS_SN_ADDR_OFFSET))); + reg_cntl = readl_relaxed((sensor_addr + + (zone * TSENS_SN_ADDR_OFFSET))); + pr_debug("tsens : zone =%d reg=%x\n", zone , reg_cntl); + + return 0; +} +EXPORT_SYMBOL(tsens_mtc_reset_history_counter); + +int tsens_set_mtc_zone_sw_mask(unsigned int zone , unsigned int th1_enable, + unsigned int th2_enable) +{ + unsigned int reg_cntl; + void __iomem *sensor_addr; + struct tsens_tm_device *tmdev = NULL; + + if (zone > TSENS_NUM_MTC_ZONES_SUPPORT) + return -EINVAL; + + tmdev = tsens_controller_is_present(); + if (!tmdev) { + pr_err("No TSENS controller present\n"); + return -EPROBE_DEFER; + } + + if (tmdev->tsens_type == TSENS_TYPE3) + sensor_addr = TSENS_TM_MTC_ZONE0_SW_MASK_ADDR + (tmdev->tsens_addr); + else + sensor_addr = TSENS_MTC_ZONE0_SW_MASK_ADDR + (tmdev->tsens_addr); + + if (th1_enable && th2_enable) + writel_relaxed(TSENS_MTC_IN_EFFECT, + (sensor_addr + + (zone * TSENS_SN_ADDR_OFFSET))); + if (!th1_enable && !th2_enable) + writel_relaxed(TSENS_MTC_DISABLE, + (sensor_addr + + (zone * TSENS_SN_ADDR_OFFSET))); + if (th1_enable && !th2_enable) + writel_relaxed(TSENS_TH1_MTC_IN_EFFECT, + (sensor_addr + + (zone * TSENS_SN_ADDR_OFFSET))); + if (!th1_enable && th2_enable) + writel_relaxed(TSENS_TH2_MTC_IN_EFFECT, + (sensor_addr + + (zone * TSENS_SN_ADDR_OFFSET))); + reg_cntl = readl_relaxed((sensor_addr + + (zone * TSENS_SN_ADDR_OFFSET))); + pr_debug("tsens : zone =%d th1=%d th2=%d reg=%x\n", + zone , th1_enable , th2_enable , reg_cntl); + + return 0; +} +EXPORT_SYMBOL(tsens_set_mtc_zone_sw_mask); + +int tsens_get_mtc_zone_log(unsigned int zone , void *zone_log) +{ + unsigned int i , reg_cntl , is_valid , log[TSENS_MTC_ZONE_LOG_SIZE]; + int *zlog = (int *)zone_log; + void __iomem *sensor_addr; + struct tsens_tm_device *tmdev = NULL; + + if (zone > TSENS_NUM_MTC_ZONES_SUPPORT) + return -EINVAL; + + tmdev = tsens_controller_is_present(); + if (!tmdev) { + pr_err("No TSENS controller present\n"); + return -EPROBE_DEFER; + } + + if (tmdev->tsens_type == TSENS_TYPE3) + sensor_addr = TSENS_TM_MTC_ZONE0_LOG(tmdev->tsens_addr); + else + sensor_addr = TSENS_MTC_ZONE0_LOG(tmdev->tsens_addr); + + reg_cntl = readl_relaxed((sensor_addr + + (zone * TSENS_SN_ADDR_OFFSET))); + is_valid = (reg_cntl & TSENS_LOGS_VALID_MASK) + >> TSENS_LOGS_VALID_SHIFT; + if (is_valid) { + log[0] = (reg_cntl & TSENS_LOGS_LATEST_MASK); + log[1] = (reg_cntl & TSENS_LOGS_LOG1_MASK) + >> TSENS_LOGS_LOG1_SHIFT; + log[2] = (reg_cntl & TSENS_LOGS_LOG2_MASK) + >> TSENS_LOGS_LOG2_SHIFT; + log[3] = (reg_cntl & TSENS_LOGS_LOG3_MASK) + >> TSENS_LOGS_LOG3_SHIFT; + log[4] = (reg_cntl & TSENS_LOGS_LOG4_MASK) + >> TSENS_LOGS_LOG4_SHIFT; + log[5] = (reg_cntl & TSENS_LOGS_LOG5_MASK) + >> TSENS_LOGS_LOG5_SHIFT; + for (i = 0; i < (TSENS_MTC_ZONE_LOG_SIZE); i++) { + *(zlog+i) = log[i]; + pr_debug("Log[%d]=%d\n", i , log[i]); + } + } else { + pr_debug("tsens: Valid bit disabled\n"); + return -EINVAL; + } + return 0; +} +EXPORT_SYMBOL(tsens_get_mtc_zone_log); + +int tsens_get_mtc_zone_history(unsigned int zone , void *zone_hist) +{ + unsigned int i, reg_cntl, hist[TSENS_MTC_ZONE_HISTORY_SIZE]; + int *zhist = (int *)zone_hist; + void __iomem *sensor_addr; + struct tsens_tm_device *tmdev = NULL; + + if (zone > TSENS_NUM_MTC_ZONES_SUPPORT) + return -EINVAL; + + tmdev = tsens_controller_is_present(); + if (!tmdev) { + pr_err("No TSENS controller present\n"); + return -EPROBE_DEFER; + } + + sensor_addr = TSENS_TM_MTC_ZONE0_HISTORY(tmdev->tsens_addr); + reg_cntl = readl_relaxed((sensor_addr + + (zone * TSENS_SN_ADDR_OFFSET))); + + hist[0] = (reg_cntl & TSENS_PS_COOL_CMD_MASK); + hist[1] = (reg_cntl & TSENS_PS_YELLOW_CMD_MASK) + >> TSENS_PS_YELLOW_CMD_SHIFT; + hist[2] = (reg_cntl & TSENS_PS_RED_CMD_MASK) + >> TSENS_PS_RED_CMD_SHIFT; + for (i = 0; i < (TSENS_MTC_ZONE_HISTORY_SIZE); i++) { + *(zhist+i) = hist[i]; + pr_debug("tsens : %d\n", hist[i]); + } + + return 0; +} +EXPORT_SYMBOL(tsens_get_mtc_zone_history); + static struct thermal_zone_device_ops tsens_thermal_zone_ops = { .get_temp = tsens_tz_get_temp, .get_mode = tsens_tz_get_mode, @@ -1264,51 +2326,72 @@ static struct thermal_zone_device_ops tsens_tm_thermal_zone_ops = { static irqreturn_t tsens_tm_critical_irq_thread(int irq, void *data) { struct tsens_tm_device *tm = data; - unsigned int i, status, threshold; + unsigned int i, status; + unsigned long flags; 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); + tm->crit_set = false; + sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_addr); sensor_int_mask_addr = - TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_addr); + TSENS_TM_CRITICAL_INT_MASK(tm->tsens_addr); sensor_critical_addr = - TSENS_TM_SN_CRITICAL_THRESHOLD(tmdev->tsens_addr); + TSENS_TM_SN_CRITICAL_THRESHOLD(tm->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; + spin_lock_irqsave(&tm->tsens_crit_lock, flags); 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); + + if ((status & TSENS_TM_SN_STATUS_CRITICAL_STATUS) && + !(int_mask & (1 << tm->sensor[i].sensor_hw_num))) { int_mask = readl_relaxed(sensor_int_mask_addr); int_mask_val = (1 << tm->sensor[i].sensor_hw_num); + /* Mask the corresponding interrupt for the sensors */ writel_relaxed(int_mask | int_mask_val, TSENS_TM_CRITICAL_INT_MASK( - tmdev->tsens_addr)); + tm->tsens_addr)); + /* Clear the corresponding sensors interrupt */ + writel_relaxed(int_mask_val, + TSENS_TM_CRITICAL_INT_CLEAR(tm->tsens_addr)); + writel_relaxed(0, + TSENS_TM_CRITICAL_INT_CLEAR( + tm->tsens_addr)); critical_thr = true; + tm->sensor[i].debug_thr_state_copy. + crit_th_state = THERMAL_DEVICE_DISABLED; } - if (critical_thr) { - unsigned long temp; - tsens_tz_get_temp(tm->sensor[i].tz_dev, &temp); + spin_unlock_irqrestore(&tm->tsens_crit_lock, flags); - rc = tsens_get_sw_id_mapping( + if (critical_thr) { + int temp; + + tsens_tz_get_temp(tm->sensor[i].tz_dev, &temp); + rc = tsens_get_sw_id_mapping_for_controller( tm->sensor[i].sensor_hw_num, - &sensor_sw_id); + &sensor_sw_id, tm); if (rc < 0) pr_err("tsens mapping index not found\n"); - pr_debug("sensor:%d trigger temp (%d degC)\n", + pr_debug("sensor:%d trigger temp (%d degC) with count:%d\n", tm->sensor[i].sensor_hw_num, - (status & TSENS_TM_SN_LAST_TEMP_MASK)); - threshold = readl_relaxed(sensor_critical_addr + - addr_offset); + (status & TSENS_TM_SN_LAST_TEMP_MASK), + tm->tsens_critical_irq_cnt); + tm->tsens_critical_irq_cnt++; } } + tm->crit_timestamp_last_interrupt_handled = sched_clock(); + tm->qtimer_val_last_detection_interrupt = arch_counter_get_cntvct(); + + complete(&tm->tsens_rslt_completion); /* Mask critical interrupt */ mb(); @@ -1319,73 +2402,110 @@ static irqreturn_t tsens_tm_irq_thread(int irq, void *data) { struct tsens_tm_device *tm = data; unsigned int i, status, threshold; + unsigned long flags; void __iomem *sensor_status_addr; void __iomem *sensor_int_mask_addr; void __iomem *sensor_upper_lower_addr; int sensor_sw_id = -EINVAL, rc = 0; + uint32_t addr_offset; - sensor_status_addr = TSENS_TM_SN_STATUS(tmdev->tsens_addr); + sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_addr); sensor_int_mask_addr = - TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_addr); + TSENS_TM_UPPER_LOWER_INT_MASK(tm->tsens_addr); sensor_upper_lower_addr = - TSENS_TM_UPPER_LOWER_THRESHOLD(tmdev->tsens_addr); + TSENS_TM_UPPER_LOWER_THRESHOLD(tm->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; + int int_mask, int_mask_val = 0; + spin_lock_irqsave(&tm->tsens_upp_low_lock, flags); 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) { + threshold = readl_relaxed(sensor_upper_lower_addr + + addr_offset); + int_mask = readl_relaxed(sensor_int_mask_addr); + + if ((status & TSENS_TM_SN_STATUS_UPPER_STATUS) && + !(int_mask & + (1 << (tm->sensor[i].sensor_hw_num + 16)))) { int_mask = readl_relaxed(sensor_int_mask_addr); int_mask_val = TSENS_TM_UPPER_INT_SET( tm->sensor[i].sensor_hw_num); + /* Mask the corresponding interrupt for the sensors */ writel_relaxed(int_mask | int_mask_val, TSENS_TM_UPPER_LOWER_INT_MASK( - tmdev->tsens_addr)); + tm->tsens_addr)); + /* Clear the corresponding sensors interrupt */ + writel_relaxed(int_mask_val, + TSENS_TM_UPPER_LOWER_INT_CLEAR( + tm->tsens_addr)); + writel_relaxed(0, + TSENS_TM_UPPER_LOWER_INT_CLEAR( + tm->tsens_addr)); upper_thr = true; + tm->sensor[i].debug_thr_state_copy. + high_th_state = THERMAL_DEVICE_DISABLED; } - if (status & TSENS_TM_SN_STATUS_LOWER_STATUS) { + + if ((status & TSENS_TM_SN_STATUS_LOWER_STATUS) && + !(int_mask & + (1 << tm->sensor[i].sensor_hw_num))) { int_mask = readl_relaxed(sensor_int_mask_addr); int_mask_val = (1 << tm->sensor[i].sensor_hw_num); + /* Mask the corresponding interrupt for the sensors */ writel_relaxed(int_mask | int_mask_val, TSENS_TM_UPPER_LOWER_INT_MASK( - tmdev->tsens_addr)); + tm->tsens_addr)); + /* Clear the corresponding sensors interrupt */ + writel_relaxed(int_mask_val, + TSENS_TM_UPPER_LOWER_INT_CLEAR( + tm->tsens_addr)); + writel_relaxed(0, + TSENS_TM_UPPER_LOWER_INT_CLEAR( + tm->tsens_addr)); lower_thr = true; + tm->sensor[i].debug_thr_state_copy. + low_th_state = THERMAL_DEVICE_DISABLED; } + spin_unlock_irqrestore(&tm->tsens_upp_low_lock, flags); + if (upper_thr || lower_thr) { - unsigned long temp; + int 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); + thermal_sensor_trip(tm->sensor[i].tz_dev, trip, temp); - rc = tsens_get_sw_id_mapping( + rc = tsens_get_sw_id_mapping_for_controller( tm->sensor[i].sensor_hw_num, - &sensor_sw_id); + &sensor_sw_id, tm); if (rc < 0) - pr_err("tsens mapping index not found\n"); + pr_debug("tsens mapping index not found\n"); + /* Use sensor_client_id for multiple controllers */ pr_debug("sensor:%d trigger temp (%d degC)\n", - tm->sensor[i].sensor_hw_num, + tm->sensor[i].sensor_client_id, (status & TSENS_TM_SN_LAST_TEMP_MASK)); - threshold = readl_relaxed(sensor_upper_lower_addr + - addr_offset); - if (upper_thr) + if (upper_thr) { trace_tsens_threshold_hit( TSENS_TM_UPPER_THRESHOLD_VALUE( threshold), - tm->sensor[i].sensor_hw_num); - else + tm->sensor[i].sensor_client_id); + tm->tsens_upper_irq_cnt++; + } else { trace_tsens_threshold_clear( TSENS_TM_LOWER_THRESHOLD_VALUE( threshold), - tm->sensor[i].sensor_hw_num); + tm->sensor[i].sensor_client_id); + tm->tsens_lower_irq_cnt++; + } } } + /* Disable monitoring sensor trip threshold for triggered sensor */ mb(); @@ -1398,20 +2518,22 @@ static irqreturn_t tsens_irq_thread(int irq, void *data) unsigned int i, status, threshold; void __iomem *sensor_status_addr; void __iomem *sensor_status_ctrl_addr; - int sensor_sw_id = -EINVAL, rc = 0; + int sensor_sw_id = -EINVAL; uint32_t idx = 0; - if (tmdev->tsens_type == TSENS_TYPE2) - sensor_status_addr = TSENS2_SN_STATUS_ADDR(tmdev->tsens_addr); + if ((tm->tsens_type == TSENS_TYPE2) || + (tm->tsens_type == TSENS_TYPE4)) + sensor_status_addr = TSENS2_SN_STATUS_ADDR(tm->tsens_addr); else - sensor_status_addr = TSENS_S0_STATUS_ADDR(tmdev->tsens_addr); + sensor_status_addr = TSENS_S0_STATUS_ADDR(tm->tsens_addr); sensor_status_ctrl_addr = - TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_addr); + TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tm->tsens_addr); for (i = 0; i < tm->tsens_num_sensor; i++) { bool upper_thr = false, lower_thr = false; uint32_t addr_offset; + sensor_sw_id = tm->sensor[i].sensor_sw_id; addr_offset = tm->sensor[i].sensor_hw_num * TSENS_SN_ADDR_OFFSET; status = readl_relaxed(sensor_status_addr + addr_offset); @@ -1420,72 +2542,743 @@ static irqreturn_t tsens_irq_thread(int irq, void *data) 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)); + tm->tsens_addr + addr_offset)); upper_thr = true; + tm->sensor[i].debug_thr_state_copy. + high_th_state = THERMAL_DEVICE_DISABLED; } 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)); + tm->tsens_addr + addr_offset)); lower_thr = true; + tm->sensor[i].debug_thr_state_copy. + low_th_state = THERMAL_DEVICE_DISABLED; } if (upper_thr || lower_thr) { - unsigned long temp; + int 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); + thermal_sensor_trip(tm->sensor[i].tz_dev, trip, 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)); + tm->sensor[i].sensor_sw_id, tm)); if (upper_thr) trace_tsens_threshold_hit( tsens_tz_code_to_degc((threshold & TSENS_UPPER_THRESHOLD_MASK) >> TSENS_UPPER_THRESHOLD_SHIFT, - sensor_sw_id), + sensor_sw_id, tm), tm->sensor[i].sensor_hw_num); else trace_tsens_threshold_clear( tsens_tz_code_to_degc((threshold & TSENS_LOWER_THRESHOLD_MASK), - sensor_sw_id), + sensor_sw_id, tm), 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++; + idx = tm->tsens_thread_iq_dbg.idx; + tm->tsens_thread_iq_dbg.dbg_count[idx%10]++; + tm->tsens_thread_iq_dbg.time_stmp[idx%10] = sched_clock(); + tm->tsens_thread_iq_dbg.idx++; + /* Disable monitoring sensor trip threshold for triggered sensor */ mb(); return IRQ_HANDLED; } -static void tsens_hw_init(void) +static int tsens_hw_init(struct tsens_tm_device *tmdev) { - if (tmdev->tsens_type == TSENS_TYPE3) + void __iomem *srot_addr; + unsigned int srot_val; + + if (!tmdev) { + pr_err("Invalid tsens device\n"); + return -EINVAL; + } + + if (tmdev->tsens_type == TSENS_TYPE3) { + srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_addr + 0x4); + srot_val = readl_relaxed(srot_addr); + if (!(srot_val & TSENS_EN)) { + pr_err("TSENS device is not enabled\n"); + return -ENODEV; + } 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 + } else writel_relaxed(TSENS_INTERRUPT_EN, TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr)); + + return 0; } -static int tsens_calib_msm8909_sensors(void) +static int tsens_calib_msm8937_msmgold_sensors(struct tsens_tm_device *tmdev) +{ + int i, tsens_base0_data = 0, tsens_base1_data = 0, ext_sen = 1; + 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 tsens9_point1 = 0, tsens9_point2 = 0; + int tsens10_point1 = 0, tsens10_point2 = 0; + + int tsens_calibration_mode = 0, temp = 0; + uint32_t calib_data[5] = {0, 0, 0, 0, 0}; + uint32_t calib_tsens_point1_data[11], calib_tsens_point2_data[11]; + + if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_MSMGOLD) + ext_sen = 0; + + if (!tmdev->calibration_less_mode) { + + calib_data[0] = readl_relaxed(tmdev->tsens_calib_addr + 0x1D8); + calib_data[1] = readl_relaxed(tmdev->tsens_calib_addr + 0x1DC); + calib_data[2] = readl_relaxed(tmdev->tsens_calib_addr + 0x210); + calib_data[3] = readl_relaxed(tmdev->tsens_calib_addr + 0x214); + calib_data[4] = readl_relaxed(tmdev->tsens_calib_addr + 0x230); + + tsens_calibration_mode = + (calib_data[2] & + TSENS_CONTR_14_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[0] & + TSENS_CONTR_14_BASE0_MASK); + tsens0_point1 = (calib_data[2] & + TSENS0_CONTR_14_POINT1_MASK) + >> TSENS0_CONTR_14_POINT1_SHIFT; + tsens1_point1 = (calib_data[2] & + TSENS1_CONTR_14_POINT1_MASK) + >> TSENS1_CONTR_14_POINT1_SHIFT; + tsens2_point1 = (calib_data[2] & + TSENS2_CONTR_14_POINT1_MASK_0_4) + >> TSENS2_CONTR_14_POINT1_SHIFT_0_4; + temp = (calib_data[3] & TSENS2_CONTR_14_POINT1_MASK_5) + << TSENS2_CONTR_14_POINT1_SHIFT_5; + tsens2_point1 |= temp; + tsens3_point1 = (calib_data[3] & + TSENS3_CONTR_14_POINT1_MASK) + >> TSENS3_CONTR_14_POINT1_SHIFT; + tsens4_point1 = (calib_data[3] & + TSENS4_CONTR_14_POINT1_MASK) + >> TSENS4_CONTR_14_POINT1_SHIFT; + tsens5_point1 = (calib_data[0] & + TSENS5_CONTR_14_POINT1_MASK) + >> TSENS5_CONTR_14_POINT1_SHIFT; + tsens6_point1 = (calib_data[0] & + TSENS6_CONTR_14_POINT1_MASK) + >> TSENS6_CONTR_14_POINT1_SHIFT; + tsens7_point1 = (calib_data[1] & + TSENS7_CONTR_14_POINT1_MASK); + tsens8_point1 = (calib_data[1] & + TSENS8_CONTR_14_POINT1_MASK) + >> TSENS8_CONTR_14_POINT1_SHIFT; + tsens9_point1 = (calib_data[4] & + TSENS9_CONTR_14_POINT1_MASK); + if (ext_sen) + tsens10_point1 = (calib_data[4] & + TSENS10_CONTR_14_POINT1_MASK) + >> TSENS10_CONTR_14_POINT1_SHIFT; + } + + if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) { + tsens_base1_data = (calib_data[1] & + TSENS_CONTR_14_BASE1_MASK) + >> TSENS_CONTR_14_BASE1_SHIFT; + tsens0_point2 = (calib_data[2] & + TSENS0_CONTR_14_POINT2_MASK) + >> TSENS0_CONTR_14_POINT2_SHIFT; + tsens1_point2 = (calib_data[2] & + TSENS1_CONTR_14_POINT2_MASK) + >> TSENS1_CONTR_14_POINT2_SHIFT; + tsens2_point2 = (calib_data[3] & + TSENS2_CONTR_14_POINT2_MASK) + >> TSENS2_CONTR_14_POINT2_SHIFT; + tsens3_point2 = (calib_data[3] & + TSENS3_CONTR_14_POINT2_MASK) + >> TSENS3_CONTR_14_POINT2_SHIFT; + tsens4_point2 = (calib_data[3] & + TSENS4_CONTR_14_POINT2_MASK) + >> TSENS4_CONTR_14_POINT2_SHIFT; + tsens5_point2 = (calib_data[0] & + TSENS5_CONTR_14_POINT2_MASK) + >> TSENS5_CONTR_14_POINT2_SHIFT; + tsens6_point2 = (calib_data[0] & + TSENS6_CONTR_14_POINT2_MASK) + >> TSENS6_CONTR_14_POINT2_SHIFT; + tsens7_point2 = (calib_data[1] & + TSENS7_CONTR_14_POINT2_MASK) + >> TSENS7_CONTR_14_POINT2_SHIFT; + tsens8_point2 = (calib_data[1] & + TSENS8_CONTR_14_POINT2_MASK) + >> TSENS8_CONTR_14_POINT2_SHIFT; + tsens9_point2 = (calib_data[4] & + TSENS9_CONTR_14_POINT2_MASK) + >> TSENS9_CONTR_14_POINT2_SHIFT; + if (ext_sen) + tsens10_point2 = (calib_data[4] & + TSENS10_CONTR_14_POINT2_MASK) + >> TSENS10_CONTR_14_POINT2_SHIFT; + } + + if (tsens_calibration_mode == 0) { + pr_debug("TSENS in calibrationless mode\n"); + for (i = 0; i < tmdev->tsens_num_sensor; i++) { + calib_tsens_point2_data[i] = TSENS_NO_CALIB_POINT2_DATA; + calib_tsens_point1_data[i] = TSENS_NO_CALIB_POINT1_DATA; + } + } + + 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) + + tmdev->sensor[0].wa_temp1_calib_offset_factor; + calib_tsens_point1_data[1] = + (((tsens_base0_data) + tsens1_point1) << 2) + + tmdev->sensor[1].wa_temp1_calib_offset_factor; + calib_tsens_point1_data[2] = + (((tsens_base0_data) + tsens2_point1) << 2) + + tmdev->sensor[2].wa_temp1_calib_offset_factor; + calib_tsens_point1_data[3] = + (((tsens_base0_data) + tsens3_point1) << 2) + + tmdev->sensor[3].wa_temp1_calib_offset_factor; + calib_tsens_point1_data[4] = + (((tsens_base0_data) + tsens4_point1) << 2) + + tmdev->sensor[4].wa_temp1_calib_offset_factor; + calib_tsens_point1_data[5] = + (((tsens_base0_data) + tsens5_point1) << 2) + + tmdev->sensor[5].wa_temp1_calib_offset_factor; + calib_tsens_point1_data[6] = + (((tsens_base0_data) + tsens6_point1) << 2) + + tmdev->sensor[6].wa_temp1_calib_offset_factor; + calib_tsens_point1_data[7] = + (((tsens_base0_data) + tsens7_point1) << 2) + + tmdev->sensor[7].wa_temp1_calib_offset_factor; + calib_tsens_point1_data[8] = + (((tsens_base0_data) + tsens8_point1) << 2) + + tmdev->sensor[8].wa_temp1_calib_offset_factor; + calib_tsens_point1_data[9] = + (((tsens_base0_data) + tsens9_point1) << 2) + + tmdev->sensor[9].wa_temp1_calib_offset_factor; + if (ext_sen) + calib_tsens_point1_data[10] = + (((tsens_base0_data) + tsens10_point1) << 2) + + tmdev->sensor[10].wa_temp1_calib_offset_factor; + } + + 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) + + tmdev->sensor[0].wa_temp2_calib_offset_factor; + calib_tsens_point2_data[1] = + ((tsens_base1_data + tsens1_point2) << 2) + + tmdev->sensor[1].wa_temp2_calib_offset_factor; + calib_tsens_point2_data[2] = + ((tsens_base1_data + tsens2_point2) << 2) + + tmdev->sensor[2].wa_temp2_calib_offset_factor; + calib_tsens_point2_data[3] = + ((tsens_base1_data + tsens3_point2) << 2) + + tmdev->sensor[3].wa_temp2_calib_offset_factor; + calib_tsens_point2_data[4] = + ((tsens_base1_data + tsens4_point2) << 2) + + tmdev->sensor[4].wa_temp2_calib_offset_factor; + calib_tsens_point2_data[5] = + ((tsens_base1_data + tsens5_point2) << 2) + + tmdev->sensor[5].wa_temp2_calib_offset_factor; + calib_tsens_point2_data[6] = + ((tsens_base1_data + tsens6_point2) << 2) + + tmdev->sensor[6].wa_temp2_calib_offset_factor; + calib_tsens_point2_data[7] = + ((tsens_base1_data + tsens7_point2) << 2) + + tmdev->sensor[7].wa_temp2_calib_offset_factor; + calib_tsens_point2_data[8] = + ((tsens_base1_data + tsens8_point2) << 2) + + tmdev->sensor[8].wa_temp2_calib_offset_factor; + calib_tsens_point2_data[9] = + ((tsens_base1_data + tsens9_point2) << 2) + + tmdev->sensor[9].wa_temp2_calib_offset_factor; + if (ext_sen) + calib_tsens_point2_data[10] = + ((tsens_base1_data + tsens10_point2) << 2) + + tmdev->sensor[10].wa_temp2_calib_offset_factor; + } + + 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_mdm9607_sensors(struct tsens_tm_device *tmdev) +{ + 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(tmdev->tsens_calib_addr + 0x228); + calib_data[1] = readl_relaxed(tmdev->tsens_calib_addr + 0x22c); + calib_data[2] = readl_relaxed(tmdev->tsens_calib_addr + 0x230); + + tsens_calibration_mode = + (calib_data[2] & TSENS_MDM9607_TSENS_CAL_SEL) >> + TSENS_MDM9607_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_MDM9607_BASE0_MASK); + tsens0_point1 = (calib_data[0] & TSENS0_MDM9607_POINT1_MASK) + >> TSENS0_MDM9607_POINT1_SHIFT; + tsens1_point1 = (calib_data[0] & TSENS1_MDM9607_POINT1_MASK) + >> TSENS1_MDM9607_POINT1_SHIFT; + tsens2_point1 = (calib_data[1] & TSENS2_MDM9607_POINT1_MASK); + tsens3_point1 = (calib_data[1] & TSENS3_MDM9607_POINT1_MASK) + >> TSENS3_MDM9607_POINT1_SHIFT; + tsens4_point1 = (calib_data[2] & TSENS4_MDM9607_POINT1_MASK); + } + + if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) { + tsens_base1_data = (calib_data[2] & TSENS_MDM9607_BASE1_MASK) + >> TSENS_MDM9607_BASE1_SHIFT; + tsens0_point2 = (calib_data[0] & TSENS0_MDM9607_POINT2_MASK) + >> TSENS0_MDM9607_POINT2_SHIFT; + tsens1_point2 = (calib_data[0] & TSENS1_MDM9607_POINT2_MASK) + >> TSENS1_MDM9607_POINT2_SHIFT; + tsens2_point2 = (calib_data[1] & TSENS2_MDM9607_POINT2_MASK) + >> TSENS2_MDM9607_POINT2_SHIFT; + tsens3_point2 = (calib_data[1] & TSENS3_MDM9607_POINT2_MASK) + >> TSENS3_MDM9607_POINT2_SHIFT; + tsens4_point2 = (calib_data[2] & TSENS4_MDM9607_POINT2_MASK) + >> TSENS4_MDM9607_POINT2_SHIFT; + } + + if (tsens_calibration_mode == 0) { + pr_debug("TSENS in calibrationless mode\n"); + for (i = 0; i < tmdev->tsens_num_sensor; i++) { + calib_tsens_point2_data[i] = TSENS_NO_CALIB_POINT2_DATA; + calib_tsens_point1_data[i] = TSENS_NO_CALIB_POINT1_DATA; + } + } + + 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_msm8952_sensors(struct tsens_tm_device *tmdev) +{ + 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 tsens9_point1 = 0, tsens9_point2 = 0; + int tsens10_point1 = 0, tsens10_point2 = 0; + + int tsens_calibration_mode = 0, temp = 0; + uint32_t calib_data[5] = {0, 0, 0, 0, 0}; + uint32_t calib_tsens_point1_data[11], calib_tsens_point2_data[11]; + + 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)); + calib_data[4] = readl_relaxed( + (TSENS_8939_EEPROM + (tmdev->tsens_calib_addr) + 0x50)); + + tsens_calibration_mode = + (calib_data[0] & + TSENS_CONTR_14_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_CONTR_14_BASE0_MASK); + tsens0_point1 = (calib_data[0] & + TSENS0_CONTR_14_POINT1_MASK) + >> TSENS0_CONTR_14_POINT1_SHIFT; + tsens1_point1 = (calib_data[0] & + TSENS1_CONTR_14_POINT1_MASK) + >> TSENS1_CONTR_14_POINT1_SHIFT; + tsens2_point1 = (calib_data[0] & + TSENS2_CONTR_14_POINT1_MASK_0_4) + >> TSENS2_CONTR_14_POINT1_SHIFT_0_4; + temp = (calib_data[1] & TSENS2_CONTR_14_POINT1_MASK_5) + << TSENS2_CONTR_14_POINT1_SHIFT_5; + tsens2_point1 |= temp; + tsens3_point1 = (calib_data[1] & + TSENS3_CONTR_14_POINT1_MASK) + >> TSENS3_CONTR_14_POINT1_SHIFT; + tsens4_point1 = (calib_data[1] & + TSENS4_CONTR_14_POINT1_MASK) + >> TSENS4_CONTR_14_POINT1_SHIFT; + tsens5_point1 = (calib_data[2] & + TSENS5_CONTR_14_POINT1_MASK) + >> TSENS5_CONTR_14_POINT1_SHIFT; + tsens6_point1 = (calib_data[2] & + TSENS6_CONTR_14_POINT1_MASK) + >> TSENS6_CONTR_14_POINT1_SHIFT; + tsens7_point1 = (calib_data[3] & + TSENS7_CONTR_14_POINT1_MASK); + tsens8_point1 = (calib_data[3] & + TSENS8_CONTR_14_POINT1_MASK) + >> TSENS8_CONTR_14_POINT1_SHIFT; + tsens9_point1 = (calib_data[4] & + TSENS9_CONTR_14_POINT1_MASK); + tsens10_point1 = (calib_data[4] & + TSENS10_CONTR_14_POINT1_MASK) + >> TSENS10_CONTR_14_POINT1_SHIFT; + } + + if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) { + tsens_base1_data = (calib_data[3] & + TSENS_CONTR_14_BASE1_MASK) + >> TSENS_CONTR_14_BASE1_SHIFT; + tsens0_point2 = (calib_data[0] & + TSENS0_CONTR_14_POINT2_MASK) + >> TSENS0_CONTR_14_POINT2_SHIFT; + tsens1_point2 = (calib_data[0] & + TSENS1_CONTR_14_POINT2_MASK) + >> TSENS1_CONTR_14_POINT2_SHIFT; + tsens2_point2 = (calib_data[1] & + TSENS2_CONTR_14_POINT2_MASK) + >> TSENS2_CONTR_14_POINT2_SHIFT; + tsens3_point2 = (calib_data[1] & + TSENS3_CONTR_14_POINT2_MASK) + >> TSENS3_CONTR_14_POINT2_SHIFT; + tsens4_point2 = (calib_data[1] & + TSENS4_CONTR_14_POINT2_MASK) + >> TSENS4_CONTR_14_POINT2_SHIFT; + tsens5_point2 = (calib_data[2] & + TSENS5_CONTR_14_POINT2_MASK) + >> TSENS5_CONTR_14_POINT2_SHIFT; + tsens6_point2 = (calib_data[2] & + TSENS6_CONTR_14_POINT2_MASK) + >> TSENS6_CONTR_14_POINT2_SHIFT; + tsens7_point2 = (calib_data[3] & + TSENS7_CONTR_14_POINT2_MASK) + >> TSENS7_CONTR_14_POINT2_SHIFT; + tsens8_point2 = (calib_data[3] & + TSENS8_CONTR_14_POINT2_MASK) + >> TSENS8_CONTR_14_POINT2_SHIFT; + tsens9_point2 = (calib_data[4] & + TSENS9_CONTR_14_POINT2_MASK) + >> TSENS9_CONTR_14_POINT2_SHIFT; + tsens10_point2 = (calib_data[4] & + TSENS10_CONTR_14_POINT2_MASK) + >> TSENS10_CONTR_14_POINT2_SHIFT; + } + + if (tsens_calibration_mode == 0) { + pr_debug("TSENS in calibrationless mode\n"); + for (i = 0; i < tmdev->tsens_num_sensor; i++) { + calib_tsens_point2_data[i] = TSENS_NO_CALIB_POINT2_DATA; + calib_tsens_point1_data[i] = TSENS_NO_CALIB_POINT1_DATA; + } + } + + 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[0] = calib_tsens_point1_data[0] + + TSENS_MSM8952_D30_WA_S0; + calib_tsens_point1_data[1] = + (((tsens_base0_data) + tsens1_point1) << 2); + calib_tsens_point1_data[1] = calib_tsens_point1_data[1] - + TSENS_MSM8952_D30_WA_S1; + calib_tsens_point1_data[2] = + (((tsens_base0_data) + tsens2_point1) << 2); + calib_tsens_point1_data[2] = calib_tsens_point1_data[2] + + TSENS_MSM8952_D30_WA_S2; + calib_tsens_point1_data[3] = + (((tsens_base0_data) + tsens3_point1) << 2); + calib_tsens_point1_data[3] = calib_tsens_point1_data[3] + + TSENS_MSM8952_D30_WA_S3; + calib_tsens_point1_data[4] = + (((tsens_base0_data) + tsens4_point1) << 2); + calib_tsens_point1_data[4] = calib_tsens_point1_data[4] + + TSENS_MSM8952_D30_WA_S4; + calib_tsens_point1_data[5] = + (((tsens_base0_data) + tsens5_point1) << 2); + calib_tsens_point1_data[5] = calib_tsens_point1_data[5] - + TSENS_MSM8952_D30_WA_S5; + 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[7] = calib_tsens_point1_data[7] + + TSENS_MSM8952_D30_WA_S7; + calib_tsens_point1_data[8] = + (((tsens_base0_data) + tsens8_point1) << 2); + calib_tsens_point1_data[8] = calib_tsens_point1_data[8] + + TSENS_MSM8952_D30_WA_S8; + calib_tsens_point1_data[9] = + (((tsens_base0_data) + tsens9_point1) << 2); + calib_tsens_point1_data[10] = + (((tsens_base0_data) + tsens10_point1) << 2); + calib_tsens_point1_data[10] = calib_tsens_point1_data[10] - + TSENS_MSM8952_D30_WA_S10; + } + + 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_point1_data[0] = calib_tsens_point1_data[0] - + TSENS_MSM8952_D120_WA_S0; + calib_tsens_point2_data[1] = + ((tsens_base1_data + tsens1_point2) << 2); + calib_tsens_point1_data[1] = calib_tsens_point1_data[1] - + TSENS_MSM8952_D120_WA_S1; + calib_tsens_point2_data[2] = + ((tsens_base1_data + tsens2_point2) << 2); + calib_tsens_point1_data[2] = calib_tsens_point1_data[2] + + TSENS_MSM8952_D120_WA_S2; + calib_tsens_point2_data[3] = + ((tsens_base1_data + tsens3_point2) << 2); + calib_tsens_point1_data[3] = calib_tsens_point1_data[3] + + TSENS_MSM8952_D120_WA_S3; + calib_tsens_point2_data[4] = + ((tsens_base1_data + tsens4_point2) << 2); + calib_tsens_point1_data[4] = calib_tsens_point1_data[4] + + TSENS_MSM8952_D120_WA_S4; + calib_tsens_point2_data[5] = + ((tsens_base1_data + tsens5_point2) << 2); + calib_tsens_point1_data[5] = calib_tsens_point1_data[5] - + TSENS_MSM8952_D120_WA_S5; + calib_tsens_point2_data[6] = + ((tsens_base1_data + tsens6_point2) << 2); + calib_tsens_point1_data[6] = calib_tsens_point1_data[6] - + TSENS_MSM8952_D120_WA_S6; + calib_tsens_point2_data[7] = + ((tsens_base1_data + tsens7_point2) << 2); + calib_tsens_point1_data[7] = calib_tsens_point1_data[7] + + TSENS_MSM8952_D120_WA_S7; + calib_tsens_point2_data[8] = + ((tsens_base1_data + tsens8_point2) << 2); + calib_tsens_point1_data[8] = calib_tsens_point1_data[8] + + TSENS_MSM8952_D120_WA_S8; + calib_tsens_point2_data[9] = + ((tsens_base1_data + tsens9_point2) << 2); + calib_tsens_point2_data[10] = + ((tsens_base1_data + tsens10_point2) << 2); + calib_tsens_point1_data[10] = calib_tsens_point1_data[10] - + TSENS_MSM8952_D120_WA_S10; + } + + if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB_N_WA) || + (tsens_calibration_mode == + TSENS_TWO_POINT_CALIB_N_OFFSET_WA)) { + 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); + calib_tsens_point1_data[9] = + (((tsens_base0_data) + tsens9_point1) << 2); + calib_tsens_point1_data[10] = + (((tsens_base0_data) + tsens10_point1) << 2); + } + + if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB_N_WA) || + (tsens_calibration_mode == + TSENS_TWO_POINT_CALIB_N_OFFSET_WA)) { + 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); + calib_tsens_point2_data[9] = + ((tsens_base1_data + tsens9_point2) << 2); + calib_tsens_point2_data[10] = + ((tsens_base1_data + tsens10_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_msm8909_sensors(struct tsens_tm_device *tmdev) { int i, tsens_base0_data = 0, tsens_base1_data = 0; int tsens0_point1 = 0, tsens0_point2 = 0; @@ -1587,6 +3380,7 @@ static int tsens_calib_msm8909_sensors(void) 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", @@ -1612,7 +3406,7 @@ static int tsens_calib_msm8909_sensors(void) return 0; } -static int tsens_calib_8939_sensors(void) +static int tsens_calib_8939_sensors(struct tsens_tm_device *tmdev) { int i, tsens_base0_data = 0, tsens_base1_data = 0; int tsens0_point1 = 0, tsens0_point2 = 0; @@ -1754,6 +3548,7 @@ static int tsens_calib_8939_sensors(void) 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", @@ -1779,7 +3574,7 @@ static int tsens_calib_8939_sensors(void) return 0; } -static int tsens_calib_8916_sensors(void) +static int tsens_calib_8916_sensors(struct tsens_tm_device *tmdev) { int i, tsens_base0_data = 0, tsens_base1_data = 0; int tsens0_point1 = 0, tsens0_point2 = 0; @@ -1877,6 +3672,7 @@ static int tsens_calib_8916_sensors(void) 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", @@ -1902,7 +3698,7 @@ static int tsens_calib_8916_sensors(void) return 0; } -static int tsens_calib_9630_sensors(void) +static int tsens_calib_9630_sensors(struct tsens_tm_device *tmdev) { int i, tsens_base0_data = 0, tsens0_point = 0, tsens1_point = 0; int tsens2_point = 0, tsens3_point = 0, tsens4_point = 0; @@ -1955,6 +3751,7 @@ calibration_less_mode: 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", @@ -1984,7 +3781,7 @@ compute_intercept_slope: return 0; } -static int tsens_calib_8994_sensors(void) +static int tsens_calib_8994_sensors(struct tsens_tm_device *tmdev) { int i, tsens_base0_data = 0, tsens0_point = 0, tsens1_point = 0; int tsens2_point = 0, tsens3_point = 0, tsens4_point = 0; @@ -2197,6 +3994,7 @@ calibration_less_mode: 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", @@ -2226,7 +4024,7 @@ calibration_less_mode: return 0; } -static int tsens_calib_8992_sensors(void) +static int tsens_calib_8992_sensors(struct tsens_tm_device *tmdev) { int i, tsens_base0_data = 0, tsens0_point = 0, tsens1_point = 0; int tsens2_point = 0, tsens3_point = 0, tsens4_point = 0; @@ -2424,6 +4222,7 @@ calibration_less_mode: 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", @@ -2453,7 +4252,7 @@ calibration_less_mode: return 0; } -static int tsens_calib_8x10_sensors(void) +static int tsens_calib_8x10_sensors(struct tsens_tm_device *tmdev) { int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0; int tsens0_point2 = 0, tsens1_point2 = 0; @@ -2538,6 +4337,7 @@ calibration_less_mode: 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", @@ -2561,7 +4361,7 @@ compute_intercept_slope: return 0; } -static int tsens_calib_8x26_sensors(void) +static int tsens_calib_8x26_sensors(struct tsens_tm_device *tmdev) { int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0; int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0; @@ -2694,6 +4494,7 @@ calibration_less_mode: 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", @@ -2717,7 +4518,7 @@ compute_intercept_slope: return 0; } -static int tsens_calib_8974_sensors(void) +static int tsens_calib_8974_sensors(struct tsens_tm_device *tmdev) { int i, tsens_base1_data = 0, tsens0_point1 = 0, tsens1_point1 = 0; int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0; @@ -3027,6 +4828,7 @@ calibration_less_mode: 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", @@ -3051,7 +4853,7 @@ compute_intercept_slope: return 0; } -static int tsens_calib_9900_sensors(void) +static int tsens_calib_9900_sensors(struct tsens_tm_device *tmdev) { int i, tsens_base1_data = 0, tsens0_point1 = 0, tsens1_point1 = 0; int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0; @@ -3299,6 +5101,7 @@ calibration_less_mode: 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", @@ -3323,7 +5126,7 @@ compute_intercept_slope: return 0; } -static int tsens_calib_msmzirc_sensors(void) +static int tsens_calib_msmzirc_sensors(struct tsens_tm_device *tmdev) { int i = 0, tsens_base0_data = 0, tsens_base1_data = 0; int tsens0_point = 0, tsens1_point = 0, tsens2_point = 0; @@ -3344,7 +5147,7 @@ static int tsens_calib_msmzirc_sensors(void) pr_debug("calib mode is %d\n", tsens_calibration_mode); } - if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) { + 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; @@ -3375,6 +5178,7 @@ static int tsens_calib_msmzirc_sensors(void) 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", @@ -3403,35 +5207,45 @@ static int tsens_calib_msmzirc_sensors(void) return 0; } -static int tsens_calib_sensors(void) +static int tsens_calib_sensors(struct tsens_tm_device *tmdev) { int rc = 0; + pr_debug("%s\n", __func__); + if (!tmdev) return -ENODEV; if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8974) - rc = tsens_calib_8974_sensors(); + rc = tsens_calib_8974_sensors(tmdev); else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X26) - rc = tsens_calib_8x26_sensors(); + rc = tsens_calib_8x26_sensors(tmdev); else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X10) - rc = tsens_calib_8x10_sensors(); + rc = tsens_calib_8x10_sensors(tmdev); else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_9900) - rc = tsens_calib_9900_sensors(); + rc = tsens_calib_9900_sensors(tmdev); else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_9630) - rc = tsens_calib_9630_sensors(); + rc = tsens_calib_9630_sensors(tmdev); else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8916) - rc = tsens_calib_8916_sensors(); + rc = tsens_calib_8916_sensors(tmdev); else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8939) - rc = tsens_calib_8939_sensors(); + rc = tsens_calib_8939_sensors(tmdev); else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8994) - rc = tsens_calib_8994_sensors(); + rc = tsens_calib_8994_sensors(tmdev); else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_MSM8909) - rc = tsens_calib_msm8909_sensors(); + rc = tsens_calib_msm8909_sensors(tmdev); else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_MSMZIRC) - rc = tsens_calib_msmzirc_sensors(); + rc = tsens_calib_msmzirc_sensors(tmdev); else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8992) - rc = tsens_calib_8992_sensors(); + rc = tsens_calib_8992_sensors(tmdev); + else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_MSM8952) + rc = tsens_calib_msm8952_sensors(tmdev); + else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_MDM9607) + rc = tsens_calib_mdm9607_sensors(tmdev); + else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_MSM8937) + rc = tsens_calib_msm8937_msmgold_sensors(tmdev); + else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_MSMGOLD) + rc = tsens_calib_msm8937_msmgold_sensors(tmdev); else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_NONE) { pr_debug("Fuse map info not required\n"); rc = 0; @@ -3443,52 +5257,14 @@ static int tsens_calib_sensors(void) 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) +static int get_device_tree_data(struct platform_device *pdev, + struct tsens_tm_device *tmdev) { 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; + u32 *tsens_slope_data, *sensor_id, *client_id; + u32 *temp1_calib_offset_factor, *temp2_calib_offset_factor; + u32 rc = 0, i, tsens_num_sensors = 0; const struct of_device_id *id; rc = of_property_read_u32(of_node, @@ -3498,12 +5274,15 @@ static int get_device_tree_data(struct platform_device *pdev) return -ENODEV; } + if (tsens_num_sensors == 0) { + pr_err("No sensors?\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"); + if (!tsens_slope_data) return -ENOMEM; - } rc = of_property_read_u32_array(of_node, "qcom,slope", tsens_slope_data, tsens_num_sensors); @@ -3515,22 +5294,12 @@ static int get_device_tree_data(struct platform_device *pdev) 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; + id = of_match_node(tsens_match, of_node); + if (id == NULL) { + pr_err("can not find tsens_match of_node\n"); + return -ENODEV; } for (i = 0; i < tsens_num_sensors; i++) @@ -3545,9 +5314,24 @@ static int get_device_tree_data(struct platform_device *pdev) 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"); + if (!sensor_id) return -ENOMEM; + + client_id = devm_kzalloc(&pdev->dev, + tsens_num_sensors * sizeof(u32), GFP_KERNEL); + if (!client_id) + return -ENOMEM; + + rc = of_property_read_u32_array(of_node, + "qcom,client-id", client_id, tsens_num_sensors); + if (rc) { + for (i = 0; i < tsens_num_sensors; i++) + tmdev->sensor[i].sensor_client_id = i; + pr_debug("Default client id mapping\n"); + } else { + for (i = 0; i < tsens_num_sensors; i++) + tmdev->sensor[i].sensor_client_id = client_id[i]; + pr_debug("Use specified client id mapping\n"); } rc = of_property_read_u32_array(of_node, @@ -3573,16 +5357,28 @@ static int get_device_tree_data(struct platform_device *pdev) tmdev->tsens_type = TSENS_TYPE2; else if (!strcmp(id->compatible, "qcom,msm8996-tsens")) tmdev->tsens_type = TSENS_TYPE3; + else if (!strcmp(id->compatible, "qcom,msmtitanium-tsens")) { + tmdev->tsens_type = TSENS_TYPE3; + tsens_poll_check = 0; + } else if (!strcmp(id->compatible, "qcom,msm8952-tsens") || + (!strcmp(id->compatible, "qcom,msmgold-tsens")) || + (!strcmp(id->compatible, "qcom,msm8937-tsens"))) + tmdev->tsens_type = TSENS_TYPE4; else tmdev->tsens_type = TSENS_TYPE0; - if (!strcmp(id->compatible, "qcom,msm8994-tsens") || + tmdev->tsens_valid_status_check = of_property_read_bool(of_node, + "qcom,valid-status-check"); + if (!tmdev->tsens_valid_status_check) { + 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; + (!strcmp(id->compatible, "qcom,msm8996-tsens")) || + (!strcmp(id->compatible, "qcom,msm8952-tsens")) || + (!strcmp(id->compatible, "qcom,msm8937-tsens")) || + (!strcmp(id->compatible, "qcom,msmtitanium-tsens"))) + tmdev->tsens_valid_status_check = true; + } tmdev->tsens_irq = platform_get_irq_byname(pdev, "tsens-upper-lower"); @@ -3592,7 +5388,8 @@ static int get_device_tree_data(struct platform_device *pdev) goto fail_tmdev; } - if (!strcmp(id->compatible, "qcom,msm8996-tsens")) { + if (!strcmp(id->compatible, "qcom,msm8996-tsens") || + (!strcmp(id->compatible, "qcom,msmtitanium-tsens"))) { tmdev->tsens_critical_irq = platform_get_irq_byname(pdev, "tsens-critical"); @@ -3603,6 +5400,44 @@ static int get_device_tree_data(struct platform_device *pdev) } } + temp1_calib_offset_factor = devm_kzalloc(&pdev->dev, + tsens_num_sensors * sizeof(u32), GFP_KERNEL); + if (!temp1_calib_offset_factor) + return -ENOMEM; + + rc = of_property_read_u32_array(of_node, + "qcom,temp1-offset", temp1_calib_offset_factor, + tsens_num_sensors); + if (rc) { + pr_debug("Default temp1-offsets\n"); + for (i = 0; i < tsens_num_sensors; i++) + tmdev->sensor[i].wa_temp1_calib_offset_factor = 0; + } else { + pr_debug("Use specific temp1-offsets\n"); + for (i = 0; i < tsens_num_sensors; i++) + tmdev->sensor[i].wa_temp1_calib_offset_factor = + temp1_calib_offset_factor[i]; + } + + temp2_calib_offset_factor = devm_kzalloc(&pdev->dev, + tsens_num_sensors * sizeof(u32), GFP_KERNEL); + if (!temp2_calib_offset_factor) + return -ENOMEM; + + rc = of_property_read_u32_array(of_node, + "qcom,temp2-offset", temp2_calib_offset_factor, + tsens_num_sensors); + if (rc) { + pr_debug("Default temp2-offsets\n"); + for (i = 0; i < tsens_num_sensors; i++) + tmdev->sensor[i].wa_temp2_calib_offset_factor = 0; + } else { + pr_debug("Use specific temp2-offsets\n"); + for (i = 0; i < tsens_num_sensors; i++) + tmdev->sensor[i].wa_temp2_calib_offset_factor = + temp2_calib_offset_factor[i]; + } + /* TSENS register region */ tmdev->res_tsens_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tsens_physical"); @@ -3642,28 +5477,16 @@ static int get_device_tree_data(struct platform_device *pdev) 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->tsens_calib_addr = ioremap(tmdev->res_calib_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; + goto fail_unmap_tsens; } 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); @@ -3672,21 +5495,32 @@ fail_unmap_tsens_region: release_mem_region(tmdev->res_tsens_mem->start, tmdev->tsens_len); fail_tmdev: - tmdev = NULL; + platform_set_drvdata(pdev, NULL); + return rc; } static int tsens_tm_probe(struct platform_device *pdev) { + struct device_node *of_node = pdev->dev.of_node; int rc, i; + u32 tsens_num_sensors; + struct tsens_tm_device *tmdev = NULL; - if (tmdev) { - pr_err("TSENS device already in use\n"); - return -EBUSY; + rc = of_property_read_u32(of_node, + "qcom,sensors", &tsens_num_sensors); + 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; } if (pdev->dev.of_node) { - rc = get_device_tree_data(pdev); + rc = get_device_tree_data(pdev, tmdev); if (rc) { pr_err("Error reading TSENS DT\n"); return rc; @@ -3703,88 +5537,134 @@ static int tsens_tm_probe(struct platform_device *pdev) goto fail; } - rc = tsens_calib_sensors(); + rc = tsens_calib_sensors(tmdev); if (rc < 0) { pr_err("Calibration failed\n"); goto fail; } - tsens_hw_init(); + rc = tsens_hw_init(tmdev); + if (rc) + return rc; tmdev->prev_reading_avail = true; for (i = 0; i < 16; i++) tmdev->sensor_dbg_info[i].idx = 0; + spin_lock_init(&tmdev->tsens_crit_lock); + spin_lock_init(&tmdev->tsens_upp_low_lock); tmdev->is_ready = true; + list_add_tail(&tmdev->list, &tsens_device_list); platform_set_drvdata(pdev, tmdev); + rc = create_tsens_mtc_sysfs(pdev); + if (rc < 0) + pr_debug("Cannot create create_tsens_mtc_sysfs %d\n", rc); + 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; + platform_set_drvdata(pdev, NULL); return rc; } -static int _tsens_register_thermal(void) +static ssize_t tsens_debugfs_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) { - struct platform_device *pdev; - int rc, i; + int nbytes = 0; + struct tsens_tm_device *tmdev = NULL; + + list_for_each_entry(tmdev, &tsens_device_list, list) { + nbytes += scnprintf(dbg_buff + nbytes, 1024 - nbytes, + "TSENS Critical count: %d\n", + tmdev->tsens_critical_irq_cnt); + nbytes += scnprintf(dbg_buff + nbytes, 1024 - nbytes, + "TSENS Upper count: %d\n", + tmdev->tsens_upper_irq_cnt); + nbytes += scnprintf(dbg_buff + nbytes, 1024 - nbytes, + "TSENS Lower count: %d\n", + tmdev->tsens_lower_irq_cnt); - if (tsens_is_ready() <= 0) { - pr_err("%s: TSENS early init not done\n", __func__); - return -ENODEV; } - pdev = tmdev->pdev; + return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes); +} + +const struct file_operations tsens_stats_ops = { + .read = tsens_debugfs_read, +}; + +static void tsens_debugfs_init(void) +{ + const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH; + + dent = debugfs_create_dir("tsens", 0); + if (IS_ERR(dent)) { + pr_err("Error creating TSENS directory\n"); + return; + } + + dfile_stats = debugfs_create_file("stats", read_only_mode, dent, + 0, &tsens_stats_ops); + if (!dfile_stats || IS_ERR(dfile_stats)) { + pr_err("Failed to create TSENS folder\n"); + return; + } +} + +int tsens_sensor_sw_idx = 0; + +static int tsens_thermal_zone_register(struct tsens_tm_device *tmdev) +{ + int rc = 0, i = 0; + + if (tmdev == NULL) { + pr_err("Invalid tsens instance\n"); + return -EINVAL; + } 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); + tsens_sensor_sw_idx); tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED; + tmdev->sensor[i].tm = tmdev; if (tmdev->tsens_type == TSENS_TYPE3) { - tmdev->sensor[i].tz_dev = - thermal_zone_device_register(name, - TSENS_TM_TRIP_NUM, + 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); + &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__); + pr_err("%s: 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); + 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__); + pr_err("%s: failed.\n", __func__); rc = -ENODEV; goto fail; } } + tsens_sensor_sw_idx++; } if (tmdev->tsens_type == TSENS_TYPE3) { @@ -3803,24 +5683,30 @@ static int _tsens_register_thermal(void) } rc = request_threaded_irq(tmdev->tsens_critical_irq, NULL, - tsens_tm_critical_irq_thread, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, - "tsens_critical_interrupt", tmdev); + 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); + tmdev->sensor[i].tz_dev); goto fail; } else { enable_irq_wake(tmdev->tsens_critical_irq); } + + if (tsens_poll_check) { + INIT_DEFERRABLE_WORK(&tmdev->tsens_critical_poll_test, + tsens_poll); + schedule_delayed_work(&tmdev->tsens_critical_poll_test, + msecs_to_jiffies(tsens_sec_to_msec_value)); + init_completion(&tmdev->tsens_rslt_completion); + } } else { rc = request_threaded_irq(tmdev->tsens_irq, NULL, - tsens_irq_thread, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, - "tsens_interrupt", - tmdev); + 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++) @@ -3832,15 +5718,10 @@ static int _tsens_register_thermal(void) } } - 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) @@ -3849,6 +5730,29 @@ fail: return rc; } +static int _tsens_register_thermal(void) +{ + struct tsens_tm_device *tmdev = NULL; + int rc; + + if (tsens_is_ready() <= 0) { + pr_err("%s: TSENS early init not done\n", __func__); + return -ENODEV; + } + + list_for_each_entry(tmdev, &tsens_device_list, list) { + rc = tsens_thermal_zone_register(tmdev); + if (rc) { + pr_err("Error registering the thermal zone\n"); + return rc; + } + } + + tsens_debugfs_init(); + + return 0; +} + static int tsens_tm_remove(struct platform_device *pdev) { struct tsens_tm_device *tmdev = platform_get_drvdata(pdev); @@ -3858,9 +5762,6 @@ static int tsens_tm_remove(struct platform_device *pdev) 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) diff --git a/include/linux/msm_tsens.h b/include/linux/msm_tsens.h index 3dfe78b2c29b..62e59dbe8385 100644 --- a/include/linux/msm_tsens.h +++ b/include/linux/msm_tsens.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-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 @@ -18,52 +18,122 @@ #ifndef __MSM_TSENS_H #define __MSM_TSENS_H -enum platform_type { - MSM_8660 = 0, - MSM_8960, - MDM_9615, - APQ_8064, - MSM_TYPE -}; - #define TSENS_MAX_SENSORS 11 - -struct tsens_platform_data { - int slope[TSENS_MAX_SENSORS]; - int tsens_factor; - uint32_t tsens_num_sensor; - enum platform_type hw_type; -}; +#define TSENS_MTC_ZONE_LOG_SIZE 6 +#define TSENS_NUM_MTC_ZONES_SUPPORT 3 +#define TSENS_ZONEMASK_PARAMS 3 +#define TSENS_ZONELOG_PARAMS 1 +#define TSENS_MTC_ZONE_HISTORY_SIZE 3 struct tsens_device { uint32_t sensor_num; }; -int32_t tsens_get_temp(struct tsens_device *dev, unsigned long *temp); -int msm_tsens_early_init(struct tsens_platform_data *pdata); - #if defined(CONFIG_THERMAL_TSENS8974) +/** + * tsens_is_ready() - Clients can use this API to check if the TSENS device + * is ready and clients can start requesting temperature reads. + * @return: Returns true if device is ready else returns -EPROBE_DEFER + * for clients to check back after a time duration. + */ int tsens_is_ready(void); +/** + * tsens_tm_init_driver() - Early initialization for clients to read + * TSENS temperature. + */ int __init tsens_tm_init_driver(void); -int tsens_get_sw_id_mapping(int sensor_num, int *sensor_sw_idx); +/** + * tsens_get_hw_id_mapping() - Mapping software or sensor ID with the physical + * TSENS sensor. On certain cases where there are more number of + * controllers the sensor ID is used to map the clients software ID + * with the physical HW sensors used by the driver. + * @sensors_sw_id: Client ID. + * @sensor_hw_num: Sensor client ID passed by the driver. This ID is used + * by the driver to map it to the physical HW sensor + * number. + * @return: If the device is not present returns -EPROBE_DEFER + * for clients to check back after a time duration. + * 0 on success else error code on error. + */ int tsens_get_hw_id_mapping(int sensor_sw_id, int *sensor_hw_num); +/** + * tsens_get_max_sensor_num() - Get the total number of active TSENS sensors. + * The total number received by the client is across multiple + * TSENS controllers if present. + * @tsens_num_sensors: Total number of sensor result to be stored. + */ +int tsens_get_max_sensor_num(uint32_t *tsens_num_sensors); +/** + * tsens_set_mtc_zone_sw_mask() - Mask the MTC threshold level of a zone. + * SW can force the MTC to stop issuing throttling commands that + * correspond to each MTC threshold level by writing the + * corresponding bit in register at any time. + * @zone: Zone ID. + * @th1_enable : Value corresponding to the threshold level. + * @th2_enable : Value corresponding to the threshold level. + */ +int tsens_set_mtc_zone_sw_mask(unsigned int zone , unsigned int th1_enable, + unsigned int th2_enable); +/** + * tsens_get_mtc_zone_log() - Get the log of last 6 commands sent to pulse + * swallower of a zone. + * zone: Zone ID + * @zone_log: Log commands result to be stored. + */ +int tsens_get_mtc_zone_log(unsigned int zone , void *zone_log); +/** + * tsens_mtc_reset_history_counter() - Reset history of throttling commands + * sent to pulse swallower. Tsens controller issues clock + * throttling commands to Pulse swallower to perform HW + * based clock throttling. Reset the history counter of a zone. + * @zone: Zone ID. + */ +int tsens_mtc_reset_history_counter(unsigned int zone); +/** + * tsens_get_mtc_zone_history() - Get the history of throttling commands sent + * to pulse swallower. Tsens controller issues clock throttling + * commands to Pulse swallower to perform HW based clock + * throttling. + * @zone: Zone ID + * @zone_hist: Commands history result to be stored. + */ +int tsens_get_mtc_zone_history(unsigned int zone , void *zone_hist); +/** + * tsens_get_temp() - Obtain the TSENS temperature for the respective sensor. + * + * @dev: Sensor number for which client wants the TSENS temperature + * reading. The ID passed by the sensor could be the sensor ID + * which the driver translates to internally to read the + * respective physical HW sensor from the controller. + * @temp: temperature result to be stored. + * @return: If the device is not present returns -EPROBE_DEFER + * for clients to check back after a time duration. + * 0 on success else error code on error. + */ +int tsens_get_temp(struct tsens_device *dev, int *temp); #else static inline int tsens_is_ready(void) { return -ENXIO; } static inline int __init tsens_tm_init_driver(void) { return -ENXIO; } -static inline int tsens_get_sw_id_mapping( - int sensor_num, int *sensor_sw_idx) -{ return -ENXIO; } static inline int tsens_get_hw_id_mapping( int sensor_sw_id, int *sensor_hw_num) { return -ENXIO; } -#endif - -#if defined(CONFIG_THERMAL_TSENS8974) -int tsens_get_max_sensor_num(uint32_t *tsens_num_sensors); -#else static inline int tsens_get_max_sensor_num(uint32_t *tsens_num_sensors) { return -ENXIO; } +static inline int tsens_set_mtc_zone_sw_mask(unsigned int zone , + unsigned int th1_enable , + unsigned int th2_enable) +{ return -ENXIO; } +static inline int tsens_get_mtc_zone_log(unsigned int zone , void *zone_log) +{ return -ENXIO; } +static inline int tsens_mtc_reset_history_counter(unsigned int zone) +{ return -ENXIO; } +static inline int tsens_get_temp(struct tsens_device *dev, + int *temp) +{ return -ENXIO; } +static inline int tsens_get_mtc_zone_history(unsigned int zone, void *zone_hist) +{ return -ENXIO; } #endif + #endif /*MSM_TSENS_H */