Skip to content

Commit ff0cf0a

Browse files
Praveenkumar Idlezcano
authored andcommitted
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 <[email protected]> Signed-off-by: Praveenkumar I <[email protected]> Signed-off-by: Manikanta Mylavarapu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Daniel Lezcano <[email protected]>
1 parent 1a685e2 commit ff0cf0a

File tree

3 files changed

+188
-1
lines changed

3 files changed

+188
-1
lines changed

drivers/thermal/qcom/tsens-v2.c

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,32 @@
44
* Copyright (c) 2018, Linaro Limited
55
*/
66

7+
#include <linux/bitfield.h>
78
#include <linux/bitops.h>
9+
#include <linux/nvmem-consumer.h>
810
#include <linux/regmap.h>
911
#include "tsens.h"
1012

1113
/* ----- SROT ------ */
1214
#define SROT_HW_VER_OFF 0x0000
1315
#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)
1433

1534
/* ----- TM ------ */
1635
#define TM_INT_EN_OFF 0x0004
@@ -50,6 +69,17 @@ static struct tsens_features ipq8074_feat = {
5069
.trip_max_temp = 204000,
5170
};
5271

72+
static struct tsens_features ipq5332_feat = {
73+
.ver_major = VER_2_X_NO_RPM,
74+
.crit_int = 1,
75+
.combo_int = 1,
76+
.adc = 0,
77+
.srot_split = 1,
78+
.max_sensors = 16,
79+
.trip_min_temp = 0,
80+
.trip_max_temp = 204000,
81+
};
82+
5383
static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
5484
/* ----- SROT ------ */
5585
/* VERSION */
@@ -59,6 +89,10 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
5989
/* CTRL_OFF */
6090
[TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0),
6191
[TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1),
92+
[SENSOR_EN] = REG_FIELD(SROT_CTRL_OFF, 3, 18),
93+
[CODE_OR_TEMP] = REG_FIELD(SROT_CTRL_OFF, 21, 21),
94+
95+
[MAIN_MEASURE_PERIOD] = REG_FIELD(SROT_MEASURE_PERIOD, 0, 7),
6296

6397
/* ----- TM ------ */
6498
/* INTERRUPT ENABLE */
@@ -104,6 +138,128 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
104138
[TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
105139
};
106140

141+
static int tsens_v2_calibrate_sensor(struct device *dev, struct tsens_sensor *sensor,
142+
struct regmap *map, u32 mode, u32 base0, u32 base1)
143+
{
144+
u32 shift = V2_SHIFT_DEFAULT;
145+
u32 slope = V2_SLOPE_DEFAULT;
146+
u32 czero = V2_CZERO_DEFAULT;
147+
char name[20];
148+
u32 val;
149+
int ret;
150+
151+
/* Read offset value */
152+
ret = snprintf(name, sizeof(name), "tsens_sens%d_off", sensor->hw_id);
153+
if (ret < 0)
154+
return ret;
155+
156+
ret = nvmem_cell_read_variable_le_u32(dev, name, &sensor->offset);
157+
if (ret)
158+
return ret;
159+
160+
/* Based on calib mode, program SHIFT, SLOPE and CZERO */
161+
switch (mode) {
162+
case TWO_PT_CALIB:
163+
slope = (TWO_PT_SHIFTED_GAIN / (base1 - base0));
164+
165+
czero = (base0 + sensor->offset - ((base1 - base0) / 3));
166+
167+
break;
168+
case ONE_PT_CALIB2:
169+
czero = base0 + sensor->offset - ONE_PT_CZERO_CONST;
170+
171+
slope = ONE_PT_SLOPE;
172+
173+
break;
174+
default:
175+
dev_dbg(dev, "calibrationless mode\n");
176+
}
177+
178+
val = FIELD_PREP(CONVERSION_SHIFT_MASK, shift) |
179+
FIELD_PREP(CONVERSION_SLOPE_MASK, slope) |
180+
FIELD_PREP(CONVERSION_CZERO_MASK, czero);
181+
182+
regmap_write(map, SENSOR_CONVERSION(sensor->hw_id), val);
183+
184+
return 0;
185+
}
186+
187+
static int tsens_v2_calibration(struct tsens_priv *priv)
188+
{
189+
struct device *dev = priv->dev;
190+
u32 mode, base0, base1;
191+
int i, ret;
192+
193+
if (priv->num_sensors > MAX_SENSORS)
194+
return -EINVAL;
195+
196+
ret = nvmem_cell_read_variable_le_u32(priv->dev, "mode", &mode);
197+
if (ret == -ENOENT)
198+
dev_warn(priv->dev, "Calibration data not present in DT\n");
199+
if (ret < 0)
200+
return ret;
201+
202+
dev_dbg(priv->dev, "calibration mode is %d\n", mode);
203+
204+
ret = nvmem_cell_read_variable_le_u32(priv->dev, "base0", &base0);
205+
if (ret < 0)
206+
return ret;
207+
208+
ret = nvmem_cell_read_variable_le_u32(priv->dev, "base1", &base1);
209+
if (ret < 0)
210+
return ret;
211+
212+
/* Calibrate each sensor */
213+
for (i = 0; i < priv->num_sensors; i++) {
214+
ret = tsens_v2_calibrate_sensor(dev, &priv->sensor[i], priv->srot_map,
215+
mode, base0, base1);
216+
if (ret < 0)
217+
return ret;
218+
}
219+
220+
return 0;
221+
}
222+
223+
static int __init init_tsens_v2_no_rpm(struct tsens_priv *priv)
224+
{
225+
struct device *dev = priv->dev;
226+
int i, ret;
227+
u32 val = 0;
228+
229+
ret = init_common(priv);
230+
if (ret < 0)
231+
return ret;
232+
233+
priv->rf[CODE_OR_TEMP] = devm_regmap_field_alloc(dev, priv->srot_map,
234+
priv->fields[CODE_OR_TEMP]);
235+
if (IS_ERR(priv->rf[CODE_OR_TEMP]))
236+
return PTR_ERR(priv->rf[CODE_OR_TEMP]);
237+
238+
priv->rf[MAIN_MEASURE_PERIOD] = devm_regmap_field_alloc(dev, priv->srot_map,
239+
priv->fields[MAIN_MEASURE_PERIOD]);
240+
if (IS_ERR(priv->rf[MAIN_MEASURE_PERIOD]))
241+
return PTR_ERR(priv->rf[MAIN_MEASURE_PERIOD]);
242+
243+
regmap_field_write(priv->rf[TSENS_SW_RST], SW_RST_ASSERT);
244+
245+
regmap_field_write(priv->rf[MAIN_MEASURE_PERIOD], MEASURE_PERIOD_2mSEC);
246+
247+
/* Enable available sensors */
248+
for (i = 0; i < priv->num_sensors; i++)
249+
val |= 1 << priv->sensor[i].hw_id;
250+
251+
regmap_field_write(priv->rf[SENSOR_EN], val);
252+
253+
/* Select temperature format, unit is deci-Celsius */
254+
regmap_field_write(priv->rf[CODE_OR_TEMP], RESULT_FORMAT_TEMP);
255+
256+
regmap_field_write(priv->rf[TSENS_SW_RST], SW_RST_DEASSERT);
257+
258+
regmap_field_write(priv->rf[TSENS_EN], TSENS_ENABLE);
259+
260+
return 0;
261+
}
262+
107263
static const struct tsens_ops ops_generic_v2 = {
108264
.init = init_common,
109265
.get_temp = get_temp_tsens_valid,
@@ -122,6 +278,28 @@ struct tsens_plat_data data_ipq8074 = {
122278
.fields = tsens_v2_regfields,
123279
};
124280

281+
static const struct tsens_ops ops_ipq5332 = {
282+
.init = init_tsens_v2_no_rpm,
283+
.get_temp = get_temp_tsens_valid,
284+
.calibrate = tsens_v2_calibration,
285+
};
286+
287+
const struct tsens_plat_data data_ipq5332 = {
288+
.num_sensors = 5,
289+
.ops = &ops_ipq5332,
290+
.hw_ids = (unsigned int []){11, 12, 13, 14, 15},
291+
.feat = &ipq5332_feat,
292+
.fields = tsens_v2_regfields,
293+
};
294+
295+
const struct tsens_plat_data data_ipq5424 = {
296+
.num_sensors = 7,
297+
.ops = &ops_ipq5332,
298+
.hw_ids = (unsigned int []){9, 10, 11, 12, 13, 14, 15},
299+
.feat = &ipq5332_feat,
300+
.fields = tsens_v2_regfields,
301+
};
302+
125303
/* Kept around for backward compatibility with old msm8996.dtsi */
126304
struct tsens_plat_data data_8996 = {
127305
.num_sensors = 13,

drivers/thermal/qcom/tsens.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,7 @@ int __init init_common(struct tsens_priv *priv)
975975
ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
976976
if (ret)
977977
goto err_put_device;
978-
if (!enabled) {
978+
if (!enabled && (tsens_version(priv) != VER_2_X_NO_RPM)) {
979979
dev_err(dev, "%s: device not enabled\n", __func__);
980980
ret = -ENODEV;
981981
goto err_put_device;
@@ -1102,6 +1102,12 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
11021102

11031103
static const struct of_device_id tsens_table[] = {
11041104
{
1105+
.compatible = "qcom,ipq5332-tsens",
1106+
.data = &data_ipq5332,
1107+
}, {
1108+
.compatible = "qcom,ipq5424-tsens",
1109+
.data = &data_ipq5424,
1110+
}, {
11051111
.compatible = "qcom,ipq8064-tsens",
11061112
.data = &data_8960,
11071113
}, {

drivers/thermal/qcom/tsens.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ enum tsens_ver {
3535
VER_0_1,
3636
VER_1_X,
3737
VER_2_X,
38+
VER_2_X_NO_RPM,
3839
};
3940

4041
enum tsens_irq_type {
@@ -168,6 +169,7 @@ enum regfield_ids {
168169
TSENS_SW_RST,
169170
SENSOR_EN,
170171
CODE_OR_TEMP,
172+
MAIN_MEASURE_PERIOD,
171173

172174
/* ----- TM ------ */
173175
/* TRDY */
@@ -651,5 +653,6 @@ extern struct tsens_plat_data data_tsens_v1, data_8937, data_8976, data_8956;
651653

652654
/* TSENS v2 targets */
653655
extern struct tsens_plat_data data_8996, data_ipq8074, data_tsens_v2;
656+
extern const struct tsens_plat_data data_ipq5332, data_ipq5424;
654657

655658
#endif /* __QCOM_TSENS_H__ */

0 commit comments

Comments
 (0)