diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-11 12:03:01 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-11 12:03:01 -0500 |
commit | baf51c43926ec9aa42ef9d33ca6ee9e3e043aebe (patch) | |
tree | 3ae0fbc2389f8264f195699721c9489dc347ff4f | |
parent | c5a37883f42be712a989e54d5d6c0159b0e56599 (diff) | |
parent | 7c5b2759bf8c2cbc60e5560c72cf51a2628f6d30 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
Pull thermal updates from Zhang Rui:
- Implement generic devfreq cooling mechanism through frequency
reduction for devices using devfreq. From Ørjan Eide and Javi
Merino.
- Introduce OMAP3 support on TI SoC thermal driver. From Pavel Mack
and Eduardo Valentin.
- A bounch of small fixes on devfreq_cooling, Exynos, IMX, Armada, and
Rockchip thermal drivers.
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: (24 commits)
thermal: exynos: Directly return 0 instead of using local ret variable
thermal: exynos: Remove unneeded semicolon
thermal: exynos: Use IS_ERR() because regulator cannot be NULL
thermal: exynos: Fix first temperature read after registering sensor
thermal: exynos: Fix unbalanced regulator disable on probe failure
devfreq_cooling: return on allocation failure
thermal: rockchip: support the sleep pinctrl state to avoid glitches in s2r
dt-bindings: rockchip-thermal: Add the pinctrl states in this document
thermal: devfreq_cooling: Make power a u64
thermal: devfreq_cooling: use a thermal_cooling_device for register and unregister
thermal: underflow bug in imx_set_trip_temp()
thermal: armada: Fix possible overflow in the Armada 380 thermal sensor formula
thermal: imx: register irq handler later in probe
thermal: rockhip: fix setting thermal shutdown polarity
thermal: rockchip: fix handling of invalid readings
devfreq_cooling: add trace information
thermal: Add devfreq cooling
PM / OPP: get the voltage for all OPPs
tools/thermal: tmon: use pkg-config also for CFLAGS
linux/thermal.h: rename KELVIN_TO_CELSIUS to DECI_KELVIN_TO_CELSIUS
...
23 files changed, 1065 insertions, 86 deletions
diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt index ef802de4957a..b38200d2583a 100644 --- a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt | |||
@@ -12,6 +12,11 @@ Required properties: | |||
12 | - resets : Must contain an entry for each entry in reset-names. | 12 | - resets : Must contain an entry for each entry in reset-names. |
13 | See ../reset/reset.txt for details. | 13 | See ../reset/reset.txt for details. |
14 | - reset-names : Must include the name "tsadc-apb". | 14 | - reset-names : Must include the name "tsadc-apb". |
15 | - pinctrl-names : The pin control state names; | ||
16 | - pinctrl-0 : The "init" pinctrl state, it will be set before device probe. | ||
17 | - pinctrl-1 : The "default" pinctrl state, it will be set after reset the | ||
18 | TSADC controller. | ||
19 | - pinctrl-2 : The "sleep" pinctrl state, it will be in for suspend. | ||
15 | - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description. | 20 | - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description. |
16 | - rockchip,hw-tshut-temp : The hardware-controlled shutdown temperature value. | 21 | - rockchip,hw-tshut-temp : The hardware-controlled shutdown temperature value. |
17 | - rockchip,hw-tshut-mode : The hardware-controlled shutdown mode 0:CRU 1:GPIO. | 22 | - rockchip,hw-tshut-mode : The hardware-controlled shutdown mode 0:CRU 1:GPIO. |
@@ -27,8 +32,10 @@ tsadc: tsadc@ff280000 { | |||
27 | clock-names = "tsadc", "apb_pclk"; | 32 | clock-names = "tsadc", "apb_pclk"; |
28 | resets = <&cru SRST_TSADC>; | 33 | resets = <&cru SRST_TSADC>; |
29 | reset-names = "tsadc-apb"; | 34 | reset-names = "tsadc-apb"; |
30 | pinctrl-names = "default"; | 35 | pinctrl-names = "init", "default", "sleep"; |
31 | pinctrl-0 = <&otp_out>; | 36 | pinctrl-0 = <&otp_gpio>; |
37 | pinctrl-1 = <&otp_out>; | ||
38 | pinctrl-2 = <&otp_gpio>; | ||
32 | #thermal-sensor-cells = <1>; | 39 | #thermal-sensor-cells = <1>; |
33 | rockchip,hw-tshut-temp = <95000>; | 40 | rockchip,hw-tshut-temp = <95000>; |
34 | rockchip,hw-tshut-mode = <0>; | 41 | rockchip,hw-tshut-mode = <0>; |
diff --git a/Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt b/Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt index 0c9222d27fae..6299dd8de339 100644 --- a/Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt +++ b/Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt | |||
@@ -10,6 +10,8 @@ to the silicon temperature. | |||
10 | 10 | ||
11 | Required properties: | 11 | Required properties: |
12 | - compatible : Should be: | 12 | - compatible : Should be: |
13 | - "ti,omap34xx-bandgap" : for OMAP34xx bandgap | ||
14 | - "ti,omap36xx-bandgap" : for OMAP36xx bandgap | ||
13 | - "ti,omap4430-bandgap" : for OMAP4430 bandgap | 15 | - "ti,omap4430-bandgap" : for OMAP4430 bandgap |
14 | - "ti,omap4460-bandgap" : for OMAP4460 bandgap | 16 | - "ti,omap4460-bandgap" : for OMAP4460 bandgap |
15 | - "ti,omap4470-bandgap" : for OMAP4470 bandgap | 17 | - "ti,omap4470-bandgap" : for OMAP4470 bandgap |
@@ -25,6 +27,18 @@ to each bandgap version, because the mapping may change from | |||
25 | soc to soc, apart of depending on available features. | 27 | soc to soc, apart of depending on available features. |
26 | 28 | ||
27 | Example: | 29 | Example: |
30 | OMAP34xx: | ||
31 | bandgap { | ||
32 | reg = <0x48002524 0x4>; | ||
33 | compatible = "ti,omap34xx-bandgap"; | ||
34 | }; | ||
35 | |||
36 | OMAP36xx: | ||
37 | bandgap { | ||
38 | reg = <0x48002524 0x4>; | ||
39 | compatible = "ti,omap36xx-bandgap"; | ||
40 | }; | ||
41 | |||
28 | OMAP4430: | 42 | OMAP4430: |
29 | bandgap { | 43 | bandgap { |
30 | reg = <0x4a002260 0x4 0x4a00232C 0x4>; | 44 | reg = <0x4a002260 0x4 0x4a00232C 0x4>; |
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 30d8518b25fb..82707f9824ca 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c | |||
@@ -315,7 +315,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) | |||
315 | if (crt == -1) { | 315 | if (crt == -1) { |
316 | tz->trips.critical.flags.valid = 0; | 316 | tz->trips.critical.flags.valid = 0; |
317 | } else if (crt > 0) { | 317 | } else if (crt > 0) { |
318 | unsigned long crt_k = CELSIUS_TO_KELVIN(crt); | 318 | unsigned long crt_k = CELSIUS_TO_DECI_KELVIN(crt); |
319 | /* | 319 | /* |
320 | * Allow override critical threshold | 320 | * Allow override critical threshold |
321 | */ | 321 | */ |
@@ -351,7 +351,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) | |||
351 | if (psv == -1) { | 351 | if (psv == -1) { |
352 | status = AE_SUPPORT; | 352 | status = AE_SUPPORT; |
353 | } else if (psv > 0) { | 353 | } else if (psv > 0) { |
354 | tmp = CELSIUS_TO_KELVIN(psv); | 354 | tmp = CELSIUS_TO_DECI_KELVIN(psv); |
355 | status = AE_OK; | 355 | status = AE_OK; |
356 | } else { | 356 | } else { |
357 | status = acpi_evaluate_integer(tz->device->handle, | 357 | status = acpi_evaluate_integer(tz->device->handle, |
@@ -431,7 +431,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) | |||
431 | break; | 431 | break; |
432 | if (i == 1) | 432 | if (i == 1) |
433 | tz->trips.active[0].temperature = | 433 | tz->trips.active[0].temperature = |
434 | CELSIUS_TO_KELVIN(act); | 434 | CELSIUS_TO_DECI_KELVIN(act); |
435 | else | 435 | else |
436 | /* | 436 | /* |
437 | * Don't allow override higher than | 437 | * Don't allow override higher than |
@@ -439,9 +439,9 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) | |||
439 | */ | 439 | */ |
440 | tz->trips.active[i - 1].temperature = | 440 | tz->trips.active[i - 1].temperature = |
441 | (tz->trips.active[i - 2].temperature < | 441 | (tz->trips.active[i - 2].temperature < |
442 | CELSIUS_TO_KELVIN(act) ? | 442 | CELSIUS_TO_DECI_KELVIN(act) ? |
443 | tz->trips.active[i - 2].temperature : | 443 | tz->trips.active[i - 2].temperature : |
444 | CELSIUS_TO_KELVIN(act)); | 444 | CELSIUS_TO_DECI_KELVIN(act)); |
445 | break; | 445 | break; |
446 | } else { | 446 | } else { |
447 | tz->trips.active[i].temperature = tmp; | 447 | tz->trips.active[i].temperature = tmp; |
@@ -1105,7 +1105,7 @@ static int acpi_thermal_add(struct acpi_device *device) | |||
1105 | INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn); | 1105 | INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn); |
1106 | 1106 | ||
1107 | pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device), | 1107 | pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device), |
1108 | acpi_device_bid(device), KELVIN_TO_CELSIUS(tz->temperature)); | 1108 | acpi_device_bid(device), DECI_KELVIN_TO_CELSIUS(tz->temperature)); |
1109 | goto end; | 1109 | goto end; |
1110 | 1110 | ||
1111 | free_memory: | 1111 | free_memory: |
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index d5c1149ff123..270902007055 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c | |||
@@ -100,7 +100,7 @@ struct device_opp *_find_device_opp(struct device *dev) | |||
100 | } | 100 | } |
101 | 101 | ||
102 | /** | 102 | /** |
103 | * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an available opp | 103 | * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an opp |
104 | * @opp: opp for which voltage has to be returned for | 104 | * @opp: opp for which voltage has to be returned for |
105 | * | 105 | * |
106 | * Return: voltage in micro volt corresponding to the opp, else | 106 | * Return: voltage in micro volt corresponding to the opp, else |
@@ -122,7 +122,7 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) | |||
122 | opp_rcu_lockdep_assert(); | 122 | opp_rcu_lockdep_assert(); |
123 | 123 | ||
124 | tmp_opp = rcu_dereference(opp); | 124 | tmp_opp = rcu_dereference(opp); |
125 | if (IS_ERR_OR_NULL(tmp_opp) || !tmp_opp->available) | 125 | if (IS_ERR_OR_NULL(tmp_opp)) |
126 | pr_err("%s: Invalid parameters\n", __func__); | 126 | pr_err("%s: Invalid parameters\n", __func__); |
127 | else | 127 | else |
128 | v = tmp_opp->u_volt; | 128 | v = tmp_opp->u_volt; |
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 1f7d80ff8cb4..e3a750224ae2 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c | |||
@@ -1320,7 +1320,7 @@ static ssize_t asus_hwmon_temp1(struct device *dev, | |||
1320 | if (err < 0) | 1320 | if (err < 0) |
1321 | return err; | 1321 | return err; |
1322 | 1322 | ||
1323 | value = KELVIN_TO_CELSIUS((value & 0xFFFF)) * 1000; | 1323 | value = DECI_KELVIN_TO_CELSIUS((value & 0xFFFF)) * 1000; |
1324 | 1324 | ||
1325 | return sprintf(buf, "%d\n", value); | 1325 | return sprintf(buf, "%d\n", value); |
1326 | } | 1326 | } |
diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c index e8b46d2c468c..0a919d81662c 100644 --- a/drivers/platform/x86/intel_menlow.c +++ b/drivers/platform/x86/intel_menlow.c | |||
@@ -315,7 +315,7 @@ static ssize_t aux0_show(struct device *dev, | |||
315 | 315 | ||
316 | result = sensor_get_auxtrip(attr->handle, 0, &value); | 316 | result = sensor_get_auxtrip(attr->handle, 0, &value); |
317 | 317 | ||
318 | return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); | 318 | return result ? result : sprintf(buf, "%lu", DECI_KELVIN_TO_CELSIUS(value)); |
319 | } | 319 | } |
320 | 320 | ||
321 | static ssize_t aux1_show(struct device *dev, | 321 | static ssize_t aux1_show(struct device *dev, |
@@ -327,7 +327,7 @@ static ssize_t aux1_show(struct device *dev, | |||
327 | 327 | ||
328 | result = sensor_get_auxtrip(attr->handle, 1, &value); | 328 | result = sensor_get_auxtrip(attr->handle, 1, &value); |
329 | 329 | ||
330 | return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); | 330 | return result ? result : sprintf(buf, "%lu", DECI_KELVIN_TO_CELSIUS(value)); |
331 | } | 331 | } |
332 | 332 | ||
333 | static ssize_t aux0_store(struct device *dev, | 333 | static ssize_t aux0_store(struct device *dev, |
@@ -345,7 +345,7 @@ static ssize_t aux0_store(struct device *dev, | |||
345 | if (value < 0) | 345 | if (value < 0) |
346 | return -EINVAL; | 346 | return -EINVAL; |
347 | 347 | ||
348 | result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value)); | 348 | result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_DECI_KELVIN(value)); |
349 | return result ? result : count; | 349 | return result ? result : count; |
350 | } | 350 | } |
351 | 351 | ||
@@ -364,7 +364,7 @@ static ssize_t aux1_store(struct device *dev, | |||
364 | if (value < 0) | 364 | if (value < 0) |
365 | return -EINVAL; | 365 | return -EINVAL; |
366 | 366 | ||
367 | result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value)); | 367 | result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_DECI_KELVIN(value)); |
368 | return result ? result : count; | 368 | return result ? result : count; |
369 | } | 369 | } |
370 | 370 | ||
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 5aabc4bc0d75..c463c89b90ef 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig | |||
@@ -147,6 +147,20 @@ config CLOCK_THERMAL | |||
147 | device that is configured to use this cooling mechanism will be | 147 | device that is configured to use this cooling mechanism will be |
148 | controlled to reduce clock frequency whenever temperature is high. | 148 | controlled to reduce clock frequency whenever temperature is high. |
149 | 149 | ||
150 | config DEVFREQ_THERMAL | ||
151 | bool "Generic device cooling support" | ||
152 | depends on PM_DEVFREQ | ||
153 | depends on PM_OPP | ||
154 | help | ||
155 | This implements the generic devfreq cooling mechanism through | ||
156 | frequency reduction for devices using devfreq. | ||
157 | |||
158 | This will throttle the device by limiting the maximum allowed DVFS | ||
159 | frequency corresponding to the cooling level. | ||
160 | |||
161 | In order to use the power extensions of the cooling device, | ||
162 | devfreq should use the simple_ondemand governor. | ||
163 | |||
150 | If you want this support, you should say Y here. | 164 | If you want this support, you should say Y here. |
151 | 165 | ||
152 | config THERMAL_EMULATION | 166 | config THERMAL_EMULATION |
@@ -275,6 +289,7 @@ config X86_PKG_TEMP_THERMAL | |||
275 | tristate "X86 package temperature thermal driver" | 289 | tristate "X86 package temperature thermal driver" |
276 | depends on X86_THERMAL_VECTOR | 290 | depends on X86_THERMAL_VECTOR |
277 | select THERMAL_GOV_USER_SPACE | 291 | select THERMAL_GOV_USER_SPACE |
292 | select THERMAL_WRITABLE_TRIPS | ||
278 | default m | 293 | default m |
279 | help | 294 | help |
280 | Enable this to register CPU digital sensor for package temperature as | 295 | Enable this to register CPU digital sensor for package temperature as |
@@ -296,6 +311,7 @@ config INTEL_SOC_DTS_THERMAL | |||
296 | tristate "Intel SoCs DTS thermal driver" | 311 | tristate "Intel SoCs DTS thermal driver" |
297 | depends on X86 | 312 | depends on X86 |
298 | select INTEL_SOC_DTS_IOSF_CORE | 313 | select INTEL_SOC_DTS_IOSF_CORE |
314 | select THERMAL_WRITABLE_TRIPS | ||
299 | help | 315 | help |
300 | Enable this to register Intel SoCs (e.g. Bay Trail) platform digital | 316 | Enable this to register Intel SoCs (e.g. Bay Trail) platform digital |
301 | temperature sensor (DTS). These SoCs have two additional DTSs in | 317 | temperature sensor (DTS). These SoCs have two additional DTSs in |
@@ -322,6 +338,7 @@ config INT340X_THERMAL | |||
322 | select ACPI_THERMAL_REL | 338 | select ACPI_THERMAL_REL |
323 | select ACPI_FAN | 339 | select ACPI_FAN |
324 | select INTEL_SOC_DTS_IOSF_CORE | 340 | select INTEL_SOC_DTS_IOSF_CORE |
341 | select THERMAL_WRITABLE_TRIPS | ||
325 | help | 342 | help |
326 | Newer laptops and tablets that use ACPI may have thermal sensors and | 343 | Newer laptops and tablets that use ACPI may have thermal sensors and |
327 | other devices with thermal control capabilities outside the core | 344 | other devices with thermal control capabilities outside the core |
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 26f160809959..cfae6a654793 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile | |||
@@ -22,6 +22,9 @@ thermal_sys-$(CONFIG_CPU_THERMAL) += cpu_cooling.o | |||
22 | # clock cooling | 22 | # clock cooling |
23 | thermal_sys-$(CONFIG_CLOCK_THERMAL) += clock_cooling.o | 23 | thermal_sys-$(CONFIG_CLOCK_THERMAL) += clock_cooling.o |
24 | 24 | ||
25 | # devfreq cooling | ||
26 | thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o | ||
27 | |||
25 | # platform thermal drivers | 28 | # platform thermal drivers |
26 | obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o | 29 | obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o |
27 | obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o | 30 | obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o |
diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c index 26b8d326546a..ae75328945f7 100644 --- a/drivers/thermal/armada_thermal.c +++ b/drivers/thermal/armada_thermal.c | |||
@@ -224,9 +224,9 @@ static const struct armada_thermal_data armada380_data = { | |||
224 | .is_valid_shift = 10, | 224 | .is_valid_shift = 10, |
225 | .temp_shift = 0, | 225 | .temp_shift = 0, |
226 | .temp_mask = 0x3ff, | 226 | .temp_mask = 0x3ff, |
227 | .coef_b = 2931108200UL, | 227 | .coef_b = 1172499100UL, |
228 | .coef_m = 5000000UL, | 228 | .coef_m = 2000096UL, |
229 | .coef_div = 10502, | 229 | .coef_div = 4201, |
230 | .inverted = true, | 230 | .inverted = true, |
231 | }; | 231 | }; |
232 | 232 | ||
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 42c6f71bdcc1..e3fbc5a5d88f 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c | |||
@@ -591,8 +591,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, | |||
591 | if (trace_thermal_power_cpu_get_power_enabled()) { | 591 | if (trace_thermal_power_cpu_get_power_enabled()) { |
592 | u32 ncpus = cpumask_weight(&cpufreq_device->allowed_cpus); | 592 | u32 ncpus = cpumask_weight(&cpufreq_device->allowed_cpus); |
593 | 593 | ||
594 | load_cpu = devm_kcalloc(&cdev->device, ncpus, sizeof(*load_cpu), | 594 | load_cpu = kcalloc(ncpus, sizeof(*load_cpu), GFP_KERNEL); |
595 | GFP_KERNEL); | ||
596 | } | 595 | } |
597 | 596 | ||
598 | for_each_cpu(cpu, &cpufreq_device->allowed_cpus) { | 597 | for_each_cpu(cpu, &cpufreq_device->allowed_cpus) { |
@@ -615,8 +614,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, | |||
615 | dynamic_power = get_dynamic_power(cpufreq_device, freq); | 614 | dynamic_power = get_dynamic_power(cpufreq_device, freq); |
616 | ret = get_static_power(cpufreq_device, tz, freq, &static_power); | 615 | ret = get_static_power(cpufreq_device, tz, freq, &static_power); |
617 | if (ret) { | 616 | if (ret) { |
618 | if (load_cpu) | 617 | kfree(load_cpu); |
619 | devm_kfree(&cdev->device, load_cpu); | ||
620 | return ret; | 618 | return ret; |
621 | } | 619 | } |
622 | 620 | ||
@@ -625,7 +623,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, | |||
625 | &cpufreq_device->allowed_cpus, | 623 | &cpufreq_device->allowed_cpus, |
626 | freq, load_cpu, i, dynamic_power, static_power); | 624 | freq, load_cpu, i, dynamic_power, static_power); |
627 | 625 | ||
628 | devm_kfree(&cdev->device, load_cpu); | 626 | kfree(load_cpu); |
629 | } | 627 | } |
630 | 628 | ||
631 | *power = static_power + dynamic_power; | 629 | *power = static_power + dynamic_power; |
diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c new file mode 100644 index 000000000000..01f0015f80dc --- /dev/null +++ b/drivers/thermal/devfreq_cooling.c | |||
@@ -0,0 +1,573 @@ | |||
1 | /* | ||
2 | * devfreq_cooling: Thermal cooling device implementation for devices using | ||
3 | * devfreq | ||
4 | * | ||
5 | * Copyright (C) 2014-2015 ARM Limited | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
12 | * kind, whether express or implied; without even the implied warranty | ||
13 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * TODO: | ||
17 | * - If OPPs are added or removed after devfreq cooling has | ||
18 | * registered, the devfreq cooling won't react to it. | ||
19 | */ | ||
20 | |||
21 | #include <linux/devfreq.h> | ||
22 | #include <linux/devfreq_cooling.h> | ||
23 | #include <linux/export.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/pm_opp.h> | ||
26 | #include <linux/thermal.h> | ||
27 | |||
28 | #include <trace/events/thermal.h> | ||
29 | |||
30 | static DEFINE_MUTEX(devfreq_lock); | ||
31 | static DEFINE_IDR(devfreq_idr); | ||
32 | |||
33 | /** | ||
34 | * struct devfreq_cooling_device - Devfreq cooling device | ||
35 | * @id: unique integer value corresponding to each | ||
36 | * devfreq_cooling_device registered. | ||
37 | * @cdev: Pointer to associated thermal cooling device. | ||
38 | * @devfreq: Pointer to associated devfreq device. | ||
39 | * @cooling_state: Current cooling state. | ||
40 | * @power_table: Pointer to table with maximum power draw for each | ||
41 | * cooling state. State is the index into the table, and | ||
42 | * the power is in mW. | ||
43 | * @freq_table: Pointer to a table with the frequencies sorted in descending | ||
44 | * order. You can index the table by cooling device state | ||
45 | * @freq_table_size: Size of the @freq_table and @power_table | ||
46 | * @power_ops: Pointer to devfreq_cooling_power, used to generate the | ||
47 | * @power_table. | ||
48 | */ | ||
49 | struct devfreq_cooling_device { | ||
50 | int id; | ||
51 | struct thermal_cooling_device *cdev; | ||
52 | struct devfreq *devfreq; | ||
53 | unsigned long cooling_state; | ||
54 | u32 *power_table; | ||
55 | u32 *freq_table; | ||
56 | size_t freq_table_size; | ||
57 | struct devfreq_cooling_power *power_ops; | ||
58 | }; | ||
59 | |||
60 | /** | ||
61 | * get_idr - function to get a unique id. | ||
62 | * @idr: struct idr * handle used to create a id. | ||
63 | * @id: int * value generated by this function. | ||
64 | * | ||
65 | * This function will populate @id with an unique | ||
66 | * id, using the idr API. | ||
67 | * | ||
68 | * Return: 0 on success, an error code on failure. | ||
69 | */ | ||
70 | static int get_idr(struct idr *idr, int *id) | ||
71 | { | ||
72 | int ret; | ||
73 | |||
74 | mutex_lock(&devfreq_lock); | ||
75 | ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL); | ||
76 | mutex_unlock(&devfreq_lock); | ||
77 | if (unlikely(ret < 0)) | ||
78 | return ret; | ||
79 | *id = ret; | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * release_idr - function to free the unique id. | ||
86 | * @idr: struct idr * handle used for creating the id. | ||
87 | * @id: int value representing the unique id. | ||
88 | */ | ||
89 | static void release_idr(struct idr *idr, int id) | ||
90 | { | ||
91 | mutex_lock(&devfreq_lock); | ||
92 | idr_remove(idr, id); | ||
93 | mutex_unlock(&devfreq_lock); | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * partition_enable_opps() - disable all opps above a given state | ||
98 | * @dfc: Pointer to devfreq we are operating on | ||
99 | * @cdev_state: cooling device state we're setting | ||
100 | * | ||
101 | * Go through the OPPs of the device, enabling all OPPs until | ||
102 | * @cdev_state and disabling those frequencies above it. | ||
103 | */ | ||
104 | static int partition_enable_opps(struct devfreq_cooling_device *dfc, | ||
105 | unsigned long cdev_state) | ||
106 | { | ||
107 | int i; | ||
108 | struct device *dev = dfc->devfreq->dev.parent; | ||
109 | |||
110 | for (i = 0; i < dfc->freq_table_size; i++) { | ||
111 | struct dev_pm_opp *opp; | ||
112 | int ret = 0; | ||
113 | unsigned int freq = dfc->freq_table[i]; | ||
114 | bool want_enable = i >= cdev_state ? true : false; | ||
115 | |||
116 | rcu_read_lock(); | ||
117 | opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable); | ||
118 | rcu_read_unlock(); | ||
119 | |||
120 | if (PTR_ERR(opp) == -ERANGE) | ||
121 | continue; | ||
122 | else if (IS_ERR(opp)) | ||
123 | return PTR_ERR(opp); | ||
124 | |||
125 | if (want_enable) | ||
126 | ret = dev_pm_opp_enable(dev, freq); | ||
127 | else | ||
128 | ret = dev_pm_opp_disable(dev, freq); | ||
129 | |||
130 | if (ret) | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int devfreq_cooling_get_max_state(struct thermal_cooling_device *cdev, | ||
138 | unsigned long *state) | ||
139 | { | ||
140 | struct devfreq_cooling_device *dfc = cdev->devdata; | ||
141 | |||
142 | *state = dfc->freq_table_size - 1; | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | static int devfreq_cooling_get_cur_state(struct thermal_cooling_device *cdev, | ||
148 | unsigned long *state) | ||
149 | { | ||
150 | struct devfreq_cooling_device *dfc = cdev->devdata; | ||
151 | |||
152 | *state = dfc->cooling_state; | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int devfreq_cooling_set_cur_state(struct thermal_cooling_device *cdev, | ||
158 | unsigned long state) | ||
159 | { | ||
160 | struct devfreq_cooling_device *dfc = cdev->devdata; | ||
161 | struct devfreq *df = dfc->devfreq; | ||
162 | struct device *dev = df->dev.parent; | ||
163 | int ret; | ||
164 | |||
165 | if (state == dfc->cooling_state) | ||
166 | return 0; | ||
167 | |||
168 | dev_dbg(dev, "Setting cooling state %lu\n", state); | ||
169 | |||
170 | if (state >= dfc->freq_table_size) | ||
171 | return -EINVAL; | ||
172 | |||
173 | ret = partition_enable_opps(dfc, state); | ||
174 | if (ret) | ||
175 | return ret; | ||
176 | |||
177 | dfc->cooling_state = state; | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /** | ||
183 | * freq_get_state() - get the cooling state corresponding to a frequency | ||
184 | * @dfc: Pointer to devfreq cooling device | ||
185 | * @freq: frequency in Hz | ||
186 | * | ||
187 | * Return: the cooling state associated with the @freq, or | ||
188 | * THERMAL_CSTATE_INVALID if it wasn't found. | ||
189 | */ | ||
190 | static unsigned long | ||
191 | freq_get_state(struct devfreq_cooling_device *dfc, unsigned long freq) | ||
192 | { | ||
193 | int i; | ||
194 | |||
195 | for (i = 0; i < dfc->freq_table_size; i++) { | ||
196 | if (dfc->freq_table[i] == freq) | ||
197 | return i; | ||
198 | } | ||
199 | |||
200 | return THERMAL_CSTATE_INVALID; | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * get_static_power() - calculate the static power | ||
205 | * @dfc: Pointer to devfreq cooling device | ||
206 | * @freq: Frequency in Hz | ||
207 | * | ||
208 | * Calculate the static power in milliwatts using the supplied | ||
209 | * get_static_power(). The current voltage is calculated using the | ||
210 | * OPP library. If no get_static_power() was supplied, assume the | ||
211 | * static power is negligible. | ||
212 | */ | ||
213 | static unsigned long | ||
214 | get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq) | ||
215 | { | ||
216 | struct devfreq *df = dfc->devfreq; | ||
217 | struct device *dev = df->dev.parent; | ||
218 | unsigned long voltage; | ||
219 | struct dev_pm_opp *opp; | ||
220 | |||
221 | if (!dfc->power_ops->get_static_power) | ||
222 | return 0; | ||
223 | |||
224 | rcu_read_lock(); | ||
225 | |||
226 | opp = dev_pm_opp_find_freq_exact(dev, freq, true); | ||
227 | if (IS_ERR(opp) && (PTR_ERR(opp) == -ERANGE)) | ||
228 | opp = dev_pm_opp_find_freq_exact(dev, freq, false); | ||
229 | |||
230 | voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ | ||
231 | |||
232 | rcu_read_unlock(); | ||
233 | |||
234 | if (voltage == 0) { | ||
235 | dev_warn_ratelimited(dev, | ||
236 | "Failed to get voltage for frequency %lu: %ld\n", | ||
237 | freq, IS_ERR(opp) ? PTR_ERR(opp) : 0); | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | return dfc->power_ops->get_static_power(voltage); | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * get_dynamic_power - calculate the dynamic power | ||
246 | * @dfc: Pointer to devfreq cooling device | ||
247 | * @freq: Frequency in Hz | ||
248 | * @voltage: Voltage in millivolts | ||
249 | * | ||
250 | * Calculate the dynamic power in milliwatts consumed by the device at | ||
251 | * frequency @freq and voltage @voltage. If the get_dynamic_power() | ||
252 | * was supplied as part of the devfreq_cooling_power struct, then that | ||
253 | * function is used. Otherwise, a simple power model (Pdyn = Coeff * | ||
254 | * Voltage^2 * Frequency) is used. | ||
255 | */ | ||
256 | static unsigned long | ||
257 | get_dynamic_power(struct devfreq_cooling_device *dfc, unsigned long freq, | ||
258 | unsigned long voltage) | ||
259 | { | ||
260 | u64 power; | ||
261 | u32 freq_mhz; | ||
262 | struct devfreq_cooling_power *dfc_power = dfc->power_ops; | ||
263 | |||
264 | if (dfc_power->get_dynamic_power) | ||
265 | return dfc_power->get_dynamic_power(freq, voltage); | ||
266 | |||
267 | freq_mhz = freq / 1000000; | ||
268 | power = (u64)dfc_power->dyn_power_coeff * freq_mhz * voltage * voltage; | ||
269 | do_div(power, 1000000000); | ||
270 | |||
271 | return power; | ||
272 | } | ||
273 | |||
274 | static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cdev, | ||
275 | struct thermal_zone_device *tz, | ||
276 | u32 *power) | ||
277 | { | ||
278 | struct devfreq_cooling_device *dfc = cdev->devdata; | ||
279 | struct devfreq *df = dfc->devfreq; | ||
280 | struct devfreq_dev_status *status = &df->last_status; | ||
281 | unsigned long state; | ||
282 | unsigned long freq = status->current_frequency; | ||
283 | u32 dyn_power, static_power; | ||
284 | |||
285 | /* Get dynamic power for state */ | ||
286 | state = freq_get_state(dfc, freq); | ||
287 | if (state == THERMAL_CSTATE_INVALID) | ||
288 | return -EAGAIN; | ||
289 | |||
290 | dyn_power = dfc->power_table[state]; | ||
291 | |||
292 | /* Scale dynamic power for utilization */ | ||
293 | dyn_power = (dyn_power * status->busy_time) / status->total_time; | ||
294 | |||
295 | /* Get static power */ | ||
296 | static_power = get_static_power(dfc, freq); | ||
297 | |||
298 | trace_thermal_power_devfreq_get_power(cdev, status, freq, dyn_power, | ||
299 | static_power); | ||
300 | |||
301 | *power = dyn_power + static_power; | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev, | ||
307 | struct thermal_zone_device *tz, | ||
308 | unsigned long state, | ||
309 | u32 *power) | ||
310 | { | ||
311 | struct devfreq_cooling_device *dfc = cdev->devdata; | ||
312 | unsigned long freq; | ||
313 | u32 static_power; | ||
314 | |||
315 | if (state < 0 || state >= dfc->freq_table_size) | ||
316 | return -EINVAL; | ||
317 | |||
318 | freq = dfc->freq_table[state]; | ||
319 | static_power = get_static_power(dfc, freq); | ||
320 | |||
321 | *power = dfc->power_table[state] + static_power; | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev, | ||
326 | struct thermal_zone_device *tz, | ||
327 | u32 power, unsigned long *state) | ||
328 | { | ||
329 | struct devfreq_cooling_device *dfc = cdev->devdata; | ||
330 | struct devfreq *df = dfc->devfreq; | ||
331 | struct devfreq_dev_status *status = &df->last_status; | ||
332 | unsigned long freq = status->current_frequency; | ||
333 | unsigned long busy_time; | ||
334 | s32 dyn_power; | ||
335 | u32 static_power; | ||
336 | int i; | ||
337 | |||
338 | static_power = get_static_power(dfc, freq); | ||
339 | |||
340 | dyn_power = power - static_power; | ||
341 | dyn_power = dyn_power > 0 ? dyn_power : 0; | ||
342 | |||
343 | /* Scale dynamic power for utilization */ | ||
344 | busy_time = status->busy_time ?: 1; | ||
345 | dyn_power = (dyn_power * status->total_time) / busy_time; | ||
346 | |||
347 | /* | ||
348 | * Find the first cooling state that is within the power | ||
349 | * budget for dynamic power. | ||
350 | */ | ||
351 | for (i = 0; i < dfc->freq_table_size - 1; i++) | ||
352 | if (dyn_power >= dfc->power_table[i]) | ||
353 | break; | ||
354 | |||
355 | *state = i; | ||
356 | trace_thermal_power_devfreq_limit(cdev, freq, *state, power); | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static struct thermal_cooling_device_ops devfreq_cooling_ops = { | ||
361 | .get_max_state = devfreq_cooling_get_max_state, | ||
362 | .get_cur_state = devfreq_cooling_get_cur_state, | ||
363 | .set_cur_state = devfreq_cooling_set_cur_state, | ||
364 | }; | ||
365 | |||
366 | /** | ||
367 | * devfreq_cooling_gen_tables() - Generate power and freq tables. | ||
368 | * @dfc: Pointer to devfreq cooling device. | ||
369 | * | ||
370 | * Generate power and frequency tables: the power table hold the | ||
371 | * device's maximum power usage at each cooling state (OPP). The | ||
372 | * static and dynamic power using the appropriate voltage and | ||
373 | * frequency for the state, is acquired from the struct | ||
374 | * devfreq_cooling_power, and summed to make the maximum power draw. | ||
375 | * | ||
376 | * The frequency table holds the frequencies in descending order. | ||
377 | * That way its indexed by cooling device state. | ||
378 | * | ||
379 | * The tables are malloced, and pointers put in dfc. They must be | ||
380 | * freed when unregistering the devfreq cooling device. | ||
381 | * | ||
382 | * Return: 0 on success, negative error code on failure. | ||
383 | */ | ||
384 | static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc) | ||
385 | { | ||
386 | struct devfreq *df = dfc->devfreq; | ||
387 | struct device *dev = df->dev.parent; | ||
388 | int ret, num_opps; | ||
389 | unsigned long freq; | ||
390 | u32 *power_table = NULL; | ||
391 | u32 *freq_table; | ||
392 | int i; | ||
393 | |||
394 | num_opps = dev_pm_opp_get_opp_count(dev); | ||
395 | |||
396 | if (dfc->power_ops) { | ||
397 | power_table = kcalloc(num_opps, sizeof(*power_table), | ||
398 | GFP_KERNEL); | ||
399 | if (!power_table) | ||
400 | return -ENOMEM; | ||
401 | } | ||
402 | |||
403 | freq_table = kcalloc(num_opps, sizeof(*freq_table), | ||
404 | GFP_KERNEL); | ||
405 | if (!freq_table) { | ||
406 | ret = -ENOMEM; | ||
407 | goto free_power_table; | ||
408 | } | ||
409 | |||
410 | for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) { | ||
411 | unsigned long power_dyn, voltage; | ||
412 | struct dev_pm_opp *opp; | ||
413 | |||
414 | rcu_read_lock(); | ||
415 | |||
416 | opp = dev_pm_opp_find_freq_floor(dev, &freq); | ||
417 | if (IS_ERR(opp)) { | ||
418 | rcu_read_unlock(); | ||
419 | ret = PTR_ERR(opp); | ||
420 | goto free_tables; | ||
421 | } | ||
422 | |||
423 | voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ | ||
424 | |||
425 | rcu_read_unlock(); | ||
426 | |||
427 | if (dfc->power_ops) { | ||
428 | power_dyn = get_dynamic_power(dfc, freq, voltage); | ||
429 | |||
430 | dev_dbg(dev, "Dynamic power table: %lu MHz @ %lu mV: %lu = %lu mW\n", | ||
431 | freq / 1000000, voltage, power_dyn, power_dyn); | ||
432 | |||
433 | power_table[i] = power_dyn; | ||
434 | } | ||
435 | |||
436 | freq_table[i] = freq; | ||
437 | } | ||
438 | |||
439 | if (dfc->power_ops) | ||
440 | dfc->power_table = power_table; | ||
441 | |||
442 | dfc->freq_table = freq_table; | ||
443 | dfc->freq_table_size = num_opps; | ||
444 | |||
445 | return 0; | ||
446 | |||
447 | free_tables: | ||
448 | kfree(freq_table); | ||
449 | free_power_table: | ||
450 | kfree(power_table); | ||
451 | |||
452 | return ret; | ||
453 | } | ||
454 | |||
455 | /** | ||
456 | * of_devfreq_cooling_register_power() - Register devfreq cooling device, | ||
457 | * with OF and power information. | ||
458 | * @np: Pointer to OF device_node. | ||
459 | * @df: Pointer to devfreq device. | ||
460 | * @dfc_power: Pointer to devfreq_cooling_power. | ||
461 | * | ||
462 | * Register a devfreq cooling device. The available OPPs must be | ||
463 | * registered on the device. | ||
464 | * | ||
465 | * If @dfc_power is provided, the cooling device is registered with the | ||
466 | * power extensions. For the power extensions to work correctly, | ||
467 | * devfreq should use the simple_ondemand governor, other governors | ||
468 | * are not currently supported. | ||
469 | */ | ||
470 | struct thermal_cooling_device * | ||
471 | of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df, | ||
472 | struct devfreq_cooling_power *dfc_power) | ||
473 | { | ||
474 | struct thermal_cooling_device *cdev; | ||
475 | struct devfreq_cooling_device *dfc; | ||
476 | char dev_name[THERMAL_NAME_LENGTH]; | ||
477 | int err; | ||
478 | |||
479 | dfc = kzalloc(sizeof(*dfc), GFP_KERNEL); | ||
480 | if (!dfc) | ||
481 | return ERR_PTR(-ENOMEM); | ||
482 | |||
483 | dfc->devfreq = df; | ||
484 | |||
485 | if (dfc_power) { | ||
486 | dfc->power_ops = dfc_power; | ||
487 | |||
488 | devfreq_cooling_ops.get_requested_power = | ||
489 | devfreq_cooling_get_requested_power; | ||
490 | devfreq_cooling_ops.state2power = devfreq_cooling_state2power; | ||
491 | devfreq_cooling_ops.power2state = devfreq_cooling_power2state; | ||
492 | } | ||
493 | |||
494 | err = devfreq_cooling_gen_tables(dfc); | ||
495 | if (err) | ||
496 | goto free_dfc; | ||
497 | |||
498 | err = get_idr(&devfreq_idr, &dfc->id); | ||
499 | if (err) | ||
500 | goto free_tables; | ||
501 | |||
502 | snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id); | ||
503 | |||
504 | cdev = thermal_of_cooling_device_register(np, dev_name, dfc, | ||
505 | &devfreq_cooling_ops); | ||
506 | if (IS_ERR(cdev)) { | ||
507 | err = PTR_ERR(cdev); | ||
508 | dev_err(df->dev.parent, | ||
509 | "Failed to register devfreq cooling device (%d)\n", | ||
510 | err); | ||
511 | goto release_idr; | ||
512 | } | ||
513 | |||
514 | dfc->cdev = cdev; | ||
515 | |||
516 | return cdev; | ||
517 | |||
518 | release_idr: | ||
519 | release_idr(&devfreq_idr, dfc->id); | ||
520 | free_tables: | ||
521 | kfree(dfc->power_table); | ||
522 | kfree(dfc->freq_table); | ||
523 | free_dfc: | ||
524 | kfree(dfc); | ||
525 | |||
526 | return ERR_PTR(err); | ||
527 | } | ||
528 | EXPORT_SYMBOL_GPL(of_devfreq_cooling_register_power); | ||
529 | |||
530 | /** | ||
531 | * of_devfreq_cooling_register() - Register devfreq cooling device, | ||
532 | * with OF information. | ||
533 | * @np: Pointer to OF device_node. | ||
534 | * @df: Pointer to devfreq device. | ||
535 | */ | ||
536 | struct thermal_cooling_device * | ||
537 | of_devfreq_cooling_register(struct device_node *np, struct devfreq *df) | ||
538 | { | ||
539 | return of_devfreq_cooling_register_power(np, df, NULL); | ||
540 | } | ||
541 | EXPORT_SYMBOL_GPL(of_devfreq_cooling_register); | ||
542 | |||
543 | /** | ||
544 | * devfreq_cooling_register() - Register devfreq cooling device. | ||
545 | * @df: Pointer to devfreq device. | ||
546 | */ | ||
547 | struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df) | ||
548 | { | ||
549 | return of_devfreq_cooling_register(NULL, df); | ||
550 | } | ||
551 | EXPORT_SYMBOL_GPL(devfreq_cooling_register); | ||
552 | |||
553 | /** | ||
554 | * devfreq_cooling_unregister() - Unregister devfreq cooling device. | ||
555 | * @dfc: Pointer to devfreq cooling device to unregister. | ||
556 | */ | ||
557 | void devfreq_cooling_unregister(struct thermal_cooling_device *cdev) | ||
558 | { | ||
559 | struct devfreq_cooling_device *dfc; | ||
560 | |||
561 | if (!cdev) | ||
562 | return; | ||
563 | |||
564 | dfc = cdev->devdata; | ||
565 | |||
566 | thermal_cooling_device_unregister(dfc->cdev); | ||
567 | release_idr(&devfreq_idr, dfc->id); | ||
568 | kfree(dfc->power_table); | ||
569 | kfree(dfc->freq_table); | ||
570 | |||
571 | kfree(dfc); | ||
572 | } | ||
573 | EXPORT_SYMBOL_GPL(devfreq_cooling_unregister); | ||
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 4bec1d3c3d27..c8fe3cac2e0e 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c | |||
@@ -288,7 +288,7 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip, | |||
288 | if (trip == IMX_TRIP_CRITICAL) | 288 | if (trip == IMX_TRIP_CRITICAL) |
289 | return -EPERM; | 289 | return -EPERM; |
290 | 290 | ||
291 | if (temp > IMX_TEMP_PASSIVE) | 291 | if (temp < 0 || temp > IMX_TEMP_PASSIVE) |
292 | return -EINVAL; | 292 | return -EINVAL; |
293 | 293 | ||
294 | data->temp_passive = temp; | 294 | data->temp_passive = temp; |
@@ -487,14 +487,6 @@ static int imx_thermal_probe(struct platform_device *pdev) | |||
487 | if (data->irq < 0) | 487 | if (data->irq < 0) |
488 | return data->irq; | 488 | return data->irq; |
489 | 489 | ||
490 | ret = devm_request_threaded_irq(&pdev->dev, data->irq, | ||
491 | imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread, | ||
492 | 0, "imx_thermal", data); | ||
493 | if (ret < 0) { | ||
494 | dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret); | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | platform_set_drvdata(pdev, data); | 490 | platform_set_drvdata(pdev, data); |
499 | 491 | ||
500 | ret = imx_get_sensor_data(pdev); | 492 | ret = imx_get_sensor_data(pdev); |
@@ -571,6 +563,17 @@ static int imx_thermal_probe(struct platform_device *pdev) | |||
571 | regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); | 563 | regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); |
572 | regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); | 564 | regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); |
573 | 565 | ||
566 | ret = devm_request_threaded_irq(&pdev->dev, data->irq, | ||
567 | imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread, | ||
568 | 0, "imx_thermal", data); | ||
569 | if (ret < 0) { | ||
570 | dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret); | ||
571 | clk_disable_unprepare(data->thermal_clk); | ||
572 | thermal_zone_device_unregister(data->tz); | ||
573 | cpufreq_cooling_unregister(data->cdev); | ||
574 | return ret; | ||
575 | } | ||
576 | |||
574 | data->irq_enabled = true; | 577 | data->irq_enabled = true; |
575 | data->mode = THERMAL_DEVICE_ENABLED; | 578 | data->mode = THERMAL_DEVICE_ENABLED; |
576 | 579 | ||
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index c89ffb26a354..2b58870c3e25 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c | |||
@@ -106,16 +106,14 @@ struct rockchip_thermal_data { | |||
106 | #define TSADCV2_AUTO_PERIOD_HT 0x6c | 106 | #define TSADCV2_AUTO_PERIOD_HT 0x6c |
107 | 107 | ||
108 | #define TSADCV2_AUTO_EN BIT(0) | 108 | #define TSADCV2_AUTO_EN BIT(0) |
109 | #define TSADCV2_AUTO_DISABLE ~BIT(0) | ||
110 | #define TSADCV2_AUTO_SRC_EN(chn) BIT(4 + (chn)) | 109 | #define TSADCV2_AUTO_SRC_EN(chn) BIT(4 + (chn)) |
111 | #define TSADCV2_AUTO_TSHUT_POLARITY_HIGH BIT(8) | 110 | #define TSADCV2_AUTO_TSHUT_POLARITY_HIGH BIT(8) |
112 | #define TSADCV2_AUTO_TSHUT_POLARITY_LOW ~BIT(8) | ||
113 | 111 | ||
114 | #define TSADCV2_INT_SRC_EN(chn) BIT(chn) | 112 | #define TSADCV2_INT_SRC_EN(chn) BIT(chn) |
115 | #define TSADCV2_SHUT_2GPIO_SRC_EN(chn) BIT(4 + (chn)) | 113 | #define TSADCV2_SHUT_2GPIO_SRC_EN(chn) BIT(4 + (chn)) |
116 | #define TSADCV2_SHUT_2CRU_SRC_EN(chn) BIT(8 + (chn)) | 114 | #define TSADCV2_SHUT_2CRU_SRC_EN(chn) BIT(8 + (chn)) |
117 | 115 | ||
118 | #define TSADCV2_INT_PD_CLEAR ~BIT(8) | 116 | #define TSADCV2_INT_PD_CLEAR_MASK ~BIT(8) |
119 | 117 | ||
120 | #define TSADCV2_DATA_MASK 0xfff | 118 | #define TSADCV2_DATA_MASK 0xfff |
121 | #define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT 4 | 119 | #define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT 4 |
@@ -124,7 +122,7 @@ struct rockchip_thermal_data { | |||
124 | #define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* msec */ | 122 | #define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* msec */ |
125 | 123 | ||
126 | struct tsadc_table { | 124 | struct tsadc_table { |
127 | unsigned long code; | 125 | u32 code; |
128 | long temp; | 126 | long temp; |
129 | }; | 127 | }; |
130 | 128 | ||
@@ -164,7 +162,6 @@ static const struct tsadc_table v2_code_table[] = { | |||
164 | {3452, 115000}, | 162 | {3452, 115000}, |
165 | {3437, 120000}, | 163 | {3437, 120000}, |
166 | {3421, 125000}, | 164 | {3421, 125000}, |
167 | {0, 125000}, | ||
168 | }; | 165 | }; |
169 | 166 | ||
170 | static u32 rk_tsadcv2_temp_to_code(long temp) | 167 | static u32 rk_tsadcv2_temp_to_code(long temp) |
@@ -191,19 +188,21 @@ static u32 rk_tsadcv2_temp_to_code(long temp) | |||
191 | return 0; | 188 | return 0; |
192 | } | 189 | } |
193 | 190 | ||
194 | static int rk_tsadcv2_code_to_temp(u32 code) | 191 | static int rk_tsadcv2_code_to_temp(u32 code, int *temp) |
195 | { | 192 | { |
196 | unsigned int low = 0; | 193 | unsigned int low = 1; |
197 | unsigned int high = ARRAY_SIZE(v2_code_table) - 1; | 194 | unsigned int high = ARRAY_SIZE(v2_code_table) - 1; |
198 | unsigned int mid = (low + high) / 2; | 195 | unsigned int mid = (low + high) / 2; |
199 | unsigned int num; | 196 | unsigned int num; |
200 | unsigned long denom; | 197 | unsigned long denom; |
201 | 198 | ||
202 | /* Invalid code, return -EAGAIN */ | 199 | BUILD_BUG_ON(ARRAY_SIZE(v2_code_table) < 2); |
203 | if (code > TSADCV2_DATA_MASK) | ||
204 | return -EAGAIN; | ||
205 | 200 | ||
206 | while (low <= high && mid) { | 201 | code &= TSADCV2_DATA_MASK; |
202 | if (code < v2_code_table[high].code) | ||
203 | return -EAGAIN; /* Incorrect reading */ | ||
204 | |||
205 | while (low <= high) { | ||
207 | if (code >= v2_code_table[mid].code && | 206 | if (code >= v2_code_table[mid].code && |
208 | code < v2_code_table[mid - 1].code) | 207 | code < v2_code_table[mid - 1].code) |
209 | break; | 208 | break; |
@@ -223,7 +222,9 @@ static int rk_tsadcv2_code_to_temp(u32 code) | |||
223 | num = v2_code_table[mid].temp - v2_code_table[mid - 1].temp; | 222 | num = v2_code_table[mid].temp - v2_code_table[mid - 1].temp; |
224 | num *= v2_code_table[mid - 1].code - code; | 223 | num *= v2_code_table[mid - 1].code - code; |
225 | denom = v2_code_table[mid - 1].code - v2_code_table[mid].code; | 224 | denom = v2_code_table[mid - 1].code - v2_code_table[mid].code; |
226 | return v2_code_table[mid - 1].temp + (num / denom); | 225 | *temp = v2_code_table[mid - 1].temp + (num / denom); |
226 | |||
227 | return 0; | ||
227 | } | 228 | } |
228 | 229 | ||
229 | /** | 230 | /** |
@@ -241,10 +242,10 @@ static void rk_tsadcv2_initialize(void __iomem *regs, | |||
241 | enum tshut_polarity tshut_polarity) | 242 | enum tshut_polarity tshut_polarity) |
242 | { | 243 | { |
243 | if (tshut_polarity == TSHUT_HIGH_ACTIVE) | 244 | if (tshut_polarity == TSHUT_HIGH_ACTIVE) |
244 | writel_relaxed(0 | (TSADCV2_AUTO_TSHUT_POLARITY_HIGH), | 245 | writel_relaxed(0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH, |
245 | regs + TSADCV2_AUTO_CON); | 246 | regs + TSADCV2_AUTO_CON); |
246 | else | 247 | else |
247 | writel_relaxed(0 | (TSADCV2_AUTO_TSHUT_POLARITY_LOW), | 248 | writel_relaxed(0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH, |
248 | regs + TSADCV2_AUTO_CON); | 249 | regs + TSADCV2_AUTO_CON); |
249 | 250 | ||
250 | writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD); | 251 | writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD); |
@@ -261,7 +262,7 @@ static void rk_tsadcv2_irq_ack(void __iomem *regs) | |||
261 | u32 val; | 262 | u32 val; |
262 | 263 | ||
263 | val = readl_relaxed(regs + TSADCV2_INT_PD); | 264 | val = readl_relaxed(regs + TSADCV2_INT_PD); |
264 | writel_relaxed(val & TSADCV2_INT_PD_CLEAR, regs + TSADCV2_INT_PD); | 265 | writel_relaxed(val & TSADCV2_INT_PD_CLEAR_MASK, regs + TSADCV2_INT_PD); |
265 | } | 266 | } |
266 | 267 | ||
267 | static void rk_tsadcv2_control(void __iomem *regs, bool enable) | 268 | static void rk_tsadcv2_control(void __iomem *regs, bool enable) |
@@ -281,14 +282,9 @@ static int rk_tsadcv2_get_temp(int chn, void __iomem *regs, int *temp) | |||
281 | { | 282 | { |
282 | u32 val; | 283 | u32 val; |
283 | 284 | ||
284 | /* the A/D value of the channel last conversion need some time */ | ||
285 | val = readl_relaxed(regs + TSADCV2_DATA(chn)); | 285 | val = readl_relaxed(regs + TSADCV2_DATA(chn)); |
286 | if (val == 0) | ||
287 | return -EAGAIN; | ||
288 | 286 | ||
289 | *temp = rk_tsadcv2_code_to_temp(val); | 287 | return rk_tsadcv2_code_to_temp(val, temp); |
290 | |||
291 | return 0; | ||
292 | } | 288 | } |
293 | 289 | ||
294 | static void rk_tsadcv2_tshut_temp(int chn, void __iomem *regs, long temp) | 290 | static void rk_tsadcv2_tshut_temp(int chn, void __iomem *regs, long temp) |
@@ -642,6 +638,8 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev) | |||
642 | clk_disable(thermal->pclk); | 638 | clk_disable(thermal->pclk); |
643 | clk_disable(thermal->clk); | 639 | clk_disable(thermal->clk); |
644 | 640 | ||
641 | pinctrl_pm_select_sleep_state(dev); | ||
642 | |||
645 | return 0; | 643 | return 0; |
646 | } | 644 | } |
647 | 645 | ||
@@ -678,6 +676,8 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev) | |||
678 | for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) | 676 | for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) |
679 | rockchip_thermal_toggle_sensor(&thermal->sensors[i], true); | 677 | rockchip_thermal_toggle_sensor(&thermal->sensors[i], true); |
680 | 678 | ||
679 | pinctrl_pm_select_default_state(dev); | ||
680 | |||
681 | return 0; | 681 | return 0; |
682 | } | 682 | } |
683 | 683 | ||
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index ca920b0ecf8f..fa61eff88496 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c | |||
@@ -548,7 +548,7 @@ static int exynos5433_tmu_initialize(struct platform_device *pdev) | |||
548 | default: | 548 | default: |
549 | pdata->cal_type = TYPE_ONE_POINT_TRIMMING; | 549 | pdata->cal_type = TYPE_ONE_POINT_TRIMMING; |
550 | break; | 550 | break; |
551 | }; | 551 | } |
552 | 552 | ||
553 | dev_info(&pdev->dev, "Calibration type is %d-point calibration\n", | 553 | dev_info(&pdev->dev, "Calibration type is %d-point calibration\n", |
554 | cal_type ? 2 : 1); | 554 | cal_type ? 2 : 1); |
@@ -608,7 +608,7 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev) | |||
608 | { | 608 | { |
609 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); | 609 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
610 | unsigned int trim_info = 0, con, rising_threshold; | 610 | unsigned int trim_info = 0, con, rising_threshold; |
611 | int ret = 0, threshold_code; | 611 | int threshold_code; |
612 | int crit_temp = 0; | 612 | int crit_temp = 0; |
613 | 613 | ||
614 | /* | 614 | /* |
@@ -651,7 +651,8 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev) | |||
651 | /* Clear the PMIN in the common TMU register */ | 651 | /* Clear the PMIN in the common TMU register */ |
652 | if (!data->id) | 652 | if (!data->id) |
653 | writel(0, data->base_second + EXYNOS5440_TMU_PMIN); | 653 | writel(0, data->base_second + EXYNOS5440_TMU_PMIN); |
654 | return ret; | 654 | |
655 | return 0; | ||
655 | } | 656 | } |
656 | 657 | ||
657 | static int exynos7_tmu_initialize(struct platform_device *pdev) | 658 | static int exynos7_tmu_initialize(struct platform_device *pdev) |
@@ -1168,27 +1169,10 @@ static int exynos_map_dt_data(struct platform_device *pdev) | |||
1168 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); | 1169 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
1169 | struct exynos_tmu_platform_data *pdata; | 1170 | struct exynos_tmu_platform_data *pdata; |
1170 | struct resource res; | 1171 | struct resource res; |
1171 | int ret; | ||
1172 | 1172 | ||
1173 | if (!data || !pdev->dev.of_node) | 1173 | if (!data || !pdev->dev.of_node) |
1174 | return -ENODEV; | 1174 | return -ENODEV; |
1175 | 1175 | ||
1176 | /* | ||
1177 | * Try enabling the regulator if found | ||
1178 | * TODO: Add regulator as an SOC feature, so that regulator enable | ||
1179 | * is a compulsory call. | ||
1180 | */ | ||
1181 | data->regulator = devm_regulator_get(&pdev->dev, "vtmu"); | ||
1182 | if (!IS_ERR(data->regulator)) { | ||
1183 | ret = regulator_enable(data->regulator); | ||
1184 | if (ret) { | ||
1185 | dev_err(&pdev->dev, "failed to enable vtmu\n"); | ||
1186 | return ret; | ||
1187 | } | ||
1188 | } else { | ||
1189 | dev_info(&pdev->dev, "Regulator node (vtmu) not found\n"); | ||
1190 | } | ||
1191 | |||
1192 | data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl"); | 1176 | data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl"); |
1193 | if (data->id < 0) | 1177 | if (data->id < 0) |
1194 | data->id = 0; | 1178 | data->id = 0; |
@@ -1306,12 +1290,22 @@ static int exynos_tmu_probe(struct platform_device *pdev) | |||
1306 | platform_set_drvdata(pdev, data); | 1290 | platform_set_drvdata(pdev, data); |
1307 | mutex_init(&data->lock); | 1291 | mutex_init(&data->lock); |
1308 | 1292 | ||
1309 | data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data, | 1293 | /* |
1310 | &exynos_sensor_ops); | 1294 | * Try enabling the regulator if found |
1311 | if (IS_ERR(data->tzd)) { | 1295 | * TODO: Add regulator as an SOC feature, so that regulator enable |
1312 | pr_err("thermal: tz: %p ERROR\n", data->tzd); | 1296 | * is a compulsory call. |
1313 | return PTR_ERR(data->tzd); | 1297 | */ |
1298 | data->regulator = devm_regulator_get(&pdev->dev, "vtmu"); | ||
1299 | if (!IS_ERR(data->regulator)) { | ||
1300 | ret = regulator_enable(data->regulator); | ||
1301 | if (ret) { | ||
1302 | dev_err(&pdev->dev, "failed to enable vtmu\n"); | ||
1303 | return ret; | ||
1304 | } | ||
1305 | } else { | ||
1306 | dev_info(&pdev->dev, "Regulator node (vtmu) not found\n"); | ||
1314 | } | 1307 | } |
1308 | |||
1315 | ret = exynos_map_dt_data(pdev); | 1309 | ret = exynos_map_dt_data(pdev); |
1316 | if (ret) | 1310 | if (ret) |
1317 | goto err_sensor; | 1311 | goto err_sensor; |
@@ -1363,23 +1357,38 @@ static int exynos_tmu_probe(struct platform_device *pdev) | |||
1363 | break; | 1357 | break; |
1364 | default: | 1358 | default: |
1365 | break; | 1359 | break; |
1366 | }; | 1360 | } |
1361 | |||
1362 | /* | ||
1363 | * data->tzd must be registered before calling exynos_tmu_initialize(), | ||
1364 | * requesting irq and calling exynos_tmu_control(). | ||
1365 | */ | ||
1366 | data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data, | ||
1367 | &exynos_sensor_ops); | ||
1368 | if (IS_ERR(data->tzd)) { | ||
1369 | ret = PTR_ERR(data->tzd); | ||
1370 | dev_err(&pdev->dev, "Failed to register sensor: %d\n", ret); | ||
1371 | goto err_sclk; | ||
1372 | } | ||
1367 | 1373 | ||
1368 | ret = exynos_tmu_initialize(pdev); | 1374 | ret = exynos_tmu_initialize(pdev); |
1369 | if (ret) { | 1375 | if (ret) { |
1370 | dev_err(&pdev->dev, "Failed to initialize TMU\n"); | 1376 | dev_err(&pdev->dev, "Failed to initialize TMU\n"); |
1371 | goto err_sclk; | 1377 | goto err_thermal; |
1372 | } | 1378 | } |
1373 | 1379 | ||
1374 | ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq, | 1380 | ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq, |
1375 | IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data); | 1381 | IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data); |
1376 | if (ret) { | 1382 | if (ret) { |
1377 | dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq); | 1383 | dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq); |
1378 | goto err_sclk; | 1384 | goto err_thermal; |
1379 | } | 1385 | } |
1380 | 1386 | ||
1381 | exynos_tmu_control(pdev, true); | 1387 | exynos_tmu_control(pdev, true); |
1382 | return 0; | 1388 | return 0; |
1389 | |||
1390 | err_thermal: | ||
1391 | thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd); | ||
1383 | err_sclk: | 1392 | err_sclk: |
1384 | clk_disable_unprepare(data->sclk); | 1393 | clk_disable_unprepare(data->sclk); |
1385 | err_clk: | 1394 | err_clk: |
@@ -1388,9 +1397,8 @@ err_clk_sec: | |||
1388 | if (!IS_ERR(data->clk_sec)) | 1397 | if (!IS_ERR(data->clk_sec)) |
1389 | clk_unprepare(data->clk_sec); | 1398 | clk_unprepare(data->clk_sec); |
1390 | err_sensor: | 1399 | err_sensor: |
1391 | if (!IS_ERR_OR_NULL(data->regulator)) | 1400 | if (!IS_ERR(data->regulator)) |
1392 | regulator_disable(data->regulator); | 1401 | regulator_disable(data->regulator); |
1393 | thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd); | ||
1394 | 1402 | ||
1395 | return ret; | 1403 | return ret; |
1396 | } | 1404 | } |
diff --git a/drivers/thermal/ti-soc-thermal/Kconfig b/drivers/thermal/ti-soc-thermal/Kconfig index cb6686ff09ae..ea8283f08aa6 100644 --- a/drivers/thermal/ti-soc-thermal/Kconfig +++ b/drivers/thermal/ti-soc-thermal/Kconfig | |||
@@ -19,6 +19,21 @@ config TI_THERMAL | |||
19 | This includes trip points definitions, extrapolation rules and | 19 | This includes trip points definitions, extrapolation rules and |
20 | CPU cooling device bindings. | 20 | CPU cooling device bindings. |
21 | 21 | ||
22 | config OMAP3_THERMAL | ||
23 | bool "Texas Instruments OMAP3 thermal support" | ||
24 | depends on TI_SOC_THERMAL | ||
25 | depends on ARCH_OMAP3 || COMPILE_TEST | ||
26 | help | ||
27 | If you say yes here you get thermal support for the Texas Instruments | ||
28 | OMAP3 SoC family. The current chips supported are: | ||
29 | - OMAP3430 | ||
30 | |||
31 | OMAP3 chips normally don't need thermal management, and sensors in | ||
32 | this generation are not accurate, nor they are very close to | ||
33 | the important hotspots. | ||
34 | |||
35 | Say 'N' here. | ||
36 | |||
22 | config OMAP4_THERMAL | 37 | config OMAP4_THERMAL |
23 | bool "Texas Instruments OMAP4 thermal support" | 38 | bool "Texas Instruments OMAP4 thermal support" |
24 | depends on TI_SOC_THERMAL | 39 | depends on TI_SOC_THERMAL |
diff --git a/drivers/thermal/ti-soc-thermal/Makefile b/drivers/thermal/ti-soc-thermal/Makefile index 1226b2484e55..0f89bdf03790 100644 --- a/drivers/thermal/ti-soc-thermal/Makefile +++ b/drivers/thermal/ti-soc-thermal/Makefile | |||
@@ -2,5 +2,6 @@ obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal.o | |||
2 | ti-soc-thermal-y := ti-bandgap.o | 2 | ti-soc-thermal-y := ti-bandgap.o |
3 | ti-soc-thermal-$(CONFIG_TI_THERMAL) += ti-thermal-common.o | 3 | ti-soc-thermal-$(CONFIG_TI_THERMAL) += ti-thermal-common.o |
4 | ti-soc-thermal-$(CONFIG_DRA752_THERMAL) += dra752-thermal-data.o | 4 | ti-soc-thermal-$(CONFIG_DRA752_THERMAL) += dra752-thermal-data.o |
5 | ti-soc-thermal-$(CONFIG_OMAP3_THERMAL) += omap3-thermal-data.o | ||
5 | ti-soc-thermal-$(CONFIG_OMAP4_THERMAL) += omap4-thermal-data.o | 6 | ti-soc-thermal-$(CONFIG_OMAP4_THERMAL) += omap4-thermal-data.o |
6 | ti-soc-thermal-$(CONFIG_OMAP5_THERMAL) += omap5-thermal-data.o | 7 | ti-soc-thermal-$(CONFIG_OMAP5_THERMAL) += omap5-thermal-data.o |
diff --git a/drivers/thermal/ti-soc-thermal/omap3-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap3-thermal-data.c new file mode 100644 index 000000000000..3ee34340edab --- /dev/null +++ b/drivers/thermal/ti-soc-thermal/omap3-thermal-data.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * OMAP3 thermal driver. | ||
3 | * | ||
4 | * Copyright (C) 2011-2012 Texas Instruments Inc. | ||
5 | * Copyright (C) 2014 Pavel Machek <pavel@ucw.cz> | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * Note | ||
17 | * http://www.ti.com/lit/er/sprz278f/sprz278f.pdf "Advisory | ||
18 | * 3.1.1.186 MMC OCP Clock Not Gated When Thermal Sensor Is Used" | ||
19 | * | ||
20 | * Also TI says: | ||
21 | * Just be careful when you try to make thermal policy like decisions | ||
22 | * based on this sensor. Placement of the sensor w.r.t the actual logic | ||
23 | * generating heat has to be a factor as well. If you are just looking | ||
24 | * for an approximation temperature (thermometerish kind), you might be | ||
25 | * ok with this. I am not sure we'd find any TI data around this.. just a | ||
26 | * heads up. | ||
27 | */ | ||
28 | |||
29 | #include "ti-thermal.h" | ||
30 | #include "ti-bandgap.h" | ||
31 | |||
32 | /* | ||
33 | * OMAP34XX has one instance of thermal sensor for MPU | ||
34 | * need to describe the individual bit fields | ||
35 | */ | ||
36 | static struct temp_sensor_registers | ||
37 | omap34xx_mpu_temp_sensor_registers = { | ||
38 | .temp_sensor_ctrl = 0, | ||
39 | .bgap_soc_mask = BIT(8), | ||
40 | .bgap_eocz_mask = BIT(7), | ||
41 | .bgap_dtemp_mask = 0x7f, | ||
42 | |||
43 | .bgap_mode_ctrl = 0, | ||
44 | .mode_ctrl_mask = BIT(9), | ||
45 | }; | ||
46 | |||
47 | /* Thresholds and limits for OMAP34XX MPU temperature sensor */ | ||
48 | static struct temp_sensor_data omap34xx_mpu_temp_sensor_data = { | ||
49 | .min_freq = 32768, | ||
50 | .max_freq = 32768, | ||
51 | .max_temp = 125000, | ||
52 | .min_temp = -40000, | ||
53 | .hyst_val = 5000, | ||
54 | }; | ||
55 | |||
56 | /* | ||
57 | * Temperature values in milli degree celsius | ||
58 | */ | ||
59 | static const int | ||
60 | omap34xx_adc_to_temp[128] = { | ||
61 | -40000, -40000, -40000, -40000, -40000, -39000, -38000, -36000, | ||
62 | -34000, -32000, -31000, -29000, -28000, -26000, -25000, -24000, | ||
63 | -22000, -21000, -19000, -18000, -17000, -15000, -14000, -12000, | ||
64 | -11000, -9000, -8000, -7000, -5000, -4000, -2000, -1000, 0000, | ||
65 | 1000, 3000, 4000, 5000, 7000, 8000, 10000, 11000, 13000, 14000, | ||
66 | 15000, 17000, 18000, 20000, 21000, 22000, 24000, 25000, 27000, | ||
67 | 28000, 30000, 31000, 32000, 34000, 35000, 37000, 38000, 39000, | ||
68 | 41000, 42000, 44000, 45000, 47000, 48000, 49000, 51000, 52000, | ||
69 | 53000, 55000, 56000, 58000, 59000, 60000, 62000, 63000, 65000, | ||
70 | 66000, 67000, 69000, 70000, 72000, 73000, 74000, 76000, 77000, | ||
71 | 79000, 80000, 81000, 83000, 84000, 85000, 87000, 88000, 89000, | ||
72 | 91000, 92000, 94000, 95000, 96000, 98000, 99000, 100000, | ||
73 | 102000, 103000, 105000, 106000, 107000, 109000, 110000, 111000, | ||
74 | 113000, 114000, 116000, 117000, 118000, 120000, 121000, 122000, | ||
75 | 124000, 124000, 125000, 125000, 125000, 125000, 125000 | ||
76 | }; | ||
77 | |||
78 | /* OMAP34XX data */ | ||
79 | const struct ti_bandgap_data omap34xx_data = { | ||
80 | .features = TI_BANDGAP_FEATURE_CLK_CTRL | TI_BANDGAP_FEATURE_UNRELIABLE, | ||
81 | .fclock_name = "ts_fck", | ||
82 | .div_ck_name = "ts_fck", | ||
83 | .conv_table = omap34xx_adc_to_temp, | ||
84 | .adc_start_val = 0, | ||
85 | .adc_end_val = 127, | ||
86 | .expose_sensor = ti_thermal_expose_sensor, | ||
87 | .remove_sensor = ti_thermal_remove_sensor, | ||
88 | |||
89 | .sensors = { | ||
90 | { | ||
91 | .registers = &omap34xx_mpu_temp_sensor_registers, | ||
92 | .ts_data = &omap34xx_mpu_temp_sensor_data, | ||
93 | .domain = "cpu", | ||
94 | .slope = 0, | ||
95 | .constant = 20000, | ||
96 | .slope_pcb = 0, | ||
97 | .constant_pcb = 20000, | ||
98 | .register_cooling = NULL, | ||
99 | .unregister_cooling = NULL, | ||
100 | }, | ||
101 | }, | ||
102 | .sensor_count = 1, | ||
103 | }; | ||
104 | |||
105 | /* | ||
106 | * OMAP36XX has one instance of thermal sensor for MPU | ||
107 | * need to describe the individual bit fields | ||
108 | */ | ||
109 | static struct temp_sensor_registers | ||
110 | omap36xx_mpu_temp_sensor_registers = { | ||
111 | .temp_sensor_ctrl = 0, | ||
112 | .bgap_soc_mask = BIT(9), | ||
113 | .bgap_eocz_mask = BIT(8), | ||
114 | .bgap_dtemp_mask = 0xFF, | ||
115 | |||
116 | .bgap_mode_ctrl = 0, | ||
117 | .mode_ctrl_mask = BIT(10), | ||
118 | }; | ||
119 | |||
120 | /* Thresholds and limits for OMAP36XX MPU temperature sensor */ | ||
121 | static struct temp_sensor_data omap36xx_mpu_temp_sensor_data = { | ||
122 | .min_freq = 32768, | ||
123 | .max_freq = 32768, | ||
124 | .max_temp = 125000, | ||
125 | .min_temp = -40000, | ||
126 | .hyst_val = 5000, | ||
127 | }; | ||
128 | |||
129 | /* | ||
130 | * Temperature values in milli degree celsius | ||
131 | */ | ||
132 | static const int | ||
133 | omap36xx_adc_to_temp[128] = { | ||
134 | -40000, -40000, -40000, -40000, -40000, -40000, -40000, -40000, | ||
135 | -40000, -40000, -40000, -40000, -40000, -38000, -35000, -34000, | ||
136 | -32000, -30000, -28000, -26000, -24000, -22000, -20000, -18500, | ||
137 | -17000, -15000, -13500, -12000, -10000, -8000, -6500, -5000, -3500, | ||
138 | -1500, 0, 2000, 3500, 5000, 6500, 8500, 10000, 12000, 13500, | ||
139 | 15000, 17000, 19000, 21000, 23000, 25000, 27000, 28500, 30000, | ||
140 | 32000, 33500, 35000, 37000, 38500, 40000, 42000, 43500, 45000, | ||
141 | 47000, 48500, 50000, 52000, 53500, 55000, 57000, 58500, 60000, | ||
142 | 62000, 64000, 66000, 68000, 70000, 71500, 73500, 75000, 77000, | ||
143 | 78500, 80000, 82000, 83500, 85000, 87000, 88500, 90000, 92000, | ||
144 | 93500, 95000, 97000, 98500, 100000, 102000, 103500, 105000, 107000, | ||
145 | 109000, 111000, 113000, 115000, 117000, 118500, 120000, 122000, | ||
146 | 123500, 125000, 125000, 125000, 125000, 125000, 125000, 125000, | ||
147 | 125000, 125000, 125000, 125000, 125000, 125000, 125000, 125000, | ||
148 | 125000, 125000, 125000, 125000, 125000, 125000, 125000 | ||
149 | }; | ||
150 | |||
151 | /* OMAP36XX data */ | ||
152 | const struct ti_bandgap_data omap36xx_data = { | ||
153 | .features = TI_BANDGAP_FEATURE_CLK_CTRL | TI_BANDGAP_FEATURE_UNRELIABLE, | ||
154 | .fclock_name = "ts_fck", | ||
155 | .div_ck_name = "ts_fck", | ||
156 | .conv_table = omap36xx_adc_to_temp, | ||
157 | .adc_start_val = 0, | ||
158 | .adc_end_val = 127, | ||
159 | .expose_sensor = ti_thermal_expose_sensor, | ||
160 | .remove_sensor = ti_thermal_remove_sensor, | ||
161 | |||
162 | .sensors = { | ||
163 | { | ||
164 | .registers = &omap36xx_mpu_temp_sensor_registers, | ||
165 | .ts_data = &omap36xx_mpu_temp_sensor_data, | ||
166 | .domain = "cpu", | ||
167 | .slope = 0, | ||
168 | .constant = 20000, | ||
169 | .slope_pcb = 0, | ||
170 | .constant_pcb = 20000, | ||
171 | .register_cooling = NULL, | ||
172 | .unregister_cooling = NULL, | ||
173 | }, | ||
174 | }, | ||
175 | .sensor_count = 1, | ||
176 | }; | ||
diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.c b/drivers/thermal/ti-soc-thermal/ti-bandgap.c index 10c47c048f7a..1e34a1efc554 100644 --- a/drivers/thermal/ti-soc-thermal/ti-bandgap.c +++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.c | |||
@@ -1274,6 +1274,10 @@ int ti_bandgap_probe(struct platform_device *pdev) | |||
1274 | } | 1274 | } |
1275 | bgp->dev = &pdev->dev; | 1275 | bgp->dev = &pdev->dev; |
1276 | 1276 | ||
1277 | if (TI_BANDGAP_HAS(bgp, UNRELIABLE)) | ||
1278 | dev_warn(&pdev->dev, | ||
1279 | "This OMAP thermal sensor is unreliable. You've been warned\n"); | ||
1280 | |||
1277 | if (TI_BANDGAP_HAS(bgp, TSHUT)) { | 1281 | if (TI_BANDGAP_HAS(bgp, TSHUT)) { |
1278 | ret = ti_bandgap_tshut_init(bgp, pdev); | 1282 | ret = ti_bandgap_tshut_init(bgp, pdev); |
1279 | if (ret) { | 1283 | if (ret) { |
@@ -1579,6 +1583,16 @@ static SIMPLE_DEV_PM_OPS(ti_bandgap_dev_pm_ops, ti_bandgap_suspend, | |||
1579 | #endif | 1583 | #endif |
1580 | 1584 | ||
1581 | static const struct of_device_id of_ti_bandgap_match[] = { | 1585 | static const struct of_device_id of_ti_bandgap_match[] = { |
1586 | #ifdef CONFIG_OMAP3_THERMAL | ||
1587 | { | ||
1588 | .compatible = "ti,omap34xx-bandgap", | ||
1589 | .data = (void *)&omap34xx_data, | ||
1590 | }, | ||
1591 | { | ||
1592 | .compatible = "ti,omap36xx-bandgap", | ||
1593 | .data = (void *)&omap36xx_data, | ||
1594 | }, | ||
1595 | #endif | ||
1582 | #ifdef CONFIG_OMAP4_THERMAL | 1596 | #ifdef CONFIG_OMAP4_THERMAL |
1583 | { | 1597 | { |
1584 | .compatible = "ti,omap4430-bandgap", | 1598 | .compatible = "ti,omap4430-bandgap", |
diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.h b/drivers/thermal/ti-soc-thermal/ti-bandgap.h index 0c52f7afba00..fe0adb898764 100644 --- a/drivers/thermal/ti-soc-thermal/ti-bandgap.h +++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.h | |||
@@ -322,6 +322,8 @@ struct ti_temp_sensor { | |||
322 | * has Errata 814 | 322 | * has Errata 814 |
323 | * TI_BANDGAP_FEATURE_ERRATA_813 - used to workaorund when the bandgap device | 323 | * TI_BANDGAP_FEATURE_ERRATA_813 - used to workaorund when the bandgap device |
324 | * has Errata 813 | 324 | * has Errata 813 |
325 | * TI_BANDGAP_FEATURE_UNRELIABLE - used when the sensor readings are too | ||
326 | * inaccurate. | ||
325 | * TI_BANDGAP_HAS(b, f) - macro to check if a bandgap device is capable of a | 327 | * TI_BANDGAP_HAS(b, f) - macro to check if a bandgap device is capable of a |
326 | * specific feature (above) or not. Return non-zero, if yes. | 328 | * specific feature (above) or not. Return non-zero, if yes. |
327 | */ | 329 | */ |
@@ -337,6 +339,7 @@ struct ti_temp_sensor { | |||
337 | #define TI_BANDGAP_FEATURE_HISTORY_BUFFER BIT(9) | 339 | #define TI_BANDGAP_FEATURE_HISTORY_BUFFER BIT(9) |
338 | #define TI_BANDGAP_FEATURE_ERRATA_814 BIT(10) | 340 | #define TI_BANDGAP_FEATURE_ERRATA_814 BIT(10) |
339 | #define TI_BANDGAP_FEATURE_ERRATA_813 BIT(11) | 341 | #define TI_BANDGAP_FEATURE_ERRATA_813 BIT(11) |
342 | #define TI_BANDGAP_FEATURE_UNRELIABLE BIT(12) | ||
340 | #define TI_BANDGAP_HAS(b, f) \ | 343 | #define TI_BANDGAP_HAS(b, f) \ |
341 | ((b)->conf->features & TI_BANDGAP_FEATURE_ ## f) | 344 | ((b)->conf->features & TI_BANDGAP_FEATURE_ ## f) |
342 | 345 | ||
@@ -390,6 +393,14 @@ int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data); | |||
390 | void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id); | 393 | void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id); |
391 | int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend); | 394 | int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend); |
392 | 395 | ||
396 | #ifdef CONFIG_OMAP3_THERMAL | ||
397 | extern const struct ti_bandgap_data omap34xx_data; | ||
398 | extern const struct ti_bandgap_data omap36xx_data; | ||
399 | #else | ||
400 | #define omap34xx_data NULL | ||
401 | #define omap36xx_data NULL | ||
402 | #endif | ||
403 | |||
393 | #ifdef CONFIG_OMAP4_THERMAL | 404 | #ifdef CONFIG_OMAP4_THERMAL |
394 | extern const struct ti_bandgap_data omap4430_data; | 405 | extern const struct ti_bandgap_data omap4430_data; |
395 | extern const struct ti_bandgap_data omap4460_data; | 406 | extern const struct ti_bandgap_data omap4460_data; |
diff --git a/include/linux/devfreq_cooling.h b/include/linux/devfreq_cooling.h new file mode 100644 index 000000000000..7adf6cc4b305 --- /dev/null +++ b/include/linux/devfreq_cooling.h | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * devfreq_cooling: Thermal cooling device implementation for devices using | ||
3 | * devfreq | ||
4 | * | ||
5 | * Copyright (C) 2014-2015 ARM Limited | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
12 | * kind, whether express or implied; without even the implied warranty | ||
13 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef __DEVFREQ_COOLING_H__ | ||
18 | #define __DEVFREQ_COOLING_H__ | ||
19 | |||
20 | #include <linux/devfreq.h> | ||
21 | #include <linux/thermal.h> | ||
22 | |||
23 | #ifdef CONFIG_DEVFREQ_THERMAL | ||
24 | |||
25 | /** | ||
26 | * struct devfreq_cooling_power - Devfreq cooling power ops | ||
27 | * @get_static_power: Take voltage, in mV, and return the static power | ||
28 | * in mW. If NULL, the static power is assumed | ||
29 | * to be 0. | ||
30 | * @get_dynamic_power: Take voltage, in mV, and frequency, in HZ, and | ||
31 | * return the dynamic power draw in mW. If NULL, | ||
32 | * a simple power model is used. | ||
33 | * @dyn_power_coeff: Coefficient for the simple dynamic power model in | ||
34 | * mW/(MHz mV mV). | ||
35 | * If get_dynamic_power() is NULL, then the | ||
36 | * dynamic power is calculated as | ||
37 | * @dyn_power_coeff * frequency * voltage^2 | ||
38 | */ | ||
39 | struct devfreq_cooling_power { | ||
40 | unsigned long (*get_static_power)(unsigned long voltage); | ||
41 | unsigned long (*get_dynamic_power)(unsigned long freq, | ||
42 | unsigned long voltage); | ||
43 | unsigned long dyn_power_coeff; | ||
44 | }; | ||
45 | |||
46 | struct thermal_cooling_device * | ||
47 | of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df, | ||
48 | struct devfreq_cooling_power *dfc_power); | ||
49 | struct thermal_cooling_device * | ||
50 | of_devfreq_cooling_register(struct device_node *np, struct devfreq *df); | ||
51 | struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df); | ||
52 | void devfreq_cooling_unregister(struct thermal_cooling_device *dfc); | ||
53 | |||
54 | #else /* !CONFIG_DEVFREQ_THERMAL */ | ||
55 | |||
56 | struct thermal_cooling_device * | ||
57 | of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df, | ||
58 | struct devfreq_cooling_power *dfc_power) | ||
59 | { | ||
60 | return ERR_PTR(-EINVAL); | ||
61 | } | ||
62 | |||
63 | static inline struct thermal_cooling_device * | ||
64 | of_devfreq_cooling_register(struct device_node *np, struct devfreq *df) | ||
65 | { | ||
66 | return ERR_PTR(-EINVAL); | ||
67 | } | ||
68 | |||
69 | static inline struct thermal_cooling_device * | ||
70 | devfreq_cooling_register(struct devfreq *df) | ||
71 | { | ||
72 | return ERR_PTR(-EINVAL); | ||
73 | } | ||
74 | |||
75 | static inline void | ||
76 | devfreq_cooling_unregister(struct thermal_cooling_device *dfc) | ||
77 | { | ||
78 | } | ||
79 | |||
80 | #endif /* CONFIG_DEVFREQ_THERMAL */ | ||
81 | #endif /* __DEVFREQ_COOLING_H__ */ | ||
diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 157d366e761b..4014a59828fc 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h | |||
@@ -44,9 +44,11 @@ | |||
44 | #define THERMAL_WEIGHT_DEFAULT 0 | 44 | #define THERMAL_WEIGHT_DEFAULT 0 |
45 | 45 | ||
46 | /* Unit conversion macros */ | 46 | /* Unit conversion macros */ |
47 | #define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \ | 47 | #define DECI_KELVIN_TO_CELSIUS(t) ({ \ |
48 | ((long)t-2732+5)/10 : ((long)t-2732-5)/10) | 48 | long _t = (t); \ |
49 | #define CELSIUS_TO_KELVIN(t) ((t)*10+2732) | 49 | ((_t-2732 >= 0) ? (_t-2732+5)/10 : (_t-2732-5)/10); \ |
50 | }) | ||
51 | #define CELSIUS_TO_DECI_KELVIN(t) ((t)*10+2732) | ||
50 | #define DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, off) (((t) - (off)) * 100) | 52 | #define DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, off) (((t) - (off)) * 100) |
51 | #define DECI_KELVIN_TO_MILLICELSIUS(t) DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, 2732) | 53 | #define DECI_KELVIN_TO_MILLICELSIUS(t) DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, 2732) |
52 | #define MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, off) (((t) / 100) + (off)) | 54 | #define MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, off) (((t) / 100) + (off)) |
diff --git a/include/trace/events/thermal.h b/include/trace/events/thermal.h index 8b1f80682b80..5738bb3e2343 100644 --- a/include/trace/events/thermal.h +++ b/include/trace/events/thermal.h | |||
@@ -4,6 +4,7 @@ | |||
4 | #if !defined(_TRACE_THERMAL_H) || defined(TRACE_HEADER_MULTI_READ) | 4 | #if !defined(_TRACE_THERMAL_H) || defined(TRACE_HEADER_MULTI_READ) |
5 | #define _TRACE_THERMAL_H | 5 | #define _TRACE_THERMAL_H |
6 | 6 | ||
7 | #include <linux/devfreq.h> | ||
7 | #include <linux/thermal.h> | 8 | #include <linux/thermal.h> |
8 | #include <linux/tracepoint.h> | 9 | #include <linux/tracepoint.h> |
9 | 10 | ||
@@ -135,6 +136,58 @@ TRACE_EVENT(thermal_power_cpu_limit, | |||
135 | __entry->power) | 136 | __entry->power) |
136 | ); | 137 | ); |
137 | 138 | ||
139 | TRACE_EVENT(thermal_power_devfreq_get_power, | ||
140 | TP_PROTO(struct thermal_cooling_device *cdev, | ||
141 | struct devfreq_dev_status *status, unsigned long freq, | ||
142 | u32 dynamic_power, u32 static_power), | ||
143 | |||
144 | TP_ARGS(cdev, status, freq, dynamic_power, static_power), | ||
145 | |||
146 | TP_STRUCT__entry( | ||
147 | __string(type, cdev->type ) | ||
148 | __field(unsigned long, freq ) | ||
149 | __field(u32, load ) | ||
150 | __field(u32, dynamic_power ) | ||
151 | __field(u32, static_power ) | ||
152 | ), | ||
153 | |||
154 | TP_fast_assign( | ||
155 | __assign_str(type, cdev->type); | ||
156 | __entry->freq = freq; | ||
157 | __entry->load = (100 * status->busy_time) / status->total_time; | ||
158 | __entry->dynamic_power = dynamic_power; | ||
159 | __entry->static_power = static_power; | ||
160 | ), | ||
161 | |||
162 | TP_printk("type=%s freq=%lu load=%u dynamic_power=%u static_power=%u", | ||
163 | __get_str(type), __entry->freq, | ||
164 | __entry->load, __entry->dynamic_power, __entry->static_power) | ||
165 | ); | ||
166 | |||
167 | TRACE_EVENT(thermal_power_devfreq_limit, | ||
168 | TP_PROTO(struct thermal_cooling_device *cdev, unsigned long freq, | ||
169 | unsigned long cdev_state, u32 power), | ||
170 | |||
171 | TP_ARGS(cdev, freq, cdev_state, power), | ||
172 | |||
173 | TP_STRUCT__entry( | ||
174 | __string(type, cdev->type) | ||
175 | __field(unsigned int, freq ) | ||
176 | __field(unsigned long, cdev_state) | ||
177 | __field(u32, power ) | ||
178 | ), | ||
179 | |||
180 | TP_fast_assign( | ||
181 | __assign_str(type, cdev->type); | ||
182 | __entry->freq = freq; | ||
183 | __entry->cdev_state = cdev_state; | ||
184 | __entry->power = power; | ||
185 | ), | ||
186 | |||
187 | TP_printk("type=%s freq=%u cdev_state=%lu power=%u", | ||
188 | __get_str(type), __entry->freq, __entry->cdev_state, | ||
189 | __entry->power) | ||
190 | ); | ||
138 | #endif /* _TRACE_THERMAL_H */ | 191 | #endif /* _TRACE_THERMAL_H */ |
139 | 192 | ||
140 | /* This part must be outside protection */ | 193 | /* This part must be outside protection */ |
diff --git a/tools/thermal/tmon/Makefile b/tools/thermal/tmon/Makefile index 2e83dd3655a2..3a961e998281 100644 --- a/tools/thermal/tmon/Makefile +++ b/tools/thermal/tmon/Makefile | |||
@@ -22,6 +22,9 @@ TMON_LIBS += $(shell pkg-config --libs $(STATIC) panelw ncursesw 2> /dev/null || | |||
22 | pkg-config --libs $(STATIC) panel ncurses 2> /dev/null || \ | 22 | pkg-config --libs $(STATIC) panel ncurses 2> /dev/null || \ |
23 | echo -lpanel -lncurses) | 23 | echo -lpanel -lncurses) |
24 | 24 | ||
25 | CFLAGS += $(shell pkg-config --cflags $(STATIC) panelw ncursesw 2> /dev/null || \ | ||
26 | pkg-config --cflags $(STATIC) panel ncurses 2> /dev/null) | ||
27 | |||
25 | OBJS = tmon.o tui.o sysfs.o pid.o | 28 | OBJS = tmon.o tui.o sysfs.o pid.o |
26 | OBJS += | 29 | OBJS += |
27 | 30 | ||