aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid HERNANDEZ SANCHEZ <david.hernandezsanchez@st.com>2018-10-05 06:08:46 -0400
committerEduardo Valentin <edubezval@gmail.com>2018-10-25 13:44:52 -0400
commit1d693155607329adff57f5307d35a3a8320d4e7f (patch)
tree2a3489a360ac74d786468e461a1da1f310145358
parent7f1a22ce597c2d6410843628c7d240e7441a81a3 (diff)
thermal: add stm32 thermal driver
Add support for DTS thermal sensor that can be found on some STM32 platforms. This driver is based on OF and works in interrupt mode. It offers two temperature trip points: passive and critical. The first is intended for passive cooling notification while the second is used for over-temperature reset. Signed-off-by: David Hernandez Sanchez <david.hernandezsanchez@st.com> Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
-rw-r--r--drivers/thermal/Kconfig2
-rw-r--r--drivers/thermal/Makefile2
-rw-r--r--drivers/thermal/st/Kconfig14
-rw-r--r--drivers/thermal/st/Makefile1
-rw-r--r--drivers/thermal/st/stm_thermal.c760
5 files changed, 777 insertions, 2 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 82979880f985..1775d4438a58 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -432,7 +432,7 @@ source "drivers/thermal/samsung/Kconfig"
432endmenu 432endmenu
433 433
434menu "STMicroelectronics thermal drivers" 434menu "STMicroelectronics thermal drivers"
435depends on ARCH_STI && OF 435depends on (ARCH_STI || ARCH_STM32) && OF
436source "drivers/thermal/st/Kconfig" 436source "drivers/thermal/st/Kconfig"
437endmenu 437endmenu
438 438
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 610344eb3e03..82bb50dc6423 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -53,7 +53,7 @@ obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
53obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ 53obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/
54obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o 54obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
55obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o 55obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o
56obj-$(CONFIG_ST_THERMAL) += st/ 56obj-y += st/
57obj-$(CONFIG_QCOM_TSENS) += qcom/ 57obj-$(CONFIG_QCOM_TSENS) += qcom/
58obj-y += tegra/ 58obj-y += tegra/
59obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o 59obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
diff --git a/drivers/thermal/st/Kconfig b/drivers/thermal/st/Kconfig
index 490fdbe22eea..b80f9a9e4f8f 100644
--- a/drivers/thermal/st/Kconfig
+++ b/drivers/thermal/st/Kconfig
@@ -1,3 +1,7 @@
1#
2# STMicroelectronics thermal drivers configuration
3#
4
1config ST_THERMAL 5config ST_THERMAL
2 tristate "Thermal sensors on STMicroelectronics STi series of SoCs" 6 tristate "Thermal sensors on STMicroelectronics STi series of SoCs"
3 help 7 help
@@ -10,3 +14,13 @@ config ST_THERMAL_SYSCFG
10config ST_THERMAL_MEMMAP 14config ST_THERMAL_MEMMAP
11 select ST_THERMAL 15 select ST_THERMAL
12 tristate "STi series memory mapped access based thermal sensors" 16 tristate "STi series memory mapped access based thermal sensors"
17
18config STM32_THERMAL
19 tristate "Thermal framework support on STMicroelectronics STM32 series of SoCs"
20 depends on MACH_STM32MP157
21 default y
22 help
23 Support for thermal framework on STMicroelectronics STM32 series of
24 SoCs. This thermal driver allows to access to general thermal framework
25 functionalities and to acces to SoC sensor functionalities. This
26 configuration is fully dependent of MACH_STM32MP157.
diff --git a/drivers/thermal/st/Makefile b/drivers/thermal/st/Makefile
index b38878977bd8..b2b9e9b96296 100644
--- a/drivers/thermal/st/Makefile
+++ b/drivers/thermal/st/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_ST_THERMAL) := st_thermal.o 1obj-$(CONFIG_ST_THERMAL) := st_thermal.o
2obj-$(CONFIG_ST_THERMAL_SYSCFG) += st_thermal_syscfg.o 2obj-$(CONFIG_ST_THERMAL_SYSCFG) += st_thermal_syscfg.o
3obj-$(CONFIG_ST_THERMAL_MEMMAP) += st_thermal_memmap.o 3obj-$(CONFIG_ST_THERMAL_MEMMAP) += st_thermal_memmap.o
4obj-$(CONFIG_STM32_THERMAL) := stm_thermal.o \ No newline at end of file
diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
new file mode 100644
index 000000000000..47623da0f91b
--- /dev/null
+++ b/drivers/thermal/st/stm_thermal.c
@@ -0,0 +1,760 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
4 * Author: David Hernandez Sanchez <david.hernandezsanchez@st.com> for
5 * STMicroelectronics.
6 */
7
8#include <linux/clk.h>
9#include <linux/clk-provider.h>
10#include <linux/delay.h>
11#include <linux/err.h>
12#include <linux/interrupt.h>
13#include <linux/io.h>
14#include <linux/iopoll.h>
15#include <linux/module.h>
16#include <linux/of.h>
17#include <linux/of_address.h>
18#include <linux/of_device.h>
19#include <linux/platform_device.h>
20#include <linux/thermal.h>
21
22#include "../thermal_core.h"
23#include "../thermal_hwmon.h"
24
25/* DTS register offsets */
26#define DTS_CFGR1_OFFSET 0x0
27#define DTS_T0VALR1_OFFSET 0x8
28#define DTS_RAMPVALR_OFFSET 0X10
29#define DTS_ITR1_OFFSET 0x14
30#define DTS_DR_OFFSET 0x1C
31#define DTS_SR_OFFSET 0x20
32#define DTS_ITENR_OFFSET 0x24
33#define DTS_CIFR_OFFSET 0x28
34
35/* DTS_CFGR1 register mask definitions */
36#define HSREF_CLK_DIV_MASK GENMASK(30, 24)
37#define TS1_SMP_TIME_MASK GENMASK(19, 16)
38#define TS1_INTRIG_SEL_MASK GENMASK(11, 8)
39
40/* DTS_T0VALR1 register mask definitions */
41#define TS1_T0_MASK GENMASK(17, 16)
42#define TS1_FMT0_MASK GENMASK(15, 0)
43
44/* DTS_RAMPVALR register mask definitions */
45#define TS1_RAMP_COEFF_MASK GENMASK(15, 0)
46
47/* DTS_ITR1 register mask definitions */
48#define TS1_HITTHD_MASK GENMASK(31, 16)
49#define TS1_LITTHD_MASK GENMASK(15, 0)
50
51/* DTS_DR register mask definitions */
52#define TS1_MFREQ_MASK GENMASK(15, 0)
53
54/* Less significant bit position definitions */
55#define TS1_T0_POS 16
56#define TS1_SMP_TIME_POS 16
57#define TS1_HITTHD_POS 16
58#define HSREF_CLK_DIV_POS 24
59
60/* DTS_CFGR1 bit definitions */
61#define TS1_EN BIT(0)
62#define TS1_START BIT(4)
63#define REFCLK_SEL BIT(20)
64#define REFCLK_LSE REFCLK_SEL
65#define Q_MEAS_OPT BIT(21)
66#define CALIBRATION_CONTROL Q_MEAS_OPT
67
68/* DTS_SR bit definitions */
69#define TS_RDY BIT(15)
70/* Bit definitions below are common for DTS_SR, DTS_ITENR and DTS_CIFR */
71#define HIGH_THRESHOLD BIT(2)
72#define LOW_THRESHOLD BIT(1)
73
74/* Constants */
75#define ADJUST 100
76#define ONE_MHZ 1000000
77#define POLL_TIMEOUT 5000
78#define STARTUP_TIME 40
79#define TS1_T0_VAL0 30
80#define TS1_T0_VAL1 130
81#define NO_HW_TRIG 0
82
83/* The Thermal Framework expects millidegrees */
84#define mcelsius(temp) ((temp) * 1000)
85
86/* The Sensor expects oC degrees */
87#define celsius(temp) ((temp) / 1000)
88
89struct stm_thermal_sensor {
90 struct device *dev;
91 struct thermal_zone_device *th_dev;
92 enum thermal_device_mode mode;
93 struct clk *clk;
94 int high_temp;
95 int low_temp;
96 int temp_critical;
97 int temp_passive;
98 unsigned int low_temp_enabled;
99 int num_trips;
100 int irq;
101 unsigned int irq_enabled;
102 void __iomem *base;
103 int t0, fmt0, ramp_coeff;
104};
105
106static irqreturn_t stm_thermal_alarm_irq(int irq, void *sdata)
107{
108 struct stm_thermal_sensor *sensor = sdata;
109
110 disable_irq_nosync(irq);
111 sensor->irq_enabled = false;
112
113 return IRQ_WAKE_THREAD;
114}
115
116static irqreturn_t stm_thermal_alarm_irq_thread(int irq, void *sdata)
117{
118 u32 value;
119 struct stm_thermal_sensor *sensor = sdata;
120
121 /* read IT reason in SR and clear flags */
122 value = readl_relaxed(sensor->base + DTS_SR_OFFSET);
123
124 if ((value & LOW_THRESHOLD) == LOW_THRESHOLD)
125 writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
126
127 if ((value & HIGH_THRESHOLD) == HIGH_THRESHOLD)
128 writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
129
130 thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED);
131
132 return IRQ_HANDLED;
133}
134
135static int stm_sensor_power_on(struct stm_thermal_sensor *sensor)
136{
137 int ret;
138 u32 value;
139
140 /* Enable sensor */
141 value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
142 value |= TS1_EN;
143 writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);
144
145 /*
146 * The DTS block can be enabled by setting TSx_EN bit in
147 * DTS_CFGRx register. It requires a startup time of
148 * 40μs. Use 5 ms as arbitrary timeout.
149 */
150 ret = readl_poll_timeout(sensor->base + DTS_SR_OFFSET,
151 value, (value & TS_RDY),
152 STARTUP_TIME, POLL_TIMEOUT);
153 if (ret)
154 return ret;
155
156 /* Start continuous measuring */
157 value = readl_relaxed(sensor->base +
158 DTS_CFGR1_OFFSET);
159 value |= TS1_START;
160 writel_relaxed(value, sensor->base +
161 DTS_CFGR1_OFFSET);
162
163 return 0;
164}
165
166static int stm_sensor_power_off(struct stm_thermal_sensor *sensor)
167{
168 u32 value;
169
170 /* Stop measuring */
171 value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
172 value &= ~TS1_START;
173 writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);
174
175 /* Ensure stop is taken into account */
176 usleep_range(STARTUP_TIME, POLL_TIMEOUT);
177
178 /* Disable sensor */
179 value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
180 value &= ~TS1_EN;
181 writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);
182
183 /* Ensure disable is taken into account */
184 return readl_poll_timeout(sensor->base + DTS_SR_OFFSET, value,
185 !(value & TS_RDY),
186 STARTUP_TIME, POLL_TIMEOUT);
187}
188
189static int stm_thermal_calibration(struct stm_thermal_sensor *sensor)
190{
191 u32 value, clk_freq;
192 u32 prescaler;
193
194 /* Figure out prescaler value for PCLK during calibration */
195 clk_freq = clk_get_rate(sensor->clk);
196 if (!clk_freq)
197 return -EINVAL;
198
199 prescaler = 0;
200 clk_freq /= ONE_MHZ;
201 if (clk_freq) {
202 while (prescaler <= clk_freq)
203 prescaler++;
204 }
205
206 value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
207
208 /* Clear prescaler */
209 value &= ~HSREF_CLK_DIV_MASK;
210
211 /* Set prescaler. pclk_freq/prescaler < 1MHz */
212 value |= (prescaler << HSREF_CLK_DIV_POS);
213
214 /* Select PCLK as reference clock */
215 value &= ~REFCLK_SEL;
216
217 /* Set maximal sampling time for better precision */
218 value |= TS1_SMP_TIME_MASK;
219
220 /* Measure with calibration */
221 value &= ~CALIBRATION_CONTROL;
222
223 /* select trigger */
224 value &= ~TS1_INTRIG_SEL_MASK;
225 value |= NO_HW_TRIG;
226
227 writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);
228
229 return 0;
230}
231
232/* Fill in DTS structure with factory sensor values */
233static int stm_thermal_read_factory_settings(struct stm_thermal_sensor *sensor)
234{
235 /* Retrieve engineering calibration temperature */
236 sensor->t0 = readl_relaxed(sensor->base + DTS_T0VALR1_OFFSET) &
237 TS1_T0_MASK;
238 if (!sensor->t0)
239 sensor->t0 = TS1_T0_VAL0;
240 else
241 sensor->t0 = TS1_T0_VAL1;
242
243 /* Retrieve fmt0 and put it on Hz */
244 sensor->fmt0 = ADJUST * readl_relaxed(sensor->base + DTS_T0VALR1_OFFSET)
245 & TS1_FMT0_MASK;
246
247 /* Retrieve ramp coefficient */
248 sensor->ramp_coeff = readl_relaxed(sensor->base + DTS_RAMPVALR_OFFSET) &
249 TS1_RAMP_COEFF_MASK;
250
251 if (!sensor->fmt0 || !sensor->ramp_coeff) {
252 dev_err(sensor->dev, "%s: wrong setting\n", __func__);
253 return -EINVAL;
254 }
255
256 dev_dbg(sensor->dev, "%s: T0 = %doC, FMT0 = %dHz, RAMP_COEFF = %dHz/oC",
257 __func__, sensor->t0, sensor->fmt0, sensor->ramp_coeff);
258
259 return 0;
260}
261
262static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor,
263 int temp, u32 *th)
264{
265 int freqM;
266 u32 sampling_time;
267
268 /* Retrieve the number of periods to sample */
269 sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) &
270 TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS;
271
272 /* Figure out the CLK_PTAT frequency for a given temperature */
273 freqM = ((temp - sensor->t0) * sensor->ramp_coeff)
274 + sensor->fmt0;
275
276 dev_dbg(sensor->dev, "%s: freqM for threshold = %d Hz",
277 __func__, freqM);
278
279 /* Figure out the threshold sample number */
280 *th = clk_get_rate(sensor->clk);
281 if (!*th)
282 return -EINVAL;
283
284 *th = *th / freqM;
285
286 *th *= sampling_time;
287
288 return 0;
289}
290
291static int stm_thermal_set_threshold(struct stm_thermal_sensor *sensor)
292{
293 u32 value, th;
294 int ret;
295
296 value = readl_relaxed(sensor->base + DTS_ITR1_OFFSET);
297
298 /* Erase threshold content */
299 value &= ~(TS1_LITTHD_MASK | TS1_HITTHD_MASK);
300
301 /* Retrieve the sample threshold number th for a given temperature */
302 ret = stm_thermal_calculate_threshold(sensor, sensor->high_temp, &th);
303 if (ret)
304 return ret;
305
306 value |= th & TS1_LITTHD_MASK;
307
308 if (sensor->low_temp_enabled) {
309 /* Retrieve the sample threshold */
310 ret = stm_thermal_calculate_threshold(sensor, sensor->low_temp,
311 &th);
312 if (ret)
313 return ret;
314
315 value |= (TS1_HITTHD_MASK & (th << TS1_HITTHD_POS));
316 }
317
318 /* Write value on the Low interrupt threshold */
319 writel_relaxed(value, sensor->base + DTS_ITR1_OFFSET);
320
321 return 0;
322}
323
324/* Disable temperature interrupt */
325static int stm_disable_irq(struct stm_thermal_sensor *sensor)
326{
327 u32 value;
328
329 /* Disable IT generation for low and high thresholds */
330 value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET);
331 writel_relaxed(value & ~(LOW_THRESHOLD | HIGH_THRESHOLD),
332 sensor->base + DTS_ITENR_OFFSET);
333
334 dev_dbg(sensor->dev, "%s: IT disabled on sensor side", __func__);
335
336 return 0;
337}
338
339/* Enable temperature interrupt */
340static int stm_enable_irq(struct stm_thermal_sensor *sensor)
341{
342 u32 value;
343
344 /*
345 * Code below enables High temperature threshold using a low threshold
346 * sampling value
347 */
348
349 /* Make sure LOW_THRESHOLD IT is clear before enabling */
350 writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
351
352 /* Enable IT generation for low threshold */
353 value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET);
354 value |= LOW_THRESHOLD;
355
356 /* Enable the low temperature threshold if needed */
357 if (sensor->low_temp_enabled) {
358 /* Make sure HIGH_THRESHOLD IT is clear before enabling */
359 writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
360
361 /* Enable IT generation for high threshold */
362 value |= HIGH_THRESHOLD;
363 }
364
365 /* Enable thresholds */
366 writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET);
367
368 dev_dbg(sensor->dev, "%s: IT enabled on sensor side", __func__);
369
370 return 0;
371}
372
373static int stm_thermal_update_threshold(struct stm_thermal_sensor *sensor)
374{
375 int ret;
376
377 sensor->mode = THERMAL_DEVICE_DISABLED;
378
379 ret = stm_sensor_power_off(sensor);
380 if (ret)
381 return ret;
382
383 ret = stm_disable_irq(sensor);
384 if (ret)
385 return ret;
386
387 ret = stm_thermal_set_threshold(sensor);
388 if (ret)
389 return ret;
390
391 ret = stm_enable_irq(sensor);
392 if (ret)
393 return ret;
394
395 ret = stm_sensor_power_on(sensor);
396 if (ret)
397 return ret;
398
399 sensor->mode = THERMAL_DEVICE_ENABLED;
400
401 return 0;
402}
403
404/* Callback to get temperature from HW */
405static int stm_thermal_get_temp(void *data, int *temp)
406{
407 struct stm_thermal_sensor *sensor = data;
408 u32 sampling_time;
409 int freqM, ret;
410
411 if (sensor->mode != THERMAL_DEVICE_ENABLED)
412 return -EAGAIN;
413
414 /* Retrieve the number of samples */
415 ret = readl_poll_timeout(sensor->base + DTS_DR_OFFSET, freqM,
416 (freqM & TS1_MFREQ_MASK), STARTUP_TIME,
417 POLL_TIMEOUT);
418
419 if (ret)
420 return ret;
421
422 if (!freqM)
423 return -ENODATA;
424
425 /* Retrieve the number of periods sampled */
426 sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) &
427 TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS;
428
429 /* Figure out the number of samples per period */
430 freqM /= sampling_time;
431
432 /* Figure out the CLK_PTAT frequency */
433 freqM = clk_get_rate(sensor->clk) / freqM;
434 if (!freqM)
435 return -EINVAL;
436
437 dev_dbg(sensor->dev, "%s: freqM=%d\n", __func__, freqM);
438
439 /* Figure out the temperature in mili celsius */
440 *temp = mcelsius(sensor->t0 + ((freqM - sensor->fmt0) /
441 sensor->ramp_coeff));
442
443 dev_dbg(sensor->dev, "%s: temperature = %d millicelsius",
444 __func__, *temp);
445
446 /* Update thresholds */
447 if (sensor->num_trips > 1) {
448 /* Update alarm threshold value to next higher trip point */
449 if (sensor->high_temp == sensor->temp_passive &&
450 celsius(*temp) >= sensor->temp_passive) {
451 sensor->high_temp = sensor->temp_critical;
452 sensor->low_temp = sensor->temp_passive;
453 sensor->low_temp_enabled = true;
454 ret = stm_thermal_update_threshold(sensor);
455 if (ret)
456 return ret;
457 }
458
459 if (sensor->high_temp == sensor->temp_critical &&
460 celsius(*temp) < sensor->temp_passive) {
461 sensor->high_temp = sensor->temp_passive;
462 sensor->low_temp_enabled = false;
463 ret = stm_thermal_update_threshold(sensor);
464 if (ret)
465 return ret;
466 }
467
468 /*
469 * Re-enable alarm IRQ if temperature below critical
470 * temperature
471 */
472 if (!sensor->irq_enabled &&
473 (celsius(*temp) < sensor->temp_critical)) {
474 sensor->irq_enabled = true;
475 enable_irq(sensor->irq);
476 }
477 }
478
479 return 0;
480}
481
482/* Registers DTS irq to be visible by GIC */
483static int stm_register_irq(struct stm_thermal_sensor *sensor)
484{
485 struct device *dev = sensor->dev;
486 struct platform_device *pdev = to_platform_device(dev);
487 int ret;
488
489 sensor->irq = platform_get_irq(pdev, 0);
490 if (sensor->irq < 0) {
491 dev_err(dev, "%s: Unable to find IRQ\n", __func__);
492 return sensor->irq;
493 }
494
495 ret = devm_request_threaded_irq(dev, sensor->irq,
496 stm_thermal_alarm_irq,
497 stm_thermal_alarm_irq_thread,
498 IRQF_ONESHOT,
499 dev->driver->name, sensor);
500 if (ret) {
501 dev_err(dev, "%s: Failed to register IRQ %d\n", __func__,
502 sensor->irq);
503 return ret;
504 }
505
506 sensor->irq_enabled = true;
507
508 dev_dbg(dev, "%s: thermal IRQ registered", __func__);
509
510 return 0;
511}
512
513static int stm_thermal_sensor_off(struct stm_thermal_sensor *sensor)
514{
515 int ret;
516
517 ret = stm_sensor_power_off(sensor);
518 if (ret)
519 return ret;
520
521 clk_disable_unprepare(sensor->clk);
522
523 return 0;
524}
525
526static int stm_thermal_prepare(struct stm_thermal_sensor *sensor)
527{
528 int ret;
529 struct device *dev = sensor->dev;
530
531 ret = clk_prepare_enable(sensor->clk);
532 if (ret)
533 return ret;
534
535 ret = stm_thermal_calibration(sensor);
536 if (ret)
537 goto thermal_unprepare;
538
539 /* Set threshold(s) for IRQ */
540 ret = stm_thermal_set_threshold(sensor);
541 if (ret)
542 goto thermal_unprepare;
543
544 ret = stm_enable_irq(sensor);
545 if (ret)
546 goto thermal_unprepare;
547
548 ret = stm_sensor_power_on(sensor);
549 if (ret) {
550 dev_err(dev, "%s: failed to power on sensor\n", __func__);
551 goto irq_disable;
552 }
553
554 return 0;
555
556irq_disable:
557 stm_disable_irq(sensor);
558
559thermal_unprepare:
560 clk_disable_unprepare(sensor->clk);
561
562 return ret;
563}
564
565#ifdef CONFIG_PM_SLEEP
566static int stm_thermal_suspend(struct device *dev)
567{
568 int ret;
569 struct platform_device *pdev = to_platform_device(dev);
570 struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
571
572 ret = stm_thermal_sensor_off(sensor);
573 if (ret)
574 return ret;
575
576 sensor->mode = THERMAL_DEVICE_DISABLED;
577
578 return 0;
579}
580
581static int stm_thermal_resume(struct device *dev)
582{
583 int ret;
584 struct platform_device *pdev = to_platform_device(dev);
585 struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
586
587 ret = stm_thermal_prepare(sensor);
588 if (ret)
589 return ret;
590
591 sensor->mode = THERMAL_DEVICE_ENABLED;
592
593 return 0;
594}
595#endif /* CONFIG_PM_SLEEP */
596
597SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops, stm_thermal_suspend, stm_thermal_resume);
598
599static const struct thermal_zone_of_device_ops stm_tz_ops = {
600 .get_temp = stm_thermal_get_temp,
601};
602
603static const struct of_device_id stm_thermal_of_match[] = {
604 { .compatible = "st,stm32-thermal"},
605 { /* sentinel */ }
606};
607MODULE_DEVICE_TABLE(of, stm_thermal_of_match);
608
609static int stm_thermal_probe(struct platform_device *pdev)
610{
611 struct stm_thermal_sensor *sensor;
612 struct resource *res;
613 const struct thermal_trip *trip;
614 void __iomem *base;
615 int ret, i;
616
617 if (!pdev->dev.of_node) {
618 dev_err(&pdev->dev, "%s: device tree node not found\n",
619 __func__);
620 return -EINVAL;
621 }
622
623 sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL);
624 if (!sensor)
625 return -ENOMEM;
626
627 platform_set_drvdata(pdev, sensor);
628
629 sensor->dev = &pdev->dev;
630
631 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
632 base = devm_ioremap_resource(&pdev->dev, res);
633 if (IS_ERR(base))
634 return PTR_ERR(base);
635
636 /* Populate sensor */
637 sensor->base = base;
638
639 ret = stm_thermal_read_factory_settings(sensor);
640 if (ret)
641 return ret;
642
643 sensor->clk = devm_clk_get(&pdev->dev, "pclk");
644 if (IS_ERR(sensor->clk)) {
645 dev_err(&pdev->dev, "%s: failed to fetch PCLK clock\n",
646 __func__);
647 return PTR_ERR(sensor->clk);
648 }
649
650 /* Register IRQ into GIC */
651 ret = stm_register_irq(sensor);
652 if (ret)
653 return ret;
654
655 sensor->th_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0,
656 sensor,
657 &stm_tz_ops);
658
659 if (IS_ERR(sensor->th_dev)) {
660 dev_err(&pdev->dev, "%s: thermal zone sensor registering KO\n",
661 __func__);
662 ret = PTR_ERR(sensor->th_dev);
663 return ret;
664 }
665
666 if (!sensor->th_dev->ops->get_crit_temp) {
667 /* Critical point must be provided */
668 ret = -EINVAL;
669 goto err_tz;
670 }
671
672 ret = sensor->th_dev->ops->get_crit_temp(sensor->th_dev,
673 &sensor->temp_critical);
674 if (ret) {
675 dev_err(&pdev->dev,
676 "Not able to read critical_temp: %d\n", ret);
677 goto err_tz;
678 }
679
680 sensor->temp_critical = celsius(sensor->temp_critical);
681
682 /* Set thresholds for IRQ */
683 sensor->high_temp = sensor->temp_critical;
684
685 trip = of_thermal_get_trip_points(sensor->th_dev);
686 sensor->num_trips = of_thermal_get_ntrips(sensor->th_dev);
687
688 /* Find out passive temperature if it exists */
689 for (i = (sensor->num_trips - 1); i >= 0; i--) {
690 if (trip[i].type == THERMAL_TRIP_PASSIVE) {
691 sensor->temp_passive = celsius(trip[i].temperature);
692 /* Update high temperature threshold */
693 sensor->high_temp = sensor->temp_passive;
694 }
695 }
696
697 /*
698 * Ensure low_temp_enabled flag is disabled.
699 * By disabling low_temp_enabled, low threshold IT will not be
700 * configured neither enabled because it is not needed as high
701 * threshold is set on the lowest temperature trip point after
702 * probe.
703 */
704 sensor->low_temp_enabled = false;
705
706 /* Configure and enable HW sensor */
707 ret = stm_thermal_prepare(sensor);
708 if (ret) {
709 dev_err(&pdev->dev,
710 "Not able to enable sensor: %d\n", ret);
711 goto err_tz;
712 }
713
714 /*
715 * Thermal_zone doesn't enable hwmon as default,
716 * enable it here
717 */
718 sensor->th_dev->tzp->no_hwmon = false;
719 ret = thermal_add_hwmon_sysfs(sensor->th_dev);
720 if (ret)
721 goto err_tz;
722
723 sensor->mode = THERMAL_DEVICE_ENABLED;
724
725 dev_info(&pdev->dev, "%s: Driver initialized successfully\n",
726 __func__);
727
728 return 0;
729
730err_tz:
731 thermal_zone_of_sensor_unregister(&pdev->dev, sensor->th_dev);
732 return ret;
733}
734
735static int stm_thermal_remove(struct platform_device *pdev)
736{
737 struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
738
739 stm_thermal_sensor_off(sensor);
740 thermal_remove_hwmon_sysfs(sensor->th_dev);
741 thermal_zone_of_sensor_unregister(&pdev->dev, sensor->th_dev);
742
743 return 0;
744}
745
746static struct platform_driver stm_thermal_driver = {
747 .driver = {
748 .name = "stm_thermal",
749 .pm = &stm_thermal_pm_ops,
750 .of_match_table = stm_thermal_of_match,
751 },
752 .probe = stm_thermal_probe,
753 .remove = stm_thermal_remove,
754};
755module_platform_driver(stm_thermal_driver);
756
757MODULE_DESCRIPTION("STMicroelectronics STM32 Thermal Sensor Driver");
758MODULE_AUTHOR("David Hernandez Sanchez <david.hernandezsanchez@st.com>");
759MODULE_LICENSE("GPL v2");
760MODULE_ALIAS("platform:stm_thermal");