aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCaesar Wang <caesar.wang@rock-chips.com>2014-11-23 23:58:59 -0500
committerEduardo Valentin <edubezval@gmail.com>2014-11-24 13:35:07 -0500
commitcbac8f63943773218f7f804754209aaa4fae33f9 (patch)
tree4e244b1616c4b5a648b4599f44b01a66058b4dee
parent6962ad52a5971dc2c91b3afe7b8124c4a197bef0 (diff)
thermal: rockchip: add driver for thermal
Thermal is TS-ADC Controller module supports user-defined mode and automatic mode. User-defined mode refers,TSADC all the control signals entirely by software writing to register for direct control. Automaic mode refers to the module automatically poll TSADC output, and the results were checked.If you find that the temperature High in a period of time,an interrupt is generated to the processor down-measures taken;If the temperature over a period of time High, the resulting TSHUT gave CRU module,let it reset the entire chip, or via GPIO give PMIC. Signed-off-by: zhaoyifeng <zyf@rock-chips.com> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com> Reviewed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
-rw-r--r--drivers/thermal/Kconfig10
-rw-r--r--drivers/thermal/Makefile1
-rw-r--r--drivers/thermal/rockchip_thermal.c693
3 files changed, 704 insertions, 0 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 911c38aba6ef..af40db0df58e 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -155,6 +155,16 @@ config SPEAR_THERMAL
155 Enable this to plug the SPEAr thermal sensor driver into the Linux 155 Enable this to plug the SPEAr thermal sensor driver into the Linux
156 thermal framework. 156 thermal framework.
157 157
158config ROCKCHIP_THERMAL
159 tristate "Rockchip thermal driver"
160 depends on ARCH_ROCKCHIP
161 depends on RESET_CONTROLLER
162 help
163 Rockchip thermal driver provides support for Temperature sensor
164 ADC (TS-ADC) found on Rockchip SoCs. It supports one critical
165 trip point. Cpufreq is used as the cooling device and will throttle
166 CPUs when the Temperature crosses the passive trip point.
167
158config RCAR_THERMAL 168config RCAR_THERMAL
159 tristate "Renesas R-Car thermal driver" 169 tristate "Renesas R-Car thermal driver"
160 depends on ARCH_SHMOBILE || COMPILE_TEST 170 depends on ARCH_SHMOBILE || COMPILE_TEST
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 2b18e3ac581f..fa0dc486790f 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -23,6 +23,7 @@ thermal_sys-$(CONFIG_CLOCK_THERMAL) += clock_cooling.o
23 23
24# platform thermal drivers 24# platform thermal drivers
25obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o 25obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
26obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o
26obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o 27obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o
27obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o 28obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o
28obj-y += samsung/ 29obj-y += samsung/
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
new file mode 100644
index 000000000000..1bcddfc60e91
--- /dev/null
+++ b/drivers/thermal/rockchip_thermal.c
@@ -0,0 +1,693 @@
1/*
2 * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include <linux/clk.h>
15#include <linux/delay.h>
16#include <linux/interrupt.h>
17#include <linux/io.h>
18#include <linux/module.h>
19#include <linux/of.h>
20#include <linux/of_address.h>
21#include <linux/of_irq.h>
22#include <linux/platform_device.h>
23#include <linux/reset.h>
24#include <linux/thermal.h>
25
26/**
27 * If the temperature over a period of time High,
28 * the resulting TSHUT gave CRU module,let it reset the entire chip,
29 * or via GPIO give PMIC.
30 */
31enum tshut_mode {
32 TSHUT_MODE_CRU = 0,
33 TSHUT_MODE_GPIO,
34};
35
36/**
37 * the system Temperature Sensors tshut(tshut) polarity
38 * the bit 8 is tshut polarity.
39 * 0: low active, 1: high active
40 */
41enum tshut_polarity {
42 TSHUT_LOW_ACTIVE = 0,
43 TSHUT_HIGH_ACTIVE,
44};
45
46/**
47 * The system has three Temperature Sensors. channel 0 is reserved,
48 * channel 1 is for CPU, and channel 2 is for GPU.
49 */
50enum sensor_id {
51 SENSOR_CPU = 1,
52 SENSOR_GPU,
53};
54
55struct rockchip_tsadc_chip {
56 /* The hardware-controlled tshut property */
57 long tshut_temp;
58 enum tshut_mode tshut_mode;
59 enum tshut_polarity tshut_polarity;
60
61 /* Chip-wide methods */
62 void (*initialize)(void __iomem *reg, enum tshut_polarity p);
63 void (*irq_ack)(void __iomem *reg);
64 void (*control)(void __iomem *reg, bool on);
65
66 /* Per-sensor methods */
67 int (*get_temp)(int chn, void __iomem *reg, long *temp);
68 void (*set_tshut_temp)(int chn, void __iomem *reg, long temp);
69 void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);
70};
71
72struct rockchip_thermal_sensor {
73 struct rockchip_thermal_data *thermal;
74 struct thermal_zone_device *tzd;
75 enum sensor_id id;
76};
77
78#define NUM_SENSORS 2 /* Ignore unused sensor 0 */
79
80struct rockchip_thermal_data {
81 const struct rockchip_tsadc_chip *chip;
82 struct platform_device *pdev;
83 struct reset_control *reset;
84
85 struct rockchip_thermal_sensor sensors[NUM_SENSORS];
86
87 struct clk *clk;
88 struct clk *pclk;
89
90 void __iomem *regs;
91
92 long tshut_temp;
93 enum tshut_mode tshut_mode;
94 enum tshut_polarity tshut_polarity;
95};
96
97/* TSADC V2 Sensor info define: */
98#define TSADCV2_AUTO_CON 0x04
99#define TSADCV2_INT_EN 0x08
100#define TSADCV2_INT_PD 0x0c
101#define TSADCV2_DATA(chn) (0x20 + (chn) * 0x04)
102#define TSADCV2_COMP_SHUT(chn) (0x40 + (chn) * 0x04)
103#define TSADCV2_HIGHT_INT_DEBOUNCE 0x60
104#define TSADCV2_HIGHT_TSHUT_DEBOUNCE 0x64
105#define TSADCV2_AUTO_PERIOD 0x68
106#define TSADCV2_AUTO_PERIOD_HT 0x6c
107
108#define TSADCV2_AUTO_EN BIT(0)
109#define TSADCV2_AUTO_DISABLE ~BIT(0)
110#define TSADCV2_AUTO_SRC_EN(chn) BIT(4 + (chn))
111#define TSADCV2_AUTO_TSHUT_POLARITY_HIGH BIT(8)
112#define TSADCV2_AUTO_TSHUT_POLARITY_LOW ~BIT(8)
113
114#define TSADCV2_INT_SRC_EN(chn) BIT(chn)
115#define TSADCV2_SHUT_2GPIO_SRC_EN(chn) BIT(4 + (chn))
116#define TSADCV2_SHUT_2CRU_SRC_EN(chn) BIT(8 + (chn))
117
118#define TSADCV2_INT_PD_CLEAR ~BIT(8)
119
120#define TSADCV2_DATA_MASK 0xfff
121#define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT 4
122#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT 4
123#define TSADCV2_AUTO_PERIOD_TIME 250 /* msec */
124#define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* msec */
125
126struct tsadc_table {
127 unsigned long code;
128 long temp;
129};
130
131static const struct tsadc_table v2_code_table[] = {
132 {TSADCV2_DATA_MASK, -40000},
133 {3800, -40000},
134 {3792, -35000},
135 {3783, -30000},
136 {3774, -25000},
137 {3765, -20000},
138 {3756, -15000},
139 {3747, -10000},
140 {3737, -5000},
141 {3728, 0},
142 {3718, 5000},
143 {3708, 10000},
144 {3698, 15000},
145 {3688, 20000},
146 {3678, 25000},
147 {3667, 30000},
148 {3656, 35000},
149 {3645, 40000},
150 {3634, 45000},
151 {3623, 50000},
152 {3611, 55000},
153 {3600, 60000},
154 {3588, 65000},
155 {3575, 70000},
156 {3563, 75000},
157 {3550, 80000},
158 {3537, 85000},
159 {3524, 90000},
160 {3510, 95000},
161 {3496, 100000},
162 {3482, 105000},
163 {3467, 110000},
164 {3452, 115000},
165 {3437, 120000},
166 {3421, 125000},
167 {0, 125000},
168};
169
170static u32 rk_tsadcv2_temp_to_code(long temp)
171{
172 int high, low, mid;
173
174 low = 0;
175 high = ARRAY_SIZE(v2_code_table) - 1;
176 mid = (high + low) / 2;
177
178 if (temp < v2_code_table[low].temp || temp > v2_code_table[high].temp)
179 return 0;
180
181 while (low <= high) {
182 if (temp == v2_code_table[mid].temp)
183 return v2_code_table[mid].code;
184 else if (temp < v2_code_table[mid].temp)
185 high = mid - 1;
186 else
187 low = mid + 1;
188 mid = (low + high) / 2;
189 }
190
191 return 0;
192}
193
194static long rk_tsadcv2_code_to_temp(u32 code)
195{
196 int high, low, mid;
197
198 low = 0;
199 high = ARRAY_SIZE(v2_code_table) - 1;
200 mid = (high + low) / 2;
201
202 if (code > v2_code_table[low].code || code < v2_code_table[high].code)
203 return 125000; /* No code available, return max temperature */
204
205 while (low <= high) {
206 if (code >= v2_code_table[mid].code && code <
207 v2_code_table[mid - 1].code)
208 return v2_code_table[mid].temp;
209 else if (code < v2_code_table[mid].code)
210 low = mid + 1;
211 else
212 high = mid - 1;
213 mid = (low + high) / 2;
214 }
215
216 return 125000;
217}
218
219/**
220 * rk_tsadcv2_initialize - initialize TASDC Controller
221 * (1) Set TSADCV2_AUTO_PERIOD, configure the interleave between
222 * every two accessing of TSADC in normal operation.
223 * (2) Set TSADCV2_AUTO_PERIOD_HT, configure the interleave between
224 * every two accessing of TSADC after the temperature is higher
225 * than COM_SHUT or COM_INT.
226 * (3) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE,
227 * if the temperature is higher than COMP_INT or COMP_SHUT for
228 * "debounce" times, TSADC controller will generate interrupt or TSHUT.
229 */
230static void rk_tsadcv2_initialize(void __iomem *regs,
231 enum tshut_polarity tshut_polarity)
232{
233 if (tshut_polarity == TSHUT_HIGH_ACTIVE)
234 writel_relaxed(0 | (TSADCV2_AUTO_TSHUT_POLARITY_HIGH),
235 regs + TSADCV2_AUTO_CON);
236 else
237 writel_relaxed(0 | (TSADCV2_AUTO_TSHUT_POLARITY_LOW),
238 regs + TSADCV2_AUTO_CON);
239
240 writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
241 writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT,
242 regs + TSADCV2_HIGHT_INT_DEBOUNCE);
243 writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME,
244 regs + TSADCV2_AUTO_PERIOD_HT);
245 writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT,
246 regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE);
247}
248
249static void rk_tsadcv2_irq_ack(void __iomem *regs)
250{
251 u32 val;
252
253 val = readl_relaxed(regs + TSADCV2_INT_PD);
254 writel_relaxed(val & TSADCV2_INT_PD_CLEAR, regs + TSADCV2_INT_PD);
255}
256
257static void rk_tsadcv2_control(void __iomem *regs, bool enable)
258{
259 u32 val;
260
261 val = readl_relaxed(regs + TSADCV2_AUTO_CON);
262 if (enable)
263 val |= TSADCV2_AUTO_EN;
264 else
265 val &= ~TSADCV2_AUTO_EN;
266
267 writel_relaxed(val, regs + TSADCV2_AUTO_CON);
268}
269
270static int rk_tsadcv2_get_temp(int chn, void __iomem *regs, long *temp)
271{
272 u32 val;
273
274 /* the A/D value of the channel last conversion need some time */
275 val = readl_relaxed(regs + TSADCV2_DATA(chn));
276 if (val == 0)
277 return -EAGAIN;
278
279 *temp = rk_tsadcv2_code_to_temp(val);
280
281 return 0;
282}
283
284static void rk_tsadcv2_tshut_temp(int chn, void __iomem *regs, long temp)
285{
286 u32 tshut_value, val;
287
288 tshut_value = rk_tsadcv2_temp_to_code(temp);
289 writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn));
290
291 /* TSHUT will be valid */
292 val = readl_relaxed(regs + TSADCV2_AUTO_CON);
293 writel_relaxed(val | TSADCV2_AUTO_SRC_EN(chn), regs + TSADCV2_AUTO_CON);
294}
295
296static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs,
297 enum tshut_mode mode)
298{
299 u32 val;
300
301 val = readl_relaxed(regs + TSADCV2_INT_EN);
302 if (mode == TSHUT_MODE_GPIO) {
303 val &= ~TSADCV2_SHUT_2CRU_SRC_EN(chn);
304 val |= TSADCV2_SHUT_2GPIO_SRC_EN(chn);
305 } else {
306 val &= ~TSADCV2_SHUT_2GPIO_SRC_EN(chn);
307 val |= TSADCV2_SHUT_2CRU_SRC_EN(chn);
308 }
309
310 writel_relaxed(val, regs + TSADCV2_INT_EN);
311}
312
313static const struct rockchip_tsadc_chip rk3288_tsadc_data = {
314 .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */
315 .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */
316 .tshut_temp = 95000,
317
318 .initialize = rk_tsadcv2_initialize,
319 .irq_ack = rk_tsadcv2_irq_ack,
320 .control = rk_tsadcv2_control,
321 .get_temp = rk_tsadcv2_get_temp,
322 .set_tshut_temp = rk_tsadcv2_tshut_temp,
323 .set_tshut_mode = rk_tsadcv2_tshut_mode,
324};
325
326static const struct of_device_id of_rockchip_thermal_match[] = {
327 {
328 .compatible = "rockchip,rk3288-tsadc",
329 .data = (void *)&rk3288_tsadc_data,
330 },
331 { /* end */ },
332};
333MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
334
335static void
336rockchip_thermal_toggle_sensor(struct rockchip_thermal_sensor *sensor, bool on)
337{
338 struct thermal_zone_device *tzd = sensor->tzd;
339
340 tzd->ops->set_mode(tzd,
341 on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
342}
343
344static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
345{
346 struct rockchip_thermal_data *thermal = dev;
347 int i;
348
349 dev_dbg(&thermal->pdev->dev, "thermal alarm\n");
350
351 thermal->chip->irq_ack(thermal->regs);
352
353 for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
354 thermal_zone_device_update(thermal->sensors[i].tzd);
355
356 return IRQ_HANDLED;
357}
358
359static int rockchip_thermal_get_temp(void *_sensor, long *out_temp)
360{
361 struct rockchip_thermal_sensor *sensor = _sensor;
362 struct rockchip_thermal_data *thermal = sensor->thermal;
363 const struct rockchip_tsadc_chip *tsadc = sensor->thermal->chip;
364 int retval;
365
366 retval = tsadc->get_temp(sensor->id, thermal->regs, out_temp);
367 dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %ld, retval: %d\n",
368 sensor->id, *out_temp, retval);
369
370 return retval;
371}
372
373static const struct thermal_zone_of_device_ops rockchip_of_thermal_ops = {
374 .get_temp = rockchip_thermal_get_temp,
375};
376
377static int rockchip_configure_from_dt(struct device *dev,
378 struct device_node *np,
379 struct rockchip_thermal_data *thermal)
380{
381 u32 shut_temp, tshut_mode, tshut_polarity;
382
383 if (of_property_read_u32(np, "rockchip,hw-tshut-temp", &shut_temp)) {
384 dev_warn(dev,
385 "Missing tshut temp property, using default %ld\n",
386 thermal->chip->tshut_temp);
387 thermal->tshut_temp = thermal->chip->tshut_temp;
388 } else {
389 thermal->tshut_temp = shut_temp;
390 }
391
392 if (thermal->tshut_temp > INT_MAX) {
393 dev_err(dev, "Invalid tshut temperature specified: %ld\n",
394 thermal->tshut_temp);
395 return -ERANGE;
396 }
397
398 if (of_property_read_u32(np, "rockchip,hw-tshut-mode", &tshut_mode)) {
399 dev_warn(dev,
400 "Missing tshut mode property, using default (%s)\n",
401 thermal->chip->tshut_mode == TSHUT_MODE_GPIO ?
402 "gpio" : "cru");
403 thermal->tshut_mode = thermal->chip->tshut_mode;
404 } else {
405 thermal->tshut_mode = tshut_mode;
406 }
407
408 if (thermal->tshut_mode > 1) {
409 dev_err(dev, "Invalid tshut mode specified: %d\n",
410 thermal->tshut_mode);
411 return -EINVAL;
412 }
413
414 if (of_property_read_u32(np, "rockchip,hw-tshut-polarity",
415 &tshut_polarity)) {
416 dev_warn(dev,
417 "Missing tshut-polarity property, using default (%s)\n",
418 thermal->chip->tshut_polarity == TSHUT_LOW_ACTIVE ?
419 "low" : "high");
420 thermal->tshut_polarity = thermal->chip->tshut_polarity;
421 } else {
422 thermal->tshut_polarity = tshut_polarity;
423 }
424
425 if (thermal->tshut_polarity > 1) {
426 dev_err(dev, "Invalid tshut-polarity specified: %d\n",
427 thermal->tshut_polarity);
428 return -EINVAL;
429 }
430
431 return 0;
432}
433
434static int
435rockchip_thermal_register_sensor(struct platform_device *pdev,
436 struct rockchip_thermal_data *thermal,
437 struct rockchip_thermal_sensor *sensor,
438 enum sensor_id id)
439{
440 const struct rockchip_tsadc_chip *tsadc = thermal->chip;
441 int error;
442
443 tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode);
444 tsadc->set_tshut_temp(id, thermal->regs, thermal->tshut_temp);
445
446 sensor->thermal = thermal;
447 sensor->id = id;
448 sensor->tzd = thermal_zone_of_sensor_register(&pdev->dev, id, sensor,
449 &rockchip_of_thermal_ops);
450 if (IS_ERR(sensor->tzd)) {
451 error = PTR_ERR(sensor->tzd);
452 dev_err(&pdev->dev, "failed to register sensor %d: %d\n",
453 id, error);
454 return error;
455 }
456
457 return 0;
458}
459
460/*
461 * Reset TSADC Controller, reset all tsadc registers.
462 */
463static void rockchip_thermal_reset_controller(struct reset_control *reset)
464{
465 reset_control_assert(reset);
466 usleep_range(10, 20);
467 reset_control_deassert(reset);
468}
469
470static int rockchip_thermal_probe(struct platform_device *pdev)
471{
472 struct device_node *np = pdev->dev.of_node;
473 struct rockchip_thermal_data *thermal;
474 const struct of_device_id *match;
475 struct resource *res;
476 int irq;
477 int i;
478 int error;
479
480 match = of_match_node(of_rockchip_thermal_match, np);
481 if (!match)
482 return -ENXIO;
483
484 irq = platform_get_irq(pdev, 0);
485 if (irq < 0) {
486 dev_err(&pdev->dev, "no irq resource?\n");
487 return -EINVAL;
488 }
489
490 thermal = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
491 GFP_KERNEL);
492 if (!thermal)
493 return -ENOMEM;
494
495 thermal->pdev = pdev;
496
497 thermal->chip = (const struct rockchip_tsadc_chip *)match->data;
498 if (!thermal->chip)
499 return -EINVAL;
500
501 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
502 thermal->regs = devm_ioremap_resource(&pdev->dev, res);
503 if (IS_ERR(thermal->regs))
504 return PTR_ERR(thermal->regs);
505
506 thermal->reset = devm_reset_control_get(&pdev->dev, "tsadc-apb");
507 if (IS_ERR(thermal->reset)) {
508 error = PTR_ERR(thermal->reset);
509 dev_err(&pdev->dev, "failed to get tsadc reset: %d\n", error);
510 return error;
511 }
512
513 thermal->clk = devm_clk_get(&pdev->dev, "tsadc");
514 if (IS_ERR(thermal->clk)) {
515 error = PTR_ERR(thermal->clk);
516 dev_err(&pdev->dev, "failed to get tsadc clock: %d\n", error);
517 return error;
518 }
519
520 thermal->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
521 if (IS_ERR(thermal->pclk)) {
522 error = PTR_ERR(thermal->clk);
523 dev_err(&pdev->dev, "failed to get apb_pclk clock: %d\n",
524 error);
525 return error;
526 }
527
528 error = clk_prepare_enable(thermal->clk);
529 if (error) {
530 dev_err(&pdev->dev, "failed to enable converter clock: %d\n",
531 error);
532 return error;
533 }
534
535 error = clk_prepare_enable(thermal->pclk);
536 if (error) {
537 dev_err(&pdev->dev, "failed to enable pclk: %d\n", error);
538 goto err_disable_clk;
539 }
540
541 rockchip_thermal_reset_controller(thermal->reset);
542
543 error = rockchip_configure_from_dt(&pdev->dev, np, thermal);
544 if (error) {
545 dev_err(&pdev->dev, "failed to parse device tree data: %d\n",
546 error);
547 goto err_disable_pclk;
548 }
549
550 thermal->chip->initialize(thermal->regs, thermal->tshut_polarity);
551
552 error = rockchip_thermal_register_sensor(pdev, thermal,
553 &thermal->sensors[0],
554 SENSOR_CPU);
555 if (error) {
556 dev_err(&pdev->dev,
557 "failed to register CPU thermal sensor: %d\n", error);
558 goto err_disable_pclk;
559 }
560
561 error = rockchip_thermal_register_sensor(pdev, thermal,
562 &thermal->sensors[1],
563 SENSOR_GPU);
564 if (error) {
565 dev_err(&pdev->dev,
566 "failed to register GPU thermal sensor: %d\n", error);
567 goto err_unregister_cpu_sensor;
568 }
569
570 error = devm_request_threaded_irq(&pdev->dev, irq, NULL,
571 &rockchip_thermal_alarm_irq_thread,
572 IRQF_ONESHOT,
573 "rockchip_thermal", thermal);
574 if (error) {
575 dev_err(&pdev->dev,
576 "failed to request tsadc irq: %d\n", error);
577 goto err_unregister_gpu_sensor;
578 }
579
580 thermal->chip->control(thermal->regs, true);
581
582 for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
583 rockchip_thermal_toggle_sensor(&thermal->sensors[i], true);
584
585 platform_set_drvdata(pdev, thermal);
586
587 return 0;
588
589err_unregister_gpu_sensor:
590 thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[1].tzd);
591err_unregister_cpu_sensor:
592 thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[0].tzd);
593err_disable_pclk:
594 clk_disable_unprepare(thermal->pclk);
595err_disable_clk:
596 clk_disable_unprepare(thermal->clk);
597
598 return error;
599}
600
601static int rockchip_thermal_remove(struct platform_device *pdev)
602{
603 struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev);
604 int i;
605
606 for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) {
607 struct rockchip_thermal_sensor *sensor = &thermal->sensors[i];
608
609 rockchip_thermal_toggle_sensor(sensor, false);
610 thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd);
611 }
612
613 thermal->chip->control(thermal->regs, false);
614
615 clk_disable_unprepare(thermal->pclk);
616 clk_disable_unprepare(thermal->clk);
617
618 return 0;
619}
620
621static int __maybe_unused rockchip_thermal_suspend(struct device *dev)
622{
623 struct platform_device *pdev = to_platform_device(dev);
624 struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev);
625 int i;
626
627 for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
628 rockchip_thermal_toggle_sensor(&thermal->sensors[i], false);
629
630 thermal->chip->control(thermal->regs, false);
631
632 clk_disable(thermal->pclk);
633 clk_disable(thermal->clk);
634
635 return 0;
636}
637
638static int __maybe_unused rockchip_thermal_resume(struct device *dev)
639{
640 struct platform_device *pdev = to_platform_device(dev);
641 struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev);
642 int i;
643 int error;
644
645 error = clk_enable(thermal->clk);
646 if (error)
647 return error;
648
649 error = clk_enable(thermal->pclk);
650 if (error)
651 return error;
652
653 rockchip_thermal_reset_controller(thermal->reset);
654
655 thermal->chip->initialize(thermal->regs, thermal->tshut_polarity);
656
657 for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) {
658 enum sensor_id id = thermal->sensors[i].id;
659
660 thermal->chip->set_tshut_mode(id, thermal->regs,
661 thermal->tshut_mode);
662 thermal->chip->set_tshut_temp(id, thermal->regs,
663 thermal->tshut_temp);
664 }
665
666 thermal->chip->control(thermal->regs, true);
667
668 for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
669 rockchip_thermal_toggle_sensor(&thermal->sensors[i], true);
670
671 return 0;
672}
673
674static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
675 rockchip_thermal_suspend, rockchip_thermal_resume);
676
677static struct platform_driver rockchip_thermal_driver = {
678 .driver = {
679 .name = "rockchip-thermal",
680 .owner = THIS_MODULE,
681 .pm = &rockchip_thermal_pm_ops,
682 .of_match_table = of_rockchip_thermal_match,
683 },
684 .probe = rockchip_thermal_probe,
685 .remove = rockchip_thermal_remove,
686};
687
688module_platform_driver(rockchip_thermal_driver);
689
690MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
691MODULE_AUTHOR("Rockchip, Inc.");
692MODULE_LICENSE("GPL v2");
693MODULE_ALIAS("platform:rockchip-thermal");