aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei Ni <wni@nvidia.com>2016-03-29 06:29:14 -0400
committerEduardo Valentin <edubezval@gmail.com>2016-05-17 10:28:28 -0400
commit65b6d57c24ed0aff1fc571e42d8f51bdfcce9a8e (patch)
tree3e2594f80a4d68d263cfe28b6ed68c53dd46b052
parent1c3bdc1627c331b4925a95453f7b61226077bebe (diff)
thermal: tegra: split tegra_soctherm driver
Split most of the Tegra124 data and code into a Tegra124-specific file. Split most of the fuse-related code into a fuse-related source file. This is in preparation for adding a Tegra210-specific driver in a future patch. Beyond the maintainability improvements, this is intended to separate chip-specific ATE and characterization-related hacks into chip-specific files, in the hopes that they won't pollute code for other chips. Signed-off-by: Wei Ni <wni@nvidia.com> Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
-rw-r--r--drivers/thermal/tegra/Kconfig2
-rw-r--r--drivers/thermal/tegra/Makefile3
-rw-r--r--drivers/thermal/tegra/soctherm-fuse.c158
-rw-r--r--drivers/thermal/tegra/soctherm.c310
-rw-r--r--drivers/thermal/tegra/soctherm.h110
-rw-r--r--drivers/thermal/tegra/tegra-soctherm.c565
-rw-r--r--drivers/thermal/tegra/tegra124-soctherm.c172
7 files changed, 754 insertions, 566 deletions
diff --git a/drivers/thermal/tegra/Kconfig b/drivers/thermal/tegra/Kconfig
index bed898858d02..cec586ec7e4b 100644
--- a/drivers/thermal/tegra/Kconfig
+++ b/drivers/thermal/tegra/Kconfig
@@ -5,7 +5,7 @@ config TEGRA_SOCTHERM
5 tristate "Tegra SOCTHERM thermal management" 5 tristate "Tegra SOCTHERM thermal management"
6 help 6 help
7 Enable this option for integrated thermal management support on NVIDIA 7 Enable this option for integrated thermal management support on NVIDIA
8 Tegra124 systems-on-chip. The driver supports four thermal zones 8 Tegra systems-on-chip. The driver supports four thermal zones
9 (CPU, GPU, MEM, PLLX). Cooling devices can be bound to the thermal 9 (CPU, GPU, MEM, PLLX). Cooling devices can be bound to the thermal
10 zones to manage temperatures. This option is also required for the 10 zones to manage temperatures. This option is also required for the
11 emergency thermal reset (thermtrip) feature to function. 11 emergency thermal reset (thermtrip) feature to function.
diff --git a/drivers/thermal/tegra/Makefile b/drivers/thermal/tegra/Makefile
index d4dc4e7f279e..d5fb15377b97 100644
--- a/drivers/thermal/tegra/Makefile
+++ b/drivers/thermal/tegra/Makefile
@@ -1 +1,4 @@
1obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o 1obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o
2
3tegra-soctherm-y := soctherm.o soctherm-fuse.o
4tegra-soctherm-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124-soctherm.o
diff --git a/drivers/thermal/tegra/soctherm-fuse.c b/drivers/thermal/tegra/soctherm-fuse.c
new file mode 100644
index 000000000000..931c299ab0e8
--- /dev/null
+++ b/drivers/thermal/tegra/soctherm-fuse.c
@@ -0,0 +1,158 @@
1/*
2 * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#include <linux/module.h>
16#include <linux/platform_device.h>
17#include <soc/tegra/fuse.h>
18
19#include "soctherm.h"
20
21#define NOMINAL_CALIB_FT 105
22#define NOMINAL_CALIB_CP 25
23
24#define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK 0x1fff
25#define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK (0x1fff << 13)
26#define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13
27
28#define FUSE_TSENSOR_COMMON 0x180
29
30/*
31 * Tegra12x, etc:
32 * FUSE_TSENSOR_COMMON:
33 * 3 2 1 0
34 * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
35 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * |-----------| SHFT_FT | BASE_FT | BASE_CP |
37 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 *
39 * FUSE_SPARE_REALIGNMENT_REG:
40 * 3 2 1 0
41 * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
42 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 * |---------------------------------------------------| SHIFT_CP |
44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 */
46
47#define CALIB_COEFFICIENT 1000000LL
48
49/**
50 * div64_s64_precise() - wrapper for div64_s64()
51 * @a: the dividend
52 * @b: the divisor
53 *
54 * Implements division with fairly accurate rounding instead of truncation by
55 * shifting the dividend to the left by 16 so that the quotient has a
56 * much higher precision.
57 *
58 * Return: the quotient of a / b.
59 */
60static s64 div64_s64_precise(s64 a, s32 b)
61{
62 s64 r, al;
63
64 /* Scale up for increased precision division */
65 al = a << 16;
66
67 r = div64_s64(al * 2 + 1, 2 * b);
68 return r >> 16;
69}
70
71int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse,
72 struct tsensor_shared_calib *shared)
73{
74 u32 val;
75 s32 shifted_cp, shifted_ft;
76 int err;
77
78 err = tegra_fuse_readl(FUSE_TSENSOR_COMMON, &val);
79 if (err)
80 return err;
81
82 shared->base_cp = (val & tfuse->fuse_base_cp_mask) >>
83 tfuse->fuse_base_cp_shift;
84 shared->base_ft = (val & tfuse->fuse_base_ft_mask) >>
85 tfuse->fuse_base_ft_shift;
86
87 shifted_ft = (val & tfuse->fuse_shift_ft_mask) >>
88 tfuse->fuse_shift_ft_shift;
89 shifted_ft = sign_extend32(shifted_ft, 4);
90
91 if (tfuse->fuse_spare_realignment) {
92 err = tegra_fuse_readl(tfuse->fuse_spare_realignment, &val);
93 if (err)
94 return err;
95 }
96
97 shifted_cp = sign_extend32(val, 5);
98
99 shared->actual_temp_cp = 2 * NOMINAL_CALIB_CP + shifted_cp;
100 shared->actual_temp_ft = 2 * NOMINAL_CALIB_FT + shifted_ft;
101
102 return 0;
103}
104
105int tegra_calc_tsensor_calib(const struct tegra_tsensor *sensor,
106 const struct tsensor_shared_calib *shared,
107 u32 *calibration)
108{
109 const struct tegra_tsensor_group *sensor_group;
110 u32 val, calib;
111 s32 actual_tsensor_ft, actual_tsensor_cp;
112 s32 delta_sens, delta_temp;
113 s32 mult, div;
114 s16 therma, thermb;
115 s64 temp;
116 int err;
117
118 sensor_group = sensor->group;
119
120 err = tegra_fuse_readl(sensor->calib_fuse_offset, &val);
121 if (err)
122 return err;
123
124 actual_tsensor_cp = (shared->base_cp * 64) + sign_extend32(val, 12);
125 val = (val & FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK) >>
126 FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT;
127 actual_tsensor_ft = (shared->base_ft * 32) + sign_extend32(val, 12);
128
129 delta_sens = actual_tsensor_ft - actual_tsensor_cp;
130 delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
131
132 mult = sensor_group->pdiv * sensor->config->tsample_ate;
133 div = sensor->config->tsample * sensor_group->pdiv_ate;
134
135 temp = (s64)delta_temp * (1LL << 13) * mult;
136 therma = div64_s64_precise(temp, (s64)delta_sens * div);
137
138 temp = ((s64)actual_tsensor_ft * shared->actual_temp_cp) -
139 ((s64)actual_tsensor_cp * shared->actual_temp_ft);
140 thermb = div64_s64_precise(temp, delta_sens);
141
142 temp = (s64)therma * sensor->fuse_corr_alpha;
143 therma = div64_s64_precise(temp, CALIB_COEFFICIENT);
144
145 temp = (s64)thermb * sensor->fuse_corr_alpha + sensor->fuse_corr_beta;
146 thermb = div64_s64_precise(temp, CALIB_COEFFICIENT);
147
148 calib = ((u16)therma << SENSOR_CONFIG2_THERMA_SHIFT) |
149 ((u16)thermb << SENSOR_CONFIG2_THERMB_SHIFT);
150
151 *calibration = calib;
152
153 return 0;
154}
155
156MODULE_AUTHOR("Wei Ni <wni@nvidia.com>");
157MODULE_DESCRIPTION("Tegra SOCTHERM fuse management");
158MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c
new file mode 100644
index 000000000000..d9b23cded69f
--- /dev/null
+++ b/drivers/thermal/tegra/soctherm.c
@@ -0,0 +1,310 @@
1/*
2 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Author:
5 * Mikko Perttunen <mperttunen@nvidia.com>
6 *
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.
10 *
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.
15 *
16 */
17
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>
23#include <linux/io.h>
24#include <linux/module.h>
25#include <linux/of.h>
26#include <linux/platform_device.h>
27#include <linux/reset.h>
28#include <linux/thermal.h>
29
30#include <dt-bindings/thermal/tegra124-soctherm.h>
31
32#include "soctherm.h"
33
34#define SENSOR_CONFIG0 0
35#define SENSOR_CONFIG0_STOP BIT(0)
36#define SENSOR_CONFIG0_TALL_SHIFT 8
37#define SENSOR_CONFIG0_TCALC_OVER BIT(4)
38#define SENSOR_CONFIG0_OVER BIT(3)
39#define SENSOR_CONFIG0_CPTR_OVER BIT(2)
40
41#define SENSOR_CONFIG1 4
42#define SENSOR_CONFIG1_TSAMPLE_SHIFT 0
43#define SENSOR_CONFIG1_TIDDQ_EN_SHIFT 15
44#define SENSOR_CONFIG1_TEN_COUNT_SHIFT 24
45#define SENSOR_CONFIG1_TEMP_ENABLE BIT(31)
46
47/*
48 * SENSOR_CONFIG2 is defined in soctherm.h
49 * because, it will be used by tegra_soctherm_fuse.c
50 */
51
52#define READBACK_VALUE_MASK 0xff00
53#define READBACK_VALUE_SHIFT 8
54#define READBACK_ADD_HALF BIT(7)
55#define READBACK_NEGATE BIT(0)
56
57/* get val from register(r) mask bits(m) */
58#define REG_GET_MASK(r, m) (((r) & (m)) >> (ffs(m) - 1))
59/* set val(v) to mask bits(m) of register(r) */
60#define REG_SET_MASK(r, m, v) (((r) & ~(m)) | \
61 (((v) & (m >> (ffs(m) - 1))) << (ffs(m) - 1)))
62
63struct tegra_thermctl_zone {
64 void __iomem *reg;
65 u32 mask;
66};
67
68struct tegra_soctherm {
69 struct reset_control *reset;
70 struct clk *clock_tsensor;
71 struct clk *clock_soctherm;
72 void __iomem *regs;
73
74 u32 *calib;
75 struct tegra_soctherm_soc *soc;
76};
77
78static int enable_tsensor(struct tegra_soctherm *tegra,
79 unsigned int i,
80 const struct tsensor_shared_calib *shared)
81{
82 const struct tegra_tsensor *sensor = &tegra->soc->tsensors[i];
83 void __iomem *base = tegra->regs + sensor->base;
84 u32 *calib = &tegra->calib[i];
85 unsigned int val;
86 int err;
87
88 err = tegra_calc_tsensor_calib(sensor, shared, calib);
89 if (err)
90 return err;
91
92 val = sensor->config->tall << SENSOR_CONFIG0_TALL_SHIFT;
93 writel(val, base + SENSOR_CONFIG0);
94
95 val = (sensor->config->tsample - 1) << SENSOR_CONFIG1_TSAMPLE_SHIFT;
96 val |= sensor->config->tiddq_en << SENSOR_CONFIG1_TIDDQ_EN_SHIFT;
97 val |= sensor->config->ten_count << SENSOR_CONFIG1_TEN_COUNT_SHIFT;
98 val |= SENSOR_CONFIG1_TEMP_ENABLE;
99 writel(val, base + SENSOR_CONFIG1);
100
101 writel(*calib, base + SENSOR_CONFIG2);
102
103 return 0;
104}
105
106/*
107 * Translate from soctherm readback format to millicelsius.
108 * The soctherm readback format in bits is as follows:
109 * TTTTTTTT H______N
110 * where T's contain the temperature in Celsius,
111 * H denotes an addition of 0.5 Celsius and N denotes negation
112 * of the final value.
113 */
114static int translate_temp(u16 val)
115{
116 int t;
117
118 t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000;
119 if (val & READBACK_ADD_HALF)
120 t += 500;
121 if (val & READBACK_NEGATE)
122 t *= -1;
123
124 return t;
125}
126
127static int tegra_thermctl_get_temp(void *data, int *out_temp)
128{
129 struct tegra_thermctl_zone *zone = data;
130 u32 val;
131
132 val = readl(zone->reg);
133 val = REG_GET_MASK(val, zone->mask);
134 *out_temp = translate_temp(val);
135
136 return 0;
137}
138
139static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = {
140 .get_temp = tegra_thermctl_get_temp,
141};
142
143static const struct of_device_id tegra_soctherm_of_match[] = {
144#ifdef CONFIG_ARCH_TEGRA_124_SOC
145 {
146 .compatible = "nvidia,tegra124-soctherm",
147 .data = &tegra124_soctherm,
148 },
149#endif
150 { },
151};
152MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match);
153
154static int tegra_soctherm_probe(struct platform_device *pdev)
155{
156 const struct of_device_id *match;
157 struct tegra_soctherm *tegra;
158 struct thermal_zone_device *z;
159 struct tsensor_shared_calib shared_calib;
160 struct resource *res;
161 struct tegra_soctherm_soc *soc;
162 unsigned int i;
163 int err;
164 u32 pdiv, hotspot;
165
166 match = of_match_node(tegra_soctherm_of_match, pdev->dev.of_node);
167 if (!match)
168 return -ENODEV;
169
170 soc = (struct tegra_soctherm_soc *)match->data;
171 if (soc->num_ttgs > TEGRA124_SOCTHERM_SENSOR_NUM)
172 return -EINVAL;
173
174 tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
175 if (!tegra)
176 return -ENOMEM;
177
178 dev_set_drvdata(&pdev->dev, tegra);
179
180 tegra->soc = soc;
181
182 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
183 tegra->regs = devm_ioremap_resource(&pdev->dev, res);
184 if (IS_ERR(tegra->regs))
185 return PTR_ERR(tegra->regs);
186
187 tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm");
188 if (IS_ERR(tegra->reset)) {
189 dev_err(&pdev->dev, "can't get soctherm reset\n");
190 return PTR_ERR(tegra->reset);
191 }
192
193 tegra->clock_tsensor = devm_clk_get(&pdev->dev, "tsensor");
194 if (IS_ERR(tegra->clock_tsensor)) {
195 dev_err(&pdev->dev, "can't get tsensor clock\n");
196 return PTR_ERR(tegra->clock_tsensor);
197 }
198
199 tegra->clock_soctherm = devm_clk_get(&pdev->dev, "soctherm");
200 if (IS_ERR(tegra->clock_soctherm)) {
201 dev_err(&pdev->dev, "can't get soctherm clock\n");
202 return PTR_ERR(tegra->clock_soctherm);
203 }
204
205 reset_control_assert(tegra->reset);
206
207 err = clk_prepare_enable(tegra->clock_soctherm);
208 if (err)
209 return err;
210
211 err = clk_prepare_enable(tegra->clock_tsensor);
212 if (err) {
213 clk_disable_unprepare(tegra->clock_soctherm);
214 return err;
215 }
216
217 reset_control_deassert(tegra->reset);
218
219 /* Initialize raw sensors */
220
221 tegra->calib = devm_kzalloc(&pdev->dev,
222 sizeof(u32) * soc->num_tsensors,
223 GFP_KERNEL);
224 if (!tegra->calib) {
225 err = -ENOMEM;
226 goto disable_clocks;
227 }
228
229 err = tegra_calc_shared_calib(soc->tfuse, &shared_calib);
230 if (err)
231 goto disable_clocks;
232
233 for (i = 0; i < soc->num_tsensors; ++i) {
234 err = enable_tsensor(tegra, i, &shared_calib);
235 if (err)
236 goto disable_clocks;
237 }
238
239 /* Program pdiv and hotspot offsets per THERM */
240 pdiv = readl(tegra->regs + SENSOR_PDIV);
241 hotspot = readl(tegra->regs + SENSOR_HOTSPOT_OFF);
242 for (i = 0; i < soc->num_ttgs; ++i) {
243 pdiv = REG_SET_MASK(pdiv, soc->ttgs[i]->pdiv_mask,
244 soc->ttgs[i]->pdiv);
245 /* hotspot offset from PLLX, doesn't need to configure PLLX */
246 if (soc->ttgs[i]->id == TEGRA124_SOCTHERM_SENSOR_PLLX)
247 continue;
248 hotspot = REG_SET_MASK(hotspot,
249 soc->ttgs[i]->pllx_hotspot_mask,
250 soc->ttgs[i]->pllx_hotspot_diff);
251 }
252 writel(pdiv, tegra->regs + SENSOR_PDIV);
253 writel(hotspot, tegra->regs + SENSOR_HOTSPOT_OFF);
254
255 /* Initialize thermctl sensors */
256
257 for (i = 0; i < soc->num_ttgs; ++i) {
258 struct tegra_thermctl_zone *zone =
259 devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL);
260 if (!zone) {
261 err = -ENOMEM;
262 goto disable_clocks;
263 }
264
265 zone->reg = tegra->regs + soc->ttgs[i]->sensor_temp_offset;
266 zone->mask = soc->ttgs[i]->sensor_temp_mask;
267
268 z = devm_thermal_zone_of_sensor_register(&pdev->dev,
269 soc->ttgs[i]->id, zone,
270 &tegra_of_thermal_ops);
271 if (IS_ERR(z)) {
272 err = PTR_ERR(z);
273 dev_err(&pdev->dev, "failed to register sensor: %d\n",
274 err);
275 goto disable_clocks;
276 }
277 }
278
279 return 0;
280
281disable_clocks:
282 clk_disable_unprepare(tegra->clock_tsensor);
283 clk_disable_unprepare(tegra->clock_soctherm);
284
285 return err;
286}
287
288static int tegra_soctherm_remove(struct platform_device *pdev)
289{
290 struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
291
292 clk_disable_unprepare(tegra->clock_tsensor);
293 clk_disable_unprepare(tegra->clock_soctherm);
294
295 return 0;
296}
297
298static struct platform_driver tegra_soctherm_driver = {
299 .probe = tegra_soctherm_probe,
300 .remove = tegra_soctherm_remove,
301 .driver = {
302 .name = "tegra_soctherm",
303 .of_match_table = tegra_soctherm_of_match,
304 },
305};
306module_platform_driver(tegra_soctherm_driver);
307
308MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
309MODULE_DESCRIPTION("NVIDIA Tegra SOCTHERM thermal management driver");
310MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/tegra/soctherm.h b/drivers/thermal/tegra/soctherm.h
new file mode 100644
index 000000000000..f80ee1492ddb
--- /dev/null
+++ b/drivers/thermal/tegra/soctherm.h
@@ -0,0 +1,110 @@
1/*
2 * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#ifndef __DRIVERS_THERMAL_TEGRA_SOCTHERM_H
16#define __DRIVERS_THERMAL_TEGRA_SOCTHERM_H
17
18#define SENSOR_CONFIG2 8
19#define SENSOR_CONFIG2_THERMA_SHIFT 16
20#define SENSOR_CONFIG2_THERMB_SHIFT 0
21
22#define SENSOR_PDIV 0x1c0
23#define SENSOR_PDIV_CPU_MASK (0xf << 12)
24#define SENSOR_PDIV_GPU_MASK (0xf << 8)
25#define SENSOR_PDIV_MEM_MASK (0xf << 4)
26#define SENSOR_PDIV_PLLX_MASK (0xf << 0)
27
28#define SENSOR_HOTSPOT_OFF 0x1c4
29#define SENSOR_HOTSPOT_CPU_MASK (0xff << 16)
30#define SENSOR_HOTSPOT_GPU_MASK (0xff << 8)
31#define SENSOR_HOTSPOT_MEM_MASK (0xff << 0)
32
33#define SENSOR_TEMP1 0x1c8
34#define SENSOR_TEMP1_CPU_TEMP_MASK (0xffff << 16)
35#define SENSOR_TEMP1_GPU_TEMP_MASK 0xffff
36#define SENSOR_TEMP2 0x1cc
37#define SENSOR_TEMP2_MEM_TEMP_MASK (0xffff << 16)
38#define SENSOR_TEMP2_PLLX_TEMP_MASK 0xffff
39
40/**
41 * struct tegra_tsensor_group - SOC_THERM sensor group data
42 * @name: short name of the temperature sensor group
43 * @id: numeric ID of the temperature sensor group
44 * @sensor_temp_offset: offset of the SENSOR_TEMP* register
45 * @sensor_temp_mask: bit mask for this sensor group in SENSOR_TEMP* register
46 * @pdiv: the sensor count post-divider to use during runtime
47 * @pdiv_ate: the sensor count post-divider used during automated test
48 * @pdiv_mask: register bitfield mask for the PDIV field for this sensor
49 * @pllx_hotspot_diff: hotspot offset from the PLLX sensor, must be 0 for
50 PLLX sensor group
51 * @pllx_hotspot_mask: register bitfield mask for the HOTSPOT field
52 */
53struct tegra_tsensor_group {
54 const char *name;
55 u8 id;
56 u16 sensor_temp_offset;
57 u32 sensor_temp_mask;
58 u32 pdiv, pdiv_ate, pdiv_mask;
59 u32 pllx_hotspot_diff, pllx_hotspot_mask;
60};
61
62struct tegra_tsensor_configuration {
63 u32 tall, tiddq_en, ten_count, pdiv, pdiv_ate, tsample, tsample_ate;
64};
65
66struct tegra_tsensor {
67 const char *name;
68 const u32 base;
69 const struct tegra_tsensor_configuration *config;
70 const u32 calib_fuse_offset;
71 /*
72 * Correction values used to modify values read from
73 * calibration fuses
74 */
75 const s32 fuse_corr_alpha, fuse_corr_beta;
76 const struct tegra_tsensor_group *group;
77};
78
79struct tegra_soctherm_fuse {
80 u32 fuse_base_cp_mask, fuse_base_cp_shift;
81 u32 fuse_base_ft_mask, fuse_base_ft_shift;
82 u32 fuse_shift_ft_mask, fuse_shift_ft_shift;
83 u32 fuse_spare_realignment;
84};
85
86struct tsensor_shared_calib {
87 u32 base_cp, base_ft;
88 u32 actual_temp_cp, actual_temp_ft;
89};
90
91struct tegra_soctherm_soc {
92 const struct tegra_tsensor *tsensors;
93 const unsigned int num_tsensors;
94 const struct tegra_tsensor_group **ttgs;
95 const unsigned int num_ttgs;
96 const struct tegra_soctherm_fuse *tfuse;
97};
98
99int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse,
100 struct tsensor_shared_calib *shared);
101int tegra_calc_tsensor_calib(const struct tegra_tsensor *sensor,
102 const struct tsensor_shared_calib *shared,
103 u32 *calib);
104
105#ifdef CONFIG_ARCH_TEGRA_124_SOC
106extern const struct tegra_soctherm_soc tegra124_soctherm;
107#endif
108
109#endif
110
diff --git a/drivers/thermal/tegra/tegra-soctherm.c b/drivers/thermal/tegra/tegra-soctherm.c
deleted file mode 100644
index e486d034adb4..000000000000
--- a/drivers/thermal/tegra/tegra-soctherm.c
+++ /dev/null
@@ -1,565 +0,0 @@
1/*
2 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Author:
5 * Mikko Perttunen <mperttunen@nvidia.com>
6 *
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.
10 *
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.
15 *
16 */
17
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>
23#include <linux/io.h>
24#include <linux/module.h>
25#include <linux/of.h>
26#include <linux/platform_device.h>
27#include <linux/reset.h>
28#include <linux/thermal.h>
29
30#include <soc/tegra/fuse.h>
31#include <dt-bindings/thermal/tegra124-soctherm.h>
32
33#define SENSOR_CONFIG0 0
34#define SENSOR_CONFIG0_STOP BIT(0)
35#define SENSOR_CONFIG0_TALL_SHIFT 8
36#define SENSOR_CONFIG0_TCALC_OVER BIT(4)
37#define SENSOR_CONFIG0_OVER BIT(3)
38#define SENSOR_CONFIG0_CPTR_OVER BIT(2)
39
40#define SENSOR_CONFIG1 4
41#define SENSOR_CONFIG1_TSAMPLE_SHIFT 0
42#define SENSOR_CONFIG1_TIDDQ_EN_SHIFT 15
43#define SENSOR_CONFIG1_TEN_COUNT_SHIFT 24
44#define SENSOR_CONFIG1_TEMP_ENABLE BIT(31)
45
46#define SENSOR_CONFIG2 8
47#define SENSOR_CONFIG2_THERMA_SHIFT 16
48#define SENSOR_CONFIG2_THERMB_SHIFT 0
49
50#define SENSOR_PDIV 0x1c0
51#define SENSOR_PDIV_CPU_MASK (0xf << 12)
52#define SENSOR_PDIV_GPU_MASK (0xf << 8)
53#define SENSOR_PDIV_MEM_MASK (0xf << 4)
54#define SENSOR_PDIV_PLLX_MASK (0xf << 0)
55
56#define SENSOR_HOTSPOT_OFF 0x1c4
57#define SENSOR_HOTSPOT_CPU_MASK (0xff << 16)
58#define SENSOR_HOTSPOT_GPU_MASK (0xff << 8)
59#define SENSOR_HOTSPOT_MEM_MASK (0xff << 0)
60
61#define SENSOR_TEMP1 0x1c8
62#define SENSOR_TEMP1_CPU_TEMP_MASK (0xffff << 16)
63#define SENSOR_TEMP1_GPU_TEMP_MASK 0xffff
64#define SENSOR_TEMP2 0x1cc
65#define SENSOR_TEMP2_MEM_TEMP_MASK (0xffff << 16)
66#define SENSOR_TEMP2_PLLX_TEMP_MASK 0xffff
67
68#define READBACK_VALUE_MASK 0xff00
69#define READBACK_VALUE_SHIFT 8
70#define READBACK_ADD_HALF BIT(7)
71#define READBACK_NEGATE BIT(0)
72
73#define FUSE_TSENSOR8_CALIB 0x180
74#define FUSE_SPARE_REALIGNMENT_REG_0 0x1fc
75
76#define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK 0x1fff
77#define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK (0x1fff << 13)
78#define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13
79
80#define FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK 0x3ff
81#define FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK (0x7ff << 10)
82#define FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT 10
83
84#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_MASK 0x3f
85#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK (0x1f << 21)
86#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT 21
87
88#define NOMINAL_CALIB_FT_T124 105
89#define NOMINAL_CALIB_CP_T124 25
90
91/* get val from register(r) mask bits(m) */
92#define REG_GET_MASK(r, m) (((r) & (m)) >> (ffs(m) - 1))
93/* set val(v) to mask bits(m) of register(r) */
94#define REG_SET_MASK(r, m, v) (((r) & ~(m)) | \
95 (((v) & (m >> (ffs(m) - 1))) << (ffs(m) - 1)))
96
97/**
98 * struct tegra_tsensor_group - SOC_THERM sensor group data
99 * @name: short name of the temperature sensor group
100 * @id: numeric ID of the temperature sensor group
101 * @sensor_temp_offset: offset of the SENSOR_TEMP* register
102 * @sensor_temp_mask: bit mask for this sensor group in SENSOR_TEMP* register
103 * @pdiv: the sensor count post-divider to use during runtime
104 * @pdiv_ate: the sensor count post-divider used during automated test
105 * @pdiv_mask: register bitfield mask for the PDIV field for this sensor
106 * @pllx_hotspot_diff: hotspot offset from the PLLX sensor, must be 0 for
107 PLLX sensor group
108 * @pllx_hotspot_mask: register bitfield mask for the HOTSPOT field
109 */
110struct tegra_tsensor_group {
111 const char *name;
112 u8 id;
113 u16 sensor_temp_offset;
114 u32 sensor_temp_mask;
115 u32 pdiv, pdiv_ate, pdiv_mask;
116 u32 pllx_hotspot_diff, pllx_hotspot_mask;
117};
118
119struct tegra_tsensor_configuration {
120 u32 tall, tiddq_en, ten_count, tsample, tsample_ate;
121};
122
123struct tegra_tsensor {
124 const struct tegra_tsensor_configuration *config;
125 u32 base, calib_fuse_offset;
126 /* Correction values used to modify values read from calibration fuses */
127 s32 fuse_corr_alpha, fuse_corr_beta;
128 const struct tegra_tsensor_group *group;
129};
130
131struct tegra_thermctl_zone {
132 void __iomem *reg;
133 u32 mask;
134};
135
136static const struct tegra_tsensor_configuration t124_tsensor_config = {
137 .tall = 16300,
138 .tiddq_en = 1,
139 .ten_count = 1,
140 .tsample = 120,
141 .tsample_ate = 480,
142};
143
144static const struct tegra_tsensor_group tegra124_tsensor_group_cpu = {
145 .id = TEGRA124_SOCTHERM_SENSOR_CPU,
146 .name = "cpu",
147 .sensor_temp_offset = SENSOR_TEMP1,
148 .sensor_temp_mask = SENSOR_TEMP1_CPU_TEMP_MASK,
149 .pdiv = 8,
150 .pdiv_ate = 8,
151 .pdiv_mask = SENSOR_PDIV_CPU_MASK,
152 .pllx_hotspot_diff = 10,
153 .pllx_hotspot_mask = SENSOR_HOTSPOT_CPU_MASK,
154};
155
156static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = {
157 .id = TEGRA124_SOCTHERM_SENSOR_GPU,
158 .name = "gpu",
159 .sensor_temp_offset = SENSOR_TEMP1,
160 .sensor_temp_mask = SENSOR_TEMP1_GPU_TEMP_MASK,
161 .pdiv = 8,
162 .pdiv_ate = 8,
163 .pdiv_mask = SENSOR_PDIV_GPU_MASK,
164 .pllx_hotspot_diff = 5,
165 .pllx_hotspot_mask = SENSOR_HOTSPOT_GPU_MASK,
166};
167
168static const struct tegra_tsensor_group tegra124_tsensor_group_pll = {
169 .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
170 .name = "pll",
171 .sensor_temp_offset = SENSOR_TEMP2,
172 .sensor_temp_mask = SENSOR_TEMP2_PLLX_TEMP_MASK,
173 .pdiv = 8,
174 .pdiv_ate = 8,
175 .pdiv_mask = SENSOR_PDIV_PLLX_MASK,
176 .pllx_hotspot_diff = 0,
177 .pllx_hotspot_mask = SENSOR_HOTSPOT_MEM_MASK,
178};
179
180static const struct tegra_tsensor_group tegra124_tsensor_group_mem = {
181 .id = TEGRA124_SOCTHERM_SENSOR_MEM,
182 .name = "mem",
183 .sensor_temp_offset = SENSOR_TEMP2,
184 .sensor_temp_mask = SENSOR_TEMP2_MEM_TEMP_MASK,
185 .pdiv = 8,
186 .pdiv_ate = 8,
187 .pdiv_mask = SENSOR_PDIV_MEM_MASK,
188};
189
190static const struct tegra_tsensor_group *
191tegra124_tsensor_groups[TEGRA124_SOCTHERM_SENSOR_NUM] = {
192 &tegra124_tsensor_group_cpu,
193 &tegra124_tsensor_group_gpu,
194 &tegra124_tsensor_group_pll,
195 &tegra124_tsensor_group_mem,
196};
197
198static const struct tegra_tsensor t124_tsensors[] = {
199 {
200 .config = &t124_tsensor_config,
201 .base = 0xc0,
202 .calib_fuse_offset = 0x098,
203 .fuse_corr_alpha = 1135400,
204 .fuse_corr_beta = -6266900,
205 .group = &tegra124_tsensor_group_cpu,
206 },
207 {
208 .config = &t124_tsensor_config,
209 .base = 0xe0,
210 .calib_fuse_offset = 0x084,
211 .fuse_corr_alpha = 1122220,
212 .fuse_corr_beta = -5700700,
213 .group = &tegra124_tsensor_group_cpu,
214 },
215 {
216 .config = &t124_tsensor_config,
217 .base = 0x100,
218 .calib_fuse_offset = 0x088,
219 .fuse_corr_alpha = 1127000,
220 .fuse_corr_beta = -6768200,
221 .group = &tegra124_tsensor_group_cpu,
222 },
223 {
224 .config = &t124_tsensor_config,
225 .base = 0x120,
226 .calib_fuse_offset = 0x12c,
227 .fuse_corr_alpha = 1110900,
228 .fuse_corr_beta = -6232000,
229 .group = &tegra124_tsensor_group_cpu,
230 },
231 {
232 .config = &t124_tsensor_config,
233 .base = 0x140,
234 .calib_fuse_offset = 0x158,
235 .fuse_corr_alpha = 1122300,
236 .fuse_corr_beta = -5936400,
237 .group = &tegra124_tsensor_group_mem,
238 },
239 {
240 .config = &t124_tsensor_config,
241 .base = 0x160,
242 .calib_fuse_offset = 0x15c,
243 .fuse_corr_alpha = 1145700,
244 .fuse_corr_beta = -7124600,
245 .group = &tegra124_tsensor_group_mem,
246 },
247 {
248 .config = &t124_tsensor_config,
249 .base = 0x180,
250 .calib_fuse_offset = 0x154,
251 .fuse_corr_alpha = 1120100,
252 .fuse_corr_beta = -6000500,
253 .group = &tegra124_tsensor_group_gpu,
254 },
255 {
256 .config = &t124_tsensor_config,
257 .base = 0x1a0,
258 .calib_fuse_offset = 0x160,
259 .fuse_corr_alpha = 1106500,
260 .fuse_corr_beta = -6729300,
261 .group = &tegra124_tsensor_group_pll,
262 },
263};
264
265struct tegra_soctherm {
266 struct reset_control *reset;
267 struct clk *clock_tsensor;
268 struct clk *clock_soctherm;
269 void __iomem *regs;
270};
271
272struct tsensor_shared_calibration {
273 u32 base_cp, base_ft;
274 u32 actual_temp_cp, actual_temp_ft;
275};
276
277static int calculate_shared_calibration(struct tsensor_shared_calibration *r)
278{
279 u32 val, shifted_cp, shifted_ft;
280 int err;
281
282 err = tegra_fuse_readl(FUSE_TSENSOR8_CALIB, &val);
283 if (err)
284 return err;
285 r->base_cp = val & FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK;
286 r->base_ft = (val & FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK)
287 >> FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT;
288 val = ((val & FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK)
289 >> FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT);
290 shifted_ft = sign_extend32(val, 4);
291
292 err = tegra_fuse_readl(FUSE_SPARE_REALIGNMENT_REG_0, &val);
293 if (err)
294 return err;
295 shifted_cp = sign_extend32(val, 5);
296
297 r->actual_temp_cp = 2 * NOMINAL_CALIB_CP_T124 + shifted_cp;
298 r->actual_temp_ft = 2 * NOMINAL_CALIB_FT_T124 + shifted_ft;
299
300 return 0;
301}
302
303static s64 div64_s64_precise(s64 a, s64 b)
304{
305 s64 r, al;
306
307 /* Scale up for increased precision division */
308 al = a << 16;
309
310 r = div64_s64(al * 2 + 1, 2 * b);
311 return r >> 16;
312}
313
314static int
315calculate_tsensor_calibration(const struct tegra_tsensor *sensor,
316 const struct tsensor_shared_calibration *shared,
317 u32 *calib)
318{
319 u32 val;
320 s32 actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp,
321 mult, div;
322 s16 therma, thermb;
323 s64 tmp;
324 int err;
325
326 err = tegra_fuse_readl(sensor->calib_fuse_offset, &val);
327 if (err)
328 return err;
329
330 actual_tsensor_cp = (shared->base_cp * 64) + sign_extend32(val, 12);
331 val = (val & FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK)
332 >> FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT;
333 actual_tsensor_ft = (shared->base_ft * 32) + sign_extend32(val, 12);
334
335 delta_sens = actual_tsensor_ft - actual_tsensor_cp;
336 delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
337
338 mult = sensor->group->pdiv * sensor->config->tsample_ate;
339 div = sensor->config->tsample * sensor->group->pdiv_ate;
340
341 therma = div64_s64_precise((s64) delta_temp * (1LL << 13) * mult,
342 (s64) delta_sens * div);
343
344 tmp = (s64)actual_tsensor_ft * shared->actual_temp_cp -
345 (s64)actual_tsensor_cp * shared->actual_temp_ft;
346 thermb = div64_s64_precise(tmp, (s64)delta_sens);
347
348 therma = div64_s64_precise((s64)therma * sensor->fuse_corr_alpha,
349 (s64)1000000LL);
350 thermb = div64_s64_precise((s64)thermb * sensor->fuse_corr_alpha +
351 sensor->fuse_corr_beta, (s64)1000000LL);
352
353 *calib = ((u16)therma << SENSOR_CONFIG2_THERMA_SHIFT) |
354 ((u16)thermb << SENSOR_CONFIG2_THERMB_SHIFT);
355
356 return 0;
357}
358
359static int enable_tsensor(struct tegra_soctherm *tegra,
360 const struct tegra_tsensor *sensor,
361 const struct tsensor_shared_calibration *shared)
362{
363 void __iomem *base = tegra->regs + sensor->base;
364 unsigned int val;
365 u32 calib;
366 int err;
367
368 err = calculate_tsensor_calibration(sensor, shared, &calib);
369 if (err)
370 return err;
371
372 val = sensor->config->tall << SENSOR_CONFIG0_TALL_SHIFT;
373 writel(val, base + SENSOR_CONFIG0);
374
375 val = (sensor->config->tsample - 1) << SENSOR_CONFIG1_TSAMPLE_SHIFT;
376 val |= sensor->config->tiddq_en << SENSOR_CONFIG1_TIDDQ_EN_SHIFT;
377 val |= sensor->config->ten_count << SENSOR_CONFIG1_TEN_COUNT_SHIFT;
378 val |= SENSOR_CONFIG1_TEMP_ENABLE;
379 writel(val, base + SENSOR_CONFIG1);
380
381 writel(calib, base + SENSOR_CONFIG2);
382
383 return 0;
384}
385
386/*
387 * Translate from soctherm readback format to millicelsius.
388 * The soctherm readback format in bits is as follows:
389 * TTTTTTTT H______N
390 * where T's contain the temperature in Celsius,
391 * H denotes an addition of 0.5 Celsius and N denotes negation
392 * of the final value.
393 */
394static int translate_temp(u16 val)
395{
396 long t;
397
398 t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000;
399 if (val & READBACK_ADD_HALF)
400 t += 500;
401 if (val & READBACK_NEGATE)
402 t *= -1;
403
404 return t;
405}
406
407static int tegra_thermctl_get_temp(void *data, int *out_temp)
408{
409 struct tegra_thermctl_zone *zone = data;
410 u32 val;
411
412 val = readl(zone->reg);
413 val = REG_GET_MASK(val, zone->mask);
414 *out_temp = translate_temp(val);
415
416 return 0;
417}
418
419static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = {
420 .get_temp = tegra_thermctl_get_temp,
421};
422
423static const struct of_device_id tegra_soctherm_of_match[] = {
424 { .compatible = "nvidia,tegra124-soctherm" },
425 { },
426};
427MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match);
428
429static int tegra_soctherm_probe(struct platform_device *pdev)
430{
431 struct tegra_soctherm *tegra;
432 struct thermal_zone_device *z;
433 struct tsensor_shared_calibration shared_calib;
434 struct resource *res;
435 unsigned int i;
436 int err;
437 u32 pdiv, hotspot;
438
439 const struct tegra_tsensor *tsensors = t124_tsensors;
440 const struct tegra_tsensor_group **ttgs = tegra124_tsensor_groups;
441
442 tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
443 if (!tegra)
444 return -ENOMEM;
445
446 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
447 tegra->regs = devm_ioremap_resource(&pdev->dev, res);
448 if (IS_ERR(tegra->regs))
449 return PTR_ERR(tegra->regs);
450
451 tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm");
452 if (IS_ERR(tegra->reset)) {
453 dev_err(&pdev->dev, "can't get soctherm reset\n");
454 return PTR_ERR(tegra->reset);
455 }
456
457 tegra->clock_tsensor = devm_clk_get(&pdev->dev, "tsensor");
458 if (IS_ERR(tegra->clock_tsensor)) {
459 dev_err(&pdev->dev, "can't get tsensor clock\n");
460 return PTR_ERR(tegra->clock_tsensor);
461 }
462
463 tegra->clock_soctherm = devm_clk_get(&pdev->dev, "soctherm");
464 if (IS_ERR(tegra->clock_soctherm)) {
465 dev_err(&pdev->dev, "can't get soctherm clock\n");
466 return PTR_ERR(tegra->clock_soctherm);
467 }
468
469 reset_control_assert(tegra->reset);
470
471 err = clk_prepare_enable(tegra->clock_soctherm);
472 if (err)
473 return err;
474
475 err = clk_prepare_enable(tegra->clock_tsensor);
476 if (err) {
477 clk_disable_unprepare(tegra->clock_soctherm);
478 return err;
479 }
480
481 reset_control_deassert(tegra->reset);
482
483 /* Initialize raw sensors */
484
485 err = calculate_shared_calibration(&shared_calib);
486 if (err)
487 goto disable_clocks;
488
489 for (i = 0; i < ARRAY_SIZE(t124_tsensors); ++i) {
490 err = enable_tsensor(tegra, tsensors + i, &shared_calib);
491 if (err)
492 goto disable_clocks;
493 }
494
495 /* Program pdiv and hotspot offsets per THERM */
496 pdiv = readl(tegra->regs + SENSOR_PDIV);
497 hotspot = readl(tegra->regs + SENSOR_HOTSPOT_OFF);
498 for (i = 0; i < TEGRA124_SOCTHERM_SENSOR_NUM; ++i) {
499 pdiv = REG_SET_MASK(pdiv, ttgs[i]->pdiv_mask,
500 ttgs[i]->pdiv);
501 /* hotspot offset from PLLX, doesn't need to configure PLLX */
502 if (ttgs[i]->id != TEGRA124_SOCTHERM_SENSOR_PLLX)
503 hotspot = REG_SET_MASK(hotspot,
504 ttgs[i]->pllx_hotspot_mask,
505 ttgs[i]->pllx_hotspot_diff);
506 }
507 writel(pdiv, tegra->regs + SENSOR_PDIV);
508 writel(hotspot, tegra->regs + SENSOR_HOTSPOT_OFF);
509
510 /* Initialize thermctl sensors */
511
512 for (i = 0; i < TEGRA124_SOCTHERM_SENSOR_NUM; ++i) {
513 struct tegra_thermctl_zone *zone =
514 devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL);
515 if (!zone) {
516 err = -ENOMEM;
517 goto disable_clocks;
518 }
519
520 zone->reg = tegra->regs + ttgs[i]->sensor_temp_offset;
521 zone->mask = ttgs[i]->sensor_temp_mask;
522
523 z = devm_thermal_zone_of_sensor_register(&pdev->dev,
524 ttgs[i]->id, zone,
525 &tegra_of_thermal_ops);
526 if (IS_ERR(z)) {
527 err = PTR_ERR(z);
528 dev_err(&pdev->dev, "failed to register sensor: %d\n",
529 err);
530 goto disable_clocks;
531 }
532 }
533
534 return 0;
535
536disable_clocks:
537 clk_disable_unprepare(tegra->clock_tsensor);
538 clk_disable_unprepare(tegra->clock_soctherm);
539
540 return err;
541}
542
543static int tegra_soctherm_remove(struct platform_device *pdev)
544{
545 struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
546
547 clk_disable_unprepare(tegra->clock_tsensor);
548 clk_disable_unprepare(tegra->clock_soctherm);
549
550 return 0;
551}
552
553static struct platform_driver tegra_soctherm_driver = {
554 .probe = tegra_soctherm_probe,
555 .remove = tegra_soctherm_remove,
556 .driver = {
557 .name = "tegra-soctherm",
558 .of_match_table = tegra_soctherm_of_match,
559 },
560};
561module_platform_driver(tegra_soctherm_driver);
562
563MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
564MODULE_DESCRIPTION("NVIDIA Tegra SOCTHERM thermal management driver");
565MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/tegra/tegra124-soctherm.c b/drivers/thermal/tegra/tegra124-soctherm.c
new file mode 100644
index 000000000000..06aad13a979f
--- /dev/null
+++ b/drivers/thermal/tegra/tegra124-soctherm.c
@@ -0,0 +1,172 @@
1/*
2 * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#include <linux/module.h>
16#include <linux/platform_device.h>
17
18#include <dt-bindings/thermal/tegra124-soctherm.h>
19
20#include "soctherm.h"
21
22static const struct tegra_tsensor_configuration tegra124_tsensor_config = {
23 .tall = 16300,
24 .tiddq_en = 1,
25 .ten_count = 1,
26 .tsample = 120,
27 .tsample_ate = 480,
28};
29
30static const struct tegra_tsensor_group tegra124_tsensor_group_cpu = {
31 .id = TEGRA124_SOCTHERM_SENSOR_CPU,
32 .name = "cpu",
33 .sensor_temp_offset = SENSOR_TEMP1,
34 .sensor_temp_mask = SENSOR_TEMP1_CPU_TEMP_MASK,
35 .pdiv = 8,
36 .pdiv_ate = 8,
37 .pdiv_mask = SENSOR_PDIV_CPU_MASK,
38 .pllx_hotspot_diff = 10,
39 .pllx_hotspot_mask = SENSOR_HOTSPOT_CPU_MASK,
40};
41
42static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = {
43 .id = TEGRA124_SOCTHERM_SENSOR_GPU,
44 .name = "gpu",
45 .sensor_temp_offset = SENSOR_TEMP1,
46 .sensor_temp_mask = SENSOR_TEMP1_GPU_TEMP_MASK,
47 .pdiv = 8,
48 .pdiv_ate = 8,
49 .pdiv_mask = SENSOR_PDIV_GPU_MASK,
50 .pllx_hotspot_diff = 5,
51 .pllx_hotspot_mask = SENSOR_HOTSPOT_GPU_MASK,
52};
53
54static const struct tegra_tsensor_group tegra124_tsensor_group_pll = {
55 .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
56 .name = "pll",
57 .sensor_temp_offset = SENSOR_TEMP2,
58 .sensor_temp_mask = SENSOR_TEMP2_PLLX_TEMP_MASK,
59 .pdiv = 8,
60 .pdiv_ate = 8,
61 .pdiv_mask = SENSOR_PDIV_PLLX_MASK,
62};
63
64static const struct tegra_tsensor_group tegra124_tsensor_group_mem = {
65 .id = TEGRA124_SOCTHERM_SENSOR_MEM,
66 .name = "mem",
67 .sensor_temp_offset = SENSOR_TEMP2,
68 .sensor_temp_mask = SENSOR_TEMP2_MEM_TEMP_MASK,
69 .pdiv = 8,
70 .pdiv_ate = 8,
71 .pdiv_mask = SENSOR_PDIV_MEM_MASK,
72 .pllx_hotspot_diff = 0,
73 .pllx_hotspot_mask = SENSOR_HOTSPOT_MEM_MASK,
74};
75
76static const struct tegra_tsensor_group *tegra124_tsensor_groups[] = {
77 &tegra124_tsensor_group_cpu,
78 &tegra124_tsensor_group_gpu,
79 &tegra124_tsensor_group_pll,
80 &tegra124_tsensor_group_mem,
81};
82
83static const struct tegra_tsensor tegra124_tsensors[] = {
84 {
85 .name = "cpu0",
86 .base = 0xc0,
87 .config = &tegra124_tsensor_config,
88 .calib_fuse_offset = 0x098,
89 .fuse_corr_alpha = 1135400,
90 .fuse_corr_beta = -6266900,
91 .group = &tegra124_tsensor_group_cpu,
92 }, {
93 .name = "cpu1",
94 .base = 0xe0,
95 .config = &tegra124_tsensor_config,
96 .calib_fuse_offset = 0x084,
97 .fuse_corr_alpha = 1122220,
98 .fuse_corr_beta = -5700700,
99 .group = &tegra124_tsensor_group_cpu,
100 }, {
101 .name = "cpu2",
102 .base = 0x100,
103 .config = &tegra124_tsensor_config,
104 .calib_fuse_offset = 0x088,
105 .fuse_corr_alpha = 1127000,
106 .fuse_corr_beta = -6768200,
107 .group = &tegra124_tsensor_group_cpu,
108 }, {
109 .name = "cpu3",
110 .base = 0x120,
111 .config = &tegra124_tsensor_config,
112 .calib_fuse_offset = 0x12c,
113 .fuse_corr_alpha = 1110900,
114 .fuse_corr_beta = -6232000,
115 .group = &tegra124_tsensor_group_cpu,
116 }, {
117 .name = "mem0",
118 .base = 0x140,
119 .config = &tegra124_tsensor_config,
120 .calib_fuse_offset = 0x158,
121 .fuse_corr_alpha = 1122300,
122 .fuse_corr_beta = -5936400,
123 .group = &tegra124_tsensor_group_mem,
124 }, {
125 .name = "mem1",
126 .base = 0x160,
127 .config = &tegra124_tsensor_config,
128 .calib_fuse_offset = 0x15c,
129 .fuse_corr_alpha = 1145700,
130 .fuse_corr_beta = -7124600,
131 .group = &tegra124_tsensor_group_mem,
132 }, {
133 .name = "gpu",
134 .base = 0x180,
135 .config = &tegra124_tsensor_config,
136 .calib_fuse_offset = 0x154,
137 .fuse_corr_alpha = 1120100,
138 .fuse_corr_beta = -6000500,
139 .group = &tegra124_tsensor_group_gpu,
140 }, {
141 .name = "pllx",
142 .base = 0x1a0,
143 .config = &tegra124_tsensor_config,
144 .calib_fuse_offset = 0x160,
145 .fuse_corr_alpha = 1106500,
146 .fuse_corr_beta = -6729300,
147 .group = &tegra124_tsensor_group_pll,
148 },
149};
150
151/*
152 * Mask/shift bits in FUSE_TSENSOR_COMMON and
153 * FUSE_TSENSOR_COMMON, which are described in
154 * tegra_soctherm_fuse.c
155 */
156static const struct tegra_soctherm_fuse tegra124_soctherm_fuse = {
157 .fuse_base_cp_mask = 0x3ff,
158 .fuse_base_cp_shift = 0,
159 .fuse_base_ft_mask = 0x7ff << 10,
160 .fuse_base_ft_shift = 10,
161 .fuse_shift_ft_mask = 0x1f << 21,
162 .fuse_shift_ft_shift = 21,
163 .fuse_spare_realignment = 0x1fc,
164};
165
166const struct tegra_soctherm_soc tegra124_soctherm = {
167 .tsensors = tegra124_tsensors,
168 .num_tsensors = ARRAY_SIZE(tegra124_tsensors),
169 .ttgs = tegra124_tsensor_groups,
170 .num_ttgs = ARRAY_SIZE(tegra124_tsensor_groups),
171 .tfuse = &tegra124_soctherm_fuse,
172};