Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

thermal/drivers/tsens: Add TSENS enable and calibration support for V2

SoCs without RPM need to enable sensors and calibrate them from the kernel.
The IPQ5332 and IPQ5424 use the tsens v2.3.3 IP and do not have RPM.
Therefore, add a new calibration function for V2, as the tsens.c calib
function only supports V1. Also add new feature_config, ops and data for
IPQ5332, IPQ5424.

Although the TSENS IP supports 16 sensors, not all are used. The hw_id
is used to enable the relevant sensors.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Praveenkumar I <quic_ipkumar@quicinc.com>
Signed-off-by: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
Link: https://lore.kernel.org/r/20250210120436.821684-3-quic_mmanikan@quicinc.com
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>

authored by

Praveenkumar I and committed by
Daniel Lezcano
ff0cf0ab 1a685e2b

+188 -1
+178
drivers/thermal/qcom/tsens-v2.c
··· 4 4 * Copyright (c) 2018, Linaro Limited 5 5 */ 6 6 7 + #include <linux/bitfield.h> 7 8 #include <linux/bitops.h> 9 + #include <linux/nvmem-consumer.h> 8 10 #include <linux/regmap.h> 9 11 #include "tsens.h" 10 12 11 13 /* ----- SROT ------ */ 12 14 #define SROT_HW_VER_OFF 0x0000 13 15 #define SROT_CTRL_OFF 0x0004 16 + #define SROT_MEASURE_PERIOD 0x0008 17 + #define SROT_Sn_CONVERSION 0x0060 18 + #define V2_SHIFT_DEFAULT 0x0003 19 + #define V2_SLOPE_DEFAULT 0x0cd0 20 + #define V2_CZERO_DEFAULT 0x016a 21 + #define ONE_PT_SLOPE 0x0cd0 22 + #define TWO_PT_SHIFTED_GAIN 921600 23 + #define ONE_PT_CZERO_CONST 94 24 + #define SW_RST_DEASSERT 0x0 25 + #define SW_RST_ASSERT 0x1 26 + #define MEASURE_PERIOD_2mSEC 0x1 27 + #define RESULT_FORMAT_TEMP 0x1 28 + #define TSENS_ENABLE 0x1 29 + #define SENSOR_CONVERSION(n) (((n) * 4) + SROT_Sn_CONVERSION) 30 + #define CONVERSION_SHIFT_MASK GENMASK(24, 23) 31 + #define CONVERSION_SLOPE_MASK GENMASK(22, 10) 32 + #define CONVERSION_CZERO_MASK GENMASK(9, 0) 14 33 15 34 /* ----- TM ------ */ 16 35 #define TM_INT_EN_OFF 0x0004 ··· 69 50 .trip_max_temp = 204000, 70 51 }; 71 52 53 + static struct tsens_features ipq5332_feat = { 54 + .ver_major = VER_2_X_NO_RPM, 55 + .crit_int = 1, 56 + .combo_int = 1, 57 + .adc = 0, 58 + .srot_split = 1, 59 + .max_sensors = 16, 60 + .trip_min_temp = 0, 61 + .trip_max_temp = 204000, 62 + }; 63 + 72 64 static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = { 73 65 /* ----- SROT ------ */ 74 66 /* VERSION */ ··· 89 59 /* CTRL_OFF */ 90 60 [TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0), 91 61 [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1), 62 + [SENSOR_EN] = REG_FIELD(SROT_CTRL_OFF, 3, 18), 63 + [CODE_OR_TEMP] = REG_FIELD(SROT_CTRL_OFF, 21, 21), 64 + 65 + [MAIN_MEASURE_PERIOD] = REG_FIELD(SROT_MEASURE_PERIOD, 0, 7), 92 66 93 67 /* ----- TM ------ */ 94 68 /* INTERRUPT ENABLE */ ··· 138 104 [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0), 139 105 }; 140 106 107 + static int tsens_v2_calibrate_sensor(struct device *dev, struct tsens_sensor *sensor, 108 + struct regmap *map, u32 mode, u32 base0, u32 base1) 109 + { 110 + u32 shift = V2_SHIFT_DEFAULT; 111 + u32 slope = V2_SLOPE_DEFAULT; 112 + u32 czero = V2_CZERO_DEFAULT; 113 + char name[20]; 114 + u32 val; 115 + int ret; 116 + 117 + /* Read offset value */ 118 + ret = snprintf(name, sizeof(name), "tsens_sens%d_off", sensor->hw_id); 119 + if (ret < 0) 120 + return ret; 121 + 122 + ret = nvmem_cell_read_variable_le_u32(dev, name, &sensor->offset); 123 + if (ret) 124 + return ret; 125 + 126 + /* Based on calib mode, program SHIFT, SLOPE and CZERO */ 127 + switch (mode) { 128 + case TWO_PT_CALIB: 129 + slope = (TWO_PT_SHIFTED_GAIN / (base1 - base0)); 130 + 131 + czero = (base0 + sensor->offset - ((base1 - base0) / 3)); 132 + 133 + break; 134 + case ONE_PT_CALIB2: 135 + czero = base0 + sensor->offset - ONE_PT_CZERO_CONST; 136 + 137 + slope = ONE_PT_SLOPE; 138 + 139 + break; 140 + default: 141 + dev_dbg(dev, "calibrationless mode\n"); 142 + } 143 + 144 + val = FIELD_PREP(CONVERSION_SHIFT_MASK, shift) | 145 + FIELD_PREP(CONVERSION_SLOPE_MASK, slope) | 146 + FIELD_PREP(CONVERSION_CZERO_MASK, czero); 147 + 148 + regmap_write(map, SENSOR_CONVERSION(sensor->hw_id), val); 149 + 150 + return 0; 151 + } 152 + 153 + static int tsens_v2_calibration(struct tsens_priv *priv) 154 + { 155 + struct device *dev = priv->dev; 156 + u32 mode, base0, base1; 157 + int i, ret; 158 + 159 + if (priv->num_sensors > MAX_SENSORS) 160 + return -EINVAL; 161 + 162 + ret = nvmem_cell_read_variable_le_u32(priv->dev, "mode", &mode); 163 + if (ret == -ENOENT) 164 + dev_warn(priv->dev, "Calibration data not present in DT\n"); 165 + if (ret < 0) 166 + return ret; 167 + 168 + dev_dbg(priv->dev, "calibration mode is %d\n", mode); 169 + 170 + ret = nvmem_cell_read_variable_le_u32(priv->dev, "base0", &base0); 171 + if (ret < 0) 172 + return ret; 173 + 174 + ret = nvmem_cell_read_variable_le_u32(priv->dev, "base1", &base1); 175 + if (ret < 0) 176 + return ret; 177 + 178 + /* Calibrate each sensor */ 179 + for (i = 0; i < priv->num_sensors; i++) { 180 + ret = tsens_v2_calibrate_sensor(dev, &priv->sensor[i], priv->srot_map, 181 + mode, base0, base1); 182 + if (ret < 0) 183 + return ret; 184 + } 185 + 186 + return 0; 187 + } 188 + 189 + static int __init init_tsens_v2_no_rpm(struct tsens_priv *priv) 190 + { 191 + struct device *dev = priv->dev; 192 + int i, ret; 193 + u32 val = 0; 194 + 195 + ret = init_common(priv); 196 + if (ret < 0) 197 + return ret; 198 + 199 + priv->rf[CODE_OR_TEMP] = devm_regmap_field_alloc(dev, priv->srot_map, 200 + priv->fields[CODE_OR_TEMP]); 201 + if (IS_ERR(priv->rf[CODE_OR_TEMP])) 202 + return PTR_ERR(priv->rf[CODE_OR_TEMP]); 203 + 204 + priv->rf[MAIN_MEASURE_PERIOD] = devm_regmap_field_alloc(dev, priv->srot_map, 205 + priv->fields[MAIN_MEASURE_PERIOD]); 206 + if (IS_ERR(priv->rf[MAIN_MEASURE_PERIOD])) 207 + return PTR_ERR(priv->rf[MAIN_MEASURE_PERIOD]); 208 + 209 + regmap_field_write(priv->rf[TSENS_SW_RST], SW_RST_ASSERT); 210 + 211 + regmap_field_write(priv->rf[MAIN_MEASURE_PERIOD], MEASURE_PERIOD_2mSEC); 212 + 213 + /* Enable available sensors */ 214 + for (i = 0; i < priv->num_sensors; i++) 215 + val |= 1 << priv->sensor[i].hw_id; 216 + 217 + regmap_field_write(priv->rf[SENSOR_EN], val); 218 + 219 + /* Select temperature format, unit is deci-Celsius */ 220 + regmap_field_write(priv->rf[CODE_OR_TEMP], RESULT_FORMAT_TEMP); 221 + 222 + regmap_field_write(priv->rf[TSENS_SW_RST], SW_RST_DEASSERT); 223 + 224 + regmap_field_write(priv->rf[TSENS_EN], TSENS_ENABLE); 225 + 226 + return 0; 227 + } 228 + 141 229 static const struct tsens_ops ops_generic_v2 = { 142 230 .init = init_common, 143 231 .get_temp = get_temp_tsens_valid, ··· 276 120 .ops = &ops_generic_v2, 277 121 .feat = &ipq8074_feat, 278 122 .fields = tsens_v2_regfields, 123 + }; 124 + 125 + static const struct tsens_ops ops_ipq5332 = { 126 + .init = init_tsens_v2_no_rpm, 127 + .get_temp = get_temp_tsens_valid, 128 + .calibrate = tsens_v2_calibration, 129 + }; 130 + 131 + const struct tsens_plat_data data_ipq5332 = { 132 + .num_sensors = 5, 133 + .ops = &ops_ipq5332, 134 + .hw_ids = (unsigned int []){11, 12, 13, 14, 15}, 135 + .feat = &ipq5332_feat, 136 + .fields = tsens_v2_regfields, 137 + }; 138 + 139 + const struct tsens_plat_data data_ipq5424 = { 140 + .num_sensors = 7, 141 + .ops = &ops_ipq5332, 142 + .hw_ids = (unsigned int []){9, 10, 11, 12, 13, 14, 15}, 143 + .feat = &ipq5332_feat, 144 + .fields = tsens_v2_regfields, 279 145 }; 280 146 281 147 /* Kept around for backward compatibility with old msm8996.dtsi */
+7 -1
drivers/thermal/qcom/tsens.c
··· 975 975 ret = regmap_field_read(priv->rf[TSENS_EN], &enabled); 976 976 if (ret) 977 977 goto err_put_device; 978 - if (!enabled) { 978 + if (!enabled && (tsens_version(priv) != VER_2_X_NO_RPM)) { 979 979 dev_err(dev, "%s: device not enabled\n", __func__); 980 980 ret = -ENODEV; 981 981 goto err_put_device; ··· 1102 1102 1103 1103 static const struct of_device_id tsens_table[] = { 1104 1104 { 1105 + .compatible = "qcom,ipq5332-tsens", 1106 + .data = &data_ipq5332, 1107 + }, { 1108 + .compatible = "qcom,ipq5424-tsens", 1109 + .data = &data_ipq5424, 1110 + }, { 1105 1111 .compatible = "qcom,ipq8064-tsens", 1106 1112 .data = &data_8960, 1107 1113 }, {
+3
drivers/thermal/qcom/tsens.h
··· 35 35 VER_0_1, 36 36 VER_1_X, 37 37 VER_2_X, 38 + VER_2_X_NO_RPM, 38 39 }; 39 40 40 41 enum tsens_irq_type { ··· 169 168 TSENS_SW_RST, 170 169 SENSOR_EN, 171 170 CODE_OR_TEMP, 171 + MAIN_MEASURE_PERIOD, 172 172 173 173 /* ----- TM ------ */ 174 174 /* TRDY */ ··· 653 651 654 652 /* TSENS v2 targets */ 655 653 extern struct tsens_plat_data data_8996, data_ipq8074, data_tsens_v2; 654 + extern const struct tsens_plat_data data_ipq5332, data_ipq5424; 656 655 657 656 #endif /* __QCOM_TSENS_H__ */