diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-12 14:58:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-12 14:58:45 -0400 |
commit | 6a776e47a045462a1df1a3a9592598259ffd614f (patch) | |
tree | 79c3ea4b96e48c7c4389114e738dcc0a972c97c0 | |
parent | a34ab101a9d27a2995142b47f9857fb46fcb072a (diff) | |
parent | cb15c81a0c1c1f7829b9809a209ecacc77f5aa63 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
Pull thermal management updates from Zhang Rui:
- Fix a problem where orderly_shutdown() is called for multiple times
due to multiple critical overheating events raised in a short period
by platform thermal driver. (Keerthy)
- Introduce a backup thermal shutdown mechanism, which invokes
kernel_power_off()/emergency_restart() directly, after
orderly_shutdown() being issued for certain amount of time(specified
via Kconfig). This is useful in certain conditions that userspace may
be unable to power off the system in a clean manner and leaves the
system in a critical state, like in the middle of driver probing
phase. (Keerthy)
- Introduce a new interface in thermal devfreq_cooling code so that the
driver can provide more precise data regarding actual power to the
thermal governor every time the power budget is calculated. (Lukasz
Luba)
- Introduce BCM 2835 soc thermal driver and northstar thermal driver,
within a new sub-folder. (Rafał Miłecki)
- Introduce DA9062/61 thermal driver. (Steve Twiss)
- Remove non-DT booting on TI-SoC driver. Also add support to fetching
coefficients from DT. (Keerthy)
- Refactorf RCAR Gen3 thermal driver. (Niklas Söderlund)
- Small fix on MTK and intel-soc-dts thermal driver. (Dawei Chien,
Brian Bian)
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: (25 commits)
thermal: core: Add a back up thermal shutdown mechanism
thermal: core: Allow orderly_poweroff to be called only once
Thermal: Intel SoC DTS: Change interrupt request behavior
trace: thermal: add another parameter 'power' to the tracing function
thermal: devfreq_cooling: add new interface for direct power read
thermal: devfreq_cooling: refactor code and add get_voltage function
thermal: mt8173: minor mtk_thermal.c cleanups
thermal: bcm2835: move to the broadcom subdirectory
thermal: broadcom: ns: specify myself as MODULE_AUTHOR
thermal: da9062/61: Thermal junction temperature monitoring driver
Documentation: devicetree: thermal: da9062/61 TJUNC temperature binding
thermal: broadcom: add Northstar thermal driver
dt-bindings: thermal: add support for Broadcom's Northstar thermal
thermal: bcm2835: add thermal driver for bcm2835 SoC
dt-bindings: Add thermal zone to bcm2835-thermal example
thermal: rcar_gen3_thermal: add suspend and resume support
thermal: rcar_gen3_thermal: store device match data in private structure
thermal: rcar_gen3_thermal: enable hardware interrupts for trip points
thermal: rcar_gen3_thermal: record and check number of TSCs found
thermal: rcar_gen3_thermal: check that TSC exists before memory allocation
...
25 files changed, 1305 insertions, 266 deletions
diff --git a/Documentation/devicetree/bindings/thermal/brcm,bcm2835-thermal.txt b/Documentation/devicetree/bindings/thermal/brcm,bcm2835-thermal.txt index 474531d2b2c5..da8c5b73ad10 100644 --- a/Documentation/devicetree/bindings/thermal/brcm,bcm2835-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/brcm,bcm2835-thermal.txt | |||
@@ -3,15 +3,39 @@ Binding for Thermal Sensor driver for BCM2835 SoCs. | |||
3 | Required parameters: | 3 | Required parameters: |
4 | ------------------- | 4 | ------------------- |
5 | 5 | ||
6 | compatible: should be one of: "brcm,bcm2835-thermal", | 6 | compatible: should be one of: "brcm,bcm2835-thermal", |
7 | "brcm,bcm2836-thermal" or "brcm,bcm2837-thermal" | 7 | "brcm,bcm2836-thermal" or "brcm,bcm2837-thermal" |
8 | reg: Address range of the thermal registers. | 8 | reg: Address range of the thermal registers. |
9 | clocks: Phandle of the clock used by the thermal sensor. | 9 | clocks: Phandle of the clock used by the thermal sensor. |
10 | #thermal-sensor-cells: should be 0 (see thermal.txt) | ||
10 | 11 | ||
11 | Example: | 12 | Example: |
12 | 13 | ||
14 | thermal-zones { | ||
15 | cpu_thermal: cpu-thermal { | ||
16 | polling-delay-passive = <0>; | ||
17 | polling-delay = <1000>; | ||
18 | |||
19 | thermal-sensors = <&thermal>; | ||
20 | |||
21 | trips { | ||
22 | cpu-crit { | ||
23 | temperature = <80000>; | ||
24 | hysteresis = <0>; | ||
25 | type = "critical"; | ||
26 | }; | ||
27 | }; | ||
28 | |||
29 | coefficients = <(-538) 407000>; | ||
30 | |||
31 | cooling-maps { | ||
32 | }; | ||
33 | }; | ||
34 | }; | ||
35 | |||
13 | thermal: thermal@7e212000 { | 36 | thermal: thermal@7e212000 { |
14 | compatible = "brcm,bcm2835-thermal"; | 37 | compatible = "brcm,bcm2835-thermal"; |
15 | reg = <0x7e212000 0x8>; | 38 | reg = <0x7e212000 0x8>; |
16 | clocks = <&clocks BCM2835_CLOCK_TSENS>; | 39 | clocks = <&clocks BCM2835_CLOCK_TSENS>; |
40 | #thermal-sensor-cells = <0>; | ||
17 | }; | 41 | }; |
diff --git a/Documentation/devicetree/bindings/thermal/brcm,ns-thermal b/Documentation/devicetree/bindings/thermal/brcm,ns-thermal new file mode 100644 index 000000000000..68e047170039 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/brcm,ns-thermal | |||
@@ -0,0 +1,37 @@ | |||
1 | * Broadcom Northstar Thermal | ||
2 | |||
3 | This binding describes thermal sensor that is part of Northstar's DMU (Device | ||
4 | Management Unit). | ||
5 | |||
6 | Required properties: | ||
7 | - compatible : Must be "brcm,ns-thermal" | ||
8 | - reg : iomem address range of PVTMON registers | ||
9 | - #thermal-sensor-cells : Should be <0> | ||
10 | |||
11 | Example: | ||
12 | |||
13 | thermal: thermal@1800c2c0 { | ||
14 | compatible = "brcm,ns-thermal"; | ||
15 | reg = <0x1800c2c0 0x10>; | ||
16 | #thermal-sensor-cells = <0>; | ||
17 | }; | ||
18 | |||
19 | thermal-zones { | ||
20 | cpu_thermal: cpu-thermal { | ||
21 | polling-delay-passive = <0>; | ||
22 | polling-delay = <1000>; | ||
23 | coefficients = <(-556) 418000>; | ||
24 | thermal-sensors = <&thermal>; | ||
25 | |||
26 | trips { | ||
27 | cpu-crit { | ||
28 | temperature = <125000>; | ||
29 | hysteresis = <0>; | ||
30 | type = "critical"; | ||
31 | }; | ||
32 | }; | ||
33 | |||
34 | cooling-maps { | ||
35 | }; | ||
36 | }; | ||
37 | }; | ||
diff --git a/Documentation/devicetree/bindings/thermal/da9062-thermal.txt b/Documentation/devicetree/bindings/thermal/da9062-thermal.txt new file mode 100644 index 000000000000..e241bb5a5584 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/da9062-thermal.txt | |||
@@ -0,0 +1,36 @@ | |||
1 | * Dialog DA9062/61 TJUNC Thermal Module | ||
2 | |||
3 | This module is part of the DA9061/DA9062. For more details about entire | ||
4 | DA9062 and DA9061 chips see Documentation/devicetree/bindings/mfd/da9062.txt | ||
5 | |||
6 | Junction temperature thermal module uses an interrupt signal to identify | ||
7 | high THERMAL_TRIP_HOT temperatures for the PMIC device. | ||
8 | |||
9 | Required properties: | ||
10 | |||
11 | - compatible: should be one of the following valid compatible string lines: | ||
12 | "dlg,da9061-thermal", "dlg,da9062-thermal" | ||
13 | "dlg,da9062-thermal" | ||
14 | |||
15 | Optional properties: | ||
16 | |||
17 | - polling-delay-passive : Specify the polling period, measured in | ||
18 | milliseconds, between thermal zone device update checks. | ||
19 | |||
20 | Example: DA9062 | ||
21 | |||
22 | pmic0: da9062@58 { | ||
23 | thermal { | ||
24 | compatible = "dlg,da9062-thermal"; | ||
25 | polling-delay-passive = <3000>; | ||
26 | }; | ||
27 | }; | ||
28 | |||
29 | Example: DA9061 using a fall-back compatible for the DA9062 onkey driver | ||
30 | |||
31 | pmic0: da9061@58 { | ||
32 | thermal { | ||
33 | compatible = "dlg,da9061-thermal", "dlg,da9062-thermal"; | ||
34 | polling-delay-passive = <3000>; | ||
35 | }; | ||
36 | }; | ||
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt index ef473dc7f55e..bb9a0a53e76b 100644 --- a/Documentation/thermal/sysfs-api.txt +++ b/Documentation/thermal/sysfs-api.txt | |||
@@ -582,3 +582,24 @@ platform data is provided, this uses the step_wise throttling policy. | |||
582 | This function serves as an arbitrator to set the state of a cooling | 582 | This function serves as an arbitrator to set the state of a cooling |
583 | device. It sets the cooling device to the deepest cooling state if | 583 | device. It sets the cooling device to the deepest cooling state if |
584 | possible. | 584 | possible. |
585 | |||
586 | 6. thermal_emergency_poweroff: | ||
587 | |||
588 | On an event of critical trip temperature crossing. Thermal framework | ||
589 | allows the system to shutdown gracefully by calling orderly_poweroff(). | ||
590 | In the event of a failure of orderly_poweroff() to shut down the system | ||
591 | we are in danger of keeping the system alive at undesirably high | ||
592 | temperatures. To mitigate this high risk scenario we program a work | ||
593 | queue to fire after a pre-determined number of seconds to start | ||
594 | an emergency shutdown of the device using the kernel_power_off() | ||
595 | function. In case kernel_power_off() fails then finally | ||
596 | emergency_restart() is called in the worst case. | ||
597 | |||
598 | The delay should be carefully profiled so as to give adequate time for | ||
599 | orderly_poweroff(). In case of failure of an orderly_poweroff() the | ||
600 | emergency poweroff kicks in after the delay has elapsed and shuts down | ||
601 | the system. | ||
602 | |||
603 | If set to 0 emergency poweroff will not be supported. So a carefully | ||
604 | profiled non-zero positive value is a must for emergerncy poweroff to be | ||
605 | triggered. | ||
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 6871ecc5b951..b5b5facb8747 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig | |||
@@ -15,6 +15,23 @@ menuconfig THERMAL | |||
15 | 15 | ||
16 | if THERMAL | 16 | if THERMAL |
17 | 17 | ||
18 | config THERMAL_EMERGENCY_POWEROFF_DELAY_MS | ||
19 | int "Emergency poweroff delay in milli-seconds" | ||
20 | depends on THERMAL | ||
21 | default 0 | ||
22 | help | ||
23 | Thermal subsystem will issue a graceful shutdown when | ||
24 | critical temperatures are reached using orderly_poweroff(). In | ||
25 | case of failure of an orderly_poweroff(), the thermal emergency | ||
26 | poweroff kicks in after a delay has elapsed and shuts down the system. | ||
27 | This config is number of milliseconds to delay before emergency | ||
28 | poweroff kicks in. Similarly to the critical trip point, | ||
29 | the delay should be carefully profiled so as to give adequate | ||
30 | time for orderly_poweroff() to finish on regular execution. | ||
31 | If set to 0 emergency poweroff will not be supported. | ||
32 | |||
33 | In doubt, leave as 0. | ||
34 | |||
18 | config THERMAL_HWMON | 35 | config THERMAL_HWMON |
19 | bool | 36 | bool |
20 | prompt "Expose thermal sensors as hwmon device" | 37 | prompt "Expose thermal sensors as hwmon device" |
@@ -291,6 +308,16 @@ config ARMADA_THERMAL | |||
291 | Enable this option if you want to have support for thermal management | 308 | Enable this option if you want to have support for thermal management |
292 | controller present in Armada 370 and Armada XP SoC. | 309 | controller present in Armada 370 and Armada XP SoC. |
293 | 310 | ||
311 | config DA9062_THERMAL | ||
312 | tristate "DA9062/DA9061 Dialog Semiconductor thermal driver" | ||
313 | depends on MFD_DA9062 || COMPILE_TEST | ||
314 | depends on OF | ||
315 | help | ||
316 | Enable this for the Dialog Semiconductor thermal sensor driver. | ||
317 | This will report PMIC junction over-temperature for one thermal trip | ||
318 | zone. | ||
319 | Compatible with the DA9062 and DA9061 PMICs. | ||
320 | |||
294 | config INTEL_POWERCLAMP | 321 | config INTEL_POWERCLAMP |
295 | tristate "Intel PowerClamp idle injection driver" | 322 | tristate "Intel PowerClamp idle injection driver" |
296 | depends on THERMAL | 323 | depends on THERMAL |
@@ -380,6 +407,11 @@ config MTK_THERMAL | |||
380 | Enable this option if you want to have support for thermal management | 407 | Enable this option if you want to have support for thermal management |
381 | controller present in Mediatek SoCs | 408 | controller present in Mediatek SoCs |
382 | 409 | ||
410 | menu "Broadcom thermal drivers" | ||
411 | depends on ARCH_BCM || COMPILE_TEST | ||
412 | source "drivers/thermal/broadcom/Kconfig" | ||
413 | endmenu | ||
414 | |||
383 | menu "Texas Instruments thermal drivers" | 415 | menu "Texas Instruments thermal drivers" |
384 | depends on ARCH_HAS_BANDGAP || COMPILE_TEST | 416 | depends on ARCH_HAS_BANDGAP || COMPILE_TEST |
385 | depends on HAS_IOMEM | 417 | depends on HAS_IOMEM |
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index c2372f10dae5..094d7039981c 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile | |||
@@ -27,6 +27,7 @@ thermal_sys-$(CONFIG_CLOCK_THERMAL) += clock_cooling.o | |||
27 | thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o | 27 | thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o |
28 | 28 | ||
29 | # platform thermal drivers | 29 | # platform thermal drivers |
30 | obj-y += broadcom/ | ||
30 | obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o | 31 | obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o |
31 | obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o | 32 | obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o |
32 | obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o | 33 | obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o |
@@ -41,6 +42,7 @@ obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o | |||
41 | obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o | 42 | obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o |
42 | obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o | 43 | obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o |
43 | obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o | 44 | obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o |
45 | obj-$(CONFIG_DA9062_THERMAL) += da9062-thermal.o | ||
44 | obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o | 46 | obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o |
45 | obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o | 47 | obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o |
46 | obj-$(CONFIG_INTEL_SOC_DTS_IOSF_CORE) += intel_soc_dts_iosf.o | 48 | obj-$(CONFIG_INTEL_SOC_DTS_IOSF_CORE) += intel_soc_dts_iosf.o |
diff --git a/drivers/thermal/broadcom/Kconfig b/drivers/thermal/broadcom/Kconfig new file mode 100644 index 000000000000..ab08af4654ef --- /dev/null +++ b/drivers/thermal/broadcom/Kconfig | |||
@@ -0,0 +1,16 @@ | |||
1 | config BCM2835_THERMAL | ||
2 | tristate "Thermal sensors on bcm2835 SoC" | ||
3 | depends on ARCH_BCM2835 || COMPILE_TEST | ||
4 | depends on HAS_IOMEM | ||
5 | depends on THERMAL_OF | ||
6 | help | ||
7 | Support for thermal sensors on Broadcom bcm2835 SoCs. | ||
8 | |||
9 | config BCM_NS_THERMAL | ||
10 | tristate "Northstar thermal driver" | ||
11 | depends on ARCH_BCM_IPROC || COMPILE_TEST | ||
12 | help | ||
13 | Northstar is a family of SoCs that includes e.g. BCM4708, BCM47081, | ||
14 | BCM4709 and BCM47094. It contains DMU (Device Management Unit) block | ||
15 | with a thermal sensor that allows checking CPU temperature. This | ||
16 | driver provides support for it. | ||
diff --git a/drivers/thermal/broadcom/Makefile b/drivers/thermal/broadcom/Makefile new file mode 100644 index 000000000000..c6f62e4fd0ee --- /dev/null +++ b/drivers/thermal/broadcom/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-$(CONFIG_BCM2835_THERMAL) += bcm2835_thermal.o | ||
2 | obj-$(CONFIG_BCM_NS_THERMAL) += ns-thermal.o | ||
diff --git a/drivers/thermal/broadcom/bcm2835_thermal.c b/drivers/thermal/broadcom/bcm2835_thermal.c new file mode 100644 index 000000000000..0ecf80890c84 --- /dev/null +++ b/drivers/thermal/broadcom/bcm2835_thermal.c | |||
@@ -0,0 +1,314 @@ | |||
1 | /* | ||
2 | * Driver for Broadcom BCM2835 SoC temperature sensor | ||
3 | * | ||
4 | * Copyright (C) 2016 Martin Sperl | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
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 | #include <linux/clk.h> | ||
18 | #include <linux/debugfs.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/of.h> | ||
25 | #include <linux/of_address.h> | ||
26 | #include <linux/of_device.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/thermal.h> | ||
29 | |||
30 | #define BCM2835_TS_TSENSCTL 0x00 | ||
31 | #define BCM2835_TS_TSENSSTAT 0x04 | ||
32 | |||
33 | #define BCM2835_TS_TSENSCTL_PRWDW BIT(0) | ||
34 | #define BCM2835_TS_TSENSCTL_RSTB BIT(1) | ||
35 | |||
36 | /* | ||
37 | * bandgap reference voltage in 6 mV increments | ||
38 | * 000b = 1178 mV, 001b = 1184 mV, ... 111b = 1220 mV | ||
39 | */ | ||
40 | #define BCM2835_TS_TSENSCTL_CTRL_BITS 3 | ||
41 | #define BCM2835_TS_TSENSCTL_CTRL_SHIFT 2 | ||
42 | #define BCM2835_TS_TSENSCTL_CTRL_MASK \ | ||
43 | GENMASK(BCM2835_TS_TSENSCTL_CTRL_BITS + \ | ||
44 | BCM2835_TS_TSENSCTL_CTRL_SHIFT - 1, \ | ||
45 | BCM2835_TS_TSENSCTL_CTRL_SHIFT) | ||
46 | #define BCM2835_TS_TSENSCTL_CTRL_DEFAULT 1 | ||
47 | #define BCM2835_TS_TSENSCTL_EN_INT BIT(5) | ||
48 | #define BCM2835_TS_TSENSCTL_DIRECT BIT(6) | ||
49 | #define BCM2835_TS_TSENSCTL_CLR_INT BIT(7) | ||
50 | #define BCM2835_TS_TSENSCTL_THOLD_SHIFT 8 | ||
51 | #define BCM2835_TS_TSENSCTL_THOLD_BITS 10 | ||
52 | #define BCM2835_TS_TSENSCTL_THOLD_MASK \ | ||
53 | GENMASK(BCM2835_TS_TSENSCTL_THOLD_BITS + \ | ||
54 | BCM2835_TS_TSENSCTL_THOLD_SHIFT - 1, \ | ||
55 | BCM2835_TS_TSENSCTL_THOLD_SHIFT) | ||
56 | /* | ||
57 | * time how long the block to be asserted in reset | ||
58 | * which based on a clock counter (TSENS clock assumed) | ||
59 | */ | ||
60 | #define BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT 18 | ||
61 | #define BCM2835_TS_TSENSCTL_RSTDELAY_BITS 8 | ||
62 | #define BCM2835_TS_TSENSCTL_REGULEN BIT(26) | ||
63 | |||
64 | #define BCM2835_TS_TSENSSTAT_DATA_BITS 10 | ||
65 | #define BCM2835_TS_TSENSSTAT_DATA_SHIFT 0 | ||
66 | #define BCM2835_TS_TSENSSTAT_DATA_MASK \ | ||
67 | GENMASK(BCM2835_TS_TSENSSTAT_DATA_BITS + \ | ||
68 | BCM2835_TS_TSENSSTAT_DATA_SHIFT - 1, \ | ||
69 | BCM2835_TS_TSENSSTAT_DATA_SHIFT) | ||
70 | #define BCM2835_TS_TSENSSTAT_VALID BIT(10) | ||
71 | #define BCM2835_TS_TSENSSTAT_INTERRUPT BIT(11) | ||
72 | |||
73 | struct bcm2835_thermal_data { | ||
74 | struct thermal_zone_device *tz; | ||
75 | void __iomem *regs; | ||
76 | struct clk *clk; | ||
77 | struct dentry *debugfsdir; | ||
78 | }; | ||
79 | |||
80 | static int bcm2835_thermal_adc2temp(u32 adc, int offset, int slope) | ||
81 | { | ||
82 | return offset + slope * adc; | ||
83 | } | ||
84 | |||
85 | static int bcm2835_thermal_temp2adc(int temp, int offset, int slope) | ||
86 | { | ||
87 | temp -= offset; | ||
88 | temp /= slope; | ||
89 | |||
90 | if (temp < 0) | ||
91 | temp = 0; | ||
92 | if (temp >= BIT(BCM2835_TS_TSENSSTAT_DATA_BITS)) | ||
93 | temp = BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1; | ||
94 | |||
95 | return temp; | ||
96 | } | ||
97 | |||
98 | static int bcm2835_thermal_get_temp(void *d, int *temp) | ||
99 | { | ||
100 | struct bcm2835_thermal_data *data = d; | ||
101 | u32 val = readl(data->regs + BCM2835_TS_TSENSSTAT); | ||
102 | |||
103 | if (!(val & BCM2835_TS_TSENSSTAT_VALID)) | ||
104 | return -EIO; | ||
105 | |||
106 | val &= BCM2835_TS_TSENSSTAT_DATA_MASK; | ||
107 | |||
108 | *temp = bcm2835_thermal_adc2temp( | ||
109 | val, | ||
110 | thermal_zone_get_offset(data->tz), | ||
111 | thermal_zone_get_slope(data->tz)); | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static const struct debugfs_reg32 bcm2835_thermal_regs[] = { | ||
117 | { | ||
118 | .name = "ctl", | ||
119 | .offset = 0 | ||
120 | }, | ||
121 | { | ||
122 | .name = "stat", | ||
123 | .offset = 4 | ||
124 | } | ||
125 | }; | ||
126 | |||
127 | static void bcm2835_thermal_debugfs(struct platform_device *pdev) | ||
128 | { | ||
129 | struct thermal_zone_device *tz = platform_get_drvdata(pdev); | ||
130 | struct bcm2835_thermal_data *data = tz->devdata; | ||
131 | struct debugfs_regset32 *regset; | ||
132 | |||
133 | data->debugfsdir = debugfs_create_dir("bcm2835_thermal", NULL); | ||
134 | if (!data->debugfsdir) | ||
135 | return; | ||
136 | |||
137 | regset = devm_kzalloc(&pdev->dev, sizeof(*regset), GFP_KERNEL); | ||
138 | if (!regset) | ||
139 | return; | ||
140 | |||
141 | regset->regs = bcm2835_thermal_regs; | ||
142 | regset->nregs = ARRAY_SIZE(bcm2835_thermal_regs); | ||
143 | regset->base = data->regs; | ||
144 | |||
145 | debugfs_create_regset32("regset", 0444, data->debugfsdir, regset); | ||
146 | } | ||
147 | |||
148 | static struct thermal_zone_of_device_ops bcm2835_thermal_ops = { | ||
149 | .get_temp = bcm2835_thermal_get_temp, | ||
150 | }; | ||
151 | |||
152 | /* | ||
153 | * Note: as per Raspberry Foundation FAQ | ||
154 | * (https://www.raspberrypi.org/help/faqs/#performanceOperatingTemperature) | ||
155 | * the recommended temperature range for the SoC -40C to +85C | ||
156 | * so the trip limit is set to 80C. | ||
157 | * this applies to all the BCM283X SoC | ||
158 | */ | ||
159 | |||
160 | static const struct of_device_id bcm2835_thermal_of_match_table[] = { | ||
161 | { | ||
162 | .compatible = "brcm,bcm2835-thermal", | ||
163 | }, | ||
164 | { | ||
165 | .compatible = "brcm,bcm2836-thermal", | ||
166 | }, | ||
167 | { | ||
168 | .compatible = "brcm,bcm2837-thermal", | ||
169 | }, | ||
170 | {}, | ||
171 | }; | ||
172 | MODULE_DEVICE_TABLE(of, bcm2835_thermal_of_match_table); | ||
173 | |||
174 | static int bcm2835_thermal_probe(struct platform_device *pdev) | ||
175 | { | ||
176 | const struct of_device_id *match; | ||
177 | struct thermal_zone_device *tz; | ||
178 | struct bcm2835_thermal_data *data; | ||
179 | struct resource *res; | ||
180 | int err = 0; | ||
181 | u32 val; | ||
182 | unsigned long rate; | ||
183 | |||
184 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | ||
185 | if (!data) | ||
186 | return -ENOMEM; | ||
187 | |||
188 | match = of_match_device(bcm2835_thermal_of_match_table, | ||
189 | &pdev->dev); | ||
190 | if (!match) | ||
191 | return -EINVAL; | ||
192 | |||
193 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
194 | data->regs = devm_ioremap_resource(&pdev->dev, res); | ||
195 | if (IS_ERR(data->regs)) { | ||
196 | err = PTR_ERR(data->regs); | ||
197 | dev_err(&pdev->dev, "Could not get registers: %d\n", err); | ||
198 | return err; | ||
199 | } | ||
200 | |||
201 | data->clk = devm_clk_get(&pdev->dev, NULL); | ||
202 | if (IS_ERR(data->clk)) { | ||
203 | err = PTR_ERR(data->clk); | ||
204 | if (err != -EPROBE_DEFER) | ||
205 | dev_err(&pdev->dev, "Could not get clk: %d\n", err); | ||
206 | return err; | ||
207 | } | ||
208 | |||
209 | err = clk_prepare_enable(data->clk); | ||
210 | if (err) | ||
211 | return err; | ||
212 | |||
213 | rate = clk_get_rate(data->clk); | ||
214 | if ((rate < 1920000) || (rate > 5000000)) | ||
215 | dev_warn(&pdev->dev, | ||
216 | "Clock %pCn running at %pCr Hz is outside of the recommended range: 1.92 to 5MHz\n", | ||
217 | data->clk, data->clk); | ||
218 | |||
219 | /* register of thermal sensor and get info from DT */ | ||
220 | tz = thermal_zone_of_sensor_register(&pdev->dev, 0, data, | ||
221 | &bcm2835_thermal_ops); | ||
222 | if (IS_ERR(tz)) { | ||
223 | err = PTR_ERR(tz); | ||
224 | dev_err(&pdev->dev, | ||
225 | "Failed to register the thermal device: %d\n", | ||
226 | err); | ||
227 | goto err_clk; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * right now the FW does set up the HW-block, so we are not | ||
232 | * touching the configuration registers. | ||
233 | * But if the HW is not enabled, then set it up | ||
234 | * using "sane" values used by the firmware right now. | ||
235 | */ | ||
236 | val = readl(data->regs + BCM2835_TS_TSENSCTL); | ||
237 | if (!(val & BCM2835_TS_TSENSCTL_RSTB)) { | ||
238 | int trip_temp, offset, slope; | ||
239 | |||
240 | slope = thermal_zone_get_slope(tz); | ||
241 | offset = thermal_zone_get_offset(tz); | ||
242 | /* | ||
243 | * For now we deal only with critical, otherwise | ||
244 | * would need to iterate | ||
245 | */ | ||
246 | err = tz->ops->get_trip_temp(tz, 0, &trip_temp); | ||
247 | if (err < 0) { | ||
248 | err = PTR_ERR(tz); | ||
249 | dev_err(&pdev->dev, | ||
250 | "Not able to read trip_temp: %d\n", | ||
251 | err); | ||
252 | goto err_tz; | ||
253 | } | ||
254 | |||
255 | /* set bandgap reference voltage and enable voltage regulator */ | ||
256 | val = (BCM2835_TS_TSENSCTL_CTRL_DEFAULT << | ||
257 | BCM2835_TS_TSENSCTL_CTRL_SHIFT) | | ||
258 | BCM2835_TS_TSENSCTL_REGULEN; | ||
259 | |||
260 | /* use the recommended reset duration */ | ||
261 | val |= (0xFE << BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT); | ||
262 | |||
263 | /* trip_adc value from info */ | ||
264 | val |= bcm2835_thermal_temp2adc(trip_temp, | ||
265 | offset, | ||
266 | slope) | ||
267 | << BCM2835_TS_TSENSCTL_THOLD_SHIFT; | ||
268 | |||
269 | /* write the value back to the register as 2 steps */ | ||
270 | writel(val, data->regs + BCM2835_TS_TSENSCTL); | ||
271 | val |= BCM2835_TS_TSENSCTL_RSTB; | ||
272 | writel(val, data->regs + BCM2835_TS_TSENSCTL); | ||
273 | } | ||
274 | |||
275 | data->tz = tz; | ||
276 | |||
277 | platform_set_drvdata(pdev, tz); | ||
278 | |||
279 | bcm2835_thermal_debugfs(pdev); | ||
280 | |||
281 | return 0; | ||
282 | err_tz: | ||
283 | thermal_zone_of_sensor_unregister(&pdev->dev, tz); | ||
284 | err_clk: | ||
285 | clk_disable_unprepare(data->clk); | ||
286 | |||
287 | return err; | ||
288 | } | ||
289 | |||
290 | static int bcm2835_thermal_remove(struct platform_device *pdev) | ||
291 | { | ||
292 | struct thermal_zone_device *tz = platform_get_drvdata(pdev); | ||
293 | struct bcm2835_thermal_data *data = tz->devdata; | ||
294 | |||
295 | debugfs_remove_recursive(data->debugfsdir); | ||
296 | thermal_zone_of_sensor_unregister(&pdev->dev, tz); | ||
297 | clk_disable_unprepare(data->clk); | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static struct platform_driver bcm2835_thermal_driver = { | ||
303 | .probe = bcm2835_thermal_probe, | ||
304 | .remove = bcm2835_thermal_remove, | ||
305 | .driver = { | ||
306 | .name = "bcm2835_thermal", | ||
307 | .of_match_table = bcm2835_thermal_of_match_table, | ||
308 | }, | ||
309 | }; | ||
310 | module_platform_driver(bcm2835_thermal_driver); | ||
311 | |||
312 | MODULE_AUTHOR("Martin Sperl"); | ||
313 | MODULE_DESCRIPTION("Thermal driver for bcm2835 chip"); | ||
314 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/thermal/broadcom/ns-thermal.c b/drivers/thermal/broadcom/ns-thermal.c new file mode 100644 index 000000000000..322e741a2463 --- /dev/null +++ b/drivers/thermal/broadcom/ns-thermal.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Rafał Miłecki <rafal@milecki.pl> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/of_address.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/thermal.h> | ||
13 | |||
14 | #define PVTMON_CONTROL0 0x00 | ||
15 | #define PVTMON_CONTROL0_SEL_MASK 0x0000000e | ||
16 | #define PVTMON_CONTROL0_SEL_TEMP_MONITOR 0x00000000 | ||
17 | #define PVTMON_CONTROL0_SEL_TEST_MODE 0x0000000e | ||
18 | #define PVTMON_STATUS 0x08 | ||
19 | |||
20 | struct ns_thermal { | ||
21 | struct thermal_zone_device *tz; | ||
22 | void __iomem *pvtmon; | ||
23 | }; | ||
24 | |||
25 | static int ns_thermal_get_temp(void *data, int *temp) | ||
26 | { | ||
27 | struct ns_thermal *ns_thermal = data; | ||
28 | int offset = thermal_zone_get_offset(ns_thermal->tz); | ||
29 | int slope = thermal_zone_get_slope(ns_thermal->tz); | ||
30 | u32 val; | ||
31 | |||
32 | val = readl(ns_thermal->pvtmon + PVTMON_CONTROL0); | ||
33 | if ((val & PVTMON_CONTROL0_SEL_MASK) != PVTMON_CONTROL0_SEL_TEMP_MONITOR) { | ||
34 | /* Clear current mode selection */ | ||
35 | val &= ~PVTMON_CONTROL0_SEL_MASK; | ||
36 | |||
37 | /* Set temp monitor mode (it's the default actually) */ | ||
38 | val |= PVTMON_CONTROL0_SEL_TEMP_MONITOR; | ||
39 | |||
40 | writel(val, ns_thermal->pvtmon + PVTMON_CONTROL0); | ||
41 | } | ||
42 | |||
43 | val = readl(ns_thermal->pvtmon + PVTMON_STATUS); | ||
44 | *temp = slope * val + offset; | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static const struct thermal_zone_of_device_ops ns_thermal_ops = { | ||
50 | .get_temp = ns_thermal_get_temp, | ||
51 | }; | ||
52 | |||
53 | static int ns_thermal_probe(struct platform_device *pdev) | ||
54 | { | ||
55 | struct device *dev = &pdev->dev; | ||
56 | struct ns_thermal *ns_thermal; | ||
57 | |||
58 | ns_thermal = devm_kzalloc(dev, sizeof(*ns_thermal), GFP_KERNEL); | ||
59 | if (!ns_thermal) | ||
60 | return -ENOMEM; | ||
61 | |||
62 | ns_thermal->pvtmon = of_iomap(dev_of_node(dev), 0); | ||
63 | if (WARN_ON(!ns_thermal->pvtmon)) | ||
64 | return -ENOENT; | ||
65 | |||
66 | ns_thermal->tz = devm_thermal_zone_of_sensor_register(dev, 0, | ||
67 | ns_thermal, | ||
68 | &ns_thermal_ops); | ||
69 | if (IS_ERR(ns_thermal->tz)) { | ||
70 | iounmap(ns_thermal->pvtmon); | ||
71 | return PTR_ERR(ns_thermal->tz); | ||
72 | } | ||
73 | |||
74 | platform_set_drvdata(pdev, ns_thermal); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int ns_thermal_remove(struct platform_device *pdev) | ||
80 | { | ||
81 | struct ns_thermal *ns_thermal = platform_get_drvdata(pdev); | ||
82 | |||
83 | iounmap(ns_thermal->pvtmon); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static const struct of_device_id ns_thermal_of_match[] = { | ||
89 | { .compatible = "brcm,ns-thermal", }, | ||
90 | {}, | ||
91 | }; | ||
92 | MODULE_DEVICE_TABLE(of, ns_thermal_of_match); | ||
93 | |||
94 | static struct platform_driver ns_thermal_driver = { | ||
95 | .probe = ns_thermal_probe, | ||
96 | .remove = ns_thermal_remove, | ||
97 | .driver = { | ||
98 | .name = "ns-thermal", | ||
99 | .of_match_table = ns_thermal_of_match, | ||
100 | }, | ||
101 | }; | ||
102 | module_platform_driver(ns_thermal_driver); | ||
103 | |||
104 | MODULE_AUTHOR("Rafał Miłecki <rafal@milecki.pl>"); | ||
105 | MODULE_DESCRIPTION("Northstar thermal driver"); | ||
106 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c new file mode 100644 index 000000000000..dd8dd947b7f0 --- /dev/null +++ b/drivers/thermal/da9062-thermal.c | |||
@@ -0,0 +1,315 @@ | |||
1 | /* | ||
2 | * Thermal device driver for DA9062 and DA9061 | ||
3 | * Copyright (C) 2017 Dialog Semiconductor | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version 2 | ||
8 | * of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | /* When over-temperature is reached, an interrupt from the device will be | ||
17 | * triggered. Following this event the interrupt will be disabled and | ||
18 | * periodic transmission of uevents (HOT trip point) should define the | ||
19 | * first level of temperature supervision. It is expected that any final | ||
20 | * implementation of the thermal driver will include a .notify() function | ||
21 | * to implement these uevents to userspace. | ||
22 | * | ||
23 | * These uevents are intended to indicate non-invasive temperature control | ||
24 | * of the system, where the necessary measures for cooling are the | ||
25 | * responsibility of the host software. Once the temperature falls again, | ||
26 | * the IRQ is re-enabled so the start of a new over-temperature event can | ||
27 | * be detected without constant software monitoring. | ||
28 | */ | ||
29 | |||
30 | #include <linux/errno.h> | ||
31 | #include <linux/interrupt.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/of.h> | ||
34 | #include <linux/platform_device.h> | ||
35 | #include <linux/regmap.h> | ||
36 | #include <linux/thermal.h> | ||
37 | #include <linux/workqueue.h> | ||
38 | |||
39 | #include <linux/mfd/da9062/core.h> | ||
40 | #include <linux/mfd/da9062/registers.h> | ||
41 | |||
42 | /* Minimum, maximum and default polling millisecond periods are provided | ||
43 | * here as an example. It is expected that any final implementation to also | ||
44 | * include a modification of these settings to match the required | ||
45 | * application. | ||
46 | */ | ||
47 | #define DA9062_DEFAULT_POLLING_MS_PERIOD 3000 | ||
48 | #define DA9062_MAX_POLLING_MS_PERIOD 10000 | ||
49 | #define DA9062_MIN_POLLING_MS_PERIOD 1000 | ||
50 | |||
51 | #define DA9062_MILLI_CELSIUS(t) ((t) * 1000) | ||
52 | |||
53 | struct da9062_thermal_config { | ||
54 | const char *name; | ||
55 | }; | ||
56 | |||
57 | struct da9062_thermal { | ||
58 | struct da9062 *hw; | ||
59 | struct delayed_work work; | ||
60 | struct thermal_zone_device *zone; | ||
61 | enum thermal_device_mode mode; | ||
62 | struct mutex lock; /* protection for da9062_thermal temperature */ | ||
63 | int temperature; | ||
64 | int irq; | ||
65 | const struct da9062_thermal_config *config; | ||
66 | struct device *dev; | ||
67 | }; | ||
68 | |||
69 | static void da9062_thermal_poll_on(struct work_struct *work) | ||
70 | { | ||
71 | struct da9062_thermal *thermal = container_of(work, | ||
72 | struct da9062_thermal, | ||
73 | work.work); | ||
74 | unsigned long delay; | ||
75 | unsigned int val; | ||
76 | int ret; | ||
77 | |||
78 | /* clear E_TEMP */ | ||
79 | ret = regmap_write(thermal->hw->regmap, | ||
80 | DA9062AA_EVENT_B, | ||
81 | DA9062AA_E_TEMP_MASK); | ||
82 | if (ret < 0) { | ||
83 | dev_err(thermal->dev, | ||
84 | "Cannot clear the TJUNC temperature status\n"); | ||
85 | goto err_enable_irq; | ||
86 | } | ||
87 | |||
88 | /* Now read E_TEMP again: it is acting like a status bit. | ||
89 | * If over-temperature, then this status will be true. | ||
90 | * If not over-temperature, this status will be false. | ||
91 | */ | ||
92 | ret = regmap_read(thermal->hw->regmap, | ||
93 | DA9062AA_EVENT_B, | ||
94 | &val); | ||
95 | if (ret < 0) { | ||
96 | dev_err(thermal->dev, | ||
97 | "Cannot check the TJUNC temperature status\n"); | ||
98 | goto err_enable_irq; | ||
99 | } | ||
100 | |||
101 | if (val & DA9062AA_E_TEMP_MASK) { | ||
102 | mutex_lock(&thermal->lock); | ||
103 | thermal->temperature = DA9062_MILLI_CELSIUS(125); | ||
104 | mutex_unlock(&thermal->lock); | ||
105 | thermal_zone_device_update(thermal->zone, | ||
106 | THERMAL_EVENT_UNSPECIFIED); | ||
107 | |||
108 | delay = msecs_to_jiffies(thermal->zone->passive_delay); | ||
109 | schedule_delayed_work(&thermal->work, delay); | ||
110 | return; | ||
111 | } | ||
112 | |||
113 | mutex_lock(&thermal->lock); | ||
114 | thermal->temperature = DA9062_MILLI_CELSIUS(0); | ||
115 | mutex_unlock(&thermal->lock); | ||
116 | thermal_zone_device_update(thermal->zone, | ||
117 | THERMAL_EVENT_UNSPECIFIED); | ||
118 | |||
119 | err_enable_irq: | ||
120 | enable_irq(thermal->irq); | ||
121 | } | ||
122 | |||
123 | static irqreturn_t da9062_thermal_irq_handler(int irq, void *data) | ||
124 | { | ||
125 | struct da9062_thermal *thermal = data; | ||
126 | |||
127 | disable_irq_nosync(thermal->irq); | ||
128 | schedule_delayed_work(&thermal->work, 0); | ||
129 | |||
130 | return IRQ_HANDLED; | ||
131 | } | ||
132 | |||
133 | static int da9062_thermal_get_mode(struct thermal_zone_device *z, | ||
134 | enum thermal_device_mode *mode) | ||
135 | { | ||
136 | struct da9062_thermal *thermal = z->devdata; | ||
137 | *mode = thermal->mode; | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int da9062_thermal_get_trip_type(struct thermal_zone_device *z, | ||
142 | int trip, | ||
143 | enum thermal_trip_type *type) | ||
144 | { | ||
145 | struct da9062_thermal *thermal = z->devdata; | ||
146 | |||
147 | switch (trip) { | ||
148 | case 0: | ||
149 | *type = THERMAL_TRIP_HOT; | ||
150 | break; | ||
151 | default: | ||
152 | dev_err(thermal->dev, | ||
153 | "Driver does not support more than 1 trip-wire\n"); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int da9062_thermal_get_trip_temp(struct thermal_zone_device *z, | ||
161 | int trip, | ||
162 | int *temp) | ||
163 | { | ||
164 | struct da9062_thermal *thermal = z->devdata; | ||
165 | |||
166 | switch (trip) { | ||
167 | case 0: | ||
168 | *temp = DA9062_MILLI_CELSIUS(125); | ||
169 | break; | ||
170 | default: | ||
171 | dev_err(thermal->dev, | ||
172 | "Driver does not support more than 1 trip-wire\n"); | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int da9062_thermal_get_temp(struct thermal_zone_device *z, | ||
180 | int *temp) | ||
181 | { | ||
182 | struct da9062_thermal *thermal = z->devdata; | ||
183 | |||
184 | mutex_lock(&thermal->lock); | ||
185 | *temp = thermal->temperature; | ||
186 | mutex_unlock(&thermal->lock); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static struct thermal_zone_device_ops da9062_thermal_ops = { | ||
192 | .get_temp = da9062_thermal_get_temp, | ||
193 | .get_mode = da9062_thermal_get_mode, | ||
194 | .get_trip_type = da9062_thermal_get_trip_type, | ||
195 | .get_trip_temp = da9062_thermal_get_trip_temp, | ||
196 | }; | ||
197 | |||
198 | static const struct da9062_thermal_config da9062_config = { | ||
199 | .name = "da9062-thermal", | ||
200 | }; | ||
201 | |||
202 | static const struct of_device_id da9062_compatible_reg_id_table[] = { | ||
203 | { .compatible = "dlg,da9062-thermal", .data = &da9062_config }, | ||
204 | { }, | ||
205 | }; | ||
206 | |||
207 | MODULE_DEVICE_TABLE(of, da9062_compatible_reg_id_table); | ||
208 | |||
209 | static int da9062_thermal_probe(struct platform_device *pdev) | ||
210 | { | ||
211 | struct da9062 *chip = dev_get_drvdata(pdev->dev.parent); | ||
212 | struct da9062_thermal *thermal; | ||
213 | unsigned int pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD; | ||
214 | const struct of_device_id *match; | ||
215 | int ret = 0; | ||
216 | |||
217 | match = of_match_node(da9062_compatible_reg_id_table, | ||
218 | pdev->dev.of_node); | ||
219 | if (!match) | ||
220 | return -ENXIO; | ||
221 | |||
222 | if (pdev->dev.of_node) { | ||
223 | if (!of_property_read_u32(pdev->dev.of_node, | ||
224 | "polling-delay-passive", | ||
225 | &pp_tmp)) { | ||
226 | if (pp_tmp < DA9062_MIN_POLLING_MS_PERIOD || | ||
227 | pp_tmp > DA9062_MAX_POLLING_MS_PERIOD) { | ||
228 | dev_warn(&pdev->dev, | ||
229 | "Out-of-range polling period %d ms\n", | ||
230 | pp_tmp); | ||
231 | pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD; | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | |||
236 | thermal = devm_kzalloc(&pdev->dev, sizeof(struct da9062_thermal), | ||
237 | GFP_KERNEL); | ||
238 | if (!thermal) { | ||
239 | ret = -ENOMEM; | ||
240 | goto err; | ||
241 | } | ||
242 | |||
243 | thermal->config = match->data; | ||
244 | thermal->hw = chip; | ||
245 | thermal->mode = THERMAL_DEVICE_ENABLED; | ||
246 | thermal->dev = &pdev->dev; | ||
247 | |||
248 | INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on); | ||
249 | mutex_init(&thermal->lock); | ||
250 | |||
251 | thermal->zone = thermal_zone_device_register(thermal->config->name, | ||
252 | 1, 0, thermal, | ||
253 | &da9062_thermal_ops, NULL, pp_tmp, | ||
254 | 0); | ||
255 | if (IS_ERR(thermal->zone)) { | ||
256 | dev_err(&pdev->dev, "Cannot register thermal zone device\n"); | ||
257 | ret = PTR_ERR(thermal->zone); | ||
258 | goto err; | ||
259 | } | ||
260 | |||
261 | dev_dbg(&pdev->dev, | ||
262 | "TJUNC temperature polling period set at %d ms\n", | ||
263 | thermal->zone->passive_delay); | ||
264 | |||
265 | ret = platform_get_irq_byname(pdev, "THERMAL"); | ||
266 | if (ret < 0) { | ||
267 | dev_err(&pdev->dev, "Failed to get platform IRQ.\n"); | ||
268 | goto err_zone; | ||
269 | } | ||
270 | thermal->irq = ret; | ||
271 | |||
272 | ret = request_threaded_irq(thermal->irq, NULL, | ||
273 | da9062_thermal_irq_handler, | ||
274 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
275 | "THERMAL", thermal); | ||
276 | if (ret) { | ||
277 | dev_err(&pdev->dev, | ||
278 | "Failed to request thermal device IRQ.\n"); | ||
279 | goto err_zone; | ||
280 | } | ||
281 | |||
282 | platform_set_drvdata(pdev, thermal); | ||
283 | return 0; | ||
284 | |||
285 | err_zone: | ||
286 | thermal_zone_device_unregister(thermal->zone); | ||
287 | err: | ||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | static int da9062_thermal_remove(struct platform_device *pdev) | ||
292 | { | ||
293 | struct da9062_thermal *thermal = platform_get_drvdata(pdev); | ||
294 | |||
295 | free_irq(thermal->irq, thermal); | ||
296 | cancel_delayed_work_sync(&thermal->work); | ||
297 | thermal_zone_device_unregister(thermal->zone); | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static struct platform_driver da9062_thermal_driver = { | ||
302 | .probe = da9062_thermal_probe, | ||
303 | .remove = da9062_thermal_remove, | ||
304 | .driver = { | ||
305 | .name = "da9062-thermal", | ||
306 | .of_match_table = da9062_compatible_reg_id_table, | ||
307 | }, | ||
308 | }; | ||
309 | |||
310 | module_platform_driver(da9062_thermal_driver); | ||
311 | |||
312 | MODULE_AUTHOR("Steve Twiss"); | ||
313 | MODULE_DESCRIPTION("Thermal TJUNC device driver for Dialog DA9062 and DA9061"); | ||
314 | MODULE_LICENSE("GPL"); | ||
315 | MODULE_ALIAS("platform:da9062-thermal"); | ||
diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c index 4bf4ad58cffd..ef59256887ff 100644 --- a/drivers/thermal/devfreq_cooling.c +++ b/drivers/thermal/devfreq_cooling.c | |||
@@ -28,6 +28,8 @@ | |||
28 | 28 | ||
29 | #include <trace/events/thermal.h> | 29 | #include <trace/events/thermal.h> |
30 | 30 | ||
31 | #define SCALE_ERROR_MITIGATION 100 | ||
32 | |||
31 | static DEFINE_IDA(devfreq_ida); | 33 | static DEFINE_IDA(devfreq_ida); |
32 | 34 | ||
33 | /** | 35 | /** |
@@ -45,6 +47,12 @@ static DEFINE_IDA(devfreq_ida); | |||
45 | * @freq_table_size: Size of the @freq_table and @power_table | 47 | * @freq_table_size: Size of the @freq_table and @power_table |
46 | * @power_ops: Pointer to devfreq_cooling_power, used to generate the | 48 | * @power_ops: Pointer to devfreq_cooling_power, used to generate the |
47 | * @power_table. | 49 | * @power_table. |
50 | * @res_util: Resource utilization scaling factor for the power. | ||
51 | * It is multiplied by 100 to minimize the error. It is used | ||
52 | * for estimation of the power budget instead of using | ||
53 | * 'utilization' (which is 'busy_time / 'total_time'). | ||
54 | * The 'res_util' range is from 100 to (power_table[state] * 100) | ||
55 | * for the corresponding 'state'. | ||
48 | */ | 56 | */ |
49 | struct devfreq_cooling_device { | 57 | struct devfreq_cooling_device { |
50 | int id; | 58 | int id; |
@@ -55,6 +63,8 @@ struct devfreq_cooling_device { | |||
55 | u32 *freq_table; | 63 | u32 *freq_table; |
56 | size_t freq_table_size; | 64 | size_t freq_table_size; |
57 | struct devfreq_cooling_power *power_ops; | 65 | struct devfreq_cooling_power *power_ops; |
66 | u32 res_util; | ||
67 | int capped_state; | ||
58 | }; | 68 | }; |
59 | 69 | ||
60 | /** | 70 | /** |
@@ -164,27 +174,12 @@ freq_get_state(struct devfreq_cooling_device *dfc, unsigned long freq) | |||
164 | return THERMAL_CSTATE_INVALID; | 174 | return THERMAL_CSTATE_INVALID; |
165 | } | 175 | } |
166 | 176 | ||
167 | /** | 177 | static unsigned long get_voltage(struct devfreq *df, unsigned long freq) |
168 | * get_static_power() - calculate the static power | ||
169 | * @dfc: Pointer to devfreq cooling device | ||
170 | * @freq: Frequency in Hz | ||
171 | * | ||
172 | * Calculate the static power in milliwatts using the supplied | ||
173 | * get_static_power(). The current voltage is calculated using the | ||
174 | * OPP library. If no get_static_power() was supplied, assume the | ||
175 | * static power is negligible. | ||
176 | */ | ||
177 | static unsigned long | ||
178 | get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq) | ||
179 | { | 178 | { |
180 | struct devfreq *df = dfc->devfreq; | ||
181 | struct device *dev = df->dev.parent; | 179 | struct device *dev = df->dev.parent; |
182 | unsigned long voltage; | 180 | unsigned long voltage; |
183 | struct dev_pm_opp *opp; | 181 | struct dev_pm_opp *opp; |
184 | 182 | ||
185 | if (!dfc->power_ops->get_static_power) | ||
186 | return 0; | ||
187 | |||
188 | opp = dev_pm_opp_find_freq_exact(dev, freq, true); | 183 | opp = dev_pm_opp_find_freq_exact(dev, freq, true); |
189 | if (PTR_ERR(opp) == -ERANGE) | 184 | if (PTR_ERR(opp) == -ERANGE) |
190 | opp = dev_pm_opp_find_freq_exact(dev, freq, false); | 185 | opp = dev_pm_opp_find_freq_exact(dev, freq, false); |
@@ -202,9 +197,35 @@ get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq) | |||
202 | dev_err_ratelimited(dev, | 197 | dev_err_ratelimited(dev, |
203 | "Failed to get voltage for frequency %lu\n", | 198 | "Failed to get voltage for frequency %lu\n", |
204 | freq); | 199 | freq); |
205 | return 0; | ||
206 | } | 200 | } |
207 | 201 | ||
202 | return voltage; | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * get_static_power() - calculate the static power | ||
207 | * @dfc: Pointer to devfreq cooling device | ||
208 | * @freq: Frequency in Hz | ||
209 | * | ||
210 | * Calculate the static power in milliwatts using the supplied | ||
211 | * get_static_power(). The current voltage is calculated using the | ||
212 | * OPP library. If no get_static_power() was supplied, assume the | ||
213 | * static power is negligible. | ||
214 | */ | ||
215 | static unsigned long | ||
216 | get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq) | ||
217 | { | ||
218 | struct devfreq *df = dfc->devfreq; | ||
219 | unsigned long voltage; | ||
220 | |||
221 | if (!dfc->power_ops->get_static_power) | ||
222 | return 0; | ||
223 | |||
224 | voltage = get_voltage(df, freq); | ||
225 | |||
226 | if (voltage == 0) | ||
227 | return 0; | ||
228 | |||
208 | return dfc->power_ops->get_static_power(df, voltage); | 229 | return dfc->power_ops->get_static_power(df, voltage); |
209 | } | 230 | } |
210 | 231 | ||
@@ -239,6 +260,16 @@ get_dynamic_power(struct devfreq_cooling_device *dfc, unsigned long freq, | |||
239 | return power; | 260 | return power; |
240 | } | 261 | } |
241 | 262 | ||
263 | |||
264 | static inline unsigned long get_total_power(struct devfreq_cooling_device *dfc, | ||
265 | unsigned long freq, | ||
266 | unsigned long voltage) | ||
267 | { | ||
268 | return get_static_power(dfc, freq) + get_dynamic_power(dfc, freq, | ||
269 | voltage); | ||
270 | } | ||
271 | |||
272 | |||
242 | static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cdev, | 273 | static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cdev, |
243 | struct thermal_zone_device *tz, | 274 | struct thermal_zone_device *tz, |
244 | u32 *power) | 275 | u32 *power) |
@@ -248,27 +279,55 @@ static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cd | |||
248 | struct devfreq_dev_status *status = &df->last_status; | 279 | struct devfreq_dev_status *status = &df->last_status; |
249 | unsigned long state; | 280 | unsigned long state; |
250 | unsigned long freq = status->current_frequency; | 281 | unsigned long freq = status->current_frequency; |
251 | u32 dyn_power, static_power; | 282 | unsigned long voltage; |
283 | u32 dyn_power = 0; | ||
284 | u32 static_power = 0; | ||
285 | int res; | ||
252 | 286 | ||
253 | /* Get dynamic power for state */ | ||
254 | state = freq_get_state(dfc, freq); | 287 | state = freq_get_state(dfc, freq); |
255 | if (state == THERMAL_CSTATE_INVALID) | 288 | if (state == THERMAL_CSTATE_INVALID) { |
256 | return -EAGAIN; | 289 | res = -EAGAIN; |
290 | goto fail; | ||
291 | } | ||
257 | 292 | ||
258 | dyn_power = dfc->power_table[state]; | 293 | if (dfc->power_ops->get_real_power) { |
294 | voltage = get_voltage(df, freq); | ||
295 | if (voltage == 0) { | ||
296 | res = -EINVAL; | ||
297 | goto fail; | ||
298 | } | ||
259 | 299 | ||
260 | /* Scale dynamic power for utilization */ | 300 | res = dfc->power_ops->get_real_power(df, power, freq, voltage); |
261 | dyn_power = (dyn_power * status->busy_time) / status->total_time; | 301 | if (!res) { |
302 | state = dfc->capped_state; | ||
303 | dfc->res_util = dfc->power_table[state]; | ||
304 | dfc->res_util *= SCALE_ERROR_MITIGATION; | ||
262 | 305 | ||
263 | /* Get static power */ | 306 | if (*power > 1) |
264 | static_power = get_static_power(dfc, freq); | 307 | dfc->res_util /= *power; |
308 | } else { | ||
309 | goto fail; | ||
310 | } | ||
311 | } else { | ||
312 | dyn_power = dfc->power_table[state]; | ||
265 | 313 | ||
266 | trace_thermal_power_devfreq_get_power(cdev, status, freq, dyn_power, | 314 | /* Scale dynamic power for utilization */ |
267 | static_power); | 315 | dyn_power *= status->busy_time; |
316 | dyn_power /= status->total_time; | ||
317 | /* Get static power */ | ||
318 | static_power = get_static_power(dfc, freq); | ||
268 | 319 | ||
269 | *power = dyn_power + static_power; | 320 | *power = dyn_power + static_power; |
321 | } | ||
322 | |||
323 | trace_thermal_power_devfreq_get_power(cdev, status, freq, dyn_power, | ||
324 | static_power, *power); | ||
270 | 325 | ||
271 | return 0; | 326 | return 0; |
327 | fail: | ||
328 | /* It is safe to set max in this case */ | ||
329 | dfc->res_util = SCALE_ERROR_MITIGATION; | ||
330 | return res; | ||
272 | } | 331 | } |
273 | 332 | ||
274 | static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev, | 333 | static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev, |
@@ -301,26 +360,34 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev, | |||
301 | unsigned long busy_time; | 360 | unsigned long busy_time; |
302 | s32 dyn_power; | 361 | s32 dyn_power; |
303 | u32 static_power; | 362 | u32 static_power; |
363 | s32 est_power; | ||
304 | int i; | 364 | int i; |
305 | 365 | ||
306 | static_power = get_static_power(dfc, freq); | 366 | if (dfc->power_ops->get_real_power) { |
367 | /* Scale for resource utilization */ | ||
368 | est_power = power * dfc->res_util; | ||
369 | est_power /= SCALE_ERROR_MITIGATION; | ||
370 | } else { | ||
371 | static_power = get_static_power(dfc, freq); | ||
307 | 372 | ||
308 | dyn_power = power - static_power; | 373 | dyn_power = power - static_power; |
309 | dyn_power = dyn_power > 0 ? dyn_power : 0; | 374 | dyn_power = dyn_power > 0 ? dyn_power : 0; |
310 | 375 | ||
311 | /* Scale dynamic power for utilization */ | 376 | /* Scale dynamic power for utilization */ |
312 | busy_time = status->busy_time ?: 1; | 377 | busy_time = status->busy_time ?: 1; |
313 | dyn_power = (dyn_power * status->total_time) / busy_time; | 378 | est_power = (dyn_power * status->total_time) / busy_time; |
379 | } | ||
314 | 380 | ||
315 | /* | 381 | /* |
316 | * Find the first cooling state that is within the power | 382 | * Find the first cooling state that is within the power |
317 | * budget for dynamic power. | 383 | * budget for dynamic power. |
318 | */ | 384 | */ |
319 | for (i = 0; i < dfc->freq_table_size - 1; i++) | 385 | for (i = 0; i < dfc->freq_table_size - 1; i++) |
320 | if (dyn_power >= dfc->power_table[i]) | 386 | if (est_power >= dfc->power_table[i]) |
321 | break; | 387 | break; |
322 | 388 | ||
323 | *state = i; | 389 | *state = i; |
390 | dfc->capped_state = i; | ||
324 | trace_thermal_power_devfreq_limit(cdev, freq, *state, power); | 391 | trace_thermal_power_devfreq_limit(cdev, freq, *state, power); |
325 | return 0; | 392 | return 0; |
326 | } | 393 | } |
@@ -376,7 +443,7 @@ static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc) | |||
376 | } | 443 | } |
377 | 444 | ||
378 | for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) { | 445 | for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) { |
379 | unsigned long power_dyn, voltage; | 446 | unsigned long power, voltage; |
380 | struct dev_pm_opp *opp; | 447 | struct dev_pm_opp *opp; |
381 | 448 | ||
382 | opp = dev_pm_opp_find_freq_floor(dev, &freq); | 449 | opp = dev_pm_opp_find_freq_floor(dev, &freq); |
@@ -389,12 +456,15 @@ static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc) | |||
389 | dev_pm_opp_put(opp); | 456 | dev_pm_opp_put(opp); |
390 | 457 | ||
391 | if (dfc->power_ops) { | 458 | if (dfc->power_ops) { |
392 | power_dyn = get_dynamic_power(dfc, freq, voltage); | 459 | if (dfc->power_ops->get_real_power) |
460 | power = get_total_power(dfc, freq, voltage); | ||
461 | else | ||
462 | power = get_dynamic_power(dfc, freq, voltage); | ||
393 | 463 | ||
394 | dev_dbg(dev, "Dynamic power table: %lu MHz @ %lu mV: %lu = %lu mW\n", | 464 | dev_dbg(dev, "Power table: %lu MHz @ %lu mV: %lu = %lu mW\n", |
395 | freq / 1000000, voltage, power_dyn, power_dyn); | 465 | freq / 1000000, voltage, power, power); |
396 | 466 | ||
397 | power_table[i] = power_dyn; | 467 | power_table[i] = power; |
398 | } | 468 | } |
399 | 469 | ||
400 | freq_table[i] = freq; | 470 | freq_table[i] = freq; |
diff --git a/drivers/thermal/intel_soc_dts_thermal.c b/drivers/thermal/intel_soc_dts_thermal.c index b2bbaa1c60b0..c27868b2c6af 100644 --- a/drivers/thermal/intel_soc_dts_thermal.c +++ b/drivers/thermal/intel_soc_dts_thermal.c | |||
@@ -73,8 +73,12 @@ static int __init intel_soc_thermal_init(void) | |||
73 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | 73 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, |
74 | "soc_dts", soc_dts); | 74 | "soc_dts", soc_dts); |
75 | if (err) { | 75 | if (err) { |
76 | pr_err("request_threaded_irq ret %d\n", err); | 76 | /* |
77 | goto error_irq; | 77 | * Do not just error out because the user space thermal |
78 | * daemon such as DPTF may use polling instead of being | ||
79 | * interrupt driven. | ||
80 | */ | ||
81 | pr_warn("request_threaded_irq ret %d\n", err); | ||
78 | } | 82 | } |
79 | } | 83 | } |
80 | 84 | ||
@@ -88,7 +92,6 @@ static int __init intel_soc_thermal_init(void) | |||
88 | error_trips: | 92 | error_trips: |
89 | if (soc_dts_thres_irq) | 93 | if (soc_dts_thres_irq) |
90 | free_irq(soc_dts_thres_irq, soc_dts); | 94 | free_irq(soc_dts_thres_irq, soc_dts); |
91 | error_irq: | ||
92 | intel_soc_dts_iosf_exit(soc_dts); | 95 | intel_soc_dts_iosf_exit(soc_dts); |
93 | 96 | ||
94 | return err; | 97 | return err; |
diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c index 1aff7fde54b1..7737f14846f9 100644 --- a/drivers/thermal/mtk_thermal.c +++ b/drivers/thermal/mtk_thermal.c | |||
@@ -191,7 +191,7 @@ static const int mt8173_bank_data[MT8173_NUM_ZONES][3] = { | |||
191 | }; | 191 | }; |
192 | 192 | ||
193 | static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = { | 193 | static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = { |
194 | TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR2 | 194 | TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3 |
195 | }; | 195 | }; |
196 | 196 | ||
197 | static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = { | 197 | static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = { |
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index d33c845244b1..37fcefd06d9f 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c | |||
@@ -20,12 +20,14 @@ | |||
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/io.h> | 21 | #include <linux/io.h> |
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/mutex.h> | ||
24 | #include <linux/of_device.h> | 23 | #include <linux/of_device.h> |
25 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
26 | #include <linux/pm_runtime.h> | 25 | #include <linux/pm_runtime.h> |
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/thermal.h> | 27 | #include <linux/thermal.h> |
28 | 28 | ||
29 | #include "thermal_core.h" | ||
30 | |||
29 | /* Register offsets */ | 31 | /* Register offsets */ |
30 | #define REG_GEN3_IRQSTR 0x04 | 32 | #define REG_GEN3_IRQSTR 0x04 |
31 | #define REG_GEN3_IRQMSK 0x08 | 33 | #define REG_GEN3_IRQMSK 0x08 |
@@ -41,6 +43,14 @@ | |||
41 | #define REG_GEN3_THCODE2 0x54 | 43 | #define REG_GEN3_THCODE2 0x54 |
42 | #define REG_GEN3_THCODE3 0x58 | 44 | #define REG_GEN3_THCODE3 0x58 |
43 | 45 | ||
46 | /* IRQ{STR,MSK,EN} bits */ | ||
47 | #define IRQ_TEMP1 BIT(0) | ||
48 | #define IRQ_TEMP2 BIT(1) | ||
49 | #define IRQ_TEMP3 BIT(2) | ||
50 | #define IRQ_TEMPD1 BIT(3) | ||
51 | #define IRQ_TEMPD2 BIT(4) | ||
52 | #define IRQ_TEMPD3 BIT(5) | ||
53 | |||
44 | /* CTSR bits */ | 54 | /* CTSR bits */ |
45 | #define CTSR_PONM BIT(8) | 55 | #define CTSR_PONM BIT(8) |
46 | #define CTSR_AOUT BIT(7) | 56 | #define CTSR_AOUT BIT(7) |
@@ -72,11 +82,15 @@ struct rcar_gen3_thermal_tsc { | |||
72 | void __iomem *base; | 82 | void __iomem *base; |
73 | struct thermal_zone_device *zone; | 83 | struct thermal_zone_device *zone; |
74 | struct equation_coefs coef; | 84 | struct equation_coefs coef; |
75 | struct mutex lock; | 85 | int low; |
86 | int high; | ||
76 | }; | 87 | }; |
77 | 88 | ||
78 | struct rcar_gen3_thermal_priv { | 89 | struct rcar_gen3_thermal_priv { |
79 | struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM]; | 90 | struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM]; |
91 | unsigned int num_tscs; | ||
92 | spinlock_t lock; /* Protect interrupts on and off */ | ||
93 | const struct rcar_gen3_thermal_data *data; | ||
80 | }; | 94 | }; |
81 | 95 | ||
82 | struct rcar_gen3_thermal_data { | 96 | struct rcar_gen3_thermal_data { |
@@ -114,6 +128,7 @@ static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc, | |||
114 | 128 | ||
115 | #define FIXPT_SHIFT 7 | 129 | #define FIXPT_SHIFT 7 |
116 | #define FIXPT_INT(_x) ((_x) << FIXPT_SHIFT) | 130 | #define FIXPT_INT(_x) ((_x) << FIXPT_SHIFT) |
131 | #define INT_FIXPT(_x) ((_x) >> FIXPT_SHIFT) | ||
117 | #define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b)) | 132 | #define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b)) |
118 | #define FIXPT_TO_MCELSIUS(_x) ((_x) * 1000 >> FIXPT_SHIFT) | 133 | #define FIXPT_TO_MCELSIUS(_x) ((_x) * 1000 >> FIXPT_SHIFT) |
119 | 134 | ||
@@ -163,16 +178,12 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp) | |||
163 | u32 reg; | 178 | u32 reg; |
164 | 179 | ||
165 | /* Read register and convert to mili Celsius */ | 180 | /* Read register and convert to mili Celsius */ |
166 | mutex_lock(&tsc->lock); | ||
167 | |||
168 | reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK; | 181 | reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK; |
169 | 182 | ||
170 | val1 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, tsc->coef.a1); | 183 | val1 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, tsc->coef.a1); |
171 | val2 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, tsc->coef.a2); | 184 | val2 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, tsc->coef.a2); |
172 | mcelsius = FIXPT_TO_MCELSIUS((val1 + val2) / 2); | 185 | mcelsius = FIXPT_TO_MCELSIUS((val1 + val2) / 2); |
173 | 186 | ||
174 | mutex_unlock(&tsc->lock); | ||
175 | |||
176 | /* Make sure we are inside specifications */ | 187 | /* Make sure we are inside specifications */ |
177 | if ((mcelsius < MCELSIUS(-40)) || (mcelsius > MCELSIUS(125))) | 188 | if ((mcelsius < MCELSIUS(-40)) || (mcelsius > MCELSIUS(125))) |
178 | return -EIO; | 189 | return -EIO; |
@@ -183,10 +194,90 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp) | |||
183 | return 0; | 194 | return 0; |
184 | } | 195 | } |
185 | 196 | ||
197 | static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc, | ||
198 | int mcelsius) | ||
199 | { | ||
200 | int celsius, val1, val2; | ||
201 | |||
202 | celsius = DIV_ROUND_CLOSEST(mcelsius, 1000); | ||
203 | val1 = celsius * tsc->coef.a1 + tsc->coef.b1; | ||
204 | val2 = celsius * tsc->coef.a2 + tsc->coef.b2; | ||
205 | |||
206 | return INT_FIXPT((val1 + val2) / 2); | ||
207 | } | ||
208 | |||
209 | static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high) | ||
210 | { | ||
211 | struct rcar_gen3_thermal_tsc *tsc = devdata; | ||
212 | |||
213 | low = clamp_val(low, -40000, 125000); | ||
214 | high = clamp_val(high, -40000, 125000); | ||
215 | |||
216 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1, | ||
217 | rcar_gen3_thermal_mcelsius_to_temp(tsc, low)); | ||
218 | |||
219 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2, | ||
220 | rcar_gen3_thermal_mcelsius_to_temp(tsc, high)); | ||
221 | |||
222 | tsc->low = low; | ||
223 | tsc->high = high; | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
186 | static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = { | 228 | static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = { |
187 | .get_temp = rcar_gen3_thermal_get_temp, | 229 | .get_temp = rcar_gen3_thermal_get_temp, |
230 | .set_trips = rcar_gen3_thermal_set_trips, | ||
188 | }; | 231 | }; |
189 | 232 | ||
233 | static void rcar_thermal_irq_set(struct rcar_gen3_thermal_priv *priv, bool on) | ||
234 | { | ||
235 | unsigned int i; | ||
236 | u32 val = on ? IRQ_TEMPD1 | IRQ_TEMP2 : 0; | ||
237 | |||
238 | for (i = 0; i < priv->num_tscs; i++) | ||
239 | rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQMSK, val); | ||
240 | } | ||
241 | |||
242 | static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data) | ||
243 | { | ||
244 | struct rcar_gen3_thermal_priv *priv = data; | ||
245 | u32 status; | ||
246 | int i, ret = IRQ_HANDLED; | ||
247 | |||
248 | spin_lock(&priv->lock); | ||
249 | for (i = 0; i < priv->num_tscs; i++) { | ||
250 | status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR); | ||
251 | rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0); | ||
252 | if (status) | ||
253 | ret = IRQ_WAKE_THREAD; | ||
254 | } | ||
255 | |||
256 | if (ret == IRQ_WAKE_THREAD) | ||
257 | rcar_thermal_irq_set(priv, false); | ||
258 | |||
259 | spin_unlock(&priv->lock); | ||
260 | |||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | static irqreturn_t rcar_gen3_thermal_irq_thread(int irq, void *data) | ||
265 | { | ||
266 | struct rcar_gen3_thermal_priv *priv = data; | ||
267 | unsigned long flags; | ||
268 | int i; | ||
269 | |||
270 | for (i = 0; i < priv->num_tscs; i++) | ||
271 | thermal_zone_device_update(priv->tscs[i]->zone, | ||
272 | THERMAL_EVENT_UNSPECIFIED); | ||
273 | |||
274 | spin_lock_irqsave(&priv->lock, flags); | ||
275 | rcar_thermal_irq_set(priv, true); | ||
276 | spin_unlock_irqrestore(&priv->lock, flags); | ||
277 | |||
278 | return IRQ_HANDLED; | ||
279 | } | ||
280 | |||
190 | static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc) | 281 | static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc) |
191 | { | 282 | { |
192 | rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_THBGR); | 283 | rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_THBGR); |
@@ -195,7 +286,11 @@ static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc) | |||
195 | usleep_range(1000, 2000); | 286 | usleep_range(1000, 2000); |
196 | 287 | ||
197 | rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_PONM); | 288 | rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_PONM); |
289 | |||
198 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F); | 290 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F); |
291 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0); | ||
292 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2); | ||
293 | |||
199 | rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, | 294 | rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, |
200 | CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN); | 295 | CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN); |
201 | 296 | ||
@@ -219,9 +314,14 @@ static void r8a7796_thermal_init(struct rcar_gen3_thermal_tsc *tsc) | |||
219 | usleep_range(1000, 2000); | 314 | usleep_range(1000, 2000); |
220 | 315 | ||
221 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F); | 316 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F); |
317 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0); | ||
318 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2); | ||
319 | |||
222 | reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR); | 320 | reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR); |
223 | reg_val |= THCTR_THSST; | 321 | reg_val |= THCTR_THSST; |
224 | rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val); | 322 | rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val); |
323 | |||
324 | usleep_range(1000, 2000); | ||
225 | } | 325 | } |
226 | 326 | ||
227 | static const struct rcar_gen3_thermal_data r8a7795_data = { | 327 | static const struct rcar_gen3_thermal_data r8a7795_data = { |
@@ -255,9 +355,8 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) | |||
255 | struct device *dev = &pdev->dev; | 355 | struct device *dev = &pdev->dev; |
256 | struct resource *res; | 356 | struct resource *res; |
257 | struct thermal_zone_device *zone; | 357 | struct thermal_zone_device *zone; |
258 | int ret, i; | 358 | int ret, irq, i; |
259 | const struct rcar_gen3_thermal_data *match_data = | 359 | char *irqname; |
260 | of_device_get_match_data(dev); | ||
261 | 360 | ||
262 | /* default values if FUSEs are missing */ | 361 | /* default values if FUSEs are missing */ |
263 | /* TODO: Read values from hardware on supported platforms */ | 362 | /* TODO: Read values from hardware on supported platforms */ |
@@ -272,24 +371,50 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) | |||
272 | if (!priv) | 371 | if (!priv) |
273 | return -ENOMEM; | 372 | return -ENOMEM; |
274 | 373 | ||
374 | priv->data = of_device_get_match_data(dev); | ||
375 | |||
376 | spin_lock_init(&priv->lock); | ||
377 | |||
275 | platform_set_drvdata(pdev, priv); | 378 | platform_set_drvdata(pdev, priv); |
276 | 379 | ||
380 | /* | ||
381 | * Request 2 (of the 3 possible) IRQs, the driver only needs to | ||
382 | * to trigger on the low and high trip points of the current | ||
383 | * temp window at this point. | ||
384 | */ | ||
385 | for (i = 0; i < 2; i++) { | ||
386 | irq = platform_get_irq(pdev, i); | ||
387 | if (irq < 0) | ||
388 | return irq; | ||
389 | |||
390 | irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:ch%d", | ||
391 | dev_name(dev), i); | ||
392 | if (!irqname) | ||
393 | return -ENOMEM; | ||
394 | |||
395 | ret = devm_request_threaded_irq(dev, irq, rcar_gen3_thermal_irq, | ||
396 | rcar_gen3_thermal_irq_thread, | ||
397 | IRQF_SHARED, irqname, priv); | ||
398 | if (ret) | ||
399 | return ret; | ||
400 | } | ||
401 | |||
277 | pm_runtime_enable(dev); | 402 | pm_runtime_enable(dev); |
278 | pm_runtime_get_sync(dev); | 403 | pm_runtime_get_sync(dev); |
279 | 404 | ||
280 | for (i = 0; i < TSC_MAX_NUM; i++) { | 405 | for (i = 0; i < TSC_MAX_NUM; i++) { |
281 | struct rcar_gen3_thermal_tsc *tsc; | 406 | struct rcar_gen3_thermal_tsc *tsc; |
282 | 407 | ||
408 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
409 | if (!res) | ||
410 | break; | ||
411 | |||
283 | tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL); | 412 | tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL); |
284 | if (!tsc) { | 413 | if (!tsc) { |
285 | ret = -ENOMEM; | 414 | ret = -ENOMEM; |
286 | goto error_unregister; | 415 | goto error_unregister; |
287 | } | 416 | } |
288 | 417 | ||
289 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
290 | if (!res) | ||
291 | break; | ||
292 | |||
293 | tsc->base = devm_ioremap_resource(dev, res); | 418 | tsc->base = devm_ioremap_resource(dev, res); |
294 | if (IS_ERR(tsc->base)) { | 419 | if (IS_ERR(tsc->base)) { |
295 | ret = PTR_ERR(tsc->base); | 420 | ret = PTR_ERR(tsc->base); |
@@ -297,9 +422,8 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) | |||
297 | } | 422 | } |
298 | 423 | ||
299 | priv->tscs[i] = tsc; | 424 | priv->tscs[i] = tsc; |
300 | mutex_init(&tsc->lock); | ||
301 | 425 | ||
302 | match_data->thermal_init(tsc); | 426 | priv->data->thermal_init(tsc); |
303 | rcar_gen3_thermal_calc_coefs(&tsc->coef, ptat, thcode[i]); | 427 | rcar_gen3_thermal_calc_coefs(&tsc->coef, ptat, thcode[i]); |
304 | 428 | ||
305 | zone = devm_thermal_zone_of_sensor_register(dev, i, tsc, | 429 | zone = devm_thermal_zone_of_sensor_register(dev, i, tsc, |
@@ -310,8 +434,23 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) | |||
310 | goto error_unregister; | 434 | goto error_unregister; |
311 | } | 435 | } |
312 | tsc->zone = zone; | 436 | tsc->zone = zone; |
437 | |||
438 | ret = of_thermal_get_ntrips(tsc->zone); | ||
439 | if (ret < 0) | ||
440 | goto error_unregister; | ||
441 | |||
442 | dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret); | ||
313 | } | 443 | } |
314 | 444 | ||
445 | priv->num_tscs = i; | ||
446 | |||
447 | if (!priv->num_tscs) { | ||
448 | ret = -ENODEV; | ||
449 | goto error_unregister; | ||
450 | } | ||
451 | |||
452 | rcar_thermal_irq_set(priv, true); | ||
453 | |||
315 | return 0; | 454 | return 0; |
316 | 455 | ||
317 | error_unregister: | 456 | error_unregister: |
@@ -320,9 +459,39 @@ error_unregister: | |||
320 | return ret; | 459 | return ret; |
321 | } | 460 | } |
322 | 461 | ||
462 | static int __maybe_unused rcar_gen3_thermal_suspend(struct device *dev) | ||
463 | { | ||
464 | struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev); | ||
465 | |||
466 | rcar_thermal_irq_set(priv, false); | ||
467 | |||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev) | ||
472 | { | ||
473 | struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev); | ||
474 | unsigned int i; | ||
475 | |||
476 | for (i = 0; i < priv->num_tscs; i++) { | ||
477 | struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i]; | ||
478 | |||
479 | priv->data->thermal_init(tsc); | ||
480 | rcar_gen3_thermal_set_trips(tsc, tsc->low, tsc->high); | ||
481 | } | ||
482 | |||
483 | rcar_thermal_irq_set(priv, true); | ||
484 | |||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops, rcar_gen3_thermal_suspend, | ||
489 | rcar_gen3_thermal_resume); | ||
490 | |||
323 | static struct platform_driver rcar_gen3_thermal_driver = { | 491 | static struct platform_driver rcar_gen3_thermal_driver = { |
324 | .driver = { | 492 | .driver = { |
325 | .name = "rcar_gen3_thermal", | 493 | .name = "rcar_gen3_thermal", |
494 | .pm = &rcar_gen3_thermal_pm_ops, | ||
326 | .of_match_table = rcar_gen3_thermal_dt_ids, | 495 | .of_match_table = rcar_gen3_thermal_dt_ids, |
327 | }, | 496 | }, |
328 | .probe = rcar_gen3_thermal_probe, | 497 | .probe = rcar_gen3_thermal_probe, |
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 11f0675cb7e5..b21b9cc2c8d6 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c | |||
@@ -45,8 +45,10 @@ static LIST_HEAD(thermal_governor_list); | |||
45 | 45 | ||
46 | static DEFINE_MUTEX(thermal_list_lock); | 46 | static DEFINE_MUTEX(thermal_list_lock); |
47 | static DEFINE_MUTEX(thermal_governor_lock); | 47 | static DEFINE_MUTEX(thermal_governor_lock); |
48 | static DEFINE_MUTEX(poweroff_lock); | ||
48 | 49 | ||
49 | static atomic_t in_suspend; | 50 | static atomic_t in_suspend; |
51 | static bool power_off_triggered; | ||
50 | 52 | ||
51 | static struct thermal_governor *def_governor; | 53 | static struct thermal_governor *def_governor; |
52 | 54 | ||
@@ -322,6 +324,54 @@ static void handle_non_critical_trips(struct thermal_zone_device *tz, | |||
322 | def_governor->throttle(tz, trip); | 324 | def_governor->throttle(tz, trip); |
323 | } | 325 | } |
324 | 326 | ||
327 | /** | ||
328 | * thermal_emergency_poweroff_func - emergency poweroff work after a known delay | ||
329 | * @work: work_struct associated with the emergency poweroff function | ||
330 | * | ||
331 | * This function is called in very critical situations to force | ||
332 | * a kernel poweroff after a configurable timeout value. | ||
333 | */ | ||
334 | static void thermal_emergency_poweroff_func(struct work_struct *work) | ||
335 | { | ||
336 | /* | ||
337 | * We have reached here after the emergency thermal shutdown | ||
338 | * Waiting period has expired. This means orderly_poweroff has | ||
339 | * not been able to shut off the system for some reason. | ||
340 | * Try to shut down the system immediately using kernel_power_off | ||
341 | * if populated | ||
342 | */ | ||
343 | WARN(1, "Attempting kernel_power_off: Temperature too high\n"); | ||
344 | kernel_power_off(); | ||
345 | |||
346 | /* | ||
347 | * Worst of the worst case trigger emergency restart | ||
348 | */ | ||
349 | WARN(1, "Attempting emergency_restart: Temperature too high\n"); | ||
350 | emergency_restart(); | ||
351 | } | ||
352 | |||
353 | static DECLARE_DELAYED_WORK(thermal_emergency_poweroff_work, | ||
354 | thermal_emergency_poweroff_func); | ||
355 | |||
356 | /** | ||
357 | * thermal_emergency_poweroff - Trigger an emergency system poweroff | ||
358 | * | ||
359 | * This may be called from any critical situation to trigger a system shutdown | ||
360 | * after a known period of time. By default this is not scheduled. | ||
361 | */ | ||
362 | void thermal_emergency_poweroff(void) | ||
363 | { | ||
364 | int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS; | ||
365 | /* | ||
366 | * poweroff_delay_ms must be a carefully profiled positive value. | ||
367 | * Its a must for thermal_emergency_poweroff_work to be scheduled | ||
368 | */ | ||
369 | if (poweroff_delay_ms <= 0) | ||
370 | return; | ||
371 | schedule_delayed_work(&thermal_emergency_poweroff_work, | ||
372 | msecs_to_jiffies(poweroff_delay_ms)); | ||
373 | } | ||
374 | |||
325 | static void handle_critical_trips(struct thermal_zone_device *tz, | 375 | static void handle_critical_trips(struct thermal_zone_device *tz, |
326 | int trip, enum thermal_trip_type trip_type) | 376 | int trip, enum thermal_trip_type trip_type) |
327 | { | 377 | { |
@@ -342,7 +392,17 @@ static void handle_critical_trips(struct thermal_zone_device *tz, | |||
342 | dev_emerg(&tz->device, | 392 | dev_emerg(&tz->device, |
343 | "critical temperature reached(%d C),shutting down\n", | 393 | "critical temperature reached(%d C),shutting down\n", |
344 | tz->temperature / 1000); | 394 | tz->temperature / 1000); |
345 | orderly_poweroff(true); | 395 | mutex_lock(&poweroff_lock); |
396 | if (!power_off_triggered) { | ||
397 | /* | ||
398 | * Queue a backup emergency shutdown in the event of | ||
399 | * orderly_poweroff failure | ||
400 | */ | ||
401 | thermal_emergency_poweroff(); | ||
402 | orderly_poweroff(true); | ||
403 | power_off_triggered = true; | ||
404 | } | ||
405 | mutex_unlock(&poweroff_lock); | ||
346 | } | 406 | } |
347 | } | 407 | } |
348 | 408 | ||
@@ -1463,6 +1523,7 @@ static int __init thermal_init(void) | |||
1463 | { | 1523 | { |
1464 | int result; | 1524 | int result; |
1465 | 1525 | ||
1526 | mutex_init(&poweroff_lock); | ||
1466 | result = thermal_register_governors(); | 1527 | result = thermal_register_governors(); |
1467 | if (result) | 1528 | if (result) |
1468 | goto error; | 1529 | goto error; |
@@ -1497,6 +1558,7 @@ error: | |||
1497 | ida_destroy(&thermal_cdev_ida); | 1558 | ida_destroy(&thermal_cdev_ida); |
1498 | mutex_destroy(&thermal_list_lock); | 1559 | mutex_destroy(&thermal_list_lock); |
1499 | mutex_destroy(&thermal_governor_lock); | 1560 | mutex_destroy(&thermal_governor_lock); |
1561 | mutex_destroy(&poweroff_lock); | ||
1500 | return result; | 1562 | return result; |
1501 | } | 1563 | } |
1502 | 1564 | ||
diff --git a/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c b/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c index 118d7d847715..4167373327d9 100644 --- a/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c +++ b/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c | |||
@@ -410,8 +410,6 @@ const struct ti_bandgap_data dra752_data = { | |||
410 | .domain = "cpu", | 410 | .domain = "cpu", |
411 | .register_cooling = ti_thermal_register_cpu_cooling, | 411 | .register_cooling = ti_thermal_register_cpu_cooling, |
412 | .unregister_cooling = ti_thermal_unregister_cpu_cooling, | 412 | .unregister_cooling = ti_thermal_unregister_cpu_cooling, |
413 | .slope = DRA752_GRADIENT_SLOPE, | ||
414 | .constant = DRA752_GRADIENT_CONST, | ||
415 | .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB, | 413 | .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB, |
416 | .constant_pcb = DRA752_GRADIENT_CONST_W_PCB, | 414 | .constant_pcb = DRA752_GRADIENT_CONST_W_PCB, |
417 | }, | 415 | }, |
@@ -419,8 +417,6 @@ const struct ti_bandgap_data dra752_data = { | |||
419 | .registers = &dra752_gpu_temp_sensor_registers, | 417 | .registers = &dra752_gpu_temp_sensor_registers, |
420 | .ts_data = &dra752_gpu_temp_sensor_data, | 418 | .ts_data = &dra752_gpu_temp_sensor_data, |
421 | .domain = "gpu", | 419 | .domain = "gpu", |
422 | .slope = DRA752_GRADIENT_SLOPE, | ||
423 | .constant = DRA752_GRADIENT_CONST, | ||
424 | .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB, | 420 | .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB, |
425 | .constant_pcb = DRA752_GRADIENT_CONST_W_PCB, | 421 | .constant_pcb = DRA752_GRADIENT_CONST_W_PCB, |
426 | }, | 422 | }, |
@@ -428,8 +424,6 @@ const struct ti_bandgap_data dra752_data = { | |||
428 | .registers = &dra752_core_temp_sensor_registers, | 424 | .registers = &dra752_core_temp_sensor_registers, |
429 | .ts_data = &dra752_core_temp_sensor_data, | 425 | .ts_data = &dra752_core_temp_sensor_data, |
430 | .domain = "core", | 426 | .domain = "core", |
431 | .slope = DRA752_GRADIENT_SLOPE, | ||
432 | .constant = DRA752_GRADIENT_CONST, | ||
433 | .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB, | 427 | .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB, |
434 | .constant_pcb = DRA752_GRADIENT_CONST_W_PCB, | 428 | .constant_pcb = DRA752_GRADIENT_CONST_W_PCB, |
435 | }, | 429 | }, |
@@ -437,8 +431,6 @@ const struct ti_bandgap_data dra752_data = { | |||
437 | .registers = &dra752_dspeve_temp_sensor_registers, | 431 | .registers = &dra752_dspeve_temp_sensor_registers, |
438 | .ts_data = &dra752_dspeve_temp_sensor_data, | 432 | .ts_data = &dra752_dspeve_temp_sensor_data, |
439 | .domain = "dspeve", | 433 | .domain = "dspeve", |
440 | .slope = DRA752_GRADIENT_SLOPE, | ||
441 | .constant = DRA752_GRADIENT_CONST, | ||
442 | .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB, | 434 | .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB, |
443 | .constant_pcb = DRA752_GRADIENT_CONST_W_PCB, | 435 | .constant_pcb = DRA752_GRADIENT_CONST_W_PCB, |
444 | }, | 436 | }, |
@@ -446,8 +438,6 @@ const struct ti_bandgap_data dra752_data = { | |||
446 | .registers = &dra752_iva_temp_sensor_registers, | 438 | .registers = &dra752_iva_temp_sensor_registers, |
447 | .ts_data = &dra752_iva_temp_sensor_data, | 439 | .ts_data = &dra752_iva_temp_sensor_data, |
448 | .domain = "iva", | 440 | .domain = "iva", |
449 | .slope = DRA752_GRADIENT_SLOPE, | ||
450 | .constant = DRA752_GRADIENT_CONST, | ||
451 | .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB, | 441 | .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB, |
452 | .constant_pcb = DRA752_GRADIENT_CONST_W_PCB, | 442 | .constant_pcb = DRA752_GRADIENT_CONST_W_PCB, |
453 | }, | 443 | }, |
diff --git a/drivers/thermal/ti-soc-thermal/omap3-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap3-thermal-data.c index 3ee34340edab..c6d217913dd1 100644 --- a/drivers/thermal/ti-soc-thermal/omap3-thermal-data.c +++ b/drivers/thermal/ti-soc-thermal/omap3-thermal-data.c | |||
@@ -91,8 +91,6 @@ const struct ti_bandgap_data omap34xx_data = { | |||
91 | .registers = &omap34xx_mpu_temp_sensor_registers, | 91 | .registers = &omap34xx_mpu_temp_sensor_registers, |
92 | .ts_data = &omap34xx_mpu_temp_sensor_data, | 92 | .ts_data = &omap34xx_mpu_temp_sensor_data, |
93 | .domain = "cpu", | 93 | .domain = "cpu", |
94 | .slope = 0, | ||
95 | .constant = 20000, | ||
96 | .slope_pcb = 0, | 94 | .slope_pcb = 0, |
97 | .constant_pcb = 20000, | 95 | .constant_pcb = 20000, |
98 | .register_cooling = NULL, | 96 | .register_cooling = NULL, |
@@ -164,8 +162,6 @@ const struct ti_bandgap_data omap36xx_data = { | |||
164 | .registers = &omap36xx_mpu_temp_sensor_registers, | 162 | .registers = &omap36xx_mpu_temp_sensor_registers, |
165 | .ts_data = &omap36xx_mpu_temp_sensor_data, | 163 | .ts_data = &omap36xx_mpu_temp_sensor_data, |
166 | .domain = "cpu", | 164 | .domain = "cpu", |
167 | .slope = 0, | ||
168 | .constant = 20000, | ||
169 | .slope_pcb = 0, | 165 | .slope_pcb = 0, |
170 | .constant_pcb = 20000, | 166 | .constant_pcb = 20000, |
171 | .register_cooling = NULL, | 167 | .register_cooling = NULL, |
diff --git a/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c index d255d33da9eb..fd1113360603 100644 --- a/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c +++ b/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c | |||
@@ -82,8 +82,6 @@ const struct ti_bandgap_data omap4430_data = { | |||
82 | .registers = &omap4430_mpu_temp_sensor_registers, | 82 | .registers = &omap4430_mpu_temp_sensor_registers, |
83 | .ts_data = &omap4430_mpu_temp_sensor_data, | 83 | .ts_data = &omap4430_mpu_temp_sensor_data, |
84 | .domain = "cpu", | 84 | .domain = "cpu", |
85 | .slope = OMAP_GRADIENT_SLOPE_4430, | ||
86 | .constant = OMAP_GRADIENT_CONST_4430, | ||
87 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4430, | 85 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4430, |
88 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4430, | 86 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4430, |
89 | .register_cooling = ti_thermal_register_cpu_cooling, | 87 | .register_cooling = ti_thermal_register_cpu_cooling, |
@@ -222,8 +220,6 @@ const struct ti_bandgap_data omap4460_data = { | |||
222 | .registers = &omap4460_mpu_temp_sensor_registers, | 220 | .registers = &omap4460_mpu_temp_sensor_registers, |
223 | .ts_data = &omap4460_mpu_temp_sensor_data, | 221 | .ts_data = &omap4460_mpu_temp_sensor_data, |
224 | .domain = "cpu", | 222 | .domain = "cpu", |
225 | .slope = OMAP_GRADIENT_SLOPE_4460, | ||
226 | .constant = OMAP_GRADIENT_CONST_4460, | ||
227 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4460, | 223 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4460, |
228 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4460, | 224 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4460, |
229 | .register_cooling = ti_thermal_register_cpu_cooling, | 225 | .register_cooling = ti_thermal_register_cpu_cooling, |
@@ -255,8 +251,6 @@ const struct ti_bandgap_data omap4470_data = { | |||
255 | .registers = &omap4460_mpu_temp_sensor_registers, | 251 | .registers = &omap4460_mpu_temp_sensor_registers, |
256 | .ts_data = &omap4460_mpu_temp_sensor_data, | 252 | .ts_data = &omap4460_mpu_temp_sensor_data, |
257 | .domain = "cpu", | 253 | .domain = "cpu", |
258 | .slope = OMAP_GRADIENT_SLOPE_4470, | ||
259 | .constant = OMAP_GRADIENT_CONST_4470, | ||
260 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4470, | 254 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4470, |
261 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4470, | 255 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4470, |
262 | .register_cooling = ti_thermal_register_cpu_cooling, | 256 | .register_cooling = ti_thermal_register_cpu_cooling, |
diff --git a/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c index 79ff70c446ba..cd9a304fb571 100644 --- a/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c +++ b/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c | |||
@@ -336,8 +336,6 @@ const struct ti_bandgap_data omap5430_data = { | |||
336 | .domain = "cpu", | 336 | .domain = "cpu", |
337 | .register_cooling = ti_thermal_register_cpu_cooling, | 337 | .register_cooling = ti_thermal_register_cpu_cooling, |
338 | .unregister_cooling = ti_thermal_unregister_cpu_cooling, | 338 | .unregister_cooling = ti_thermal_unregister_cpu_cooling, |
339 | .slope = OMAP_GRADIENT_SLOPE_5430_CPU, | ||
340 | .constant = OMAP_GRADIENT_CONST_5430_CPU, | ||
341 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU, | 339 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU, |
342 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_CPU, | 340 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_CPU, |
343 | }, | 341 | }, |
@@ -345,8 +343,6 @@ const struct ti_bandgap_data omap5430_data = { | |||
345 | .registers = &omap5430_gpu_temp_sensor_registers, | 343 | .registers = &omap5430_gpu_temp_sensor_registers, |
346 | .ts_data = &omap5430_gpu_temp_sensor_data, | 344 | .ts_data = &omap5430_gpu_temp_sensor_data, |
347 | .domain = "gpu", | 345 | .domain = "gpu", |
348 | .slope = OMAP_GRADIENT_SLOPE_5430_GPU, | ||
349 | .constant = OMAP_GRADIENT_CONST_5430_GPU, | ||
350 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU, | 346 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU, |
351 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_GPU, | 347 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_GPU, |
352 | }, | 348 | }, |
diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.h b/drivers/thermal/ti-soc-thermal/ti-bandgap.h index fe0adb898764..209c664c2823 100644 --- a/drivers/thermal/ti-soc-thermal/ti-bandgap.h +++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.h | |||
@@ -254,8 +254,6 @@ struct ti_bandgap { | |||
254 | * @ts_data: pointer to struct with thresholds, limits of temperature sensor | 254 | * @ts_data: pointer to struct with thresholds, limits of temperature sensor |
255 | * @registers: pointer to the list of register offsets and bitfields | 255 | * @registers: pointer to the list of register offsets and bitfields |
256 | * @domain: the name of the domain where the sensor is located | 256 | * @domain: the name of the domain where the sensor is located |
257 | * @slope: sensor gradient slope info for hotspot extrapolation equation | ||
258 | * @constant: sensor gradient const info for hotspot extrapolation equation | ||
259 | * @slope_pcb: sensor gradient slope info for hotspot extrapolation equation | 257 | * @slope_pcb: sensor gradient slope info for hotspot extrapolation equation |
260 | * with no external influence | 258 | * with no external influence |
261 | * @constant_pcb: sensor gradient const info for hotspot extrapolation equation | 259 | * @constant_pcb: sensor gradient const info for hotspot extrapolation equation |
@@ -274,8 +272,6 @@ struct ti_temp_sensor { | |||
274 | struct temp_sensor_registers *registers; | 272 | struct temp_sensor_registers *registers; |
275 | char *domain; | 273 | char *domain; |
276 | /* for hotspot extrapolation */ | 274 | /* for hotspot extrapolation */ |
277 | const int slope; | ||
278 | const int constant; | ||
279 | const int slope_pcb; | 275 | const int slope_pcb; |
280 | const int constant_pcb; | 276 | const int constant_pcb; |
281 | int (*register_cooling)(struct ti_bandgap *bgp, int id); | 277 | int (*register_cooling)(struct ti_bandgap *bgp, int id); |
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c index 0586bd0f2bab..02790f69e26c 100644 --- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c +++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c | |||
@@ -96,8 +96,8 @@ static inline int __ti_thermal_get_temp(void *devdata, int *temp) | |||
96 | return ret; | 96 | return ret; |
97 | 97 | ||
98 | /* Default constants */ | 98 | /* Default constants */ |
99 | slope = s->slope; | 99 | slope = thermal_zone_get_slope(data->ti_thermal); |
100 | constant = s->constant; | 100 | constant = thermal_zone_get_offset(data->ti_thermal); |
101 | 101 | ||
102 | pcb_tz = data->pcb_tz; | 102 | pcb_tz = data->pcb_tz; |
103 | /* In case pcb zone is available, use the extrapolation rule with it */ | 103 | /* In case pcb zone is available, use the extrapolation rule with it */ |
@@ -126,119 +126,6 @@ static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal, | |||
126 | return __ti_thermal_get_temp(data, temp); | 126 | return __ti_thermal_get_temp(data, temp); |
127 | } | 127 | } |
128 | 128 | ||
129 | /* Bind callback functions for thermal zone */ | ||
130 | static int ti_thermal_bind(struct thermal_zone_device *thermal, | ||
131 | struct thermal_cooling_device *cdev) | ||
132 | { | ||
133 | struct ti_thermal_data *data = thermal->devdata; | ||
134 | int id; | ||
135 | |||
136 | if (!data || IS_ERR(data)) | ||
137 | return -ENODEV; | ||
138 | |||
139 | /* check if this is the cooling device we registered */ | ||
140 | if (data->cool_dev != cdev) | ||
141 | return 0; | ||
142 | |||
143 | id = data->sensor_id; | ||
144 | |||
145 | /* Simple thing, two trips, one passive another critical */ | ||
146 | return thermal_zone_bind_cooling_device(thermal, 0, cdev, | ||
147 | /* bind with min and max states defined by cpu_cooling */ | ||
148 | THERMAL_NO_LIMIT, | ||
149 | THERMAL_NO_LIMIT, | ||
150 | THERMAL_WEIGHT_DEFAULT); | ||
151 | } | ||
152 | |||
153 | /* Unbind callback functions for thermal zone */ | ||
154 | static int ti_thermal_unbind(struct thermal_zone_device *thermal, | ||
155 | struct thermal_cooling_device *cdev) | ||
156 | { | ||
157 | struct ti_thermal_data *data = thermal->devdata; | ||
158 | |||
159 | if (!data || IS_ERR(data)) | ||
160 | return -ENODEV; | ||
161 | |||
162 | /* check if this is the cooling device we registered */ | ||
163 | if (data->cool_dev != cdev) | ||
164 | return 0; | ||
165 | |||
166 | /* Simple thing, two trips, one passive another critical */ | ||
167 | return thermal_zone_unbind_cooling_device(thermal, 0, cdev); | ||
168 | } | ||
169 | |||
170 | /* Get mode callback functions for thermal zone */ | ||
171 | static int ti_thermal_get_mode(struct thermal_zone_device *thermal, | ||
172 | enum thermal_device_mode *mode) | ||
173 | { | ||
174 | struct ti_thermal_data *data = thermal->devdata; | ||
175 | |||
176 | if (data) | ||
177 | *mode = data->mode; | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /* Set mode callback functions for thermal zone */ | ||
183 | static int ti_thermal_set_mode(struct thermal_zone_device *thermal, | ||
184 | enum thermal_device_mode mode) | ||
185 | { | ||
186 | struct ti_thermal_data *data = thermal->devdata; | ||
187 | struct ti_bandgap *bgp; | ||
188 | |||
189 | bgp = data->bgp; | ||
190 | |||
191 | if (!data->ti_thermal) { | ||
192 | dev_notice(&thermal->device, "thermal zone not registered\n"); | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | mutex_lock(&data->ti_thermal->lock); | ||
197 | |||
198 | if (mode == THERMAL_DEVICE_ENABLED) | ||
199 | data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE; | ||
200 | else | ||
201 | data->ti_thermal->polling_delay = 0; | ||
202 | |||
203 | mutex_unlock(&data->ti_thermal->lock); | ||
204 | |||
205 | data->mode = mode; | ||
206 | ti_bandgap_write_update_interval(bgp, data->sensor_id, | ||
207 | data->ti_thermal->polling_delay); | ||
208 | thermal_zone_device_update(data->ti_thermal, THERMAL_EVENT_UNSPECIFIED); | ||
209 | dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n", | ||
210 | data->ti_thermal->polling_delay); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | /* Get trip type callback functions for thermal zone */ | ||
216 | static int ti_thermal_get_trip_type(struct thermal_zone_device *thermal, | ||
217 | int trip, enum thermal_trip_type *type) | ||
218 | { | ||
219 | if (!ti_thermal_is_valid_trip(trip)) | ||
220 | return -EINVAL; | ||
221 | |||
222 | if (trip + 1 == OMAP_TRIP_NUMBER) | ||
223 | *type = THERMAL_TRIP_CRITICAL; | ||
224 | else | ||
225 | *type = THERMAL_TRIP_PASSIVE; | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | /* Get trip temperature callback functions for thermal zone */ | ||
231 | static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal, | ||
232 | int trip, int *temp) | ||
233 | { | ||
234 | if (!ti_thermal_is_valid_trip(trip)) | ||
235 | return -EINVAL; | ||
236 | |||
237 | *temp = ti_thermal_get_trip_value(trip); | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend) | 129 | static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend) |
243 | { | 130 | { |
244 | struct ti_thermal_data *data = p; | 131 | struct ti_thermal_data *data = p; |
@@ -262,38 +149,11 @@ static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend) | |||
262 | return 0; | 149 | return 0; |
263 | } | 150 | } |
264 | 151 | ||
265 | /* Get the temperature trend callback functions for thermal zone */ | ||
266 | static int ti_thermal_get_trend(struct thermal_zone_device *thermal, | ||
267 | int trip, enum thermal_trend *trend) | ||
268 | { | ||
269 | return __ti_thermal_get_trend(thermal->devdata, trip, trend); | ||
270 | } | ||
271 | |||
272 | /* Get critical temperature callback functions for thermal zone */ | ||
273 | static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal, | ||
274 | int *temp) | ||
275 | { | ||
276 | /* shutdown zone */ | ||
277 | return ti_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp); | ||
278 | } | ||
279 | |||
280 | static const struct thermal_zone_of_device_ops ti_of_thermal_ops = { | 152 | static const struct thermal_zone_of_device_ops ti_of_thermal_ops = { |
281 | .get_temp = __ti_thermal_get_temp, | 153 | .get_temp = __ti_thermal_get_temp, |
282 | .get_trend = __ti_thermal_get_trend, | 154 | .get_trend = __ti_thermal_get_trend, |
283 | }; | 155 | }; |
284 | 156 | ||
285 | static struct thermal_zone_device_ops ti_thermal_ops = { | ||
286 | .get_temp = ti_thermal_get_temp, | ||
287 | .get_trend = ti_thermal_get_trend, | ||
288 | .bind = ti_thermal_bind, | ||
289 | .unbind = ti_thermal_unbind, | ||
290 | .get_mode = ti_thermal_get_mode, | ||
291 | .set_mode = ti_thermal_set_mode, | ||
292 | .get_trip_type = ti_thermal_get_trip_type, | ||
293 | .get_trip_temp = ti_thermal_get_trip_temp, | ||
294 | .get_crit_temp = ti_thermal_get_crit_temp, | ||
295 | }; | ||
296 | |||
297 | static struct ti_thermal_data | 157 | static struct ti_thermal_data |
298 | *ti_thermal_build_data(struct ti_bandgap *bgp, int id) | 158 | *ti_thermal_build_data(struct ti_bandgap *bgp, int id) |
299 | { | 159 | { |
@@ -331,18 +191,10 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, | |||
331 | data->ti_thermal = devm_thermal_zone_of_sensor_register(bgp->dev, id, | 191 | data->ti_thermal = devm_thermal_zone_of_sensor_register(bgp->dev, id, |
332 | data, &ti_of_thermal_ops); | 192 | data, &ti_of_thermal_ops); |
333 | if (IS_ERR(data->ti_thermal)) { | 193 | if (IS_ERR(data->ti_thermal)) { |
334 | /* Create thermal zone */ | 194 | dev_err(bgp->dev, "thermal zone device is NULL\n"); |
335 | data->ti_thermal = thermal_zone_device_register(domain, | 195 | return PTR_ERR(data->ti_thermal); |
336 | OMAP_TRIP_NUMBER, 0, data, &ti_thermal_ops, | ||
337 | NULL, FAST_TEMP_MONITORING_RATE, | ||
338 | FAST_TEMP_MONITORING_RATE); | ||
339 | if (IS_ERR(data->ti_thermal)) { | ||
340 | dev_err(bgp->dev, "thermal zone device is NULL\n"); | ||
341 | return PTR_ERR(data->ti_thermal); | ||
342 | } | ||
343 | data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE; | ||
344 | data->our_zone = true; | ||
345 | } | 196 | } |
197 | |||
346 | ti_bandgap_set_sensor_data(bgp, id, data); | 198 | ti_bandgap_set_sensor_data(bgp, id, data); |
347 | ti_bandgap_write_update_interval(bgp, data->sensor_id, | 199 | ti_bandgap_write_update_interval(bgp, data->sensor_id, |
348 | data->ti_thermal->polling_delay); | 200 | data->ti_thermal->polling_delay); |
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal.h b/drivers/thermal/ti-soc-thermal/ti-thermal.h index f8b7ffea6194..8e85ca973967 100644 --- a/drivers/thermal/ti-soc-thermal/ti-thermal.h +++ b/drivers/thermal/ti-soc-thermal/ti-thermal.h | |||
@@ -25,22 +25,6 @@ | |||
25 | 25 | ||
26 | #include "ti-bandgap.h" | 26 | #include "ti-bandgap.h" |
27 | 27 | ||
28 | /* sensors gradient and offsets */ | ||
29 | #define OMAP_GRADIENT_SLOPE_4430 0 | ||
30 | #define OMAP_GRADIENT_CONST_4430 20000 | ||
31 | #define OMAP_GRADIENT_SLOPE_4460 348 | ||
32 | #define OMAP_GRADIENT_CONST_4460 -9301 | ||
33 | #define OMAP_GRADIENT_SLOPE_4470 308 | ||
34 | #define OMAP_GRADIENT_CONST_4470 -7896 | ||
35 | |||
36 | #define OMAP_GRADIENT_SLOPE_5430_CPU 65 | ||
37 | #define OMAP_GRADIENT_CONST_5430_CPU -1791 | ||
38 | #define OMAP_GRADIENT_SLOPE_5430_GPU 117 | ||
39 | #define OMAP_GRADIENT_CONST_5430_GPU -2992 | ||
40 | |||
41 | #define DRA752_GRADIENT_SLOPE 0 | ||
42 | #define DRA752_GRADIENT_CONST 2000 | ||
43 | |||
44 | /* PCB sensor calculation constants */ | 28 | /* PCB sensor calculation constants */ |
45 | #define OMAP_GRADIENT_SLOPE_W_PCB_4430 0 | 29 | #define OMAP_GRADIENT_SLOPE_W_PCB_4430 0 |
46 | #define OMAP_GRADIENT_CONST_W_PCB_4430 20000 | 30 | #define OMAP_GRADIENT_CONST_W_PCB_4430 20000 |
diff --git a/include/linux/devfreq_cooling.h b/include/linux/devfreq_cooling.h index c35d0c0e0ada..4635f95000a4 100644 --- a/include/linux/devfreq_cooling.h +++ b/include/linux/devfreq_cooling.h | |||
@@ -34,6 +34,23 @@ | |||
34 | * If get_dynamic_power() is NULL, then the | 34 | * If get_dynamic_power() is NULL, then the |
35 | * dynamic power is calculated as | 35 | * dynamic power is calculated as |
36 | * @dyn_power_coeff * frequency * voltage^2 | 36 | * @dyn_power_coeff * frequency * voltage^2 |
37 | * @get_real_power: When this is set, the framework uses it to ask the | ||
38 | * device driver for the actual power. | ||
39 | * Some devices have more sophisticated methods | ||
40 | * (like power counters) to approximate the actual power | ||
41 | * that they use. | ||
42 | * This function provides more accurate data to the | ||
43 | * thermal governor. When the driver does not provide | ||
44 | * such function, framework just uses pre-calculated | ||
45 | * table and scale the power by 'utilization' | ||
46 | * (based on 'busy_time' and 'total_time' taken from | ||
47 | * devfreq 'last_status'). | ||
48 | * The value returned by this function must be lower | ||
49 | * or equal than the maximum power value | ||
50 | * for the current state | ||
51 | * (which can be found in power_table[state]). | ||
52 | * When this interface is used, the power_table holds | ||
53 | * max total (static + dynamic) power value for each OPP. | ||
37 | */ | 54 | */ |
38 | struct devfreq_cooling_power { | 55 | struct devfreq_cooling_power { |
39 | unsigned long (*get_static_power)(struct devfreq *devfreq, | 56 | unsigned long (*get_static_power)(struct devfreq *devfreq, |
@@ -41,6 +58,8 @@ struct devfreq_cooling_power { | |||
41 | unsigned long (*get_dynamic_power)(struct devfreq *devfreq, | 58 | unsigned long (*get_dynamic_power)(struct devfreq *devfreq, |
42 | unsigned long freq, | 59 | unsigned long freq, |
43 | unsigned long voltage); | 60 | unsigned long voltage); |
61 | int (*get_real_power)(struct devfreq *df, u32 *power, | ||
62 | unsigned long freq, unsigned long voltage); | ||
44 | unsigned long dyn_power_coeff; | 63 | unsigned long dyn_power_coeff; |
45 | }; | 64 | }; |
46 | 65 | ||
diff --git a/include/trace/events/thermal.h b/include/trace/events/thermal.h index 2b4a8ff72d0d..6cde5b3514c2 100644 --- a/include/trace/events/thermal.h +++ b/include/trace/events/thermal.h | |||
@@ -151,9 +151,9 @@ TRACE_EVENT(thermal_power_cpu_limit, | |||
151 | TRACE_EVENT(thermal_power_devfreq_get_power, | 151 | TRACE_EVENT(thermal_power_devfreq_get_power, |
152 | TP_PROTO(struct thermal_cooling_device *cdev, | 152 | TP_PROTO(struct thermal_cooling_device *cdev, |
153 | struct devfreq_dev_status *status, unsigned long freq, | 153 | struct devfreq_dev_status *status, unsigned long freq, |
154 | u32 dynamic_power, u32 static_power), | 154 | u32 dynamic_power, u32 static_power, u32 power), |
155 | 155 | ||
156 | TP_ARGS(cdev, status, freq, dynamic_power, static_power), | 156 | TP_ARGS(cdev, status, freq, dynamic_power, static_power, power), |
157 | 157 | ||
158 | TP_STRUCT__entry( | 158 | TP_STRUCT__entry( |
159 | __string(type, cdev->type ) | 159 | __string(type, cdev->type ) |
@@ -161,6 +161,7 @@ TRACE_EVENT(thermal_power_devfreq_get_power, | |||
161 | __field(u32, load ) | 161 | __field(u32, load ) |
162 | __field(u32, dynamic_power ) | 162 | __field(u32, dynamic_power ) |
163 | __field(u32, static_power ) | 163 | __field(u32, static_power ) |
164 | __field(u32, power) | ||
164 | ), | 165 | ), |
165 | 166 | ||
166 | TP_fast_assign( | 167 | TP_fast_assign( |
@@ -169,11 +170,13 @@ TRACE_EVENT(thermal_power_devfreq_get_power, | |||
169 | __entry->load = (100 * status->busy_time) / status->total_time; | 170 | __entry->load = (100 * status->busy_time) / status->total_time; |
170 | __entry->dynamic_power = dynamic_power; | 171 | __entry->dynamic_power = dynamic_power; |
171 | __entry->static_power = static_power; | 172 | __entry->static_power = static_power; |
173 | __entry->power = power; | ||
172 | ), | 174 | ), |
173 | 175 | ||
174 | TP_printk("type=%s freq=%lu load=%u dynamic_power=%u static_power=%u", | 176 | TP_printk("type=%s freq=%lu load=%u dynamic_power=%u static_power=%u power=%u", |
175 | __get_str(type), __entry->freq, | 177 | __get_str(type), __entry->freq, |
176 | __entry->load, __entry->dynamic_power, __entry->static_power) | 178 | __entry->load, __entry->dynamic_power, __entry->static_power, |
179 | __entry->power) | ||
177 | ); | 180 | ); |
178 | 181 | ||
179 | TRACE_EVENT(thermal_power_devfreq_limit, | 182 | TRACE_EVENT(thermal_power_devfreq_limit, |