thermal: tegra: split tegra_soctherm driver
[deliverable/linux.git] / drivers / thermal / tegra / soctherm.c
CommitLineData
65b6d57c
WN
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");
This page took 0.03608 seconds and 5 git commands to generate.