diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-05 19:01:16 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-05 19:01:16 -0500 |
commit | c280230254635da33703dd8f4a10cad23f640fb0 (patch) | |
tree | 6f27fd600b3eaf8b00116332ca67bc8625248d87 | |
parent | a67012412e5a820c44239af9712a1a6037b33fd4 (diff) | |
parent | 9d216211fded20fff301d0317af3238d8383634c (diff) |
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal
Pull thermal SoC updates from Eduardo Valentin:
- Tegra DT binding documentation for Tegra194
- Armada now supports ap806 and cp110
- RCAR thermal now supports R8A774C0 and R8A77990
- Fixes on thermal_hwmon, IMX, generic-ADC, ST, RCAR, Broadcom,
Uniphier, QCOM, Tegra, PowerClamp, and Armada thermal drivers.
* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal: (22 commits)
thermal: generic-adc: Fix adc to temp interpolation
thermal: rcar_thermal: add R8A77990 support
dt-bindings: thermal: rcar-thermal: add R8A77990 support
thermal: rcar_thermal: add R8A774C0 support
dt-bindings: thermal: rcar-thermal: add R8A774C0 support
dt-bindings: cp110: document the thermal interrupt capabilities
dt-bindings: ap806: document the thermal interrupt capabilities
MAINTAINERS: thermal: add entry for Marvell MVEBU thermal driver
thermal: armada: add overheat interrupt support
thermal: st: fix Makefile typo
thermal: uniphier: Convert to SPDX identifier
thermal/intel_powerclamp: Change to use DEFINE_SHOW_ATTRIBUTE macro
thermal: tegra: soctherm: Change to use DEFINE_SHOW_ATTRIBUTE macro
dt-bindings: thermal: tegra-bpmp: Add Tegra194 support
thermal: imx: save one condition block for normal case of nvmem initialization
thermal: imx: fix for dependency on cpu-freq
thermal: tsens: qcom: do not create duplicate regmap debugfs entries
thermal: armada: Use PTR_ERR_OR_ZERO in armada_thermal_probe_legacy()
dt-bindings: thermal: rcar-gen3-thermal: All variants use 3 interrupts
thermal: broadcom: use devm_thermal_zone_of_sensor_register
...
-rw-r--r-- | Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt | 7 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/arm/marvell/cp110-system-controller.txt | 9 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt | 3 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/thermal/rcar-thermal.txt | 6 | ||||
-rw-r--r-- | MAINTAINERS | 5 | ||||
-rw-r--r-- | drivers/thermal/Kconfig | 2 | ||||
-rw-r--r-- | drivers/thermal/armada_thermal.c | 280 | ||||
-rw-r--r-- | drivers/thermal/broadcom/bcm2835_thermal.c | 11 | ||||
-rw-r--r-- | drivers/thermal/broadcom/brcmstb_thermal.c | 24 | ||||
-rw-r--r-- | drivers/thermal/imx_thermal.c | 52 | ||||
-rw-r--r-- | drivers/thermal/intel_powerclamp.c | 14 | ||||
-rw-r--r-- | drivers/thermal/qcom/tsens-common.c | 12 | ||||
-rw-r--r-- | drivers/thermal/rcar_thermal.c | 8 | ||||
-rw-r--r-- | drivers/thermal/st/Makefile | 2 | ||||
-rw-r--r-- | drivers/thermal/tegra/soctherm.c | 12 | ||||
-rw-r--r-- | drivers/thermal/thermal-generic-adc.c | 12 | ||||
-rw-r--r-- | drivers/thermal/thermal_hwmon.h | 4 | ||||
-rw-r--r-- | drivers/thermal/uniphier_thermal.c | 13 |
18 files changed, 383 insertions, 93 deletions
diff --git a/Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt b/Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt index 3fd21bb7cb37..7b8b8eb0191f 100644 --- a/Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt +++ b/Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt | |||
@@ -114,12 +114,17 @@ Documentation/devicetree/bindings/thermal/thermal.txt | |||
114 | The thermal IP can probe the temperature all around the processor. It | 114 | The thermal IP can probe the temperature all around the processor. It |
115 | may feature several channels, each of them wired to one sensor. | 115 | may feature several channels, each of them wired to one sensor. |
116 | 116 | ||
117 | It is possible to setup an overheat interrupt by giving at least one | ||
118 | critical point to any subnode of the thermal-zone node. | ||
119 | |||
117 | Required properties: | 120 | Required properties: |
118 | - compatible: must be one of: | 121 | - compatible: must be one of: |
119 | * marvell,armada-ap806-thermal | 122 | * marvell,armada-ap806-thermal |
120 | - reg: register range associated with the thermal functions. | 123 | - reg: register range associated with the thermal functions. |
121 | 124 | ||
122 | Optional properties: | 125 | Optional properties: |
126 | - interrupts: overheat interrupt handle. Should point to line 18 of the | ||
127 | SEI irqchip. See interrupt-controller/interrupts.txt | ||
123 | - #thermal-sensor-cells: shall be <1> when thermal-zones subnodes refer | 128 | - #thermal-sensor-cells: shall be <1> when thermal-zones subnodes refer |
124 | to this IP and represents the channel ID. There is one sensor per | 129 | to this IP and represents the channel ID. There is one sensor per |
125 | channel. O refers to the thermal IP internal channel, while positive | 130 | channel. O refers to the thermal IP internal channel, while positive |
@@ -133,6 +138,8 @@ ap_syscon1: system-controller@6f8000 { | |||
133 | ap_thermal: thermal-sensor@80 { | 138 | ap_thermal: thermal-sensor@80 { |
134 | compatible = "marvell,armada-ap806-thermal"; | 139 | compatible = "marvell,armada-ap806-thermal"; |
135 | reg = <0x80 0x10>; | 140 | reg = <0x80 0x10>; |
141 | interrupt-parent = <&sei>; | ||
142 | interrupts = <18>; | ||
136 | #thermal-sensor-cells = <1>; | 143 | #thermal-sensor-cells = <1>; |
137 | }; | 144 | }; |
138 | }; | 145 | }; |
diff --git a/Documentation/devicetree/bindings/arm/marvell/cp110-system-controller.txt b/Documentation/devicetree/bindings/arm/marvell/cp110-system-controller.txt index 81ce742d2760..4db4119a6d19 100644 --- a/Documentation/devicetree/bindings/arm/marvell/cp110-system-controller.txt +++ b/Documentation/devicetree/bindings/arm/marvell/cp110-system-controller.txt | |||
@@ -199,6 +199,9 @@ Thermal: | |||
199 | The thermal IP can probe the temperature all around the processor. It | 199 | The thermal IP can probe the temperature all around the processor. It |
200 | may feature several channels, each of them wired to one sensor. | 200 | may feature several channels, each of them wired to one sensor. |
201 | 201 | ||
202 | It is possible to setup an overheat interrupt by giving at least one | ||
203 | critical point to any subnode of the thermal-zone node. | ||
204 | |||
202 | For common binding part and usage, refer to | 205 | For common binding part and usage, refer to |
203 | Documentation/devicetree/bindings/thermal/thermal.txt | 206 | Documentation/devicetree/bindings/thermal/thermal.txt |
204 | 207 | ||
@@ -208,6 +211,11 @@ Required properties: | |||
208 | - reg: register range associated with the thermal functions. | 211 | - reg: register range associated with the thermal functions. |
209 | 212 | ||
210 | Optional properties: | 213 | Optional properties: |
214 | - interrupts-extended: overheat interrupt handle. Should point to | ||
215 | a line of the ICU-SEI irqchip (116 is what is usually used by the | ||
216 | firmware). The ICU-SEI will redirect towards interrupt line #37 of the | ||
217 | AP SEI which is shared across all CPs. | ||
218 | See interrupt-controller/interrupts.txt | ||
211 | - #thermal-sensor-cells: shall be <1> when thermal-zones subnodes refer | 219 | - #thermal-sensor-cells: shall be <1> when thermal-zones subnodes refer |
212 | to this IP and represents the channel ID. There is one sensor per | 220 | to this IP and represents the channel ID. There is one sensor per |
213 | channel. O refers to the thermal IP internal channel. | 221 | channel. O refers to the thermal IP internal channel. |
@@ -220,6 +228,7 @@ CP110_LABEL(syscon1): system-controller@6f8000 { | |||
220 | CP110_LABEL(thermal): thermal-sensor@70 { | 228 | CP110_LABEL(thermal): thermal-sensor@70 { |
221 | compatible = "marvell,armada-cp110-thermal"; | 229 | compatible = "marvell,armada-cp110-thermal"; |
222 | reg = <0x70 0x10>; | 230 | reg = <0x70 0x10>; |
231 | interrupts-extended = <&CP110_LABEL(icu_sei) 116 IRQ_TYPE_LEVEL_HIGH>; | ||
223 | #thermal-sensor-cells = <1>; | 232 | #thermal-sensor-cells = <1>; |
224 | }; | 233 | }; |
225 | }; | 234 | }; |
diff --git a/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt index ad9a435afef4..b6ab60f6abbf 100644 --- a/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt | |||
@@ -21,8 +21,7 @@ Required properties: | |||
21 | 21 | ||
22 | Optional properties: | 22 | Optional properties: |
23 | 23 | ||
24 | - interrupts : interrupts routed to the TSC (3 for H3, M3-W, M3-N, | 24 | - interrupts : interrupts routed to the TSC (must be 3). |
25 | and V3H) | ||
26 | - power-domain : Must contain a reference to the power domain. This | 25 | - power-domain : Must contain a reference to the power domain. This |
27 | property is mandatory if the thermal sensor instance | 26 | property is mandatory if the thermal sensor instance |
28 | is part of a controllable power domain. | 27 | is part of a controllable power domain. |
diff --git a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt index 73e1613d2cb0..196112d23b1e 100644 --- a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt | |||
@@ -4,17 +4,19 @@ Required properties: | |||
4 | - compatible : "renesas,thermal-<soctype>", | 4 | - compatible : "renesas,thermal-<soctype>", |
5 | "renesas,rcar-gen2-thermal" (with thermal-zone) or | 5 | "renesas,rcar-gen2-thermal" (with thermal-zone) or |
6 | "renesas,rcar-thermal" (without thermal-zone) as | 6 | "renesas,rcar-thermal" (without thermal-zone) as |
7 | fallback except R-Car V3M/D3. | 7 | fallback except R-Car V3M/E3/D3 and RZ/G2E. |
8 | Examples with soctypes are: | 8 | Examples with soctypes are: |
9 | - "renesas,thermal-r8a73a4" (R-Mobile APE6) | 9 | - "renesas,thermal-r8a73a4" (R-Mobile APE6) |
10 | - "renesas,thermal-r8a7743" (RZ/G1M) | 10 | - "renesas,thermal-r8a7743" (RZ/G1M) |
11 | - "renesas,thermal-r8a7744" (RZ/G1N) | 11 | - "renesas,thermal-r8a7744" (RZ/G1N) |
12 | - "renesas,thermal-r8a774c0" (RZ/G2E) | ||
12 | - "renesas,thermal-r8a7779" (R-Car H1) | 13 | - "renesas,thermal-r8a7779" (R-Car H1) |
13 | - "renesas,thermal-r8a7790" (R-Car H2) | 14 | - "renesas,thermal-r8a7790" (R-Car H2) |
14 | - "renesas,thermal-r8a7791" (R-Car M2-W) | 15 | - "renesas,thermal-r8a7791" (R-Car M2-W) |
15 | - "renesas,thermal-r8a7792" (R-Car V2H) | 16 | - "renesas,thermal-r8a7792" (R-Car V2H) |
16 | - "renesas,thermal-r8a7793" (R-Car M2-N) | 17 | - "renesas,thermal-r8a7793" (R-Car M2-N) |
17 | - "renesas,thermal-r8a77970" (R-Car V3M) | 18 | - "renesas,thermal-r8a77970" (R-Car V3M) |
19 | - "renesas,thermal-r8a77990" (R-Car E3) | ||
18 | - "renesas,thermal-r8a77995" (R-Car D3) | 20 | - "renesas,thermal-r8a77995" (R-Car D3) |
19 | - reg : Address range of the thermal registers. | 21 | - reg : Address range of the thermal registers. |
20 | The 1st reg will be recognized as common register | 22 | The 1st reg will be recognized as common register |
@@ -23,7 +25,7 @@ Required properties: | |||
23 | Option properties: | 25 | Option properties: |
24 | 26 | ||
25 | - interrupts : If present should contain 3 interrupts for | 27 | - interrupts : If present should contain 3 interrupts for |
26 | R-Car V3M/D3 or 1 interrupt otherwise. | 28 | R-Car V3M/E3/D3 and RZ/G2E or 1 interrupt otherwise. |
27 | 29 | ||
28 | Example (non interrupt support): | 30 | Example (non interrupt support): |
29 | 31 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index bc00793a03c8..39e75bbefc3d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -9109,6 +9109,11 @@ L: netdev@vger.kernel.org | |||
9109 | S: Maintained | 9109 | S: Maintained |
9110 | F: drivers/net/phy/marvell10g.c | 9110 | F: drivers/net/phy/marvell10g.c |
9111 | 9111 | ||
9112 | MARVELL MVEBU THERMAL DRIVER | ||
9113 | M: Miquel Raynal <miquel.raynal@bootlin.com> | ||
9114 | S: Maintained | ||
9115 | F: drivers/thermal/armada_thermal.c | ||
9116 | |||
9112 | MARVELL MVNETA ETHERNET DRIVER | 9117 | MARVELL MVNETA ETHERNET DRIVER |
9113 | M: Thomas Petazzoni <thomas.petazzoni@bootlin.com> | 9118 | M: Thomas Petazzoni <thomas.petazzoni@bootlin.com> |
9114 | L: netdev@vger.kernel.org | 9119 | L: netdev@vger.kernel.org |
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 5fbfabbf627b..fdc48a1655e7 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig | |||
@@ -212,7 +212,7 @@ config HISI_THERMAL | |||
212 | 212 | ||
213 | config IMX_THERMAL | 213 | config IMX_THERMAL |
214 | tristate "Temperature sensor driver for Freescale i.MX SoCs" | 214 | tristate "Temperature sensor driver for Freescale i.MX SoCs" |
215 | depends on (ARCH_MXC && CPU_THERMAL) || COMPILE_TEST | 215 | depends on ARCH_MXC || COMPILE_TEST |
216 | depends on NVMEM || !NVMEM | 216 | depends on NVMEM || !NVMEM |
217 | depends on MFD_SYSCON | 217 | depends on MFD_SYSCON |
218 | depends on OF | 218 | depends on OF |
diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c index d7105d01859a..53129de59dd9 100644 --- a/drivers/thermal/armada_thermal.c +++ b/drivers/thermal/armada_thermal.c | |||
@@ -26,6 +26,11 @@ | |||
26 | #include <linux/iopoll.h> | 26 | #include <linux/iopoll.h> |
27 | #include <linux/mfd/syscon.h> | 27 | #include <linux/mfd/syscon.h> |
28 | #include <linux/regmap.h> | 28 | #include <linux/regmap.h> |
29 | #include <linux/interrupt.h> | ||
30 | |||
31 | #include "thermal_core.h" | ||
32 | |||
33 | #define TO_MCELSIUS(c) ((c) * 1000) | ||
29 | 34 | ||
30 | /* Thermal Manager Control and Status Register */ | 35 | /* Thermal Manager Control and Status Register */ |
31 | #define PMU_TDC0_SW_RST_MASK (0x1 << 1) | 36 | #define PMU_TDC0_SW_RST_MASK (0x1 << 1) |
@@ -61,9 +66,13 @@ | |||
61 | #define CONTROL1_TSEN_AVG_MASK 0x7 | 66 | #define CONTROL1_TSEN_AVG_MASK 0x7 |
62 | #define CONTROL1_EXT_TSEN_SW_RESET BIT(7) | 67 | #define CONTROL1_EXT_TSEN_SW_RESET BIT(7) |
63 | #define CONTROL1_EXT_TSEN_HW_RESETn BIT(8) | 68 | #define CONTROL1_EXT_TSEN_HW_RESETn BIT(8) |
69 | #define CONTROL1_TSEN_INT_EN BIT(25) | ||
70 | #define CONTROL1_TSEN_SELECT_OFF 21 | ||
71 | #define CONTROL1_TSEN_SELECT_MASK 0x3 | ||
64 | 72 | ||
65 | #define STATUS_POLL_PERIOD_US 1000 | 73 | #define STATUS_POLL_PERIOD_US 1000 |
66 | #define STATUS_POLL_TIMEOUT_US 100000 | 74 | #define STATUS_POLL_TIMEOUT_US 100000 |
75 | #define OVERHEAT_INT_POLL_DELAY_MS 1000 | ||
67 | 76 | ||
68 | struct armada_thermal_data; | 77 | struct armada_thermal_data; |
69 | 78 | ||
@@ -75,7 +84,11 @@ struct armada_thermal_priv { | |||
75 | /* serialize temperature reads/updates */ | 84 | /* serialize temperature reads/updates */ |
76 | struct mutex update_lock; | 85 | struct mutex update_lock; |
77 | struct armada_thermal_data *data; | 86 | struct armada_thermal_data *data; |
87 | struct thermal_zone_device *overheat_sensor; | ||
88 | int interrupt_source; | ||
78 | int current_channel; | 89 | int current_channel; |
90 | long current_threshold; | ||
91 | long current_hysteresis; | ||
79 | }; | 92 | }; |
80 | 93 | ||
81 | struct armada_thermal_data { | 94 | struct armada_thermal_data { |
@@ -93,12 +106,20 @@ struct armada_thermal_data { | |||
93 | /* Register shift and mask to access the sensor temperature */ | 106 | /* Register shift and mask to access the sensor temperature */ |
94 | unsigned int temp_shift; | 107 | unsigned int temp_shift; |
95 | unsigned int temp_mask; | 108 | unsigned int temp_mask; |
109 | unsigned int thresh_shift; | ||
110 | unsigned int hyst_shift; | ||
111 | unsigned int hyst_mask; | ||
96 | u32 is_valid_bit; | 112 | u32 is_valid_bit; |
97 | 113 | ||
98 | /* Syscon access */ | 114 | /* Syscon access */ |
99 | unsigned int syscon_control0_off; | 115 | unsigned int syscon_control0_off; |
100 | unsigned int syscon_control1_off; | 116 | unsigned int syscon_control1_off; |
101 | unsigned int syscon_status_off; | 117 | unsigned int syscon_status_off; |
118 | unsigned int dfx_irq_cause_off; | ||
119 | unsigned int dfx_irq_mask_off; | ||
120 | unsigned int dfx_overheat_irq; | ||
121 | unsigned int dfx_server_irq_mask_off; | ||
122 | unsigned int dfx_server_irq_en; | ||
102 | 123 | ||
103 | /* One sensor is in the thermal IC, the others are in the CPUs if any */ | 124 | /* One sensor is in the thermal IC, the others are in the CPUs if any */ |
104 | unsigned int cpu_nr; | 125 | unsigned int cpu_nr; |
@@ -272,6 +293,41 @@ static bool armada_is_valid(struct armada_thermal_priv *priv) | |||
272 | return reg & priv->data->is_valid_bit; | 293 | return reg & priv->data->is_valid_bit; |
273 | } | 294 | } |
274 | 295 | ||
296 | static void armada_enable_overheat_interrupt(struct armada_thermal_priv *priv) | ||
297 | { | ||
298 | struct armada_thermal_data *data = priv->data; | ||
299 | u32 reg; | ||
300 | |||
301 | /* Clear DFX temperature IRQ cause */ | ||
302 | regmap_read(priv->syscon, data->dfx_irq_cause_off, ®); | ||
303 | |||
304 | /* Enable DFX Temperature IRQ */ | ||
305 | regmap_read(priv->syscon, data->dfx_irq_mask_off, ®); | ||
306 | reg |= data->dfx_overheat_irq; | ||
307 | regmap_write(priv->syscon, data->dfx_irq_mask_off, reg); | ||
308 | |||
309 | /* Enable DFX server IRQ */ | ||
310 | regmap_read(priv->syscon, data->dfx_server_irq_mask_off, ®); | ||
311 | reg |= data->dfx_server_irq_en; | ||
312 | regmap_write(priv->syscon, data->dfx_server_irq_mask_off, reg); | ||
313 | |||
314 | /* Enable overheat interrupt */ | ||
315 | regmap_read(priv->syscon, data->syscon_control1_off, ®); | ||
316 | reg |= CONTROL1_TSEN_INT_EN; | ||
317 | regmap_write(priv->syscon, data->syscon_control1_off, reg); | ||
318 | } | ||
319 | |||
320 | static void __maybe_unused | ||
321 | armada_disable_overheat_interrupt(struct armada_thermal_priv *priv) | ||
322 | { | ||
323 | struct armada_thermal_data *data = priv->data; | ||
324 | u32 reg; | ||
325 | |||
326 | regmap_read(priv->syscon, data->syscon_control1_off, ®); | ||
327 | reg &= ~CONTROL1_TSEN_INT_EN; | ||
328 | regmap_write(priv->syscon, data->syscon_control1_off, reg); | ||
329 | } | ||
330 | |||
275 | /* There is currently no board with more than one sensor per channel */ | 331 | /* There is currently no board with more than one sensor per channel */ |
276 | static int armada_select_channel(struct armada_thermal_priv *priv, int channel) | 332 | static int armada_select_channel(struct armada_thermal_priv *priv, int channel) |
277 | { | 333 | { |
@@ -388,6 +444,14 @@ static int armada_get_temp(void *_sensor, int *temp) | |||
388 | 444 | ||
389 | /* Do the actual reading */ | 445 | /* Do the actual reading */ |
390 | ret = armada_read_sensor(priv, temp); | 446 | ret = armada_read_sensor(priv, temp); |
447 | if (ret) | ||
448 | goto unlock_mutex; | ||
449 | |||
450 | /* | ||
451 | * Select back the interrupt source channel from which a potential | ||
452 | * critical trip point has been set. | ||
453 | */ | ||
454 | ret = armada_select_channel(priv, priv->interrupt_source); | ||
391 | 455 | ||
392 | unlock_mutex: | 456 | unlock_mutex: |
393 | mutex_unlock(&priv->update_lock); | 457 | mutex_unlock(&priv->update_lock); |
@@ -399,6 +463,123 @@ static const struct thermal_zone_of_device_ops of_ops = { | |||
399 | .get_temp = armada_get_temp, | 463 | .get_temp = armada_get_temp, |
400 | }; | 464 | }; |
401 | 465 | ||
466 | static unsigned int armada_mc_to_reg_temp(struct armada_thermal_data *data, | ||
467 | unsigned int temp_mc) | ||
468 | { | ||
469 | s64 b = data->coef_b; | ||
470 | s64 m = data->coef_m; | ||
471 | s64 div = data->coef_div; | ||
472 | unsigned int sample; | ||
473 | |||
474 | if (data->inverted) | ||
475 | sample = div_s64(((temp_mc * div) + b), m); | ||
476 | else | ||
477 | sample = div_s64((b - (temp_mc * div)), m); | ||
478 | |||
479 | return sample & data->temp_mask; | ||
480 | } | ||
481 | |||
482 | /* | ||
483 | * The documentation states: | ||
484 | * high/low watermark = threshold +/- 0.4761 * 2^(hysteresis + 2) | ||
485 | * which is the mathematical derivation for: | ||
486 | * 0x0 <=> 1.9°C, 0x1 <=> 3.8°C, 0x2 <=> 7.6°C, 0x3 <=> 15.2°C | ||
487 | */ | ||
488 | static unsigned int hyst_levels_mc[] = {1900, 3800, 7600, 15200}; | ||
489 | |||
490 | static unsigned int armada_mc_to_reg_hyst(struct armada_thermal_data *data, | ||
491 | unsigned int hyst_mc) | ||
492 | { | ||
493 | int i; | ||
494 | |||
495 | /* | ||
496 | * We will always take the smallest possible hysteresis to avoid risking | ||
497 | * the hardware integrity by enlarging the threshold by +8°C in the | ||
498 | * worst case. | ||
499 | */ | ||
500 | for (i = ARRAY_SIZE(hyst_levels_mc) - 1; i > 0; i--) | ||
501 | if (hyst_mc >= hyst_levels_mc[i]) | ||
502 | break; | ||
503 | |||
504 | return i & data->hyst_mask; | ||
505 | } | ||
506 | |||
507 | static void armada_set_overheat_thresholds(struct armada_thermal_priv *priv, | ||
508 | int thresh_mc, int hyst_mc) | ||
509 | { | ||
510 | struct armada_thermal_data *data = priv->data; | ||
511 | unsigned int threshold = armada_mc_to_reg_temp(data, thresh_mc); | ||
512 | unsigned int hysteresis = armada_mc_to_reg_hyst(data, hyst_mc); | ||
513 | u32 ctrl1; | ||
514 | |||
515 | regmap_read(priv->syscon, data->syscon_control1_off, &ctrl1); | ||
516 | |||
517 | /* Set Threshold */ | ||
518 | if (thresh_mc >= 0) { | ||
519 | ctrl1 &= ~(data->temp_mask << data->thresh_shift); | ||
520 | ctrl1 |= threshold << data->thresh_shift; | ||
521 | priv->current_threshold = thresh_mc; | ||
522 | } | ||
523 | |||
524 | /* Set Hysteresis */ | ||
525 | if (hyst_mc >= 0) { | ||
526 | ctrl1 &= ~(data->hyst_mask << data->hyst_shift); | ||
527 | ctrl1 |= hysteresis << data->hyst_shift; | ||
528 | priv->current_hysteresis = hyst_mc; | ||
529 | } | ||
530 | |||
531 | regmap_write(priv->syscon, data->syscon_control1_off, ctrl1); | ||
532 | } | ||
533 | |||
534 | static irqreturn_t armada_overheat_isr(int irq, void *blob) | ||
535 | { | ||
536 | /* | ||
537 | * Disable the IRQ and continue in thread context (thermal core | ||
538 | * notification and temperature monitoring). | ||
539 | */ | ||
540 | disable_irq_nosync(irq); | ||
541 | |||
542 | return IRQ_WAKE_THREAD; | ||
543 | } | ||
544 | |||
545 | static irqreturn_t armada_overheat_isr_thread(int irq, void *blob) | ||
546 | { | ||
547 | struct armada_thermal_priv *priv = blob; | ||
548 | int low_threshold = priv->current_threshold - priv->current_hysteresis; | ||
549 | int temperature; | ||
550 | u32 dummy; | ||
551 | int ret; | ||
552 | |||
553 | /* Notify the core in thread context */ | ||
554 | thermal_zone_device_update(priv->overheat_sensor, | ||
555 | THERMAL_EVENT_UNSPECIFIED); | ||
556 | |||
557 | /* | ||
558 | * The overheat interrupt must be cleared by reading the DFX interrupt | ||
559 | * cause _after_ the temperature has fallen down to the low threshold. | ||
560 | * Otherwise future interrupts might not be served. | ||
561 | */ | ||
562 | do { | ||
563 | msleep(OVERHEAT_INT_POLL_DELAY_MS); | ||
564 | mutex_lock(&priv->update_lock); | ||
565 | ret = armada_read_sensor(priv, &temperature); | ||
566 | mutex_unlock(&priv->update_lock); | ||
567 | if (ret) | ||
568 | goto enable_irq; | ||
569 | } while (temperature >= low_threshold); | ||
570 | |||
571 | regmap_read(priv->syscon, priv->data->dfx_irq_cause_off, &dummy); | ||
572 | |||
573 | /* Notify the thermal core that the temperature is acceptable again */ | ||
574 | thermal_zone_device_update(priv->overheat_sensor, | ||
575 | THERMAL_EVENT_UNSPECIFIED); | ||
576 | |||
577 | enable_irq: | ||
578 | enable_irq(irq); | ||
579 | |||
580 | return IRQ_HANDLED; | ||
581 | } | ||
582 | |||
402 | static const struct armada_thermal_data armadaxp_data = { | 583 | static const struct armada_thermal_data armadaxp_data = { |
403 | .init = armadaxp_init, | 584 | .init = armadaxp_init, |
404 | .temp_shift = 10, | 585 | .temp_shift = 10, |
@@ -454,6 +635,9 @@ static const struct armada_thermal_data armada_ap806_data = { | |||
454 | .is_valid_bit = BIT(16), | 635 | .is_valid_bit = BIT(16), |
455 | .temp_shift = 0, | 636 | .temp_shift = 0, |
456 | .temp_mask = 0x3ff, | 637 | .temp_mask = 0x3ff, |
638 | .thresh_shift = 3, | ||
639 | .hyst_shift = 19, | ||
640 | .hyst_mask = 0x3, | ||
457 | .coef_b = -150000LL, | 641 | .coef_b = -150000LL, |
458 | .coef_m = 423ULL, | 642 | .coef_m = 423ULL, |
459 | .coef_div = 1, | 643 | .coef_div = 1, |
@@ -462,6 +646,11 @@ static const struct armada_thermal_data armada_ap806_data = { | |||
462 | .syscon_control0_off = 0x84, | 646 | .syscon_control0_off = 0x84, |
463 | .syscon_control1_off = 0x88, | 647 | .syscon_control1_off = 0x88, |
464 | .syscon_status_off = 0x8C, | 648 | .syscon_status_off = 0x8C, |
649 | .dfx_irq_cause_off = 0x108, | ||
650 | .dfx_irq_mask_off = 0x10C, | ||
651 | .dfx_overheat_irq = BIT(22), | ||
652 | .dfx_server_irq_mask_off = 0x104, | ||
653 | .dfx_server_irq_en = BIT(1), | ||
465 | .cpu_nr = 4, | 654 | .cpu_nr = 4, |
466 | }; | 655 | }; |
467 | 656 | ||
@@ -470,6 +659,9 @@ static const struct armada_thermal_data armada_cp110_data = { | |||
470 | .is_valid_bit = BIT(10), | 659 | .is_valid_bit = BIT(10), |
471 | .temp_shift = 0, | 660 | .temp_shift = 0, |
472 | .temp_mask = 0x3ff, | 661 | .temp_mask = 0x3ff, |
662 | .thresh_shift = 16, | ||
663 | .hyst_shift = 26, | ||
664 | .hyst_mask = 0x3, | ||
473 | .coef_b = 1172499100ULL, | 665 | .coef_b = 1172499100ULL, |
474 | .coef_m = 2000096ULL, | 666 | .coef_m = 2000096ULL, |
475 | .coef_div = 4201, | 667 | .coef_div = 4201, |
@@ -477,6 +669,11 @@ static const struct armada_thermal_data armada_cp110_data = { | |||
477 | .syscon_control0_off = 0x70, | 669 | .syscon_control0_off = 0x70, |
478 | .syscon_control1_off = 0x74, | 670 | .syscon_control1_off = 0x74, |
479 | .syscon_status_off = 0x78, | 671 | .syscon_status_off = 0x78, |
672 | .dfx_irq_cause_off = 0x108, | ||
673 | .dfx_irq_mask_off = 0x10C, | ||
674 | .dfx_overheat_irq = BIT(20), | ||
675 | .dfx_server_irq_mask_off = 0x104, | ||
676 | .dfx_server_irq_en = BIT(1), | ||
480 | }; | 677 | }; |
481 | 678 | ||
482 | static const struct of_device_id armada_thermal_id_table[] = { | 679 | static const struct of_device_id armada_thermal_id_table[] = { |
@@ -543,20 +740,14 @@ static int armada_thermal_probe_legacy(struct platform_device *pdev, | |||
543 | 740 | ||
544 | priv->syscon = devm_regmap_init_mmio(&pdev->dev, base, | 741 | priv->syscon = devm_regmap_init_mmio(&pdev->dev, base, |
545 | &armada_thermal_regmap_config); | 742 | &armada_thermal_regmap_config); |
546 | if (IS_ERR(priv->syscon)) | 743 | return PTR_ERR_OR_ZERO(priv->syscon); |
547 | return PTR_ERR(priv->syscon); | ||
548 | |||
549 | return 0; | ||
550 | } | 744 | } |
551 | 745 | ||
552 | static int armada_thermal_probe_syscon(struct platform_device *pdev, | 746 | static int armada_thermal_probe_syscon(struct platform_device *pdev, |
553 | struct armada_thermal_priv *priv) | 747 | struct armada_thermal_priv *priv) |
554 | { | 748 | { |
555 | priv->syscon = syscon_node_to_regmap(pdev->dev.parent->of_node); | 749 | priv->syscon = syscon_node_to_regmap(pdev->dev.parent->of_node); |
556 | if (IS_ERR(priv->syscon)) | 750 | return PTR_ERR_OR_ZERO(priv->syscon); |
557 | return PTR_ERR(priv->syscon); | ||
558 | |||
559 | return 0; | ||
560 | } | 751 | } |
561 | 752 | ||
562 | static void armada_set_sane_name(struct platform_device *pdev, | 753 | static void armada_set_sane_name(struct platform_device *pdev, |
@@ -590,6 +781,48 @@ static void armada_set_sane_name(struct platform_device *pdev, | |||
590 | } while (insane_char); | 781 | } while (insane_char); |
591 | } | 782 | } |
592 | 783 | ||
784 | /* | ||
785 | * The IP can manage to trigger interrupts on overheat situation from all the | ||
786 | * sensors. However, the interrupt source changes along with the last selected | ||
787 | * source (ie. the last read sensor), which is an inconsistent behavior. Avoid | ||
788 | * possible glitches by always selecting back only one channel (arbitrarily: the | ||
789 | * first in the DT which has a critical trip point). We also disable sensor | ||
790 | * switch during overheat situations. | ||
791 | */ | ||
792 | static int armada_configure_overheat_int(struct armada_thermal_priv *priv, | ||
793 | struct thermal_zone_device *tz, | ||
794 | int sensor_id) | ||
795 | { | ||
796 | /* Retrieve the critical trip point to enable the overheat interrupt */ | ||
797 | const struct thermal_trip *trips = of_thermal_get_trip_points(tz); | ||
798 | int ret; | ||
799 | int i; | ||
800 | |||
801 | if (!trips) | ||
802 | return -EINVAL; | ||
803 | |||
804 | for (i = 0; i < of_thermal_get_ntrips(tz); i++) | ||
805 | if (trips[i].type == THERMAL_TRIP_CRITICAL) | ||
806 | break; | ||
807 | |||
808 | if (i == of_thermal_get_ntrips(tz)) | ||
809 | return -EINVAL; | ||
810 | |||
811 | ret = armada_select_channel(priv, sensor_id); | ||
812 | if (ret) | ||
813 | return ret; | ||
814 | |||
815 | armada_set_overheat_thresholds(priv, | ||
816 | trips[i].temperature, | ||
817 | trips[i].hysteresis); | ||
818 | priv->overheat_sensor = tz; | ||
819 | priv->interrupt_source = sensor_id; | ||
820 | |||
821 | armada_enable_overheat_interrupt(priv); | ||
822 | |||
823 | return 0; | ||
824 | } | ||
825 | |||
593 | static int armada_thermal_probe(struct platform_device *pdev) | 826 | static int armada_thermal_probe(struct platform_device *pdev) |
594 | { | 827 | { |
595 | struct thermal_zone_device *tz; | 828 | struct thermal_zone_device *tz; |
@@ -597,7 +830,7 @@ static int armada_thermal_probe(struct platform_device *pdev) | |||
597 | struct armada_drvdata *drvdata; | 830 | struct armada_drvdata *drvdata; |
598 | const struct of_device_id *match; | 831 | const struct of_device_id *match; |
599 | struct armada_thermal_priv *priv; | 832 | struct armada_thermal_priv *priv; |
600 | int sensor_id; | 833 | int sensor_id, irq; |
601 | int ret; | 834 | int ret; |
602 | 835 | ||
603 | match = of_match_device(armada_thermal_id_table, &pdev->dev); | 836 | match = of_match_device(armada_thermal_id_table, &pdev->dev); |
@@ -667,6 +900,23 @@ static int armada_thermal_probe(struct platform_device *pdev) | |||
667 | drvdata->data.priv = priv; | 900 | drvdata->data.priv = priv; |
668 | platform_set_drvdata(pdev, drvdata); | 901 | platform_set_drvdata(pdev, drvdata); |
669 | 902 | ||
903 | irq = platform_get_irq(pdev, 0); | ||
904 | if (irq == -EPROBE_DEFER) | ||
905 | return irq; | ||
906 | |||
907 | /* The overheat interrupt feature is not mandatory */ | ||
908 | if (irq > 0) { | ||
909 | ret = devm_request_threaded_irq(&pdev->dev, irq, | ||
910 | armada_overheat_isr, | ||
911 | armada_overheat_isr_thread, | ||
912 | 0, NULL, priv); | ||
913 | if (ret) { | ||
914 | dev_err(&pdev->dev, "Cannot request threaded IRQ %d\n", | ||
915 | irq); | ||
916 | return ret; | ||
917 | } | ||
918 | } | ||
919 | |||
670 | /* | 920 | /* |
671 | * There is one channel for the IC and one per CPU (if any), each | 921 | * There is one channel for the IC and one per CPU (if any), each |
672 | * channel has one sensor. | 922 | * channel has one sensor. |
@@ -690,8 +940,20 @@ static int armada_thermal_probe(struct platform_device *pdev) | |||
690 | devm_kfree(&pdev->dev, sensor); | 940 | devm_kfree(&pdev->dev, sensor); |
691 | continue; | 941 | continue; |
692 | } | 942 | } |
943 | |||
944 | /* | ||
945 | * The first channel that has a critical trip point registered | ||
946 | * in the DT will serve as interrupt source. Others possible | ||
947 | * critical trip points will simply be ignored by the driver. | ||
948 | */ | ||
949 | if (irq > 0 && !priv->overheat_sensor) | ||
950 | armada_configure_overheat_int(priv, tz, sensor->id); | ||
693 | } | 951 | } |
694 | 952 | ||
953 | /* Just complain if no overheat interrupt was set up */ | ||
954 | if (!priv->overheat_sensor) | ||
955 | dev_warn(&pdev->dev, "Overheat interrupt not available\n"); | ||
956 | |||
695 | return 0; | 957 | return 0; |
696 | } | 958 | } |
697 | 959 | ||
diff --git a/drivers/thermal/broadcom/bcm2835_thermal.c b/drivers/thermal/broadcom/bcm2835_thermal.c index b9d90f0ed504..720760cd493f 100644 --- a/drivers/thermal/broadcom/bcm2835_thermal.c +++ b/drivers/thermal/broadcom/bcm2835_thermal.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/thermal.h> | 19 | #include <linux/thermal.h> |
20 | 20 | ||
21 | #include "../thermal_hwmon.h" | ||
22 | |||
21 | #define BCM2835_TS_TSENSCTL 0x00 | 23 | #define BCM2835_TS_TSENSCTL 0x00 |
22 | #define BCM2835_TS_TSENSSTAT 0x04 | 24 | #define BCM2835_TS_TSENSSTAT 0x04 |
23 | 25 | ||
@@ -266,6 +268,15 @@ static int bcm2835_thermal_probe(struct platform_device *pdev) | |||
266 | 268 | ||
267 | platform_set_drvdata(pdev, tz); | 269 | platform_set_drvdata(pdev, tz); |
268 | 270 | ||
271 | /* | ||
272 | * Thermal_zone doesn't enable hwmon as default, | ||
273 | * enable it here | ||
274 | */ | ||
275 | tz->tzp->no_hwmon = false; | ||
276 | err = thermal_add_hwmon_sysfs(tz); | ||
277 | if (err) | ||
278 | goto err_tz; | ||
279 | |||
269 | bcm2835_thermal_debugfs(pdev); | 280 | bcm2835_thermal_debugfs(pdev); |
270 | 281 | ||
271 | return 0; | 282 | return 0; |
diff --git a/drivers/thermal/broadcom/brcmstb_thermal.c b/drivers/thermal/broadcom/brcmstb_thermal.c index e8b1570cc388..65704bdd18e4 100644 --- a/drivers/thermal/broadcom/brcmstb_thermal.c +++ b/drivers/thermal/broadcom/brcmstb_thermal.c | |||
@@ -329,7 +329,8 @@ static int brcmstb_thermal_probe(struct platform_device *pdev) | |||
329 | priv->dev = &pdev->dev; | 329 | priv->dev = &pdev->dev; |
330 | platform_set_drvdata(pdev, priv); | 330 | platform_set_drvdata(pdev, priv); |
331 | 331 | ||
332 | thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &of_ops); | 332 | thermal = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, priv, |
333 | &of_ops); | ||
333 | if (IS_ERR(thermal)) { | 334 | if (IS_ERR(thermal)) { |
334 | ret = PTR_ERR(thermal); | 335 | ret = PTR_ERR(thermal); |
335 | dev_err(&pdev->dev, "could not register sensor: %d\n", ret); | 336 | dev_err(&pdev->dev, "could not register sensor: %d\n", ret); |
@@ -341,40 +342,23 @@ static int brcmstb_thermal_probe(struct platform_device *pdev) | |||
341 | irq = platform_get_irq(pdev, 0); | 342 | irq = platform_get_irq(pdev, 0); |
342 | if (irq < 0) { | 343 | if (irq < 0) { |
343 | dev_err(&pdev->dev, "could not get IRQ\n"); | 344 | dev_err(&pdev->dev, "could not get IRQ\n"); |
344 | ret = irq; | 345 | return irq; |
345 | goto err; | ||
346 | } | 346 | } |
347 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | 347 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, |
348 | brcmstb_tmon_irq_thread, IRQF_ONESHOT, | 348 | brcmstb_tmon_irq_thread, IRQF_ONESHOT, |
349 | DRV_NAME, priv); | 349 | DRV_NAME, priv); |
350 | if (ret < 0) { | 350 | if (ret < 0) { |
351 | dev_err(&pdev->dev, "could not request IRQ: %d\n", ret); | 351 | dev_err(&pdev->dev, "could not request IRQ: %d\n", ret); |
352 | goto err; | 352 | return ret; |
353 | } | 353 | } |
354 | 354 | ||
355 | dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n"); | 355 | dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n"); |
356 | 356 | ||
357 | return 0; | 357 | return 0; |
358 | |||
359 | err: | ||
360 | thermal_zone_of_sensor_unregister(&pdev->dev, thermal); | ||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | static int brcmstb_thermal_exit(struct platform_device *pdev) | ||
365 | { | ||
366 | struct brcmstb_thermal_priv *priv = platform_get_drvdata(pdev); | ||
367 | struct thermal_zone_device *thermal = priv->thermal; | ||
368 | |||
369 | if (thermal) | ||
370 | thermal_zone_of_sensor_unregister(&pdev->dev, priv->thermal); | ||
371 | |||
372 | return 0; | ||
373 | } | 358 | } |
374 | 359 | ||
375 | static struct platform_driver brcmstb_thermal_driver = { | 360 | static struct platform_driver brcmstb_thermal_driver = { |
376 | .probe = brcmstb_thermal_probe, | 361 | .probe = brcmstb_thermal_probe, |
377 | .remove = brcmstb_thermal_exit, | ||
378 | .driver = { | 362 | .driver = { |
379 | .name = DRV_NAME, | 363 | .name = DRV_NAME, |
380 | .of_match_table = brcmstb_thermal_id_table, | 364 | .of_match_table = brcmstb_thermal_id_table, |
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 15661549eb67..bb6754a5342c 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c | |||
@@ -648,15 +648,24 @@ static const struct of_device_id of_imx_thermal_match[] = { | |||
648 | }; | 648 | }; |
649 | MODULE_DEVICE_TABLE(of, of_imx_thermal_match); | 649 | MODULE_DEVICE_TABLE(of, of_imx_thermal_match); |
650 | 650 | ||
651 | #ifdef CONFIG_CPU_FREQ | ||
651 | /* | 652 | /* |
652 | * Create cooling device in case no #cooling-cells property is available in | 653 | * Create cooling device in case no #cooling-cells property is available in |
653 | * CPU node | 654 | * CPU node |
654 | */ | 655 | */ |
655 | static int imx_thermal_register_legacy_cooling(struct imx_thermal_data *data) | 656 | static int imx_thermal_register_legacy_cooling(struct imx_thermal_data *data) |
656 | { | 657 | { |
657 | struct device_node *np = of_get_cpu_node(data->policy->cpu, NULL); | 658 | struct device_node *np; |
658 | int ret; | 659 | int ret; |
659 | 660 | ||
661 | data->policy = cpufreq_cpu_get(0); | ||
662 | if (!data->policy) { | ||
663 | pr_debug("%s: CPUFreq policy not found\n", __func__); | ||
664 | return -EPROBE_DEFER; | ||
665 | } | ||
666 | |||
667 | np = of_get_cpu_node(data->policy->cpu, NULL); | ||
668 | |||
660 | if (!np || !of_find_property(np, "#cooling-cells", NULL)) { | 669 | if (!np || !of_find_property(np, "#cooling-cells", NULL)) { |
661 | data->cdev = cpufreq_cooling_register(data->policy); | 670 | data->cdev = cpufreq_cooling_register(data->policy); |
662 | if (IS_ERR(data->cdev)) { | 671 | if (IS_ERR(data->cdev)) { |
@@ -669,6 +678,24 @@ static int imx_thermal_register_legacy_cooling(struct imx_thermal_data *data) | |||
669 | return 0; | 678 | return 0; |
670 | } | 679 | } |
671 | 680 | ||
681 | static void imx_thermal_unregister_legacy_cooling(struct imx_thermal_data *data) | ||
682 | { | ||
683 | cpufreq_cooling_unregister(data->cdev); | ||
684 | cpufreq_cpu_put(data->policy); | ||
685 | } | ||
686 | |||
687 | #else | ||
688 | |||
689 | static inline int imx_thermal_register_legacy_cooling(struct imx_thermal_data *data) | ||
690 | { | ||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | static inline void imx_thermal_unregister_legacy_cooling(struct imx_thermal_data *data) | ||
695 | { | ||
696 | } | ||
697 | #endif | ||
698 | |||
672 | static int imx_thermal_probe(struct platform_device *pdev) | 699 | static int imx_thermal_probe(struct platform_device *pdev) |
673 | { | 700 | { |
674 | struct imx_thermal_data *data; | 701 | struct imx_thermal_data *data; |
@@ -715,9 +742,10 @@ static int imx_thermal_probe(struct platform_device *pdev) | |||
715 | 742 | ||
716 | if (of_find_property(pdev->dev.of_node, "nvmem-cells", NULL)) { | 743 | if (of_find_property(pdev->dev.of_node, "nvmem-cells", NULL)) { |
717 | ret = imx_init_from_nvmem_cells(pdev); | 744 | ret = imx_init_from_nvmem_cells(pdev); |
718 | if (ret == -EPROBE_DEFER) | ||
719 | return ret; | ||
720 | if (ret) { | 745 | if (ret) { |
746 | if (ret == -EPROBE_DEFER) | ||
747 | return ret; | ||
748 | |||
721 | dev_err(&pdev->dev, "failed to init from nvmem: %d\n", | 749 | dev_err(&pdev->dev, "failed to init from nvmem: %d\n", |
722 | ret); | 750 | ret); |
723 | return ret; | 751 | return ret; |
@@ -743,14 +771,11 @@ static int imx_thermal_probe(struct platform_device *pdev) | |||
743 | regmap_write(map, data->socdata->sensor_ctrl + REG_SET, | 771 | regmap_write(map, data->socdata->sensor_ctrl + REG_SET, |
744 | data->socdata->power_down_mask); | 772 | data->socdata->power_down_mask); |
745 | 773 | ||
746 | data->policy = cpufreq_cpu_get(0); | ||
747 | if (!data->policy) { | ||
748 | pr_debug("%s: CPUFreq policy not found\n", __func__); | ||
749 | return -EPROBE_DEFER; | ||
750 | } | ||
751 | |||
752 | ret = imx_thermal_register_legacy_cooling(data); | 774 | ret = imx_thermal_register_legacy_cooling(data); |
753 | if (ret) { | 775 | if (ret) { |
776 | if (ret == -EPROBE_DEFER) | ||
777 | return ret; | ||
778 | |||
754 | dev_err(&pdev->dev, | 779 | dev_err(&pdev->dev, |
755 | "failed to register cpufreq cooling device: %d\n", ret); | 780 | "failed to register cpufreq cooling device: %d\n", ret); |
756 | return ret; | 781 | return ret; |
@@ -762,7 +787,7 @@ static int imx_thermal_probe(struct platform_device *pdev) | |||
762 | if (ret != -EPROBE_DEFER) | 787 | if (ret != -EPROBE_DEFER) |
763 | dev_err(&pdev->dev, | 788 | dev_err(&pdev->dev, |
764 | "failed to get thermal clk: %d\n", ret); | 789 | "failed to get thermal clk: %d\n", ret); |
765 | goto cpufreq_put; | 790 | goto legacy_cleanup; |
766 | } | 791 | } |
767 | 792 | ||
768 | /* | 793 | /* |
@@ -775,7 +800,7 @@ static int imx_thermal_probe(struct platform_device *pdev) | |||
775 | ret = clk_prepare_enable(data->thermal_clk); | 800 | ret = clk_prepare_enable(data->thermal_clk); |
776 | if (ret) { | 801 | if (ret) { |
777 | dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret); | 802 | dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret); |
778 | goto cpufreq_put; | 803 | goto legacy_cleanup; |
779 | } | 804 | } |
780 | 805 | ||
781 | data->tz = thermal_zone_device_register("imx_thermal_zone", | 806 | data->tz = thermal_zone_device_register("imx_thermal_zone", |
@@ -829,9 +854,8 @@ thermal_zone_unregister: | |||
829 | thermal_zone_device_unregister(data->tz); | 854 | thermal_zone_device_unregister(data->tz); |
830 | clk_disable: | 855 | clk_disable: |
831 | clk_disable_unprepare(data->thermal_clk); | 856 | clk_disable_unprepare(data->thermal_clk); |
832 | cpufreq_put: | 857 | legacy_cleanup: |
833 | cpufreq_cooling_unregister(data->cdev); | 858 | imx_thermal_unregister_legacy_cooling(data); |
834 | cpufreq_cpu_put(data->policy); | ||
835 | 859 | ||
836 | return ret; | 860 | return ret; |
837 | } | 861 | } |
diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index cde891c54cde..7571f7c2e7c9 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c | |||
@@ -708,19 +708,7 @@ static int powerclamp_debug_show(struct seq_file *m, void *unused) | |||
708 | return 0; | 708 | return 0; |
709 | } | 709 | } |
710 | 710 | ||
711 | static int powerclamp_debug_open(struct inode *inode, | 711 | DEFINE_SHOW_ATTRIBUTE(powerclamp_debug); |
712 | struct file *file) | ||
713 | { | ||
714 | return single_open(file, powerclamp_debug_show, inode->i_private); | ||
715 | } | ||
716 | |||
717 | static const struct file_operations powerclamp_debug_fops = { | ||
718 | .open = powerclamp_debug_open, | ||
719 | .read = seq_read, | ||
720 | .llseek = seq_lseek, | ||
721 | .release = single_release, | ||
722 | .owner = THIS_MODULE, | ||
723 | }; | ||
724 | 712 | ||
725 | static inline void powerclamp_create_debug_files(void) | 713 | static inline void powerclamp_create_debug_files(void) |
726 | { | 714 | { |
diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index 3be4be2e0465..78652cac7f3d 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c | |||
@@ -114,6 +114,14 @@ int get_temp_common(struct tsens_device *tmdev, int id, int *temp) | |||
114 | } | 114 | } |
115 | 115 | ||
116 | static const struct regmap_config tsens_config = { | 116 | static const struct regmap_config tsens_config = { |
117 | .name = "tm", | ||
118 | .reg_bits = 32, | ||
119 | .val_bits = 32, | ||
120 | .reg_stride = 4, | ||
121 | }; | ||
122 | |||
123 | static const struct regmap_config tsens_srot_config = { | ||
124 | .name = "srot", | ||
117 | .reg_bits = 32, | 125 | .reg_bits = 32, |
118 | .val_bits = 32, | 126 | .val_bits = 32, |
119 | .reg_stride = 4, | 127 | .reg_stride = 4, |
@@ -139,8 +147,8 @@ int __init init_common(struct tsens_device *tmdev) | |||
139 | if (IS_ERR(srot_base)) | 147 | if (IS_ERR(srot_base)) |
140 | return PTR_ERR(srot_base); | 148 | return PTR_ERR(srot_base); |
141 | 149 | ||
142 | tmdev->srot_map = devm_regmap_init_mmio(tmdev->dev, | 150 | tmdev->srot_map = devm_regmap_init_mmio(tmdev->dev, srot_base, |
143 | srot_base, &tsens_config); | 151 | &tsens_srot_config); |
144 | if (IS_ERR(tmdev->srot_map)) | 152 | if (IS_ERR(tmdev->srot_map)) |
145 | return PTR_ERR(tmdev->srot_map); | 153 | return PTR_ERR(tmdev->srot_map); |
146 | 154 | ||
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index 8014a207d8d9..97462e9b40d8 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c | |||
@@ -113,10 +113,18 @@ static const struct of_device_id rcar_thermal_dt_ids[] = { | |||
113 | .data = &rcar_gen2_thermal, | 113 | .data = &rcar_gen2_thermal, |
114 | }, | 114 | }, |
115 | { | 115 | { |
116 | .compatible = "renesas,thermal-r8a774c0", | ||
117 | .data = &rcar_gen3_thermal, | ||
118 | }, | ||
119 | { | ||
116 | .compatible = "renesas,thermal-r8a77970", | 120 | .compatible = "renesas,thermal-r8a77970", |
117 | .data = &rcar_gen3_thermal, | 121 | .data = &rcar_gen3_thermal, |
118 | }, | 122 | }, |
119 | { | 123 | { |
124 | .compatible = "renesas,thermal-r8a77990", | ||
125 | .data = &rcar_gen3_thermal, | ||
126 | }, | ||
127 | { | ||
120 | .compatible = "renesas,thermal-r8a77995", | 128 | .compatible = "renesas,thermal-r8a77995", |
121 | .data = &rcar_gen3_thermal, | 129 | .data = &rcar_gen3_thermal, |
122 | }, | 130 | }, |
diff --git a/drivers/thermal/st/Makefile b/drivers/thermal/st/Makefile index b2b9e9b96296..243ca7881b12 100644 --- a/drivers/thermal/st/Makefile +++ b/drivers/thermal/st/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-$(CONFIG_ST_THERMAL) := st_thermal.o | 1 | obj-$(CONFIG_ST_THERMAL) := st_thermal.o |
2 | obj-$(CONFIG_ST_THERMAL_SYSCFG) += st_thermal_syscfg.o | 2 | obj-$(CONFIG_ST_THERMAL_SYSCFG) += st_thermal_syscfg.o |
3 | obj-$(CONFIG_ST_THERMAL_MEMMAP) += st_thermal_memmap.o | 3 | obj-$(CONFIG_ST_THERMAL_MEMMAP) += st_thermal_memmap.o |
4 | obj-$(CONFIG_STM32_THERMAL) := stm_thermal.o \ No newline at end of file | 4 | obj-$(CONFIG_STM32_THERMAL) += stm_thermal.o |
diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index ed28110a3535..45b41b885f49 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c | |||
@@ -803,17 +803,7 @@ static int regs_show(struct seq_file *s, void *data) | |||
803 | return 0; | 803 | return 0; |
804 | } | 804 | } |
805 | 805 | ||
806 | static int regs_open(struct inode *inode, struct file *file) | 806 | DEFINE_SHOW_ATTRIBUTE(regs); |
807 | { | ||
808 | return single_open(file, regs_show, inode->i_private); | ||
809 | } | ||
810 | |||
811 | static const struct file_operations regs_fops = { | ||
812 | .open = regs_open, | ||
813 | .read = seq_read, | ||
814 | .llseek = seq_lseek, | ||
815 | .release = single_release, | ||
816 | }; | ||
817 | 807 | ||
818 | static void soctherm_debug_init(struct platform_device *pdev) | 808 | static void soctherm_debug_init(struct platform_device *pdev) |
819 | { | 809 | { |
diff --git a/drivers/thermal/thermal-generic-adc.c b/drivers/thermal/thermal-generic-adc.c index bf1c628d4a7a..e22fc60ad36d 100644 --- a/drivers/thermal/thermal-generic-adc.c +++ b/drivers/thermal/thermal-generic-adc.c | |||
@@ -26,7 +26,7 @@ struct gadc_thermal_info { | |||
26 | 26 | ||
27 | static int gadc_thermal_adc_to_temp(struct gadc_thermal_info *gti, int val) | 27 | static int gadc_thermal_adc_to_temp(struct gadc_thermal_info *gti, int val) |
28 | { | 28 | { |
29 | int temp, adc_hi, adc_lo; | 29 | int temp, temp_hi, temp_lo, adc_hi, adc_lo; |
30 | int i; | 30 | int i; |
31 | 31 | ||
32 | for (i = 0; i < gti->nlookup_table; i++) { | 32 | for (i = 0; i < gti->nlookup_table; i++) { |
@@ -36,13 +36,17 @@ static int gadc_thermal_adc_to_temp(struct gadc_thermal_info *gti, int val) | |||
36 | 36 | ||
37 | if (i == 0) { | 37 | if (i == 0) { |
38 | temp = gti->lookup_table[0]; | 38 | temp = gti->lookup_table[0]; |
39 | } else if (i >= (gti->nlookup_table - 1)) { | 39 | } else if (i >= gti->nlookup_table) { |
40 | temp = gti->lookup_table[2 * (gti->nlookup_table - 1)]; | 40 | temp = gti->lookup_table[2 * (gti->nlookup_table - 1)]; |
41 | } else { | 41 | } else { |
42 | adc_hi = gti->lookup_table[2 * i - 1]; | 42 | adc_hi = gti->lookup_table[2 * i - 1]; |
43 | adc_lo = gti->lookup_table[2 * i + 1]; | 43 | adc_lo = gti->lookup_table[2 * i + 1]; |
44 | temp = gti->lookup_table[2 * i]; | 44 | |
45 | temp -= ((val - adc_lo) * 1000) / (adc_hi - adc_lo); | 45 | temp_hi = gti->lookup_table[2 * i - 2]; |
46 | temp_lo = gti->lookup_table[2 * i]; | ||
47 | |||
48 | temp = temp_hi + mult_frac(temp_lo - temp_hi, val - adc_hi, | ||
49 | adc_lo - adc_hi); | ||
46 | } | 50 | } |
47 | 51 | ||
48 | return temp; | 52 | return temp; |
diff --git a/drivers/thermal/thermal_hwmon.h b/drivers/thermal/thermal_hwmon.h index 019f6f88224e..a160b9d62dd0 100644 --- a/drivers/thermal/thermal_hwmon.h +++ b/drivers/thermal/thermal_hwmon.h | |||
@@ -19,13 +19,13 @@ | |||
19 | int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz); | 19 | int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz); |
20 | void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz); | 20 | void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz); |
21 | #else | 21 | #else |
22 | static int | 22 | static inline int |
23 | thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) | 23 | thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) |
24 | { | 24 | { |
25 | return 0; | 25 | return 0; |
26 | } | 26 | } |
27 | 27 | ||
28 | static void | 28 | static inline void |
29 | thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) | 29 | thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) |
30 | { | 30 | { |
31 | } | 31 | } |
diff --git a/drivers/thermal/uniphier_thermal.c b/drivers/thermal/uniphier_thermal.c index 55477d74d591..bba2284412d3 100644 --- a/drivers/thermal/uniphier_thermal.c +++ b/drivers/thermal/uniphier_thermal.c | |||
@@ -1,21 +1,10 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /** | 2 | /** |
2 | * uniphier_thermal.c - Socionext UniPhier thermal driver | 3 | * uniphier_thermal.c - Socionext UniPhier thermal driver |
3 | * | ||
4 | * Copyright 2014 Panasonic Corporation | 4 | * Copyright 2014 Panasonic Corporation |
5 | * Copyright 2016-2017 Socionext Inc. | 5 | * Copyright 2016-2017 Socionext Inc. |
6 | * All rights reserved. | ||
7 | * | ||
8 | * Author: | 6 | * Author: |
9 | * Kunihiko Hayashi <hayashi.kunihiko@socionext.com> | 7 | * Kunihiko Hayashi <hayashi.kunihiko@socionext.com> |
10 | * | ||
11 | * This program is free software: you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 of | ||
13 | * the License as published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | */ | 8 | */ |
20 | 9 | ||
21 | #include <linux/bitops.h> | 10 | #include <linux/bitops.h> |