2 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
5 * Mikko Perttunen <mperttunen@nvidia.com>
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
18 #include <linux/bitops.h>
19 #include <linux/clk.h>
20 #include <linux/delay.h>
21 #include <linux/err.h>
22 #include <linux/interrupt.h>
24 #include <linux/module.h>
26 #include <linux/platform_device.h>
27 #include <linux/reset.h>
28 #include <linux/thermal.h>
30 #include <soc/tegra/fuse.h>
32 #define SENSOR_CONFIG0 0
33 #define SENSOR_CONFIG0_STOP BIT(0)
34 #define SENSOR_CONFIG0_TALL_SHIFT 8
35 #define SENSOR_CONFIG0_TCALC_OVER BIT(4)
36 #define SENSOR_CONFIG0_OVER BIT(3)
37 #define SENSOR_CONFIG0_CPTR_OVER BIT(2)
39 #define SENSOR_CONFIG1 4
40 #define SENSOR_CONFIG1_TSAMPLE_SHIFT 0
41 #define SENSOR_CONFIG1_TIDDQ_EN_SHIFT 15
42 #define SENSOR_CONFIG1_TEN_COUNT_SHIFT 24
43 #define SENSOR_CONFIG1_TEMP_ENABLE BIT(31)
45 #define SENSOR_CONFIG2 8
46 #define SENSOR_CONFIG2_THERMA_SHIFT 16
47 #define SENSOR_CONFIG2_THERMB_SHIFT 0
49 #define SENSOR_PDIV 0x1c0
50 #define SENSOR_PDIV_T124 0x8888
51 #define SENSOR_HOTSPOT_OFF 0x1c4
52 #define SENSOR_HOTSPOT_OFF_T124 0x00060600
53 #define SENSOR_TEMP1 0x1c8
54 #define SENSOR_TEMP2 0x1cc
56 #define SENSOR_TEMP_MASK 0xffff
57 #define READBACK_VALUE_MASK 0xff00
58 #define READBACK_VALUE_SHIFT 8
59 #define READBACK_ADD_HALF BIT(7)
60 #define READBACK_NEGATE BIT(1)
62 #define FUSE_TSENSOR8_CALIB 0x180
63 #define FUSE_SPARE_REALIGNMENT_REG_0 0x1fc
65 #define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK 0x1fff
66 #define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK (0x1fff << 13)
67 #define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13
69 #define FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK 0x3ff
70 #define FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK (0x7ff << 10)
71 #define FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT 10
73 #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_MASK 0x3f
74 #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK (0x1f << 21)
75 #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT 21
77 #define NOMINAL_CALIB_FT_T124 105
78 #define NOMINAL_CALIB_CP_T124 25
80 struct tegra_tsensor_configuration
{
81 u32 tall
, tsample
, tiddq_en
, ten_count
, pdiv
, tsample_ate
, pdiv_ate
;
84 struct tegra_tsensor
{
85 const struct tegra_tsensor_configuration
*config
;
86 u32 base
, calib_fuse_offset
;
87 /* Correction values used to modify values read from calibration fuses */
88 s32 fuse_corr_alpha
, fuse_corr_beta
;
91 struct tegra_thermctl_zone
{
96 static const struct tegra_tsensor_configuration t124_tsensor_config
= {
106 static const struct tegra_tsensor t124_tsensors
[] = {
108 .config
= &t124_tsensor_config
,
110 .calib_fuse_offset
= 0x098,
111 .fuse_corr_alpha
= 1135400,
112 .fuse_corr_beta
= -6266900,
115 .config
= &t124_tsensor_config
,
117 .calib_fuse_offset
= 0x084,
118 .fuse_corr_alpha
= 1122220,
119 .fuse_corr_beta
= -5700700,
122 .config
= &t124_tsensor_config
,
124 .calib_fuse_offset
= 0x088,
125 .fuse_corr_alpha
= 1127000,
126 .fuse_corr_beta
= -6768200,
129 .config
= &t124_tsensor_config
,
131 .calib_fuse_offset
= 0x12c,
132 .fuse_corr_alpha
= 1110900,
133 .fuse_corr_beta
= -6232000,
136 .config
= &t124_tsensor_config
,
138 .calib_fuse_offset
= 0x158,
139 .fuse_corr_alpha
= 1122300,
140 .fuse_corr_beta
= -5936400,
143 .config
= &t124_tsensor_config
,
145 .calib_fuse_offset
= 0x15c,
146 .fuse_corr_alpha
= 1145700,
147 .fuse_corr_beta
= -7124600,
150 .config
= &t124_tsensor_config
,
152 .calib_fuse_offset
= 0x154,
153 .fuse_corr_alpha
= 1120100,
154 .fuse_corr_beta
= -6000500,
157 .config
= &t124_tsensor_config
,
159 .calib_fuse_offset
= 0x160,
160 .fuse_corr_alpha
= 1106500,
161 .fuse_corr_beta
= -6729300,
165 struct tegra_soctherm
{
166 struct reset_control
*reset
;
167 struct clk
*clock_tsensor
;
168 struct clk
*clock_soctherm
;
171 struct thermal_zone_device
*thermctl_tzs
[4];
174 struct tsensor_shared_calibration
{
175 u32 base_cp
, base_ft
;
176 u32 actual_temp_cp
, actual_temp_ft
;
179 static int calculate_shared_calibration(struct tsensor_shared_calibration
*r
)
181 u32 val
, shifted_cp
, shifted_ft
;
184 err
= tegra_fuse_readl(FUSE_TSENSOR8_CALIB
, &val
);
187 r
->base_cp
= val
& FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK
;
188 r
->base_ft
= (val
& FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK
)
189 >> FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT
;
190 val
= ((val
& FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK
)
191 >> FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT
);
192 shifted_ft
= sign_extend32(val
, 4);
194 err
= tegra_fuse_readl(FUSE_SPARE_REALIGNMENT_REG_0
, &val
);
197 shifted_cp
= sign_extend32(val
, 5);
199 r
->actual_temp_cp
= 2 * NOMINAL_CALIB_CP_T124
+ shifted_cp
;
200 r
->actual_temp_ft
= 2 * NOMINAL_CALIB_FT_T124
+ shifted_ft
;
205 static s64
div64_s64_precise(s64 a
, s64 b
)
209 /* Scale up for increased precision division */
212 r
= div64_s64(al
* 2 + 1, 2 * b
);
217 calculate_tsensor_calibration(const struct tegra_tsensor
*sensor
,
218 const struct tsensor_shared_calibration
*shared
,
222 s32 actual_tsensor_ft
, actual_tsensor_cp
, delta_sens
, delta_temp
,
228 err
= tegra_fuse_readl(sensor
->calib_fuse_offset
, &val
);
232 actual_tsensor_cp
= (shared
->base_cp
* 64) + sign_extend32(val
, 12);
233 val
= (val
& FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK
)
234 >> FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT
;
235 actual_tsensor_ft
= (shared
->base_ft
* 32) + sign_extend32(val
, 12);
237 delta_sens
= actual_tsensor_ft
- actual_tsensor_cp
;
238 delta_temp
= shared
->actual_temp_ft
- shared
->actual_temp_cp
;
240 mult
= sensor
->config
->pdiv
* sensor
->config
->tsample_ate
;
241 div
= sensor
->config
->tsample
* sensor
->config
->pdiv_ate
;
243 therma
= div64_s64_precise((s64
) delta_temp
* (1LL << 13) * mult
,
244 (s64
) delta_sens
* div
);
246 tmp
= (s64
)actual_tsensor_ft
* shared
->actual_temp_cp
-
247 (s64
)actual_tsensor_cp
* shared
->actual_temp_ft
;
248 thermb
= div64_s64_precise(tmp
, (s64
)delta_sens
);
250 therma
= div64_s64_precise((s64
)therma
* sensor
->fuse_corr_alpha
,
252 thermb
= div64_s64_precise((s64
)thermb
* sensor
->fuse_corr_alpha
+
253 sensor
->fuse_corr_beta
, (s64
)1000000LL);
255 *calib
= ((u16
)therma
<< SENSOR_CONFIG2_THERMA_SHIFT
) |
256 ((u16
)thermb
<< SENSOR_CONFIG2_THERMB_SHIFT
);
261 static int enable_tsensor(struct tegra_soctherm
*tegra
,
262 const struct tegra_tsensor
*sensor
,
263 const struct tsensor_shared_calibration
*shared
)
265 void __iomem
*base
= tegra
->regs
+ sensor
->base
;
270 err
= calculate_tsensor_calibration(sensor
, shared
, &calib
);
274 val
= sensor
->config
->tall
<< SENSOR_CONFIG0_TALL_SHIFT
;
275 writel(val
, base
+ SENSOR_CONFIG0
);
277 val
= (sensor
->config
->tsample
- 1) << SENSOR_CONFIG1_TSAMPLE_SHIFT
;
278 val
|= sensor
->config
->tiddq_en
<< SENSOR_CONFIG1_TIDDQ_EN_SHIFT
;
279 val
|= sensor
->config
->ten_count
<< SENSOR_CONFIG1_TEN_COUNT_SHIFT
;
280 val
|= SENSOR_CONFIG1_TEMP_ENABLE
;
281 writel(val
, base
+ SENSOR_CONFIG1
);
283 writel(calib
, base
+ SENSOR_CONFIG2
);
289 * Translate from soctherm readback format to millicelsius.
290 * The soctherm readback format in bits is as follows:
292 * where T's contain the temperature in Celsius,
293 * H denotes an addition of 0.5 Celsius and N denotes negation
294 * of the final value.
296 static long translate_temp(u16 val
)
300 t
= ((val
& READBACK_VALUE_MASK
) >> READBACK_VALUE_SHIFT
) * 1000;
301 if (val
& READBACK_ADD_HALF
)
303 if (val
& READBACK_NEGATE
)
309 static int tegra_thermctl_get_temp(void *data
, long *out_temp
)
311 struct tegra_thermctl_zone
*zone
= data
;
314 val
= (readl(zone
->reg
) >> zone
->shift
) & SENSOR_TEMP_MASK
;
315 *out_temp
= translate_temp(val
);
320 static const struct thermal_zone_of_device_ops tegra_of_thermal_ops
= {
321 .get_temp
= tegra_thermctl_get_temp
,
324 static const struct of_device_id tegra_soctherm_of_match
[] = {
325 { .compatible
= "nvidia,tegra124-soctherm" },
328 MODULE_DEVICE_TABLE(of
, tegra_soctherm_of_match
);
330 struct thermctl_zone_desc
{
335 static const struct thermctl_zone_desc t124_thermctl_temp_zones
[] = {
336 { SENSOR_TEMP1
, 16 },
337 { SENSOR_TEMP2
, 16 },
342 static int tegra_soctherm_probe(struct platform_device
*pdev
)
344 struct tegra_soctherm
*tegra
;
345 struct thermal_zone_device
*tz
;
346 struct tsensor_shared_calibration shared_calib
;
347 struct resource
*res
;
351 const struct tegra_tsensor
*tsensors
= t124_tsensors
;
353 tegra
= devm_kzalloc(&pdev
->dev
, sizeof(*tegra
), GFP_KERNEL
);
357 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
358 tegra
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
359 if (IS_ERR(tegra
->regs
))
360 return PTR_ERR(tegra
->regs
);
362 tegra
->reset
= devm_reset_control_get(&pdev
->dev
, "soctherm");
363 if (IS_ERR(tegra
->reset
)) {
364 dev_err(&pdev
->dev
, "can't get soctherm reset\n");
365 return PTR_ERR(tegra
->reset
);
368 tegra
->clock_tsensor
= devm_clk_get(&pdev
->dev
, "tsensor");
369 if (IS_ERR(tegra
->clock_tsensor
)) {
370 dev_err(&pdev
->dev
, "can't get tsensor clock\n");
371 return PTR_ERR(tegra
->clock_tsensor
);
374 tegra
->clock_soctherm
= devm_clk_get(&pdev
->dev
, "soctherm");
375 if (IS_ERR(tegra
->clock_soctherm
)) {
376 dev_err(&pdev
->dev
, "can't get soctherm clock\n");
377 return PTR_ERR(tegra
->clock_soctherm
);
380 reset_control_assert(tegra
->reset
);
382 err
= clk_prepare_enable(tegra
->clock_soctherm
);
386 err
= clk_prepare_enable(tegra
->clock_tsensor
);
388 clk_disable_unprepare(tegra
->clock_soctherm
);
392 reset_control_deassert(tegra
->reset
);
394 /* Initialize raw sensors */
396 err
= calculate_shared_calibration(&shared_calib
);
400 for (i
= 0; i
< ARRAY_SIZE(t124_tsensors
); ++i
) {
401 err
= enable_tsensor(tegra
, tsensors
+ i
, &shared_calib
);
406 writel(SENSOR_PDIV_T124
, tegra
->regs
+ SENSOR_PDIV
);
407 writel(SENSOR_HOTSPOT_OFF_T124
, tegra
->regs
+ SENSOR_HOTSPOT_OFF
);
409 /* Initialize thermctl sensors */
411 for (i
= 0; i
< ARRAY_SIZE(tegra
->thermctl_tzs
); ++i
) {
412 struct tegra_thermctl_zone
*zone
=
413 devm_kzalloc(&pdev
->dev
, sizeof(*zone
), GFP_KERNEL
);
419 zone
->reg
= tegra
->regs
+ t124_thermctl_temp_zones
[i
].offset
;
420 zone
->shift
= t124_thermctl_temp_zones
[i
].shift
;
422 tz
= thermal_zone_of_sensor_register(&pdev
->dev
, i
, zone
,
423 &tegra_of_thermal_ops
);
426 dev_err(&pdev
->dev
, "failed to register sensor: %d\n",
431 tegra
->thermctl_tzs
[i
] = tz
;
438 thermal_zone_of_sensor_unregister(&pdev
->dev
,
439 tegra
->thermctl_tzs
[i
]);
442 clk_disable_unprepare(tegra
->clock_tsensor
);
443 clk_disable_unprepare(tegra
->clock_soctherm
);
448 static int tegra_soctherm_remove(struct platform_device
*pdev
)
450 struct tegra_soctherm
*tegra
= platform_get_drvdata(pdev
);
453 for (i
= 0; i
< ARRAY_SIZE(tegra
->thermctl_tzs
); ++i
) {
454 thermal_zone_of_sensor_unregister(&pdev
->dev
,
455 tegra
->thermctl_tzs
[i
]);
458 clk_disable_unprepare(tegra
->clock_tsensor
);
459 clk_disable_unprepare(tegra
->clock_soctherm
);
464 static struct platform_driver tegra_soctherm_driver
= {
465 .probe
= tegra_soctherm_probe
,
466 .remove
= tegra_soctherm_remove
,
468 .name
= "tegra-soctherm",
469 .of_match_table
= tegra_soctherm_of_match
,
472 module_platform_driver(tegra_soctherm_driver
);
474 MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
475 MODULE_DESCRIPTION("NVIDIA Tegra SOCTHERM thermal management driver");
476 MODULE_LICENSE("GPL v2");