diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-26 12:23:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-26 12:23:43 -0400 |
commit | bfb764440d5bee109003295473a0b387bc799222 (patch) | |
tree | 23f4683f6aca3b75d81e009f1c8f9b201a6422c1 | |
parent | 159d08f4b85ce454cd05fb9e2c539276e148d366 (diff) | |
parent | 88ac99063e6e38bf9577e75f0d65dd02e2326d58 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
Pull thermal management updates from Zhang Rui:
- Introduce generic ADC thermal driver, based on OF thermal (Laxman
Dewangan)
- Introduce new thermal driver for Tango chips (Marc Gonzalez)
- Rockchip driver support for RK3399, RK3366, and some fixes (Caesar
Wang, Elaine Zhang and Shawn Lin)
- Add CPU power cooling model to Mediatek thermal driver (Dawei Chien)
- Wider usage of dev_thermal_zone_of_sensor_register (Eduardo Valentin)
- TI thermal driver gained a new maintainer (Keerthy).
- Enabled powerclamp driver by checking CPU feature and package cstate
counter instead of CPU whitelist (Jacob Pan)
- Various fixes on thermal governor, OF thermal, Tegra, and RCAR
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: (50 commits)
thermal: tango: initialize TEMPSI_CFG
thermal: rockchip: use the usleep_range instead of udelay
thermal: rockchip: add the notes for better reading
thermal: rockchip: Support RK3366 SoCs in the thermal driver
thermal: rockchip: handle the power sequence for tsadc controller
thermal: rockchip: update the tsadc table for rk3399
thermal: rockchip: fixes the code_to_temp for tsadc driver
thermal: rockchip: disable thermal->clk in err case
thermal: tegra: add Tegra132 specific SOC_THERM driver
thermal: fix ptr_ret.cocci warnings
thermal: mediatek: Add cpu dynamic power cooling model.
thermal: generic-adc: Add ADC based thermal sensor driver
thermal: generic-adc: Add DT binding for ADC based thermal sensor
thermal: tegra: fix static checker warning
thermal: tegra: mark PM functions __maybe_unused
thermal: add temperature sensor support for tango SoC
thermal: hisilicon: fix IRQ imbalance enabling
thermal: hisilicon: support to use any sensor
thermal: rcar: Remove binding docs for r8a7794
thermal: tegra: add PM support
...
38 files changed, 2414 insertions, 763 deletions
diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt index 6908d3aca598..edebfa0a985e 100644 --- a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt +++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt | |||
@@ -26,6 +26,10 @@ Required properties : | |||
26 | of this property. See <dt-bindings/thermal/tegra124-soctherm.h> for a | 26 | of this property. See <dt-bindings/thermal/tegra124-soctherm.h> for a |
27 | list of valid values when referring to thermal sensors. | 27 | list of valid values when referring to thermal sensors. |
28 | 28 | ||
29 | Note: | ||
30 | - the "critical" type trip points will be set to SOC_THERM hardware as the | ||
31 | shut down temperature. Once the temperature of this thermal zone is higher | ||
32 | than it, the system will be shutdown or reset by hardware. | ||
29 | 33 | ||
30 | Example : | 34 | Example : |
31 | 35 | ||
@@ -51,5 +55,13 @@ Example: referring to thermal sensors : | |||
51 | 55 | ||
52 | thermal-sensors = | 56 | thermal-sensors = |
53 | <&soctherm TEGRA124_SOCTHERM_SENSOR_CPU>; | 57 | <&soctherm TEGRA124_SOCTHERM_SENSOR_CPU>; |
58 | |||
59 | trips { | ||
60 | cpu_shutdown_trip: shutdown-trip { | ||
61 | temperature = <102500>; | ||
62 | hysteresis = <1000>; | ||
63 | type = "critical"; | ||
64 | }; | ||
65 | }; | ||
54 | }; | 66 | }; |
55 | }; | 67 | }; |
diff --git a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt index e5ee3f159893..a8e52c8ccfcc 100644 --- a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt | |||
@@ -11,7 +11,6 @@ Required properties: | |||
11 | - "renesas,thermal-r8a7791" (R-Car M2-W) | 11 | - "renesas,thermal-r8a7791" (R-Car M2-W) |
12 | - "renesas,thermal-r8a7792" (R-Car V2H) | 12 | - "renesas,thermal-r8a7792" (R-Car V2H) |
13 | - "renesas,thermal-r8a7793" (R-Car M2-N) | 13 | - "renesas,thermal-r8a7793" (R-Car M2-N) |
14 | - "renesas,thermal-r8a7794" (R-Car E2) | ||
15 | - reg : Address range of the thermal registers. | 14 | - reg : Address range of the thermal registers. |
16 | The 1st reg will be recognized as common register | 15 | The 1st reg will be recognized as common register |
17 | if it has "interrupts". | 16 | if it has "interrupts". |
diff --git a/Documentation/devicetree/bindings/thermal/tango-thermal.txt b/Documentation/devicetree/bindings/thermal/tango-thermal.txt new file mode 100644 index 000000000000..212198d4b937 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/tango-thermal.txt | |||
@@ -0,0 +1,17 @@ | |||
1 | * Tango Thermal | ||
2 | |||
3 | The SMP8758 SoC includes 3 instances of this temperature sensor | ||
4 | (in the CPU, video decoder, and PCIe controller). | ||
5 | |||
6 | Required properties: | ||
7 | - #thermal-sensor-cells: Should be 0 (see thermal.txt) | ||
8 | - compatible: "sigma,smp8758-thermal" | ||
9 | - reg: Address range of the thermal registers | ||
10 | |||
11 | Example: | ||
12 | |||
13 | cpu_temp: thermal@920100 { | ||
14 | #thermal-sensor-cells = <0>; | ||
15 | compatible = "sigma,smp8758-thermal"; | ||
16 | reg = <0x920100 12>; | ||
17 | }; | ||
diff --git a/Documentation/devicetree/bindings/thermal/thermal-generic-adc.txt b/Documentation/devicetree/bindings/thermal/thermal-generic-adc.txt new file mode 100644 index 000000000000..d72355502b78 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/thermal-generic-adc.txt | |||
@@ -0,0 +1,89 @@ | |||
1 | General Purpose Analog To Digital Converter (ADC) based thermal sensor. | ||
2 | |||
3 | On some of platforms, thermal sensor like thermistors are connected to | ||
4 | one of ADC channel and sensor resistance is read via voltage across the | ||
5 | sensor resistor. The voltage read across the sensor is mapped to | ||
6 | temperature using voltage-temperature lookup table. | ||
7 | |||
8 | Required properties: | ||
9 | =================== | ||
10 | - compatible: Must be "generic-adc-thermal". | ||
11 | - temperature-lookup-table: Two dimensional array of Integer; lookup table | ||
12 | to map the relation between ADC value and | ||
13 | temperature. When ADC is read, the value is | ||
14 | looked up on the table to get the equivalent | ||
15 | temperature. | ||
16 | The first value of the each row of array is the | ||
17 | temperature in milliCelsius and second value of | ||
18 | the each row of array is the ADC read value. | ||
19 | - #thermal-sensor-cells: Should be 1. See ./thermal.txt for a description | ||
20 | of this property. | ||
21 | |||
22 | Example : | ||
23 | #include <dt-bindings/thermal/thermal.h> | ||
24 | |||
25 | i2c@7000c400 { | ||
26 | ads1015: ads1015@4a { | ||
27 | reg = <0x4a>; | ||
28 | compatible = "ads1015"; | ||
29 | sampling-frequency = <3300>; | ||
30 | #io-channel-cells = <1>; | ||
31 | }; | ||
32 | }; | ||
33 | |||
34 | tboard_thermistor: thermal-sensor { | ||
35 | compatible = "generic-adc-thermal"; | ||
36 | #thermal-sensor-cells = <0>; | ||
37 | io-channels = <&ads1015 1>; | ||
38 | io-channel-names = "sensor-channel"; | ||
39 | temperature-lookup-table = < (-40000) 2578 | ||
40 | (-39000) 2577 | ||
41 | (-38000) 2576 | ||
42 | (-37000) 2575 | ||
43 | (-36000) 2574 | ||
44 | (-35000) 2573 | ||
45 | (-34000) 2572 | ||
46 | (-33000) 2571 | ||
47 | (-32000) 2569 | ||
48 | (-31000) 2568 | ||
49 | (-30000) 2567 | ||
50 | :::::::::: | ||
51 | 118000 254 | ||
52 | 119000 247 | ||
53 | 120000 240 | ||
54 | 121000 233 | ||
55 | 122000 226 | ||
56 | 123000 220 | ||
57 | 124000 214 | ||
58 | 125000 208>; | ||
59 | }; | ||
60 | |||
61 | dummy_cool_dev: dummy-cool-dev { | ||
62 | compatible = "dummy-cooling-dev"; | ||
63 | #cooling-cells = <2>; /* min followed by max */ | ||
64 | }; | ||
65 | |||
66 | thermal-zones { | ||
67 | Tboard { | ||
68 | polling-delay = <15000>; /* milliseconds */ | ||
69 | polling-delay-passive = <0>; /* milliseconds */ | ||
70 | thermal-sensors = <&tboard_thermistor>; | ||
71 | |||
72 | trips { | ||
73 | therm_est_trip: therm_est_trip { | ||
74 | temperature = <40000>; | ||
75 | type = "active"; | ||
76 | hysteresis = <1000>; | ||
77 | }; | ||
78 | }; | ||
79 | |||
80 | cooling-maps { | ||
81 | map0 { | ||
82 | trip = <&therm_est_trip>; | ||
83 | cooling-device = <&dummy_cool_dev THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; | ||
84 | contribution = <100>; | ||
85 | }; | ||
86 | |||
87 | }; | ||
88 | }; | ||
89 | }; | ||
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt index ed419d6c8dec..efc3f3d293c4 100644 --- a/Documentation/thermal/sysfs-api.txt +++ b/Documentation/thermal/sysfs-api.txt | |||
@@ -69,8 +69,8 @@ temperature) and throttle appropriate devices. | |||
69 | 1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device *tz) | 69 | 1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device *tz) |
70 | 70 | ||
71 | This interface function removes the thermal zone device. | 71 | This interface function removes the thermal zone device. |
72 | It deletes the corresponding entry form /sys/class/thermal folder and | 72 | It deletes the corresponding entry from /sys/class/thermal folder and |
73 | unbind all the thermal cooling devices it uses. | 73 | unbinds all the thermal cooling devices it uses. |
74 | 74 | ||
75 | 1.1.3 struct thermal_zone_device *thermal_zone_of_sensor_register( | 75 | 1.1.3 struct thermal_zone_device *thermal_zone_of_sensor_register( |
76 | struct device *dev, int sensor_id, void *data, | 76 | struct device *dev, int sensor_id, void *data, |
@@ -146,32 +146,32 @@ temperature) and throttle appropriate devices. | |||
146 | 146 | ||
147 | This interface function adds a new thermal cooling device (fan/processor/...) | 147 | This interface function adds a new thermal cooling device (fan/processor/...) |
148 | to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself | 148 | to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself |
149 | to all the thermal zone devices register at the same time. | 149 | to all the thermal zone devices registered at the same time. |
150 | name: the cooling device name. | 150 | name: the cooling device name. |
151 | devdata: device private data. | 151 | devdata: device private data. |
152 | ops: thermal cooling devices call-backs. | 152 | ops: thermal cooling devices call-backs. |
153 | .get_max_state: get the Maximum throttle state of the cooling device. | 153 | .get_max_state: get the Maximum throttle state of the cooling device. |
154 | .get_cur_state: get the Current throttle state of the cooling device. | 154 | .get_cur_state: get the Currently requested throttle state of the cooling device. |
155 | .set_cur_state: set the Current throttle state of the cooling device. | 155 | .set_cur_state: set the Current throttle state of the cooling device. |
156 | 156 | ||
157 | 1.2.2 void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev) | 157 | 1.2.2 void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev) |
158 | 158 | ||
159 | This interface function remove the thermal cooling device. | 159 | This interface function removes the thermal cooling device. |
160 | It deletes the corresponding entry form /sys/class/thermal folder and | 160 | It deletes the corresponding entry from /sys/class/thermal folder and |
161 | unbind itself from all the thermal zone devices using it. | 161 | unbinds itself from all the thermal zone devices using it. |
162 | 162 | ||
163 | 1.3 interface for binding a thermal zone device with a thermal cooling device | 163 | 1.3 interface for binding a thermal zone device with a thermal cooling device |
164 | 1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, | 164 | 1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, |
165 | int trip, struct thermal_cooling_device *cdev, | 165 | int trip, struct thermal_cooling_device *cdev, |
166 | unsigned long upper, unsigned long lower, unsigned int weight); | 166 | unsigned long upper, unsigned long lower, unsigned int weight); |
167 | 167 | ||
168 | This interface function bind a thermal cooling device to the certain trip | 168 | This interface function binds a thermal cooling device to a particular trip |
169 | point of a thermal zone device. | 169 | point of a thermal zone device. |
170 | This function is usually called in the thermal zone device .bind callback. | 170 | This function is usually called in the thermal zone device .bind callback. |
171 | tz: the thermal zone device | 171 | tz: the thermal zone device |
172 | cdev: thermal cooling device | 172 | cdev: thermal cooling device |
173 | trip: indicates which trip point the cooling devices is associated with | 173 | trip: indicates which trip point in this thermal zone the cooling device |
174 | in this thermal zone. | 174 | is associated with. |
175 | upper:the Maximum cooling state for this trip point. | 175 | upper:the Maximum cooling state for this trip point. |
176 | THERMAL_NO_LIMIT means no upper limit, | 176 | THERMAL_NO_LIMIT means no upper limit, |
177 | and the cooling device can be in max_state. | 177 | and the cooling device can be in max_state. |
@@ -184,13 +184,13 @@ temperature) and throttle appropriate devices. | |||
184 | 1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, | 184 | 1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, |
185 | int trip, struct thermal_cooling_device *cdev); | 185 | int trip, struct thermal_cooling_device *cdev); |
186 | 186 | ||
187 | This interface function unbind a thermal cooling device from the certain | 187 | This interface function unbinds a thermal cooling device from a particular |
188 | trip point of a thermal zone device. This function is usually called in | 188 | trip point of a thermal zone device. This function is usually called in |
189 | the thermal zone device .unbind callback. | 189 | the thermal zone device .unbind callback. |
190 | tz: the thermal zone device | 190 | tz: the thermal zone device |
191 | cdev: thermal cooling device | 191 | cdev: thermal cooling device |
192 | trip: indicates which trip point the cooling devices is associated with | 192 | trip: indicates which trip point in this thermal zone the cooling device |
193 | in this thermal zone. | 193 | is associated with. |
194 | 194 | ||
195 | 1.4 Thermal Zone Parameters | 195 | 1.4 Thermal Zone Parameters |
196 | 1.4.1 struct thermal_bind_params | 196 | 1.4.1 struct thermal_bind_params |
@@ -210,13 +210,13 @@ temperature) and throttle appropriate devices. | |||
210 | this thermal zone and cdev, for a particular trip point. | 210 | this thermal zone and cdev, for a particular trip point. |
211 | If nth bit is set, then the cdev and thermal zone are bound | 211 | If nth bit is set, then the cdev and thermal zone are bound |
212 | for trip point n. | 212 | for trip point n. |
213 | .limits: This is an array of cooling state limits. Must have exactly | 213 | .binding_limits: This is an array of cooling state limits. Must have |
214 | 2 * thermal_zone.number_of_trip_points. It is an array consisting | 214 | exactly 2 * thermal_zone.number_of_trip_points. It is an |
215 | of tuples <lower-state upper-state> of state limits. Each trip | 215 | array consisting of tuples <lower-state upper-state> of |
216 | will be associated with one state limit tuple when binding. | 216 | state limits. Each trip will be associated with one state |
217 | A NULL pointer means <THERMAL_NO_LIMITS THERMAL_NO_LIMITS> | 217 | limit tuple when binding. A NULL pointer means |
218 | on all trips. These limits are used when binding a cdev to a | 218 | <THERMAL_NO_LIMITS THERMAL_NO_LIMITS> on all trips. |
219 | trip point. | 219 | These limits are used when binding a cdev to a trip point. |
220 | .match: This call back returns success(0) if the 'tz and cdev' need to | 220 | .match: This call back returns success(0) if the 'tz and cdev' need to |
221 | be bound, as per platform data. | 221 | be bound, as per platform data. |
222 | 1.4.2 struct thermal_zone_params | 222 | 1.4.2 struct thermal_zone_params |
@@ -351,8 +351,8 @@ cdev[0-*] | |||
351 | RO, Optional | 351 | RO, Optional |
352 | 352 | ||
353 | cdev[0-*]_trip_point | 353 | cdev[0-*]_trip_point |
354 | The trip point with which cdev[0-*] is associated in this thermal | 354 | The trip point in this thermal zone which cdev[0-*] is associated |
355 | zone; -1 means the cooling device is not associated with any trip | 355 | with; -1 means the cooling device is not associated with any trip |
356 | point. | 356 | point. |
357 | RO, Optional | 357 | RO, Optional |
358 | 358 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index ab7e05d328c1..81e9c984d2f3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -11296,6 +11296,7 @@ F: drivers/platform/x86/thinkpad_acpi.c | |||
11296 | 11296 | ||
11297 | TI BANDGAP AND THERMAL DRIVER | 11297 | TI BANDGAP AND THERMAL DRIVER |
11298 | M: Eduardo Valentin <edubezval@gmail.com> | 11298 | M: Eduardo Valentin <edubezval@gmail.com> |
11299 | M: Keerthy <j-keerthy@ti.com> | ||
11299 | L: linux-pm@vger.kernel.org | 11300 | L: linux-pm@vger.kernel.org |
11300 | L: linux-omap@vger.kernel.org | 11301 | L: linux-omap@vger.kernel.org |
11301 | S: Maintained | 11302 | S: Maintained |
diff --git a/drivers/cpufreq/mt8173-cpufreq.c b/drivers/cpufreq/mt8173-cpufreq.c index 6f602c7a71bd..643f43179df1 100644 --- a/drivers/cpufreq/mt8173-cpufreq.c +++ b/drivers/cpufreq/mt8173-cpufreq.c | |||
@@ -307,17 +307,24 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy, | |||
307 | return 0; | 307 | return 0; |
308 | } | 308 | } |
309 | 309 | ||
310 | #define DYNAMIC_POWER "dynamic-power-coefficient" | ||
311 | |||
310 | static void mtk_cpufreq_ready(struct cpufreq_policy *policy) | 312 | static void mtk_cpufreq_ready(struct cpufreq_policy *policy) |
311 | { | 313 | { |
312 | struct mtk_cpu_dvfs_info *info = policy->driver_data; | 314 | struct mtk_cpu_dvfs_info *info = policy->driver_data; |
313 | struct device_node *np = of_node_get(info->cpu_dev->of_node); | 315 | struct device_node *np = of_node_get(info->cpu_dev->of_node); |
316 | u32 capacitance = 0; | ||
314 | 317 | ||
315 | if (WARN_ON(!np)) | 318 | if (WARN_ON(!np)) |
316 | return; | 319 | return; |
317 | 320 | ||
318 | if (of_find_property(np, "#cooling-cells", NULL)) { | 321 | if (of_find_property(np, "#cooling-cells", NULL)) { |
319 | info->cdev = of_cpufreq_cooling_register(np, | 322 | of_property_read_u32(np, DYNAMIC_POWER, &capacitance); |
320 | policy->related_cpus); | 323 | |
324 | info->cdev = of_cpufreq_power_cooling_register(np, | ||
325 | policy->related_cpus, | ||
326 | capacitance, | ||
327 | NULL); | ||
321 | 328 | ||
322 | if (IS_ERR(info->cdev)) { | 329 | if (IS_ERR(info->cdev)) { |
323 | dev_err(info->cpu_dev, | 330 | dev_err(info->cpu_dev, |
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 0addc84ba948..69166ab3151d 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c | |||
@@ -77,7 +77,6 @@ static const u8 LM75_REG_TEMP[3] = { | |||
77 | struct lm75_data { | 77 | struct lm75_data { |
78 | struct i2c_client *client; | 78 | struct i2c_client *client; |
79 | struct device *hwmon_dev; | 79 | struct device *hwmon_dev; |
80 | struct thermal_zone_device *tz; | ||
81 | struct mutex update_lock; | 80 | struct mutex update_lock; |
82 | u8 orig_conf; | 81 | u8 orig_conf; |
83 | u8 resolution; /* In bits, between 9 and 12 */ | 82 | u8 resolution; /* In bits, between 9 and 12 */ |
@@ -306,11 +305,9 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
306 | if (IS_ERR(data->hwmon_dev)) | 305 | if (IS_ERR(data->hwmon_dev)) |
307 | return PTR_ERR(data->hwmon_dev); | 306 | return PTR_ERR(data->hwmon_dev); |
308 | 307 | ||
309 | data->tz = thermal_zone_of_sensor_register(data->hwmon_dev, 0, | 308 | devm_thermal_zone_of_sensor_register(data->hwmon_dev, 0, |
310 | data->hwmon_dev, | 309 | data->hwmon_dev, |
311 | &lm75_of_thermal_ops); | 310 | &lm75_of_thermal_ops); |
312 | if (IS_ERR(data->tz)) | ||
313 | data->tz = NULL; | ||
314 | 311 | ||
315 | dev_info(dev, "%s: sensor '%s'\n", | 312 | dev_info(dev, "%s: sensor '%s'\n", |
316 | dev_name(data->hwmon_dev), client->name); | 313 | dev_name(data->hwmon_dev), client->name); |
@@ -322,7 +319,6 @@ static int lm75_remove(struct i2c_client *client) | |||
322 | { | 319 | { |
323 | struct lm75_data *data = i2c_get_clientdata(client); | 320 | struct lm75_data *data = i2c_get_clientdata(client); |
324 | 321 | ||
325 | thermal_zone_of_sensor_unregister(data->hwmon_dev, data->tz); | ||
326 | hwmon_device_unregister(data->hwmon_dev); | 322 | hwmon_device_unregister(data->hwmon_dev); |
327 | lm75_write_value(client, LM75_REG_CONF, data->orig_conf); | 323 | lm75_write_value(client, LM75_REG_CONF, data->orig_conf); |
328 | return 0; | 324 | return 0; |
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index faa6e8dfbaaf..8ef7b713cb1a 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c | |||
@@ -259,7 +259,6 @@ struct ntc_data { | |||
259 | struct device *dev; | 259 | struct device *dev; |
260 | int n_comp; | 260 | int n_comp; |
261 | char name[PLATFORM_NAME_SIZE]; | 261 | char name[PLATFORM_NAME_SIZE]; |
262 | struct thermal_zone_device *tz; | ||
263 | }; | 262 | }; |
264 | 263 | ||
265 | #if defined(CONFIG_OF) && IS_ENABLED(CONFIG_IIO) | 264 | #if defined(CONFIG_OF) && IS_ENABLED(CONFIG_IIO) |
@@ -579,6 +578,7 @@ static const struct thermal_zone_of_device_ops ntc_of_thermal_ops = { | |||
579 | 578 | ||
580 | static int ntc_thermistor_probe(struct platform_device *pdev) | 579 | static int ntc_thermistor_probe(struct platform_device *pdev) |
581 | { | 580 | { |
581 | struct thermal_zone_device *tz; | ||
582 | const struct of_device_id *of_id = | 582 | const struct of_device_id *of_id = |
583 | of_match_device(of_match_ptr(ntc_match), &pdev->dev); | 583 | of_match_device(of_match_ptr(ntc_match), &pdev->dev); |
584 | const struct platform_device_id *pdev_id; | 584 | const struct platform_device_id *pdev_id; |
@@ -677,12 +677,10 @@ static int ntc_thermistor_probe(struct platform_device *pdev) | |||
677 | dev_info(&pdev->dev, "Thermistor type: %s successfully probed.\n", | 677 | dev_info(&pdev->dev, "Thermistor type: %s successfully probed.\n", |
678 | pdev_id->name); | 678 | pdev_id->name); |
679 | 679 | ||
680 | data->tz = thermal_zone_of_sensor_register(data->dev, 0, data->dev, | 680 | tz = devm_thermal_zone_of_sensor_register(data->dev, 0, data->dev, |
681 | &ntc_of_thermal_ops); | 681 | &ntc_of_thermal_ops); |
682 | if (IS_ERR(data->tz)) { | 682 | if (IS_ERR(tz)) |
683 | dev_dbg(&pdev->dev, "Failed to register to thermal fw.\n"); | 683 | dev_dbg(&pdev->dev, "Failed to register to thermal fw.\n"); |
684 | data->tz = NULL; | ||
685 | } | ||
686 | 684 | ||
687 | return 0; | 685 | return 0; |
688 | err_after_sysfs: | 686 | err_after_sysfs: |
@@ -700,8 +698,6 @@ static int ntc_thermistor_remove(struct platform_device *pdev) | |||
700 | sysfs_remove_group(&data->dev->kobj, &ntc_attr_group); | 698 | sysfs_remove_group(&data->dev->kobj, &ntc_attr_group); |
701 | ntc_iio_channel_release(pdata); | 699 | ntc_iio_channel_release(pdata); |
702 | 700 | ||
703 | thermal_zone_of_sensor_unregister(data->dev, data->tz); | ||
704 | |||
705 | return 0; | 701 | return 0; |
706 | } | 702 | } |
707 | 703 | ||
diff --git a/drivers/hwmon/scpi-hwmon.c b/drivers/hwmon/scpi-hwmon.c index 912b449c8303..25b44e68926d 100644 --- a/drivers/hwmon/scpi-hwmon.c +++ b/drivers/hwmon/scpi-hwmon.c | |||
@@ -31,10 +31,8 @@ struct sensor_data { | |||
31 | }; | 31 | }; |
32 | 32 | ||
33 | struct scpi_thermal_zone { | 33 | struct scpi_thermal_zone { |
34 | struct list_head list; | ||
35 | int sensor_id; | 34 | int sensor_id; |
36 | struct scpi_sensors *scpi_sensors; | 35 | struct scpi_sensors *scpi_sensors; |
37 | struct thermal_zone_device *tzd; | ||
38 | }; | 36 | }; |
39 | 37 | ||
40 | struct scpi_sensors { | 38 | struct scpi_sensors { |
@@ -92,20 +90,6 @@ scpi_show_label(struct device *dev, struct device_attribute *attr, char *buf) | |||
92 | return sprintf(buf, "%s\n", sensor->info.name); | 90 | return sprintf(buf, "%s\n", sensor->info.name); |
93 | } | 91 | } |
94 | 92 | ||
95 | static void | ||
96 | unregister_thermal_zones(struct platform_device *pdev, | ||
97 | struct scpi_sensors *scpi_sensors) | ||
98 | { | ||
99 | struct list_head *pos; | ||
100 | |||
101 | list_for_each(pos, &scpi_sensors->thermal_zones) { | ||
102 | struct scpi_thermal_zone *zone; | ||
103 | |||
104 | zone = list_entry(pos, struct scpi_thermal_zone, list); | ||
105 | thermal_zone_of_sensor_unregister(&pdev->dev, zone->tzd); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | static struct thermal_zone_of_device_ops scpi_sensor_ops = { | 93 | static struct thermal_zone_of_device_ops scpi_sensor_ops = { |
110 | .get_temp = scpi_read_temp, | 94 | .get_temp = scpi_read_temp, |
111 | }; | 95 | }; |
@@ -118,7 +102,7 @@ static int scpi_hwmon_probe(struct platform_device *pdev) | |||
118 | struct scpi_ops *scpi_ops; | 102 | struct scpi_ops *scpi_ops; |
119 | struct device *hwdev, *dev = &pdev->dev; | 103 | struct device *hwdev, *dev = &pdev->dev; |
120 | struct scpi_sensors *scpi_sensors; | 104 | struct scpi_sensors *scpi_sensors; |
121 | int ret, idx; | 105 | int idx, ret; |
122 | 106 | ||
123 | scpi_ops = get_scpi_ops(); | 107 | scpi_ops = get_scpi_ops(); |
124 | if (!scpi_ops) | 108 | if (!scpi_ops) |
@@ -232,48 +216,35 @@ static int scpi_hwmon_probe(struct platform_device *pdev) | |||
232 | INIT_LIST_HEAD(&scpi_sensors->thermal_zones); | 216 | INIT_LIST_HEAD(&scpi_sensors->thermal_zones); |
233 | for (i = 0; i < nr_sensors; i++) { | 217 | for (i = 0; i < nr_sensors; i++) { |
234 | struct sensor_data *sensor = &scpi_sensors->data[i]; | 218 | struct sensor_data *sensor = &scpi_sensors->data[i]; |
219 | struct thermal_zone_device *z; | ||
235 | struct scpi_thermal_zone *zone; | 220 | struct scpi_thermal_zone *zone; |
236 | 221 | ||
237 | if (sensor->info.class != TEMPERATURE) | 222 | if (sensor->info.class != TEMPERATURE) |
238 | continue; | 223 | continue; |
239 | 224 | ||
240 | zone = devm_kzalloc(dev, sizeof(*zone), GFP_KERNEL); | 225 | zone = devm_kzalloc(dev, sizeof(*zone), GFP_KERNEL); |
241 | if (!zone) { | 226 | if (!zone) |
242 | ret = -ENOMEM; | 227 | return -ENOMEM; |
243 | goto unregister_tzd; | ||
244 | } | ||
245 | 228 | ||
246 | zone->sensor_id = i; | 229 | zone->sensor_id = i; |
247 | zone->scpi_sensors = scpi_sensors; | 230 | zone->scpi_sensors = scpi_sensors; |
248 | zone->tzd = thermal_zone_of_sensor_register(dev, | 231 | z = devm_thermal_zone_of_sensor_register(dev, |
249 | sensor->info.sensor_id, zone, &scpi_sensor_ops); | 232 | sensor->info.sensor_id, |
233 | zone, | ||
234 | &scpi_sensor_ops); | ||
250 | /* | 235 | /* |
251 | * The call to thermal_zone_of_sensor_register returns | 236 | * The call to thermal_zone_of_sensor_register returns |
252 | * an error for sensors that are not associated with | 237 | * an error for sensors that are not associated with |
253 | * any thermal zones or if the thermal subsystem is | 238 | * any thermal zones or if the thermal subsystem is |
254 | * not configured. | 239 | * not configured. |
255 | */ | 240 | */ |
256 | if (IS_ERR(zone->tzd)) { | 241 | if (IS_ERR(z)) { |
257 | devm_kfree(dev, zone); | 242 | devm_kfree(dev, zone); |
258 | continue; | 243 | continue; |
259 | } | 244 | } |
260 | list_add(&zone->list, &scpi_sensors->thermal_zones); | ||
261 | } | 245 | } |
262 | 246 | ||
263 | return 0; | 247 | return 0; |
264 | |||
265 | unregister_tzd: | ||
266 | unregister_thermal_zones(pdev, scpi_sensors); | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | static int scpi_hwmon_remove(struct platform_device *pdev) | ||
271 | { | ||
272 | struct scpi_sensors *scpi_sensors = platform_get_drvdata(pdev); | ||
273 | |||
274 | unregister_thermal_zones(pdev, scpi_sensors); | ||
275 | |||
276 | return 0; | ||
277 | } | 248 | } |
278 | 249 | ||
279 | static const struct of_device_id scpi_of_match[] = { | 250 | static const struct of_device_id scpi_of_match[] = { |
@@ -288,7 +259,6 @@ static struct platform_driver scpi_hwmon_platdrv = { | |||
288 | .of_match_table = scpi_of_match, | 259 | .of_match_table = scpi_of_match, |
289 | }, | 260 | }, |
290 | .probe = scpi_hwmon_probe, | 261 | .probe = scpi_hwmon_probe, |
291 | .remove = scpi_hwmon_remove, | ||
292 | }; | 262 | }; |
293 | module_platform_driver(scpi_hwmon_platdrv); | 263 | module_platform_driver(scpi_hwmon_platdrv); |
294 | 264 | ||
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 5289aa0980a8..f1e96fd7f445 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c | |||
@@ -53,7 +53,6 @@ | |||
53 | struct tmp102 { | 53 | struct tmp102 { |
54 | struct i2c_client *client; | 54 | struct i2c_client *client; |
55 | struct device *hwmon_dev; | 55 | struct device *hwmon_dev; |
56 | struct thermal_zone_device *tz; | ||
57 | struct mutex lock; | 56 | struct mutex lock; |
58 | u16 config_orig; | 57 | u16 config_orig; |
59 | unsigned long last_update; | 58 | unsigned long last_update; |
@@ -232,10 +231,8 @@ static int tmp102_probe(struct i2c_client *client, | |||
232 | goto fail_restore_config; | 231 | goto fail_restore_config; |
233 | } | 232 | } |
234 | tmp102->hwmon_dev = hwmon_dev; | 233 | tmp102->hwmon_dev = hwmon_dev; |
235 | tmp102->tz = thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev, | 234 | devm_thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev, |
236 | &tmp102_of_thermal_ops); | 235 | &tmp102_of_thermal_ops); |
237 | if (IS_ERR(tmp102->tz)) | ||
238 | tmp102->tz = NULL; | ||
239 | 236 | ||
240 | dev_info(dev, "initialized\n"); | 237 | dev_info(dev, "initialized\n"); |
241 | 238 | ||
@@ -251,7 +248,6 @@ static int tmp102_remove(struct i2c_client *client) | |||
251 | { | 248 | { |
252 | struct tmp102 *tmp102 = i2c_get_clientdata(client); | 249 | struct tmp102 *tmp102 = i2c_get_clientdata(client); |
253 | 250 | ||
254 | thermal_zone_of_sensor_unregister(tmp102->hwmon_dev, tmp102->tz); | ||
255 | hwmon_device_unregister(tmp102->hwmon_dev); | 251 | hwmon_device_unregister(tmp102->hwmon_dev); |
256 | 252 | ||
257 | /* Stop monitoring if device was stopped originally */ | 253 | /* Stop monitoring if device was stopped originally */ |
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index 485794376ee5..d07dd29d4848 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c | |||
@@ -115,7 +115,6 @@ | |||
115 | struct sun4i_ts_data { | 115 | struct sun4i_ts_data { |
116 | struct device *dev; | 116 | struct device *dev; |
117 | struct input_dev *input; | 117 | struct input_dev *input; |
118 | struct thermal_zone_device *tz; | ||
119 | void __iomem *base; | 118 | void __iomem *base; |
120 | unsigned int irq; | 119 | unsigned int irq; |
121 | bool ignore_fifo_data; | 120 | bool ignore_fifo_data; |
@@ -366,10 +365,7 @@ static int sun4i_ts_probe(struct platform_device *pdev) | |||
366 | if (IS_ERR(hwmon)) | 365 | if (IS_ERR(hwmon)) |
367 | return PTR_ERR(hwmon); | 366 | return PTR_ERR(hwmon); |
368 | 367 | ||
369 | ts->tz = thermal_zone_of_sensor_register(ts->dev, 0, ts, | 368 | devm_thermal_zone_of_sensor_register(ts->dev, 0, ts, &sun4i_ts_tz_ops); |
370 | &sun4i_ts_tz_ops); | ||
371 | if (IS_ERR(ts->tz)) | ||
372 | ts->tz = NULL; | ||
373 | 369 | ||
374 | writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); | 370 | writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); |
375 | 371 | ||
@@ -377,7 +373,6 @@ static int sun4i_ts_probe(struct platform_device *pdev) | |||
377 | error = input_register_device(ts->input); | 373 | error = input_register_device(ts->input); |
378 | if (error) { | 374 | if (error) { |
379 | writel(0, ts->base + TP_INT_FIFOC); | 375 | writel(0, ts->base + TP_INT_FIFOC); |
380 | thermal_zone_of_sensor_unregister(ts->dev, ts->tz); | ||
381 | return error; | 376 | return error; |
382 | } | 377 | } |
383 | } | 378 | } |
@@ -394,8 +389,6 @@ static int sun4i_ts_remove(struct platform_device *pdev) | |||
394 | if (ts->input) | 389 | if (ts->input) |
395 | input_unregister_device(ts->input); | 390 | input_unregister_device(ts->input); |
396 | 391 | ||
397 | thermal_zone_of_sensor_unregister(ts->dev, ts->tz); | ||
398 | |||
399 | /* Deactivate all IRQs */ | 392 | /* Deactivate all IRQs */ |
400 | writel(0, ts->base + TP_INT_FIFOC); | 393 | writel(0, ts->base + TP_INT_FIFOC); |
401 | 394 | ||
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index d89d60c8b6cf..2d702ca6556f 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig | |||
@@ -260,16 +260,6 @@ config ARMADA_THERMAL | |||
260 | Enable this option if you want to have support for thermal management | 260 | Enable this option if you want to have support for thermal management |
261 | controller present in Armada 370 and Armada XP SoC. | 261 | controller present in Armada 370 and Armada XP SoC. |
262 | 262 | ||
263 | config TEGRA_SOCTHERM | ||
264 | tristate "Tegra SOCTHERM thermal management" | ||
265 | depends on ARCH_TEGRA | ||
266 | help | ||
267 | Enable this option for integrated thermal management support on NVIDIA | ||
268 | Tegra124 systems-on-chip. The driver supports four thermal zones | ||
269 | (CPU, GPU, MEM, PLLX). Cooling devices can be bound to the thermal | ||
270 | zones to manage temperatures. This option is also required for the | ||
271 | emergency thermal reset (thermtrip) feature to function. | ||
272 | |||
273 | config DB8500_CPUFREQ_COOLING | 263 | config DB8500_CPUFREQ_COOLING |
274 | tristate "DB8500 cpufreq cooling" | 264 | tristate "DB8500 cpufreq cooling" |
275 | depends on ARCH_U8500 || COMPILE_TEST | 265 | depends on ARCH_U8500 || COMPILE_TEST |
@@ -377,6 +367,17 @@ depends on ARCH_STI && OF | |||
377 | source "drivers/thermal/st/Kconfig" | 367 | source "drivers/thermal/st/Kconfig" |
378 | endmenu | 368 | endmenu |
379 | 369 | ||
370 | config TANGO_THERMAL | ||
371 | tristate "Tango thermal management" | ||
372 | depends on ARCH_TANGO || COMPILE_TEST | ||
373 | help | ||
374 | Enable the Tango thermal driver, which supports the primitive | ||
375 | temperature sensor embedded in Tango chips since the SMP8758. | ||
376 | This sensor only generates a 1-bit signal to indicate whether | ||
377 | the die temperature exceeds a programmable threshold. | ||
378 | |||
379 | source "drivers/thermal/tegra/Kconfig" | ||
380 | |||
380 | config QCOM_SPMI_TEMP_ALARM | 381 | config QCOM_SPMI_TEMP_ALARM |
381 | tristate "Qualcomm SPMI PMIC Temperature Alarm" | 382 | tristate "Qualcomm SPMI PMIC Temperature Alarm" |
382 | depends on OF && SPMI && IIO | 383 | depends on OF && SPMI && IIO |
@@ -388,4 +389,14 @@ config QCOM_SPMI_TEMP_ALARM | |||
388 | real time die temperature if an ADC is present or an estimate of the | 389 | real time die temperature if an ADC is present or an estimate of the |
389 | temperature based upon the over temperature stage value. | 390 | temperature based upon the over temperature stage value. |
390 | 391 | ||
392 | config GENERIC_ADC_THERMAL | ||
393 | tristate "Generic ADC based thermal sensor" | ||
394 | depends on IIO | ||
395 | help | ||
396 | This enabled a thermal sysfs driver for the temperature sensor | ||
397 | which is connected to the General Purpose ADC. The ADC channel | ||
398 | is read via IIO framework and the channel information is provided | ||
399 | to this driver. This driver reports the temperature by reading ADC | ||
400 | channel and converts it to temperature based on lookup table. | ||
401 | |||
391 | endif | 402 | endif |
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 8e9cbc3b5679..10b07c14f8a9 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile | |||
@@ -35,6 +35,7 @@ obj-y += samsung/ | |||
35 | obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o | 35 | obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o |
36 | obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o | 36 | obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o |
37 | obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o | 37 | obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o |
38 | obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o | ||
38 | obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o | 39 | obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o |
39 | obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o | 40 | obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o |
40 | obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o | 41 | obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o |
@@ -46,6 +47,7 @@ obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ | |||
46 | obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ | 47 | obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ |
47 | obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o | 48 | obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o |
48 | obj-$(CONFIG_ST_THERMAL) += st/ | 49 | obj-$(CONFIG_ST_THERMAL) += st/ |
49 | obj-$(CONFIG_TEGRA_SOCTHERM) += tegra_soctherm.o | 50 | obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/ |
50 | obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o | 51 | obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o |
51 | obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o | 52 | obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o |
53 | obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o | ||
diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c index 70836c5b89bc..fc52016d4e85 100644 --- a/drivers/thermal/gov_bang_bang.c +++ b/drivers/thermal/gov_bang_bang.c | |||
@@ -29,7 +29,13 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) | |||
29 | struct thermal_instance *instance; | 29 | struct thermal_instance *instance; |
30 | 30 | ||
31 | tz->ops->get_trip_temp(tz, trip, &trip_temp); | 31 | tz->ops->get_trip_temp(tz, trip, &trip_temp); |
32 | tz->ops->get_trip_hyst(tz, trip, &trip_hyst); | 32 | |
33 | if (!tz->ops->get_trip_hyst) { | ||
34 | pr_warn_once("Undefined get_trip_hyst for thermal zone %s - " | ||
35 | "running with default hysteresis zero\n", tz->type); | ||
36 | trip_hyst = 0; | ||
37 | } else | ||
38 | tz->ops->get_trip_hyst(tz, trip, &trip_hyst); | ||
33 | 39 | ||
34 | dev_dbg(&tz->device, "Trip%d[temp=%d]:temp=%d:hyst=%d\n", | 40 | dev_dbg(&tz->device, "Trip%d[temp=%d]:temp=%d:hyst=%d\n", |
35 | trip, trip_temp, tz->temperature, | 41 | trip, trip_temp, tz->temperature, |
diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index 5e820b541506..97fad8f51e1c 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c | |||
@@ -160,7 +160,7 @@ static int hisi_thermal_get_temp(void *_sensor, int *temp) | |||
160 | struct hisi_thermal_sensor *sensor = _sensor; | 160 | struct hisi_thermal_sensor *sensor = _sensor; |
161 | struct hisi_thermal_data *data = sensor->thermal; | 161 | struct hisi_thermal_data *data = sensor->thermal; |
162 | 162 | ||
163 | int sensor_id = 0, i; | 163 | int sensor_id = -1, i; |
164 | long max_temp = 0; | 164 | long max_temp = 0; |
165 | 165 | ||
166 | *temp = hisi_thermal_get_sensor_temp(data, sensor); | 166 | *temp = hisi_thermal_get_sensor_temp(data, sensor); |
@@ -168,12 +168,19 @@ static int hisi_thermal_get_temp(void *_sensor, int *temp) | |||
168 | sensor->sensor_temp = *temp; | 168 | sensor->sensor_temp = *temp; |
169 | 169 | ||
170 | for (i = 0; i < HISI_MAX_SENSORS; i++) { | 170 | for (i = 0; i < HISI_MAX_SENSORS; i++) { |
171 | if (!data->sensors[i].tzd) | ||
172 | continue; | ||
173 | |||
171 | if (data->sensors[i].sensor_temp >= max_temp) { | 174 | if (data->sensors[i].sensor_temp >= max_temp) { |
172 | max_temp = data->sensors[i].sensor_temp; | 175 | max_temp = data->sensors[i].sensor_temp; |
173 | sensor_id = i; | 176 | sensor_id = i; |
174 | } | 177 | } |
175 | } | 178 | } |
176 | 179 | ||
180 | /* If no sensor has been enabled, then skip to enable irq */ | ||
181 | if (sensor_id == -1) | ||
182 | return 0; | ||
183 | |||
177 | mutex_lock(&data->thermal_lock); | 184 | mutex_lock(&data->thermal_lock); |
178 | data->irq_bind_sensor = sensor_id; | 185 | data->irq_bind_sensor = sensor_id; |
179 | mutex_unlock(&data->thermal_lock); | 186 | mutex_unlock(&data->thermal_lock); |
@@ -226,8 +233,12 @@ static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev) | |||
226 | sensor->thres_temp / 1000); | 233 | sensor->thres_temp / 1000); |
227 | mutex_unlock(&data->thermal_lock); | 234 | mutex_unlock(&data->thermal_lock); |
228 | 235 | ||
229 | for (i = 0; i < HISI_MAX_SENSORS; i++) | 236 | for (i = 0; i < HISI_MAX_SENSORS; i++) { |
237 | if (!data->sensors[i].tzd) | ||
238 | continue; | ||
239 | |||
230 | thermal_zone_device_update(data->sensors[i].tzd); | 240 | thermal_zone_device_update(data->sensors[i].tzd); |
241 | } | ||
231 | 242 | ||
232 | return IRQ_HANDLED; | 243 | return IRQ_HANDLED; |
233 | } | 244 | } |
@@ -243,10 +254,11 @@ static int hisi_thermal_register_sensor(struct platform_device *pdev, | |||
243 | sensor->id = index; | 254 | sensor->id = index; |
244 | sensor->thermal = data; | 255 | sensor->thermal = data; |
245 | 256 | ||
246 | sensor->tzd = thermal_zone_of_sensor_register(&pdev->dev, sensor->id, | 257 | sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, |
247 | sensor, &hisi_of_thermal_ops); | 258 | sensor->id, sensor, &hisi_of_thermal_ops); |
248 | if (IS_ERR(sensor->tzd)) { | 259 | if (IS_ERR(sensor->tzd)) { |
249 | ret = PTR_ERR(sensor->tzd); | 260 | ret = PTR_ERR(sensor->tzd); |
261 | sensor->tzd = NULL; | ||
250 | dev_err(&pdev->dev, "failed to register sensor id %d: %d\n", | 262 | dev_err(&pdev->dev, "failed to register sensor id %d: %d\n", |
251 | sensor->id, ret); | 263 | sensor->id, ret); |
252 | return ret; | 264 | return ret; |
@@ -331,28 +343,21 @@ static int hisi_thermal_probe(struct platform_device *pdev) | |||
331 | return ret; | 343 | return ret; |
332 | } | 344 | } |
333 | 345 | ||
346 | hisi_thermal_enable_bind_irq_sensor(data); | ||
347 | irq_get_irqchip_state(data->irq, IRQCHIP_STATE_MASKED, | ||
348 | &data->irq_enabled); | ||
349 | |||
334 | for (i = 0; i < HISI_MAX_SENSORS; ++i) { | 350 | for (i = 0; i < HISI_MAX_SENSORS; ++i) { |
335 | ret = hisi_thermal_register_sensor(pdev, data, | 351 | ret = hisi_thermal_register_sensor(pdev, data, |
336 | &data->sensors[i], i); | 352 | &data->sensors[i], i); |
337 | if (ret) { | 353 | if (ret) |
338 | dev_err(&pdev->dev, | 354 | dev_err(&pdev->dev, |
339 | "failed to register thermal sensor: %d\n", ret); | 355 | "failed to register thermal sensor: %d\n", ret); |
340 | goto err_get_sensor_data; | 356 | else |
341 | } | 357 | hisi_thermal_toggle_sensor(&data->sensors[i], true); |
342 | } | 358 | } |
343 | 359 | ||
344 | hisi_thermal_enable_bind_irq_sensor(data); | ||
345 | data->irq_enabled = true; | ||
346 | |||
347 | for (i = 0; i < HISI_MAX_SENSORS; i++) | ||
348 | hisi_thermal_toggle_sensor(&data->sensors[i], true); | ||
349 | |||
350 | return 0; | 360 | return 0; |
351 | |||
352 | err_get_sensor_data: | ||
353 | clk_disable_unprepare(data->clk); | ||
354 | |||
355 | return ret; | ||
356 | } | 361 | } |
357 | 362 | ||
358 | static int hisi_thermal_remove(struct platform_device *pdev) | 363 | static int hisi_thermal_remove(struct platform_device *pdev) |
@@ -363,8 +368,10 @@ static int hisi_thermal_remove(struct platform_device *pdev) | |||
363 | for (i = 0; i < HISI_MAX_SENSORS; i++) { | 368 | for (i = 0; i < HISI_MAX_SENSORS; i++) { |
364 | struct hisi_thermal_sensor *sensor = &data->sensors[i]; | 369 | struct hisi_thermal_sensor *sensor = &data->sensors[i]; |
365 | 370 | ||
371 | if (!sensor->tzd) | ||
372 | continue; | ||
373 | |||
366 | hisi_thermal_toggle_sensor(sensor, false); | 374 | hisi_thermal_toggle_sensor(sensor, false); |
367 | thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd); | ||
368 | } | 375 | } |
369 | 376 | ||
370 | hisi_thermal_disable_sensor(data); | 377 | hisi_thermal_disable_sensor(data); |
diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c index 36fa724a36c8..42c1ac057bad 100644 --- a/drivers/thermal/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c | |||
@@ -198,49 +198,33 @@ static struct thermal_zone_device_ops proc_thermal_local_ops = { | |||
198 | .get_temp = proc_thermal_get_zone_temp, | 198 | .get_temp = proc_thermal_get_zone_temp, |
199 | }; | 199 | }; |
200 | 200 | ||
201 | static int proc_thermal_add(struct device *dev, | 201 | static int proc_thermal_read_ppcc(struct proc_thermal_device *proc_priv) |
202 | struct proc_thermal_device **priv) | ||
203 | { | 202 | { |
204 | struct proc_thermal_device *proc_priv; | 203 | int i; |
205 | struct acpi_device *adev; | ||
206 | acpi_status status; | 204 | acpi_status status; |
207 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; | 205 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; |
208 | union acpi_object *elements, *ppcc; | 206 | union acpi_object *elements, *ppcc; |
209 | union acpi_object *p; | 207 | union acpi_object *p; |
210 | unsigned long long tmp; | 208 | int ret = 0; |
211 | struct thermal_zone_device_ops *ops = NULL; | ||
212 | int i; | ||
213 | int ret; | ||
214 | |||
215 | adev = ACPI_COMPANION(dev); | ||
216 | if (!adev) | ||
217 | return -ENODEV; | ||
218 | 209 | ||
219 | status = acpi_evaluate_object(adev->handle, "PPCC", NULL, &buf); | 210 | status = acpi_evaluate_object(proc_priv->adev->handle, "PPCC", |
211 | NULL, &buf); | ||
220 | if (ACPI_FAILURE(status)) | 212 | if (ACPI_FAILURE(status)) |
221 | return -ENODEV; | 213 | return -ENODEV; |
222 | 214 | ||
223 | p = buf.pointer; | 215 | p = buf.pointer; |
224 | if (!p || (p->type != ACPI_TYPE_PACKAGE)) { | 216 | if (!p || (p->type != ACPI_TYPE_PACKAGE)) { |
225 | dev_err(dev, "Invalid PPCC data\n"); | 217 | dev_err(proc_priv->dev, "Invalid PPCC data\n"); |
226 | ret = -EFAULT; | 218 | ret = -EFAULT; |
227 | goto free_buffer; | 219 | goto free_buffer; |
228 | } | 220 | } |
221 | |||
229 | if (!p->package.count) { | 222 | if (!p->package.count) { |
230 | dev_err(dev, "Invalid PPCC package size\n"); | 223 | dev_err(proc_priv->dev, "Invalid PPCC package size\n"); |
231 | ret = -EFAULT; | 224 | ret = -EFAULT; |
232 | goto free_buffer; | 225 | goto free_buffer; |
233 | } | 226 | } |
234 | 227 | ||
235 | proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL); | ||
236 | if (!proc_priv) { | ||
237 | ret = -ENOMEM; | ||
238 | goto free_buffer; | ||
239 | } | ||
240 | |||
241 | proc_priv->dev = dev; | ||
242 | proc_priv->adev = adev; | ||
243 | |||
244 | for (i = 0; i < min((int)p->package.count - 1, 2); ++i) { | 228 | for (i = 0; i < min((int)p->package.count - 1, 2); ++i) { |
245 | elements = &(p->package.elements[i+1]); | 229 | elements = &(p->package.elements[i+1]); |
246 | if (elements->type != ACPI_TYPE_PACKAGE || | 230 | if (elements->type != ACPI_TYPE_PACKAGE || |
@@ -257,12 +241,62 @@ static int proc_thermal_add(struct device *dev, | |||
257 | proc_priv->power_limits[i].step_uw = ppcc[5].integer.value; | 241 | proc_priv->power_limits[i].step_uw = ppcc[5].integer.value; |
258 | } | 242 | } |
259 | 243 | ||
244 | free_buffer: | ||
245 | kfree(buf.pointer); | ||
246 | |||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | #define PROC_POWER_CAPABILITY_CHANGED 0x83 | ||
251 | static void proc_thermal_notify(acpi_handle handle, u32 event, void *data) | ||
252 | { | ||
253 | struct proc_thermal_device *proc_priv = data; | ||
254 | |||
255 | if (!proc_priv) | ||
256 | return; | ||
257 | |||
258 | switch (event) { | ||
259 | case PROC_POWER_CAPABILITY_CHANGED: | ||
260 | proc_thermal_read_ppcc(proc_priv); | ||
261 | int340x_thermal_zone_device_update(proc_priv->int340x_zone); | ||
262 | break; | ||
263 | default: | ||
264 | dev_err(proc_priv->dev, "Unsupported event [0x%x]\n", event); | ||
265 | break; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | |||
270 | static int proc_thermal_add(struct device *dev, | ||
271 | struct proc_thermal_device **priv) | ||
272 | { | ||
273 | struct proc_thermal_device *proc_priv; | ||
274 | struct acpi_device *adev; | ||
275 | acpi_status status; | ||
276 | unsigned long long tmp; | ||
277 | struct thermal_zone_device_ops *ops = NULL; | ||
278 | int ret; | ||
279 | |||
280 | adev = ACPI_COMPANION(dev); | ||
281 | if (!adev) | ||
282 | return -ENODEV; | ||
283 | |||
284 | proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL); | ||
285 | if (!proc_priv) | ||
286 | return -ENOMEM; | ||
287 | |||
288 | proc_priv->dev = dev; | ||
289 | proc_priv->adev = adev; | ||
260 | *priv = proc_priv; | 290 | *priv = proc_priv; |
261 | 291 | ||
262 | ret = sysfs_create_group(&dev->kobj, | 292 | ret = proc_thermal_read_ppcc(proc_priv); |
263 | &power_limit_attribute_group); | 293 | if (!ret) { |
294 | ret = sysfs_create_group(&dev->kobj, | ||
295 | &power_limit_attribute_group); | ||
296 | |||
297 | } | ||
264 | if (ret) | 298 | if (ret) |
265 | goto free_buffer; | 299 | return ret; |
266 | 300 | ||
267 | status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp); | 301 | status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp); |
268 | if (ACPI_FAILURE(status)) { | 302 | if (ACPI_FAILURE(status)) { |
@@ -274,20 +308,32 @@ static int proc_thermal_add(struct device *dev, | |||
274 | 308 | ||
275 | proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops); | 309 | proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops); |
276 | if (IS_ERR(proc_priv->int340x_zone)) { | 310 | if (IS_ERR(proc_priv->int340x_zone)) { |
277 | sysfs_remove_group(&proc_priv->dev->kobj, | ||
278 | &power_limit_attribute_group); | ||
279 | ret = PTR_ERR(proc_priv->int340x_zone); | 311 | ret = PTR_ERR(proc_priv->int340x_zone); |
312 | goto remove_group; | ||
280 | } else | 313 | } else |
281 | ret = 0; | 314 | ret = 0; |
282 | 315 | ||
283 | free_buffer: | 316 | ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, |
284 | kfree(buf.pointer); | 317 | proc_thermal_notify, |
318 | (void *)proc_priv); | ||
319 | if (ret) | ||
320 | goto remove_zone; | ||
321 | |||
322 | return 0; | ||
323 | |||
324 | remove_zone: | ||
325 | int340x_thermal_zone_remove(proc_priv->int340x_zone); | ||
326 | remove_group: | ||
327 | sysfs_remove_group(&proc_priv->dev->kobj, | ||
328 | &power_limit_attribute_group); | ||
285 | 329 | ||
286 | return ret; | 330 | return ret; |
287 | } | 331 | } |
288 | 332 | ||
289 | static void proc_thermal_remove(struct proc_thermal_device *proc_priv) | 333 | static void proc_thermal_remove(struct proc_thermal_device *proc_priv) |
290 | { | 334 | { |
335 | acpi_remove_notify_handler(proc_priv->adev->handle, | ||
336 | ACPI_DEVICE_NOTIFY, proc_thermal_notify); | ||
291 | int340x_thermal_zone_remove(proc_priv->int340x_zone); | 337 | int340x_thermal_zone_remove(proc_priv->int340x_zone); |
292 | sysfs_remove_group(&proc_priv->dev->kobj, | 338 | sysfs_remove_group(&proc_priv->dev->kobj, |
293 | &power_limit_attribute_group); | 339 | &power_limit_attribute_group); |
diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index 6c79588251d5..015ce2eb6eb7 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c | |||
@@ -510,12 +510,6 @@ static int start_power_clamp(void) | |||
510 | unsigned long cpu; | 510 | unsigned long cpu; |
511 | struct task_struct *thread; | 511 | struct task_struct *thread; |
512 | 512 | ||
513 | /* check if pkg cstate counter is completely 0, abort in this case */ | ||
514 | if (!has_pkg_state_counter()) { | ||
515 | pr_err("pkg cstate counter not functional, abort\n"); | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | |||
519 | set_target_ratio = clamp(set_target_ratio, 0U, MAX_TARGET_RATIO - 1); | 513 | set_target_ratio = clamp(set_target_ratio, 0U, MAX_TARGET_RATIO - 1); |
520 | /* prevent cpu hotplug */ | 514 | /* prevent cpu hotplug */ |
521 | get_online_cpus(); | 515 | get_online_cpus(); |
@@ -672,35 +666,11 @@ static struct thermal_cooling_device_ops powerclamp_cooling_ops = { | |||
672 | .set_cur_state = powerclamp_set_cur_state, | 666 | .set_cur_state = powerclamp_set_cur_state, |
673 | }; | 667 | }; |
674 | 668 | ||
675 | /* runs on Nehalem and later */ | ||
676 | static const struct x86_cpu_id intel_powerclamp_ids[] __initconst = { | 669 | static const struct x86_cpu_id intel_powerclamp_ids[] __initconst = { |
677 | { X86_VENDOR_INTEL, 6, 0x1a}, | 670 | { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_MWAIT }, |
678 | { X86_VENDOR_INTEL, 6, 0x1c}, | 671 | { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_ARAT }, |
679 | { X86_VENDOR_INTEL, 6, 0x1e}, | 672 | { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_NONSTOP_TSC }, |
680 | { X86_VENDOR_INTEL, 6, 0x1f}, | 673 | { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_CONSTANT_TSC}, |
681 | { X86_VENDOR_INTEL, 6, 0x25}, | ||
682 | { X86_VENDOR_INTEL, 6, 0x26}, | ||
683 | { X86_VENDOR_INTEL, 6, 0x2a}, | ||
684 | { X86_VENDOR_INTEL, 6, 0x2c}, | ||
685 | { X86_VENDOR_INTEL, 6, 0x2d}, | ||
686 | { X86_VENDOR_INTEL, 6, 0x2e}, | ||
687 | { X86_VENDOR_INTEL, 6, 0x2f}, | ||
688 | { X86_VENDOR_INTEL, 6, 0x37}, | ||
689 | { X86_VENDOR_INTEL, 6, 0x3a}, | ||
690 | { X86_VENDOR_INTEL, 6, 0x3c}, | ||
691 | { X86_VENDOR_INTEL, 6, 0x3d}, | ||
692 | { X86_VENDOR_INTEL, 6, 0x3e}, | ||
693 | { X86_VENDOR_INTEL, 6, 0x3f}, | ||
694 | { X86_VENDOR_INTEL, 6, 0x45}, | ||
695 | { X86_VENDOR_INTEL, 6, 0x46}, | ||
696 | { X86_VENDOR_INTEL, 6, 0x47}, | ||
697 | { X86_VENDOR_INTEL, 6, 0x4c}, | ||
698 | { X86_VENDOR_INTEL, 6, 0x4d}, | ||
699 | { X86_VENDOR_INTEL, 6, 0x4e}, | ||
700 | { X86_VENDOR_INTEL, 6, 0x4f}, | ||
701 | { X86_VENDOR_INTEL, 6, 0x56}, | ||
702 | { X86_VENDOR_INTEL, 6, 0x57}, | ||
703 | { X86_VENDOR_INTEL, 6, 0x5e}, | ||
704 | {} | 674 | {} |
705 | }; | 675 | }; |
706 | MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids); | 676 | MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids); |
@@ -712,11 +682,12 @@ static int __init powerclamp_probe(void) | |||
712 | boot_cpu_data.x86, boot_cpu_data.x86_model); | 682 | boot_cpu_data.x86, boot_cpu_data.x86_model); |
713 | return -ENODEV; | 683 | return -ENODEV; |
714 | } | 684 | } |
715 | if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC) || | 685 | |
716 | !boot_cpu_has(X86_FEATURE_CONSTANT_TSC) || | 686 | /* The goal for idle time alignment is to achieve package cstate. */ |
717 | !boot_cpu_has(X86_FEATURE_MWAIT) || | 687 | if (!has_pkg_state_counter()) { |
718 | !boot_cpu_has(X86_FEATURE_ARAT)) | 688 | pr_info("No package C-state available"); |
719 | return -ENODEV; | 689 | return -ENODEV; |
690 | } | ||
720 | 691 | ||
721 | /* find the deepest mwait value */ | 692 | /* find the deepest mwait value */ |
722 | find_target_mwait(); | 693 | find_target_mwait(); |
diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c index 507632b9648e..262ab0a2266f 100644 --- a/drivers/thermal/mtk_thermal.c +++ b/drivers/thermal/mtk_thermal.c | |||
@@ -144,7 +144,6 @@ struct mtk_thermal { | |||
144 | s32 o_slope; | 144 | s32 o_slope; |
145 | s32 vts[MT8173_NUM_SENSORS]; | 145 | s32 vts[MT8173_NUM_SENSORS]; |
146 | 146 | ||
147 | struct thermal_zone_device *tzd; | ||
148 | }; | 147 | }; |
149 | 148 | ||
150 | struct mtk_thermal_bank_cfg { | 149 | struct mtk_thermal_bank_cfg { |
@@ -572,16 +571,11 @@ static int mtk_thermal_probe(struct platform_device *pdev) | |||
572 | 571 | ||
573 | platform_set_drvdata(pdev, mt); | 572 | platform_set_drvdata(pdev, mt); |
574 | 573 | ||
575 | mt->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, mt, | 574 | devm_thermal_zone_of_sensor_register(&pdev->dev, 0, mt, |
576 | &mtk_thermal_ops); | 575 | &mtk_thermal_ops); |
577 | if (IS_ERR(mt->tzd)) | ||
578 | goto err_register; | ||
579 | 576 | ||
580 | return 0; | 577 | return 0; |
581 | 578 | ||
582 | err_register: | ||
583 | clk_disable_unprepare(mt->clk_peri_therm); | ||
584 | |||
585 | err_disable_clk_auxadc: | 579 | err_disable_clk_auxadc: |
586 | clk_disable_unprepare(mt->clk_auxadc); | 580 | clk_disable_unprepare(mt->clk_auxadc); |
587 | 581 | ||
@@ -592,8 +586,6 @@ static int mtk_thermal_remove(struct platform_device *pdev) | |||
592 | { | 586 | { |
593 | struct mtk_thermal *mt = platform_get_drvdata(pdev); | 587 | struct mtk_thermal *mt = platform_get_drvdata(pdev); |
594 | 588 | ||
595 | thermal_zone_of_sensor_unregister(&pdev->dev, mt->tzd); | ||
596 | |||
597 | clk_disable_unprepare(mt->clk_peri_therm); | 589 | clk_disable_unprepare(mt->clk_peri_therm); |
598 | clk_disable_unprepare(mt->clk_auxadc); | 590 | clk_disable_unprepare(mt->clk_auxadc); |
599 | 591 | ||
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index d8ec44b194d6..b8e509c60848 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c | |||
@@ -331,6 +331,14 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip, | |||
331 | if (trip >= data->ntrips || trip < 0) | 331 | if (trip >= data->ntrips || trip < 0) |
332 | return -EDOM; | 332 | return -EDOM; |
333 | 333 | ||
334 | if (data->ops->set_trip_temp) { | ||
335 | int ret; | ||
336 | |||
337 | ret = data->ops->set_trip_temp(data->sensor_data, trip, temp); | ||
338 | if (ret) | ||
339 | return ret; | ||
340 | } | ||
341 | |||
334 | /* thermal framework should take care of data->mask & (1 << trip) */ | 342 | /* thermal framework should take care of data->mask & (1 << trip) */ |
335 | data->trips[trip].temperature = temp; | 343 | data->trips[trip].temperature = temp; |
336 | 344 | ||
@@ -906,7 +914,7 @@ finish: | |||
906 | return tz; | 914 | return tz; |
907 | 915 | ||
908 | free_tbps: | 916 | free_tbps: |
909 | for (i = 0; i < tz->num_tbps; i++) | 917 | for (i = i - 1; i >= 0; i--) |
910 | of_node_put(tz->tbps[i].cooling_device); | 918 | of_node_put(tz->tbps[i].cooling_device); |
911 | kfree(tz->tbps); | 919 | kfree(tz->tbps); |
912 | free_trips: | 920 | free_trips: |
diff --git a/drivers/thermal/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom-spmi-temp-alarm.c index b677aada5b52..f8a3c60bef94 100644 --- a/drivers/thermal/qcom-spmi-temp-alarm.c +++ b/drivers/thermal/qcom-spmi-temp-alarm.c | |||
@@ -260,7 +260,7 @@ static int qpnp_tm_probe(struct platform_device *pdev) | |||
260 | if (ret < 0) | 260 | if (ret < 0) |
261 | goto fail; | 261 | goto fail; |
262 | 262 | ||
263 | chip->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, 0, chip, | 263 | chip->tz_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, chip, |
264 | &qpnp_tm_sensor_ops); | 264 | &qpnp_tm_sensor_ops); |
265 | if (IS_ERR(chip->tz_dev)) { | 265 | if (IS_ERR(chip->tz_dev)) { |
266 | dev_err(&pdev->dev, "failed to register sensor\n"); | 266 | dev_err(&pdev->dev, "failed to register sensor\n"); |
@@ -281,7 +281,6 @@ static int qpnp_tm_remove(struct platform_device *pdev) | |||
281 | { | 281 | { |
282 | struct qpnp_tm_chip *chip = dev_get_drvdata(&pdev->dev); | 282 | struct qpnp_tm_chip *chip = dev_get_drvdata(&pdev->dev); |
283 | 283 | ||
284 | thermal_zone_of_sensor_unregister(&pdev->dev, chip->tz_dev); | ||
285 | if (!IS_ERR(chip->adc)) | 284 | if (!IS_ERR(chip->adc)) |
286 | iio_channel_release(chip->adc); | 285 | iio_channel_release(chip->adc); |
287 | 286 | ||
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index 82daba09e150..71a339271fa5 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c | |||
@@ -492,7 +492,7 @@ static int rcar_thermal_probe(struct platform_device *pdev) | |||
492 | goto error_unregister; | 492 | goto error_unregister; |
493 | 493 | ||
494 | if (of_data == USE_OF_THERMAL) | 494 | if (of_data == USE_OF_THERMAL) |
495 | priv->zone = thermal_zone_of_sensor_register( | 495 | priv->zone = devm_thermal_zone_of_sensor_register( |
496 | dev, i, priv, | 496 | dev, i, priv, |
497 | &rcar_thermal_zone_of_ops); | 497 | &rcar_thermal_zone_of_ops); |
498 | else | 498 | else |
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 233a564442a0..5d491f16a866 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c | |||
@@ -1,7 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd | 2 | * Copyright (c) 2014-2016, Fuzhou Rockchip Electronics Co., Ltd |
3 | * | ||
4 | * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd | ||
5 | * Caesar Wang <wxt@rock-chips.com> | 3 | * Caesar Wang <wxt@rock-chips.com> |
6 | * | 4 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
@@ -23,8 +21,10 @@ | |||
23 | #include <linux/of_address.h> | 21 | #include <linux/of_address.h> |
24 | #include <linux/of_irq.h> | 22 | #include <linux/of_irq.h> |
25 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/regmap.h> | ||
26 | #include <linux/reset.h> | 25 | #include <linux/reset.h> |
27 | #include <linux/thermal.h> | 26 | #include <linux/thermal.h> |
27 | #include <linux/mfd/syscon.h> | ||
28 | #include <linux/pinctrl/consumer.h> | 28 | #include <linux/pinctrl/consumer.h> |
29 | 29 | ||
30 | /** | 30 | /** |
@@ -73,7 +73,7 @@ enum adc_sort_mode { | |||
73 | #define SOC_MAX_SENSORS 2 | 73 | #define SOC_MAX_SENSORS 2 |
74 | 74 | ||
75 | /** | 75 | /** |
76 | * struct chip_tsadc_table: hold information about chip-specific differences | 76 | * struct chip_tsadc_table - hold information about chip-specific differences |
77 | * @id: conversion table | 77 | * @id: conversion table |
78 | * @length: size of conversion table | 78 | * @length: size of conversion table |
79 | * @data_mask: mask to apply on data inputs | 79 | * @data_mask: mask to apply on data inputs |
@@ -86,6 +86,20 @@ struct chip_tsadc_table { | |||
86 | enum adc_sort_mode mode; | 86 | enum adc_sort_mode mode; |
87 | }; | 87 | }; |
88 | 88 | ||
89 | /** | ||
90 | * struct rockchip_tsadc_chip - hold the private data of tsadc chip | ||
91 | * @chn_id[SOC_MAX_SENSORS]: the sensor id of chip correspond to the channel | ||
92 | * @chn_num: the channel number of tsadc chip | ||
93 | * @tshut_temp: the hardware-controlled shutdown temperature value | ||
94 | * @tshut_mode: the hardware-controlled shutdown mode (0:CRU 1:GPIO) | ||
95 | * @tshut_polarity: the hardware-controlled active polarity (0:LOW 1:HIGH) | ||
96 | * @initialize: SoC special initialize tsadc controller method | ||
97 | * @irq_ack: clear the interrupt | ||
98 | * @get_temp: get the temperature | ||
99 | * @set_tshut_temp: set the hardware-controlled shutdown temperature | ||
100 | * @set_tshut_mode: set the hardware-controlled shutdown mode | ||
101 | * @table: the chip-specific conversion table | ||
102 | */ | ||
89 | struct rockchip_tsadc_chip { | 103 | struct rockchip_tsadc_chip { |
90 | /* The sensor id of chip correspond to the ADC channel */ | 104 | /* The sensor id of chip correspond to the ADC channel */ |
91 | int chn_id[SOC_MAX_SENSORS]; | 105 | int chn_id[SOC_MAX_SENSORS]; |
@@ -97,7 +111,8 @@ struct rockchip_tsadc_chip { | |||
97 | enum tshut_polarity tshut_polarity; | 111 | enum tshut_polarity tshut_polarity; |
98 | 112 | ||
99 | /* Chip-wide methods */ | 113 | /* Chip-wide methods */ |
100 | void (*initialize)(void __iomem *reg, enum tshut_polarity p); | 114 | void (*initialize)(struct regmap *grf, |
115 | void __iomem *reg, enum tshut_polarity p); | ||
101 | void (*irq_ack)(void __iomem *reg); | 116 | void (*irq_ack)(void __iomem *reg); |
102 | void (*control)(void __iomem *reg, bool on); | 117 | void (*control)(void __iomem *reg, bool on); |
103 | 118 | ||
@@ -112,12 +127,32 @@ struct rockchip_tsadc_chip { | |||
112 | struct chip_tsadc_table table; | 127 | struct chip_tsadc_table table; |
113 | }; | 128 | }; |
114 | 129 | ||
130 | /** | ||
131 | * struct rockchip_thermal_sensor - hold the information of thermal sensor | ||
132 | * @thermal: pointer to the platform/configuration data | ||
133 | * @tzd: pointer to a thermal zone | ||
134 | * @id: identifier of the thermal sensor | ||
135 | */ | ||
115 | struct rockchip_thermal_sensor { | 136 | struct rockchip_thermal_sensor { |
116 | struct rockchip_thermal_data *thermal; | 137 | struct rockchip_thermal_data *thermal; |
117 | struct thermal_zone_device *tzd; | 138 | struct thermal_zone_device *tzd; |
118 | int id; | 139 | int id; |
119 | }; | 140 | }; |
120 | 141 | ||
142 | /** | ||
143 | * struct rockchip_thermal_data - hold the private data of thermal driver | ||
144 | * @chip: pointer to the platform/configuration data | ||
145 | * @pdev: platform device of thermal | ||
146 | * @reset: the reset controller of tsadc | ||
147 | * @sensors[SOC_MAX_SENSORS]: the thermal sensor | ||
148 | * @clk: the controller clock is divided by the exteral 24MHz | ||
149 | * @pclk: the advanced peripherals bus clock | ||
150 | * @grf: the general register file will be used to do static set by software | ||
151 | * @regs: the base address of tsadc controller | ||
152 | * @tshut_temp: the hardware-controlled shutdown temperature value | ||
153 | * @tshut_mode: the hardware-controlled shutdown mode (0:CRU 1:GPIO) | ||
154 | * @tshut_polarity: the hardware-controlled active polarity (0:LOW 1:HIGH) | ||
155 | */ | ||
121 | struct rockchip_thermal_data { | 156 | struct rockchip_thermal_data { |
122 | const struct rockchip_tsadc_chip *chip; | 157 | const struct rockchip_tsadc_chip *chip; |
123 | struct platform_device *pdev; | 158 | struct platform_device *pdev; |
@@ -128,6 +163,7 @@ struct rockchip_thermal_data { | |||
128 | struct clk *clk; | 163 | struct clk *clk; |
129 | struct clk *pclk; | 164 | struct clk *pclk; |
130 | 165 | ||
166 | struct regmap *grf; | ||
131 | void __iomem *regs; | 167 | void __iomem *regs; |
132 | 168 | ||
133 | int tshut_temp; | 169 | int tshut_temp; |
@@ -142,6 +178,7 @@ struct rockchip_thermal_data { | |||
142 | * TSADCV3_* are used for newer SoCs than RK3288. (e.g: RK3228, RK3399) | 178 | * TSADCV3_* are used for newer SoCs than RK3288. (e.g: RK3228, RK3399) |
143 | * | 179 | * |
144 | */ | 180 | */ |
181 | #define TSADCV2_USER_CON 0x00 | ||
145 | #define TSADCV2_AUTO_CON 0x04 | 182 | #define TSADCV2_AUTO_CON 0x04 |
146 | #define TSADCV2_INT_EN 0x08 | 183 | #define TSADCV2_INT_EN 0x08 |
147 | #define TSADCV2_INT_PD 0x0c | 184 | #define TSADCV2_INT_PD 0x0c |
@@ -155,12 +192,7 @@ struct rockchip_thermal_data { | |||
155 | #define TSADCV2_AUTO_EN BIT(0) | 192 | #define TSADCV2_AUTO_EN BIT(0) |
156 | #define TSADCV2_AUTO_SRC_EN(chn) BIT(4 + (chn)) | 193 | #define TSADCV2_AUTO_SRC_EN(chn) BIT(4 + (chn)) |
157 | #define TSADCV2_AUTO_TSHUT_POLARITY_HIGH BIT(8) | 194 | #define TSADCV2_AUTO_TSHUT_POLARITY_HIGH BIT(8) |
158 | /** | 195 | |
159 | * TSADCV1_AUTO_Q_SEL_EN: | ||
160 | * whether select (1024 - tsadc_q) as output | ||
161 | * 1'b0:use tsadc_q as output(temperature-code is rising sequence) | ||
162 | * 1'b1:use(1024 - tsadc_q) as output (temperature-code is falling sequence) | ||
163 | */ | ||
164 | #define TSADCV3_AUTO_Q_SEL_EN BIT(1) | 196 | #define TSADCV3_AUTO_Q_SEL_EN BIT(1) |
165 | 197 | ||
166 | #define TSADCV2_INT_SRC_EN(chn) BIT(chn) | 198 | #define TSADCV2_INT_SRC_EN(chn) BIT(chn) |
@@ -177,19 +209,32 @@ struct rockchip_thermal_data { | |||
177 | #define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT 4 | 209 | #define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT 4 |
178 | #define TSADCV2_AUTO_PERIOD_TIME 250 /* msec */ | 210 | #define TSADCV2_AUTO_PERIOD_TIME 250 /* msec */ |
179 | #define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* msec */ | 211 | #define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* msec */ |
212 | #define TSADCV2_USER_INTER_PD_SOC 0x340 /* 13 clocks */ | ||
180 | 213 | ||
181 | struct tsadc_table { | 214 | #define GRF_SARADC_TESTBIT 0x0e644 |
182 | u32 code; | 215 | #define GRF_TSADC_TESTBIT_L 0x0e648 |
183 | int temp; | 216 | #define GRF_TSADC_TESTBIT_H 0x0e64c |
184 | }; | 217 | |
218 | #define GRF_TSADC_TSEN_PD_ON (0x30003 << 0) | ||
219 | #define GRF_TSADC_TSEN_PD_OFF (0x30000 << 0) | ||
220 | #define GRF_SARADC_TESTBIT_ON (0x10001 << 2) | ||
221 | #define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2) | ||
185 | 222 | ||
186 | /** | 223 | /** |
224 | * struct tsadc_table - code to temperature conversion table | ||
225 | * @code: the value of adc channel | ||
226 | * @temp: the temperature | ||
187 | * Note: | 227 | * Note: |
188 | * Code to Temperature mapping of the Temperature sensor is a piece wise linear | 228 | * code to temperature mapping of the temperature sensor is a piece wise linear |
189 | * curve.Any temperature, code faling between to 2 give temperatures can be | 229 | * curve.Any temperature, code faling between to 2 give temperatures can be |
190 | * linearly interpolated. | 230 | * linearly interpolated. |
191 | * Code to Temperature mapping should be updated based on sillcon results. | 231 | * Code to Temperature mapping should be updated based on manufacturer results. |
192 | */ | 232 | */ |
233 | struct tsadc_table { | ||
234 | u32 code; | ||
235 | int temp; | ||
236 | }; | ||
237 | |||
193 | static const struct tsadc_table rk3228_code_table[] = { | 238 | static const struct tsadc_table rk3228_code_table[] = { |
194 | {0, -40000}, | 239 | {0, -40000}, |
195 | {588, -40000}, | 240 | {588, -40000}, |
@@ -308,40 +353,40 @@ static const struct tsadc_table rk3368_code_table[] = { | |||
308 | 353 | ||
309 | static const struct tsadc_table rk3399_code_table[] = { | 354 | static const struct tsadc_table rk3399_code_table[] = { |
310 | {0, -40000}, | 355 | {0, -40000}, |
311 | {593, -40000}, | 356 | {402, -40000}, |
312 | {598, -35000}, | 357 | {410, -35000}, |
313 | {603, -30000}, | 358 | {419, -30000}, |
314 | {609, -25000}, | 359 | {427, -25000}, |
315 | {614, -20000}, | 360 | {436, -20000}, |
316 | {619, -15000}, | 361 | {444, -15000}, |
317 | {625, -10000}, | 362 | {453, -10000}, |
318 | {630, -5000}, | 363 | {461, -5000}, |
319 | {635, 0}, | 364 | {470, 0}, |
320 | {641, 5000}, | 365 | {478, 5000}, |
321 | {646, 10000}, | 366 | {487, 10000}, |
322 | {651, 15000}, | 367 | {496, 15000}, |
323 | {657, 20000}, | 368 | {504, 20000}, |
324 | {662, 25000}, | 369 | {513, 25000}, |
325 | {667, 30000}, | 370 | {521, 30000}, |
326 | {673, 35000}, | 371 | {530, 35000}, |
327 | {678, 40000}, | 372 | {538, 40000}, |
328 | {684, 45000}, | 373 | {547, 45000}, |
329 | {689, 50000}, | 374 | {555, 50000}, |
330 | {694, 55000}, | 375 | {564, 55000}, |
331 | {700, 60000}, | 376 | {573, 60000}, |
332 | {705, 65000}, | 377 | {581, 65000}, |
333 | {711, 70000}, | 378 | {590, 70000}, |
334 | {716, 75000}, | 379 | {599, 75000}, |
335 | {722, 80000}, | 380 | {607, 80000}, |
336 | {727, 85000}, | 381 | {616, 85000}, |
337 | {733, 90000}, | 382 | {624, 90000}, |
338 | {738, 95000}, | 383 | {633, 95000}, |
339 | {743, 100000}, | 384 | {642, 100000}, |
340 | {749, 105000}, | 385 | {650, 105000}, |
341 | {754, 110000}, | 386 | {659, 110000}, |
342 | {760, 115000}, | 387 | {668, 115000}, |
343 | {765, 120000}, | 388 | {677, 120000}, |
344 | {771, 125000}, | 389 | {685, 125000}, |
345 | {TSADCV3_DATA_MASK, 125000}, | 390 | {TSADCV3_DATA_MASK, 125000}, |
346 | }; | 391 | }; |
347 | 392 | ||
@@ -405,8 +450,8 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, | |||
405 | return -EAGAIN; /* Incorrect reading */ | 450 | return -EAGAIN; /* Incorrect reading */ |
406 | 451 | ||
407 | while (low <= high) { | 452 | while (low <= high) { |
408 | if (code >= table.id[mid - 1].code && | 453 | if (code <= table.id[mid].code && |
409 | code < table.id[mid].code) | 454 | code > table.id[mid - 1].code) |
410 | break; | 455 | break; |
411 | else if (code > table.id[mid].code) | 456 | else if (code > table.id[mid].code) |
412 | low = mid + 1; | 457 | low = mid + 1; |
@@ -449,7 +494,7 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, | |||
449 | * If the temperature is higher than COMP_INT or COMP_SHUT for | 494 | * If the temperature is higher than COMP_INT or COMP_SHUT for |
450 | * "debounce" times, TSADC controller will generate interrupt or TSHUT. | 495 | * "debounce" times, TSADC controller will generate interrupt or TSHUT. |
451 | */ | 496 | */ |
452 | static void rk_tsadcv2_initialize(void __iomem *regs, | 497 | static void rk_tsadcv2_initialize(struct regmap *grf, void __iomem *regs, |
453 | enum tshut_polarity tshut_polarity) | 498 | enum tshut_polarity tshut_polarity) |
454 | { | 499 | { |
455 | if (tshut_polarity == TSHUT_HIGH_ACTIVE) | 500 | if (tshut_polarity == TSHUT_HIGH_ACTIVE) |
@@ -466,6 +511,62 @@ static void rk_tsadcv2_initialize(void __iomem *regs, | |||
466 | regs + TSADCV2_AUTO_PERIOD_HT); | 511 | regs + TSADCV2_AUTO_PERIOD_HT); |
467 | writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, | 512 | writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, |
468 | regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); | 513 | regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); |
514 | |||
515 | if (IS_ERR(grf)) { | ||
516 | pr_warn("%s: Missing rockchip,grf property\n", __func__); | ||
517 | return; | ||
518 | } | ||
519 | } | ||
520 | |||
521 | /** | ||
522 | * rk_tsadcv3_initialize - initialize TASDC Controller. | ||
523 | * | ||
524 | * (1) The tsadc control power sequence. | ||
525 | * | ||
526 | * (2) Set TSADC_V2_AUTO_PERIOD: | ||
527 | * Configure the interleave between every two accessing of | ||
528 | * TSADC in normal operation. | ||
529 | * | ||
530 | * (2) Set TSADCV2_AUTO_PERIOD_HT: | ||
531 | * Configure the interleave between every two accessing of | ||
532 | * TSADC after the temperature is higher than COM_SHUT or COM_INT. | ||
533 | * | ||
534 | * (3) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE: | ||
535 | * If the temperature is higher than COMP_INT or COMP_SHUT for | ||
536 | * "debounce" times, TSADC controller will generate interrupt or TSHUT. | ||
537 | */ | ||
538 | static void rk_tsadcv3_initialize(struct regmap *grf, void __iomem *regs, | ||
539 | enum tshut_polarity tshut_polarity) | ||
540 | { | ||
541 | /* The tsadc control power sequence */ | ||
542 | if (IS_ERR(grf)) { | ||
543 | /* Set interleave value to workround ic time sync issue */ | ||
544 | writel_relaxed(TSADCV2_USER_INTER_PD_SOC, regs + | ||
545 | TSADCV2_USER_CON); | ||
546 | } else { | ||
547 | regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_TSEN_PD_ON); | ||
548 | mdelay(10); | ||
549 | regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_TSEN_PD_OFF); | ||
550 | usleep_range(15, 100); /* The spec note says at least 15 us */ | ||
551 | regmap_write(grf, GRF_SARADC_TESTBIT, GRF_SARADC_TESTBIT_ON); | ||
552 | regmap_write(grf, GRF_TSADC_TESTBIT_H, GRF_TSADC_TESTBIT_H_ON); | ||
553 | usleep_range(90, 200); /* The spec note says at least 90 us */ | ||
554 | } | ||
555 | |||
556 | if (tshut_polarity == TSHUT_HIGH_ACTIVE) | ||
557 | writel_relaxed(0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH, | ||
558 | regs + TSADCV2_AUTO_CON); | ||
559 | else | ||
560 | writel_relaxed(0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH, | ||
561 | regs + TSADCV2_AUTO_CON); | ||
562 | |||
563 | writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD); | ||
564 | writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, | ||
565 | regs + TSADCV2_HIGHT_INT_DEBOUNCE); | ||
566 | writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, | ||
567 | regs + TSADCV2_AUTO_PERIOD_HT); | ||
568 | writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, | ||
569 | regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); | ||
469 | } | 570 | } |
470 | 571 | ||
471 | static void rk_tsadcv2_irq_ack(void __iomem *regs) | 572 | static void rk_tsadcv2_irq_ack(void __iomem *regs) |
@@ -498,10 +599,11 @@ static void rk_tsadcv2_control(void __iomem *regs, bool enable) | |||
498 | } | 599 | } |
499 | 600 | ||
500 | /** | 601 | /** |
501 | * @rk_tsadcv3_control: | 602 | * rk_tsadcv3_control - the tsadc controller is enabled or disabled. |
502 | * TSADC controller works at auto mode, and some SoCs need set the tsadc_q_sel | 603 | * |
503 | * bit on TSADCV2_AUTO_CON[1]. The (1024 - tsadc_q) as output adc value if | 604 | * NOTE: TSADC controller works at auto mode, and some SoCs need set the |
504 | * setting this bit to enable. | 605 | * tsadc_q_sel bit on TSADCV2_AUTO_CON[1]. The (1024 - tsadc_q) as output |
606 | * adc value if setting this bit to enable. | ||
505 | */ | 607 | */ |
506 | static void rk_tsadcv3_control(void __iomem *regs, bool enable) | 608 | static void rk_tsadcv3_control(void __iomem *regs, bool enable) |
507 | { | 609 | { |
@@ -603,6 +705,30 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = { | |||
603 | }, | 705 | }, |
604 | }; | 706 | }; |
605 | 707 | ||
708 | static const struct rockchip_tsadc_chip rk3366_tsadc_data = { | ||
709 | .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ | ||
710 | .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */ | ||
711 | .chn_num = 2, /* two channels for tsadc */ | ||
712 | |||
713 | .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ | ||
714 | .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ | ||
715 | .tshut_temp = 95000, | ||
716 | |||
717 | .initialize = rk_tsadcv3_initialize, | ||
718 | .irq_ack = rk_tsadcv3_irq_ack, | ||
719 | .control = rk_tsadcv3_control, | ||
720 | .get_temp = rk_tsadcv2_get_temp, | ||
721 | .set_tshut_temp = rk_tsadcv2_tshut_temp, | ||
722 | .set_tshut_mode = rk_tsadcv2_tshut_mode, | ||
723 | |||
724 | .table = { | ||
725 | .id = rk3228_code_table, | ||
726 | .length = ARRAY_SIZE(rk3228_code_table), | ||
727 | .data_mask = TSADCV3_DATA_MASK, | ||
728 | .mode = ADC_INCREMENT, | ||
729 | }, | ||
730 | }; | ||
731 | |||
606 | static const struct rockchip_tsadc_chip rk3368_tsadc_data = { | 732 | static const struct rockchip_tsadc_chip rk3368_tsadc_data = { |
607 | .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ | 733 | .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ |
608 | .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */ | 734 | .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */ |
@@ -636,7 +762,7 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = { | |||
636 | .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ | 762 | .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ |
637 | .tshut_temp = 95000, | 763 | .tshut_temp = 95000, |
638 | 764 | ||
639 | .initialize = rk_tsadcv2_initialize, | 765 | .initialize = rk_tsadcv3_initialize, |
640 | .irq_ack = rk_tsadcv3_irq_ack, | 766 | .irq_ack = rk_tsadcv3_irq_ack, |
641 | .control = rk_tsadcv3_control, | 767 | .control = rk_tsadcv3_control, |
642 | .get_temp = rk_tsadcv2_get_temp, | 768 | .get_temp = rk_tsadcv2_get_temp, |
@@ -661,6 +787,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = { | |||
661 | .data = (void *)&rk3288_tsadc_data, | 787 | .data = (void *)&rk3288_tsadc_data, |
662 | }, | 788 | }, |
663 | { | 789 | { |
790 | .compatible = "rockchip,rk3366-tsadc", | ||
791 | .data = (void *)&rk3366_tsadc_data, | ||
792 | }, | ||
793 | { | ||
664 | .compatible = "rockchip,rk3368-tsadc", | 794 | .compatible = "rockchip,rk3368-tsadc", |
665 | .data = (void *)&rk3368_tsadc_data, | 795 | .data = (void *)&rk3368_tsadc_data, |
666 | }, | 796 | }, |
@@ -768,6 +898,11 @@ static int rockchip_configure_from_dt(struct device *dev, | |||
768 | return -EINVAL; | 898 | return -EINVAL; |
769 | } | 899 | } |
770 | 900 | ||
901 | /* The tsadc wont to handle the error in here since some SoCs didn't | ||
902 | * need this property. | ||
903 | */ | ||
904 | thermal->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); | ||
905 | |||
771 | return 0; | 906 | return 0; |
772 | } | 907 | } |
773 | 908 | ||
@@ -786,8 +921,8 @@ rockchip_thermal_register_sensor(struct platform_device *pdev, | |||
786 | 921 | ||
787 | sensor->thermal = thermal; | 922 | sensor->thermal = thermal; |
788 | sensor->id = id; | 923 | sensor->id = id; |
789 | sensor->tzd = thermal_zone_of_sensor_register(&pdev->dev, id, sensor, | 924 | sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, id, |
790 | &rockchip_of_thermal_ops); | 925 | sensor, &rockchip_of_thermal_ops); |
791 | if (IS_ERR(sensor->tzd)) { | 926 | if (IS_ERR(sensor->tzd)) { |
792 | error = PTR_ERR(sensor->tzd); | 927 | error = PTR_ERR(sensor->tzd); |
793 | dev_err(&pdev->dev, "failed to register sensor %d: %d\n", | 928 | dev_err(&pdev->dev, "failed to register sensor %d: %d\n", |
@@ -815,7 +950,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev) | |||
815 | const struct of_device_id *match; | 950 | const struct of_device_id *match; |
816 | struct resource *res; | 951 | struct resource *res; |
817 | int irq; | 952 | int irq; |
818 | int i, j; | 953 | int i; |
819 | int error; | 954 | int error; |
820 | 955 | ||
821 | match = of_match_node(of_rockchip_thermal_match, np); | 956 | match = of_match_node(of_rockchip_thermal_match, np); |
@@ -888,7 +1023,8 @@ static int rockchip_thermal_probe(struct platform_device *pdev) | |||
888 | goto err_disable_pclk; | 1023 | goto err_disable_pclk; |
889 | } | 1024 | } |
890 | 1025 | ||
891 | thermal->chip->initialize(thermal->regs, thermal->tshut_polarity); | 1026 | thermal->chip->initialize(thermal->grf, thermal->regs, |
1027 | thermal->tshut_polarity); | ||
892 | 1028 | ||
893 | for (i = 0; i < thermal->chip->chn_num; i++) { | 1029 | for (i = 0; i < thermal->chip->chn_num; i++) { |
894 | error = rockchip_thermal_register_sensor(pdev, thermal, | 1030 | error = rockchip_thermal_register_sensor(pdev, thermal, |
@@ -898,9 +1034,6 @@ static int rockchip_thermal_probe(struct platform_device *pdev) | |||
898 | dev_err(&pdev->dev, | 1034 | dev_err(&pdev->dev, |
899 | "failed to register sensor[%d] : error = %d\n", | 1035 | "failed to register sensor[%d] : error = %d\n", |
900 | i, error); | 1036 | i, error); |
901 | for (j = 0; j < i; j++) | ||
902 | thermal_zone_of_sensor_unregister(&pdev->dev, | ||
903 | thermal->sensors[j].tzd); | ||
904 | goto err_disable_pclk; | 1037 | goto err_disable_pclk; |
905 | } | 1038 | } |
906 | } | 1039 | } |
@@ -912,7 +1045,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev) | |||
912 | if (error) { | 1045 | if (error) { |
913 | dev_err(&pdev->dev, | 1046 | dev_err(&pdev->dev, |
914 | "failed to request tsadc irq: %d\n", error); | 1047 | "failed to request tsadc irq: %d\n", error); |
915 | goto err_unregister_sensor; | 1048 | goto err_disable_pclk; |
916 | } | 1049 | } |
917 | 1050 | ||
918 | thermal->chip->control(thermal->regs, true); | 1051 | thermal->chip->control(thermal->regs, true); |
@@ -924,11 +1057,6 @@ static int rockchip_thermal_probe(struct platform_device *pdev) | |||
924 | 1057 | ||
925 | return 0; | 1058 | return 0; |
926 | 1059 | ||
927 | err_unregister_sensor: | ||
928 | while (i--) | ||
929 | thermal_zone_of_sensor_unregister(&pdev->dev, | ||
930 | thermal->sensors[i].tzd); | ||
931 | |||
932 | err_disable_pclk: | 1060 | err_disable_pclk: |
933 | clk_disable_unprepare(thermal->pclk); | 1061 | clk_disable_unprepare(thermal->pclk); |
934 | err_disable_clk: | 1062 | err_disable_clk: |
@@ -946,7 +1074,6 @@ static int rockchip_thermal_remove(struct platform_device *pdev) | |||
946 | struct rockchip_thermal_sensor *sensor = &thermal->sensors[i]; | 1074 | struct rockchip_thermal_sensor *sensor = &thermal->sensors[i]; |
947 | 1075 | ||
948 | rockchip_thermal_toggle_sensor(sensor, false); | 1076 | rockchip_thermal_toggle_sensor(sensor, false); |
949 | thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd); | ||
950 | } | 1077 | } |
951 | 1078 | ||
952 | thermal->chip->control(thermal->regs, false); | 1079 | thermal->chip->control(thermal->regs, false); |
@@ -988,12 +1115,15 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev) | |||
988 | return error; | 1115 | return error; |
989 | 1116 | ||
990 | error = clk_enable(thermal->pclk); | 1117 | error = clk_enable(thermal->pclk); |
991 | if (error) | 1118 | if (error) { |
1119 | clk_disable(thermal->clk); | ||
992 | return error; | 1120 | return error; |
1121 | } | ||
993 | 1122 | ||
994 | rockchip_thermal_reset_controller(thermal->reset); | 1123 | rockchip_thermal_reset_controller(thermal->reset); |
995 | 1124 | ||
996 | thermal->chip->initialize(thermal->regs, thermal->tshut_polarity); | 1125 | thermal->chip->initialize(thermal->grf, thermal->regs, |
1126 | thermal->tshut_polarity); | ||
997 | 1127 | ||
998 | for (i = 0; i < thermal->chip->chn_num; i++) { | 1128 | for (i = 0; i < thermal->chip->chn_num; i++) { |
999 | int id = thermal->sensors[i].id; | 1129 | int id = thermal->sensors[i].id; |
diff --git a/drivers/thermal/tango_thermal.c b/drivers/thermal/tango_thermal.c new file mode 100644 index 000000000000..70e0d9f406e9 --- /dev/null +++ b/drivers/thermal/tango_thermal.c | |||
@@ -0,0 +1,109 @@ | |||
1 | #include <linux/io.h> | ||
2 | #include <linux/delay.h> | ||
3 | #include <linux/module.h> | ||
4 | #include <linux/thermal.h> | ||
5 | #include <linux/platform_device.h> | ||
6 | |||
7 | /* | ||
8 | * According to a data sheet draft, "this temperature sensor uses a bandgap | ||
9 | * type of circuit to compare a voltage which has a negative temperature | ||
10 | * coefficient with a voltage that is proportional to absolute temperature. | ||
11 | * A resistor bank allows 41 different temperature thresholds to be selected | ||
12 | * and the logic output will then indicate whether the actual die temperature | ||
13 | * lies above or below the selected threshold." | ||
14 | */ | ||
15 | |||
16 | #define TEMPSI_CMD 0 | ||
17 | #define TEMPSI_RES 4 | ||
18 | #define TEMPSI_CFG 8 | ||
19 | |||
20 | #define CMD_OFF 0 | ||
21 | #define CMD_ON 1 | ||
22 | #define CMD_READ 2 | ||
23 | |||
24 | #define IDX_MIN 15 | ||
25 | #define IDX_MAX 40 | ||
26 | |||
27 | struct tango_thermal_priv { | ||
28 | void __iomem *base; | ||
29 | int thresh_idx; | ||
30 | }; | ||
31 | |||
32 | static bool temp_above_thresh(void __iomem *base, int thresh_idx) | ||
33 | { | ||
34 | writel(CMD_READ | thresh_idx << 8, base + TEMPSI_CMD); | ||
35 | usleep_range(10, 20); | ||
36 | writel(CMD_READ | thresh_idx << 8, base + TEMPSI_CMD); | ||
37 | |||
38 | return readl(base + TEMPSI_RES); | ||
39 | } | ||
40 | |||
41 | static int tango_get_temp(void *arg, int *res) | ||
42 | { | ||
43 | struct tango_thermal_priv *priv = arg; | ||
44 | int idx = priv->thresh_idx; | ||
45 | |||
46 | if (temp_above_thresh(priv->base, idx)) { | ||
47 | /* Search upward by incrementing thresh_idx */ | ||
48 | while (idx < IDX_MAX && temp_above_thresh(priv->base, ++idx)) | ||
49 | cpu_relax(); | ||
50 | idx = idx - 1; /* always return lower bound */ | ||
51 | } else { | ||
52 | /* Search downward by decrementing thresh_idx */ | ||
53 | while (idx > IDX_MIN && !temp_above_thresh(priv->base, --idx)) | ||
54 | cpu_relax(); | ||
55 | } | ||
56 | |||
57 | *res = (idx * 9 / 2 - 38) * 1000; /* millidegrees Celsius */ | ||
58 | priv->thresh_idx = idx; | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static const struct thermal_zone_of_device_ops ops = { | ||
64 | .get_temp = tango_get_temp, | ||
65 | }; | ||
66 | |||
67 | static int tango_thermal_probe(struct platform_device *pdev) | ||
68 | { | ||
69 | struct resource *res; | ||
70 | struct tango_thermal_priv *priv; | ||
71 | struct thermal_zone_device *tzdev; | ||
72 | |||
73 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
74 | if (!priv) | ||
75 | return -ENOMEM; | ||
76 | |||
77 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
78 | priv->base = devm_ioremap_resource(&pdev->dev, res); | ||
79 | if (IS_ERR(priv->base)) | ||
80 | return PTR_ERR(priv->base); | ||
81 | |||
82 | priv->thresh_idx = IDX_MIN; | ||
83 | writel(0, priv->base + TEMPSI_CFG); | ||
84 | writel(CMD_ON, priv->base + TEMPSI_CMD); | ||
85 | |||
86 | tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &ops); | ||
87 | return PTR_ERR_OR_ZERO(tzdev); | ||
88 | } | ||
89 | |||
90 | static const struct of_device_id tango_sensor_ids[] = { | ||
91 | { | ||
92 | .compatible = "sigma,smp8758-thermal", | ||
93 | }, | ||
94 | { /* sentinel */ } | ||
95 | }; | ||
96 | |||
97 | static struct platform_driver tango_thermal_driver = { | ||
98 | .probe = tango_thermal_probe, | ||
99 | .driver = { | ||
100 | .name = "tango-thermal", | ||
101 | .of_match_table = tango_sensor_ids, | ||
102 | }, | ||
103 | }; | ||
104 | |||
105 | module_platform_driver(tango_thermal_driver); | ||
106 | |||
107 | MODULE_LICENSE("GPL"); | ||
108 | MODULE_AUTHOR("Sigma Designs"); | ||
109 | MODULE_DESCRIPTION("Tango temperature sensor"); | ||
diff --git a/drivers/thermal/tegra/Kconfig b/drivers/thermal/tegra/Kconfig new file mode 100644 index 000000000000..cec586ec7e4b --- /dev/null +++ b/drivers/thermal/tegra/Kconfig | |||
@@ -0,0 +1,13 @@ | |||
1 | menu "NVIDIA Tegra thermal drivers" | ||
2 | depends on ARCH_TEGRA | ||
3 | |||
4 | config TEGRA_SOCTHERM | ||
5 | tristate "Tegra SOCTHERM thermal management" | ||
6 | help | ||
7 | Enable this option for integrated thermal management support on NVIDIA | ||
8 | Tegra systems-on-chip. The driver supports four thermal zones | ||
9 | (CPU, GPU, MEM, PLLX). Cooling devices can be bound to the thermal | ||
10 | zones to manage temperatures. This option is also required for the | ||
11 | emergency thermal reset (thermtrip) feature to function. | ||
12 | |||
13 | endmenu | ||
diff --git a/drivers/thermal/tegra/Makefile b/drivers/thermal/tegra/Makefile new file mode 100644 index 000000000000..1ce1af2cf0f5 --- /dev/null +++ b/drivers/thermal/tegra/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o | ||
2 | |||
3 | tegra-soctherm-y := soctherm.o soctherm-fuse.o | ||
4 | tegra-soctherm-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124-soctherm.o | ||
5 | tegra-soctherm-$(CONFIG_ARCH_TEGRA_132_SOC) += tegra132-soctherm.o | ||
6 | tegra-soctherm-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-soctherm.o | ||
diff --git a/drivers/thermal/tegra/soctherm-fuse.c b/drivers/thermal/tegra/soctherm-fuse.c new file mode 100644 index 000000000000..29963180c453 --- /dev/null +++ b/drivers/thermal/tegra/soctherm-fuse.c | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This software is licensed under the terms of the GNU General Public | ||
5 | * License version 2, as published by the Free Software Foundation, and | ||
6 | * may be copied, distributed, and modified under those terms. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <soc/tegra/fuse.h> | ||
18 | |||
19 | #include "soctherm.h" | ||
20 | |||
21 | #define NOMINAL_CALIB_FT 105 | ||
22 | #define NOMINAL_CALIB_CP 25 | ||
23 | |||
24 | #define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK 0x1fff | ||
25 | #define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK (0x1fff << 13) | ||
26 | #define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13 | ||
27 | |||
28 | #define FUSE_TSENSOR_COMMON 0x180 | ||
29 | |||
30 | /* | ||
31 | * Tegra210: Layout of bits in FUSE_TSENSOR_COMMON: | ||
32 | * 3 2 1 0 | ||
33 | * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 | ||
34 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
35 | * | BASE_FT | BASE_CP | SHFT_FT | SHIFT_CP | | ||
36 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
37 | * | ||
38 | * Tegra12x, etc: | ||
39 | * In chips prior to Tegra210, this fuse was incorrectly sized as 26 bits, | ||
40 | * and didn't hold SHIFT_CP in [31:26]. Therefore these missing six bits | ||
41 | * were obtained via the FUSE_SPARE_REALIGNMENT_REG register [5:0]. | ||
42 | * | ||
43 | * FUSE_TSENSOR_COMMON: | ||
44 | * 3 2 1 0 | ||
45 | * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 | ||
46 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
47 | * |-----------| SHFT_FT | BASE_FT | BASE_CP | | ||
48 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
49 | * | ||
50 | * FUSE_SPARE_REALIGNMENT_REG: | ||
51 | * 3 2 1 0 | ||
52 | * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 | ||
53 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
54 | * |---------------------------------------------------| SHIFT_CP | | ||
55 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
56 | */ | ||
57 | |||
58 | #define CALIB_COEFFICIENT 1000000LL | ||
59 | |||
60 | /** | ||
61 | * div64_s64_precise() - wrapper for div64_s64() | ||
62 | * @a: the dividend | ||
63 | * @b: the divisor | ||
64 | * | ||
65 | * Implements division with fairly accurate rounding instead of truncation by | ||
66 | * shifting the dividend to the left by 16 so that the quotient has a | ||
67 | * much higher precision. | ||
68 | * | ||
69 | * Return: the quotient of a / b. | ||
70 | */ | ||
71 | static s64 div64_s64_precise(s64 a, s32 b) | ||
72 | { | ||
73 | s64 r, al; | ||
74 | |||
75 | /* Scale up for increased precision division */ | ||
76 | al = a << 16; | ||
77 | |||
78 | r = div64_s64(al * 2 + 1, 2 * b); | ||
79 | return r >> 16; | ||
80 | } | ||
81 | |||
82 | int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse, | ||
83 | struct tsensor_shared_calib *shared) | ||
84 | { | ||
85 | u32 val; | ||
86 | s32 shifted_cp, shifted_ft; | ||
87 | int err; | ||
88 | |||
89 | err = tegra_fuse_readl(FUSE_TSENSOR_COMMON, &val); | ||
90 | if (err) | ||
91 | return err; | ||
92 | |||
93 | shared->base_cp = (val & tfuse->fuse_base_cp_mask) >> | ||
94 | tfuse->fuse_base_cp_shift; | ||
95 | shared->base_ft = (val & tfuse->fuse_base_ft_mask) >> | ||
96 | tfuse->fuse_base_ft_shift; | ||
97 | |||
98 | shifted_ft = (val & tfuse->fuse_shift_ft_mask) >> | ||
99 | tfuse->fuse_shift_ft_shift; | ||
100 | shifted_ft = sign_extend32(shifted_ft, 4); | ||
101 | |||
102 | if (tfuse->fuse_spare_realignment) { | ||
103 | err = tegra_fuse_readl(tfuse->fuse_spare_realignment, &val); | ||
104 | if (err) | ||
105 | return err; | ||
106 | } | ||
107 | |||
108 | shifted_cp = sign_extend32(val, 5); | ||
109 | |||
110 | shared->actual_temp_cp = 2 * NOMINAL_CALIB_CP + shifted_cp; | ||
111 | shared->actual_temp_ft = 2 * NOMINAL_CALIB_FT + shifted_ft; | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | int tegra_calc_tsensor_calib(const struct tegra_tsensor *sensor, | ||
117 | const struct tsensor_shared_calib *shared, | ||
118 | u32 *calibration) | ||
119 | { | ||
120 | const struct tegra_tsensor_group *sensor_group; | ||
121 | u32 val, calib; | ||
122 | s32 actual_tsensor_ft, actual_tsensor_cp; | ||
123 | s32 delta_sens, delta_temp; | ||
124 | s32 mult, div; | ||
125 | s16 therma, thermb; | ||
126 | s64 temp; | ||
127 | int err; | ||
128 | |||
129 | sensor_group = sensor->group; | ||
130 | |||
131 | err = tegra_fuse_readl(sensor->calib_fuse_offset, &val); | ||
132 | if (err) | ||
133 | return err; | ||
134 | |||
135 | actual_tsensor_cp = (shared->base_cp * 64) + sign_extend32(val, 12); | ||
136 | val = (val & FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK) >> | ||
137 | FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT; | ||
138 | actual_tsensor_ft = (shared->base_ft * 32) + sign_extend32(val, 12); | ||
139 | |||
140 | delta_sens = actual_tsensor_ft - actual_tsensor_cp; | ||
141 | delta_temp = shared->actual_temp_ft - shared->actual_temp_cp; | ||
142 | |||
143 | mult = sensor_group->pdiv * sensor->config->tsample_ate; | ||
144 | div = sensor->config->tsample * sensor_group->pdiv_ate; | ||
145 | |||
146 | temp = (s64)delta_temp * (1LL << 13) * mult; | ||
147 | therma = div64_s64_precise(temp, (s64)delta_sens * div); | ||
148 | |||
149 | temp = ((s64)actual_tsensor_ft * shared->actual_temp_cp) - | ||
150 | ((s64)actual_tsensor_cp * shared->actual_temp_ft); | ||
151 | thermb = div64_s64_precise(temp, delta_sens); | ||
152 | |||
153 | temp = (s64)therma * sensor->fuse_corr_alpha; | ||
154 | therma = div64_s64_precise(temp, CALIB_COEFFICIENT); | ||
155 | |||
156 | temp = (s64)thermb * sensor->fuse_corr_alpha + sensor->fuse_corr_beta; | ||
157 | thermb = div64_s64_precise(temp, CALIB_COEFFICIENT); | ||
158 | |||
159 | calib = ((u16)therma << SENSOR_CONFIG2_THERMA_SHIFT) | | ||
160 | ((u16)thermb << SENSOR_CONFIG2_THERMB_SHIFT); | ||
161 | |||
162 | *calibration = calib; | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | MODULE_AUTHOR("Wei Ni <wni@nvidia.com>"); | ||
168 | MODULE_DESCRIPTION("Tegra SOCTHERM fuse management"); | ||
169 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c new file mode 100644 index 000000000000..b8651726201e --- /dev/null +++ b/drivers/thermal/tegra/soctherm.c | |||
@@ -0,0 +1,685 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Author: | ||
5 | * Mikko Perttunen <mperttunen@nvidia.com> | ||
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 | */ | ||
17 | |||
18 | #include <linux/debugfs.h> | ||
19 | #include <linux/bitops.h> | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/of.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/reset.h> | ||
29 | #include <linux/thermal.h> | ||
30 | |||
31 | #include <dt-bindings/thermal/tegra124-soctherm.h> | ||
32 | |||
33 | #include "soctherm.h" | ||
34 | |||
35 | #define SENSOR_CONFIG0 0 | ||
36 | #define SENSOR_CONFIG0_STOP BIT(0) | ||
37 | #define SENSOR_CONFIG0_CPTR_OVER BIT(2) | ||
38 | #define SENSOR_CONFIG0_OVER BIT(3) | ||
39 | #define SENSOR_CONFIG0_TCALC_OVER BIT(4) | ||
40 | #define SENSOR_CONFIG0_TALL_MASK (0xfffff << 8) | ||
41 | #define SENSOR_CONFIG0_TALL_SHIFT 8 | ||
42 | |||
43 | #define SENSOR_CONFIG1 4 | ||
44 | #define SENSOR_CONFIG1_TSAMPLE_MASK 0x3ff | ||
45 | #define SENSOR_CONFIG1_TSAMPLE_SHIFT 0 | ||
46 | #define SENSOR_CONFIG1_TIDDQ_EN_MASK (0x3f << 15) | ||
47 | #define SENSOR_CONFIG1_TIDDQ_EN_SHIFT 15 | ||
48 | #define SENSOR_CONFIG1_TEN_COUNT_MASK (0x3f << 24) | ||
49 | #define SENSOR_CONFIG1_TEN_COUNT_SHIFT 24 | ||
50 | #define SENSOR_CONFIG1_TEMP_ENABLE BIT(31) | ||
51 | |||
52 | /* | ||
53 | * SENSOR_CONFIG2 is defined in soctherm.h | ||
54 | * because, it will be used by tegra_soctherm_fuse.c | ||
55 | */ | ||
56 | |||
57 | #define SENSOR_STATUS0 0xc | ||
58 | #define SENSOR_STATUS0_VALID_MASK BIT(31) | ||
59 | #define SENSOR_STATUS0_CAPTURE_MASK 0xffff | ||
60 | |||
61 | #define SENSOR_STATUS1 0x10 | ||
62 | #define SENSOR_STATUS1_TEMP_VALID_MASK BIT(31) | ||
63 | #define SENSOR_STATUS1_TEMP_MASK 0xffff | ||
64 | |||
65 | #define READBACK_VALUE_MASK 0xff00 | ||
66 | #define READBACK_VALUE_SHIFT 8 | ||
67 | #define READBACK_ADD_HALF BIT(7) | ||
68 | #define READBACK_NEGATE BIT(0) | ||
69 | |||
70 | /* get val from register(r) mask bits(m) */ | ||
71 | #define REG_GET_MASK(r, m) (((r) & (m)) >> (ffs(m) - 1)) | ||
72 | /* set val(v) to mask bits(m) of register(r) */ | ||
73 | #define REG_SET_MASK(r, m, v) (((r) & ~(m)) | \ | ||
74 | (((v) & (m >> (ffs(m) - 1))) << (ffs(m) - 1))) | ||
75 | |||
76 | static const int min_low_temp = -127000; | ||
77 | static const int max_high_temp = 127000; | ||
78 | |||
79 | struct tegra_thermctl_zone { | ||
80 | void __iomem *reg; | ||
81 | struct device *dev; | ||
82 | struct thermal_zone_device *tz; | ||
83 | const struct tegra_tsensor_group *sg; | ||
84 | }; | ||
85 | |||
86 | struct tegra_soctherm { | ||
87 | struct reset_control *reset; | ||
88 | struct clk *clock_tsensor; | ||
89 | struct clk *clock_soctherm; | ||
90 | void __iomem *regs; | ||
91 | struct thermal_zone_device **thermctl_tzs; | ||
92 | |||
93 | u32 *calib; | ||
94 | struct tegra_soctherm_soc *soc; | ||
95 | |||
96 | struct dentry *debugfs_dir; | ||
97 | }; | ||
98 | |||
99 | static void enable_tsensor(struct tegra_soctherm *tegra, unsigned int i) | ||
100 | { | ||
101 | const struct tegra_tsensor *sensor = &tegra->soc->tsensors[i]; | ||
102 | void __iomem *base = tegra->regs + sensor->base; | ||
103 | unsigned int val; | ||
104 | |||
105 | val = sensor->config->tall << SENSOR_CONFIG0_TALL_SHIFT; | ||
106 | writel(val, base + SENSOR_CONFIG0); | ||
107 | |||
108 | val = (sensor->config->tsample - 1) << SENSOR_CONFIG1_TSAMPLE_SHIFT; | ||
109 | val |= sensor->config->tiddq_en << SENSOR_CONFIG1_TIDDQ_EN_SHIFT; | ||
110 | val |= sensor->config->ten_count << SENSOR_CONFIG1_TEN_COUNT_SHIFT; | ||
111 | val |= SENSOR_CONFIG1_TEMP_ENABLE; | ||
112 | writel(val, base + SENSOR_CONFIG1); | ||
113 | |||
114 | writel(tegra->calib[i], base + SENSOR_CONFIG2); | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * Translate from soctherm readback format to millicelsius. | ||
119 | * The soctherm readback format in bits is as follows: | ||
120 | * TTTTTTTT H______N | ||
121 | * where T's contain the temperature in Celsius, | ||
122 | * H denotes an addition of 0.5 Celsius and N denotes negation | ||
123 | * of the final value. | ||
124 | */ | ||
125 | static int translate_temp(u16 val) | ||
126 | { | ||
127 | int t; | ||
128 | |||
129 | t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000; | ||
130 | if (val & READBACK_ADD_HALF) | ||
131 | t += 500; | ||
132 | if (val & READBACK_NEGATE) | ||
133 | t *= -1; | ||
134 | |||
135 | return t; | ||
136 | } | ||
137 | |||
138 | static int tegra_thermctl_get_temp(void *data, int *out_temp) | ||
139 | { | ||
140 | struct tegra_thermctl_zone *zone = data; | ||
141 | u32 val; | ||
142 | |||
143 | val = readl(zone->reg); | ||
144 | val = REG_GET_MASK(val, zone->sg->sensor_temp_mask); | ||
145 | *out_temp = translate_temp(val); | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int | ||
151 | thermtrip_program(struct device *dev, const struct tegra_tsensor_group *sg, | ||
152 | int trip_temp); | ||
153 | |||
154 | static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp) | ||
155 | { | ||
156 | struct tegra_thermctl_zone *zone = data; | ||
157 | struct thermal_zone_device *tz = zone->tz; | ||
158 | const struct tegra_tsensor_group *sg = zone->sg; | ||
159 | struct device *dev = zone->dev; | ||
160 | enum thermal_trip_type type; | ||
161 | int ret; | ||
162 | |||
163 | if (!tz) | ||
164 | return -EINVAL; | ||
165 | |||
166 | ret = tz->ops->get_trip_type(tz, trip, &type); | ||
167 | if (ret) | ||
168 | return ret; | ||
169 | |||
170 | if (type != THERMAL_TRIP_CRITICAL) | ||
171 | return 0; | ||
172 | |||
173 | return thermtrip_program(dev, sg, temp); | ||
174 | } | ||
175 | |||
176 | static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = { | ||
177 | .get_temp = tegra_thermctl_get_temp, | ||
178 | .set_trip_temp = tegra_thermctl_set_trip_temp, | ||
179 | }; | ||
180 | |||
181 | /** | ||
182 | * enforce_temp_range() - check and enforce temperature range [min, max] | ||
183 | * @trip_temp: the trip temperature to check | ||
184 | * | ||
185 | * Checks and enforces the permitted temperature range that SOC_THERM | ||
186 | * HW can support This is | ||
187 | * done while taking care of precision. | ||
188 | * | ||
189 | * Return: The precision adjusted capped temperature in millicelsius. | ||
190 | */ | ||
191 | static int enforce_temp_range(struct device *dev, int trip_temp) | ||
192 | { | ||
193 | int temp; | ||
194 | |||
195 | temp = clamp_val(trip_temp, min_low_temp, max_high_temp); | ||
196 | if (temp != trip_temp) | ||
197 | dev_info(dev, "soctherm: trip temperature %d forced to %d\n", | ||
198 | trip_temp, temp); | ||
199 | return temp; | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * thermtrip_program() - Configures the hardware to shut down the | ||
204 | * system if a given sensor group reaches a given temperature | ||
205 | * @dev: ptr to the struct device for the SOC_THERM IP block | ||
206 | * @sg: pointer to the sensor group to set the thermtrip temperature for | ||
207 | * @trip_temp: the temperature in millicelsius to trigger the thermal trip at | ||
208 | * | ||
209 | * Sets the thermal trip threshold of the given sensor group to be the | ||
210 | * @trip_temp. If this threshold is crossed, the hardware will shut | ||
211 | * down. | ||
212 | * | ||
213 | * Note that, although @trip_temp is specified in millicelsius, the | ||
214 | * hardware is programmed in degrees Celsius. | ||
215 | * | ||
216 | * Return: 0 upon success, or %-EINVAL upon failure. | ||
217 | */ | ||
218 | static int thermtrip_program(struct device *dev, | ||
219 | const struct tegra_tsensor_group *sg, | ||
220 | int trip_temp) | ||
221 | { | ||
222 | struct tegra_soctherm *ts = dev_get_drvdata(dev); | ||
223 | int temp; | ||
224 | u32 r; | ||
225 | |||
226 | if (!sg || !sg->thermtrip_threshold_mask) | ||
227 | return -EINVAL; | ||
228 | |||
229 | temp = enforce_temp_range(dev, trip_temp) / ts->soc->thresh_grain; | ||
230 | |||
231 | r = readl(ts->regs + THERMCTL_THERMTRIP_CTL); | ||
232 | r = REG_SET_MASK(r, sg->thermtrip_threshold_mask, temp); | ||
233 | r = REG_SET_MASK(r, sg->thermtrip_enable_mask, 1); | ||
234 | r = REG_SET_MASK(r, sg->thermtrip_any_en_mask, 0); | ||
235 | writel(r, ts->regs + THERMCTL_THERMTRIP_CTL); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * tegra_soctherm_set_hwtrips() - set HW trip point from DT data | ||
242 | * @dev: struct device * of the SOC_THERM instance | ||
243 | * | ||
244 | * Configure the SOC_THERM HW trip points, setting "THERMTRIP" | ||
245 | * trip points , using "critical" type trip_temp from thermal | ||
246 | * zone. | ||
247 | * After they have been configured, THERMTRIP will take action | ||
248 | * when the configured SoC thermal sensor group reaches a | ||
249 | * certain temperature. | ||
250 | * | ||
251 | * Return: 0 upon success, or a negative error code on failure. | ||
252 | * "Success" does not mean that trips was enabled; it could also | ||
253 | * mean that no node was found in DT. | ||
254 | * THERMTRIP has been enabled successfully when a message similar to | ||
255 | * this one appears on the serial console: | ||
256 | * "thermtrip: will shut down when sensor group XXX reaches YYYYYY mC" | ||
257 | */ | ||
258 | static int tegra_soctherm_set_hwtrips(struct device *dev, | ||
259 | const struct tegra_tsensor_group *sg, | ||
260 | struct thermal_zone_device *tz) | ||
261 | { | ||
262 | int temperature; | ||
263 | int ret; | ||
264 | |||
265 | ret = tz->ops->get_crit_temp(tz, &temperature); | ||
266 | if (ret) { | ||
267 | dev_warn(dev, "thermtrip: %s: missing critical temperature\n", | ||
268 | sg->name); | ||
269 | return ret; | ||
270 | } | ||
271 | |||
272 | ret = thermtrip_program(dev, sg, temperature); | ||
273 | if (ret) { | ||
274 | dev_err(dev, "thermtrip: %s: error during enable\n", | ||
275 | sg->name); | ||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | dev_info(dev, | ||
280 | "thermtrip: will shut down when %s reaches %d mC\n", | ||
281 | sg->name, temperature); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | #ifdef CONFIG_DEBUG_FS | ||
287 | static int regs_show(struct seq_file *s, void *data) | ||
288 | { | ||
289 | struct platform_device *pdev = s->private; | ||
290 | struct tegra_soctherm *ts = platform_get_drvdata(pdev); | ||
291 | const struct tegra_tsensor *tsensors = ts->soc->tsensors; | ||
292 | const struct tegra_tsensor_group **ttgs = ts->soc->ttgs; | ||
293 | u32 r, state; | ||
294 | int i; | ||
295 | |||
296 | seq_puts(s, "-----TSENSE (convert HW)-----\n"); | ||
297 | |||
298 | for (i = 0; i < ts->soc->num_tsensors; i++) { | ||
299 | r = readl(ts->regs + tsensors[i].base + SENSOR_CONFIG1); | ||
300 | state = REG_GET_MASK(r, SENSOR_CONFIG1_TEMP_ENABLE); | ||
301 | |||
302 | seq_printf(s, "%s: ", tsensors[i].name); | ||
303 | seq_printf(s, "En(%d) ", state); | ||
304 | |||
305 | if (!state) { | ||
306 | seq_puts(s, "\n"); | ||
307 | continue; | ||
308 | } | ||
309 | |||
310 | state = REG_GET_MASK(r, SENSOR_CONFIG1_TIDDQ_EN_MASK); | ||
311 | seq_printf(s, "tiddq(%d) ", state); | ||
312 | state = REG_GET_MASK(r, SENSOR_CONFIG1_TEN_COUNT_MASK); | ||
313 | seq_printf(s, "ten_count(%d) ", state); | ||
314 | state = REG_GET_MASK(r, SENSOR_CONFIG1_TSAMPLE_MASK); | ||
315 | seq_printf(s, "tsample(%d) ", state + 1); | ||
316 | |||
317 | r = readl(ts->regs + tsensors[i].base + SENSOR_STATUS1); | ||
318 | state = REG_GET_MASK(r, SENSOR_STATUS1_TEMP_VALID_MASK); | ||
319 | seq_printf(s, "Temp(%d/", state); | ||
320 | state = REG_GET_MASK(r, SENSOR_STATUS1_TEMP_MASK); | ||
321 | seq_printf(s, "%d) ", translate_temp(state)); | ||
322 | |||
323 | r = readl(ts->regs + tsensors[i].base + SENSOR_STATUS0); | ||
324 | state = REG_GET_MASK(r, SENSOR_STATUS0_VALID_MASK); | ||
325 | seq_printf(s, "Capture(%d/", state); | ||
326 | state = REG_GET_MASK(r, SENSOR_STATUS0_CAPTURE_MASK); | ||
327 | seq_printf(s, "%d) ", state); | ||
328 | |||
329 | r = readl(ts->regs + tsensors[i].base + SENSOR_CONFIG0); | ||
330 | state = REG_GET_MASK(r, SENSOR_CONFIG0_STOP); | ||
331 | seq_printf(s, "Stop(%d) ", state); | ||
332 | state = REG_GET_MASK(r, SENSOR_CONFIG0_TALL_MASK); | ||
333 | seq_printf(s, "Tall(%d) ", state); | ||
334 | state = REG_GET_MASK(r, SENSOR_CONFIG0_TCALC_OVER); | ||
335 | seq_printf(s, "Over(%d/", state); | ||
336 | state = REG_GET_MASK(r, SENSOR_CONFIG0_OVER); | ||
337 | seq_printf(s, "%d/", state); | ||
338 | state = REG_GET_MASK(r, SENSOR_CONFIG0_CPTR_OVER); | ||
339 | seq_printf(s, "%d) ", state); | ||
340 | |||
341 | r = readl(ts->regs + tsensors[i].base + SENSOR_CONFIG2); | ||
342 | state = REG_GET_MASK(r, SENSOR_CONFIG2_THERMA_MASK); | ||
343 | seq_printf(s, "Therm_A/B(%d/", state); | ||
344 | state = REG_GET_MASK(r, SENSOR_CONFIG2_THERMB_MASK); | ||
345 | seq_printf(s, "%d)\n", (s16)state); | ||
346 | } | ||
347 | |||
348 | r = readl(ts->regs + SENSOR_PDIV); | ||
349 | seq_printf(s, "PDIV: 0x%x\n", r); | ||
350 | |||
351 | r = readl(ts->regs + SENSOR_HOTSPOT_OFF); | ||
352 | seq_printf(s, "HOTSPOT: 0x%x\n", r); | ||
353 | |||
354 | seq_puts(s, "\n"); | ||
355 | seq_puts(s, "-----SOC_THERM-----\n"); | ||
356 | |||
357 | r = readl(ts->regs + SENSOR_TEMP1); | ||
358 | state = REG_GET_MASK(r, SENSOR_TEMP1_CPU_TEMP_MASK); | ||
359 | seq_printf(s, "Temperatures: CPU(%d) ", translate_temp(state)); | ||
360 | state = REG_GET_MASK(r, SENSOR_TEMP1_GPU_TEMP_MASK); | ||
361 | seq_printf(s, " GPU(%d) ", translate_temp(state)); | ||
362 | r = readl(ts->regs + SENSOR_TEMP2); | ||
363 | state = REG_GET_MASK(r, SENSOR_TEMP2_PLLX_TEMP_MASK); | ||
364 | seq_printf(s, " PLLX(%d) ", translate_temp(state)); | ||
365 | state = REG_GET_MASK(r, SENSOR_TEMP2_MEM_TEMP_MASK); | ||
366 | seq_printf(s, " MEM(%d)\n", translate_temp(state)); | ||
367 | |||
368 | r = readl(ts->regs + THERMCTL_THERMTRIP_CTL); | ||
369 | state = REG_GET_MASK(r, ttgs[0]->thermtrip_any_en_mask); | ||
370 | seq_printf(s, "Thermtrip Any En(%d)\n", state); | ||
371 | for (i = 0; i < ts->soc->num_ttgs; i++) { | ||
372 | state = REG_GET_MASK(r, ttgs[i]->thermtrip_enable_mask); | ||
373 | seq_printf(s, " %s En(%d) ", ttgs[i]->name, state); | ||
374 | state = REG_GET_MASK(r, ttgs[i]->thermtrip_threshold_mask); | ||
375 | state *= ts->soc->thresh_grain; | ||
376 | seq_printf(s, "Thresh(%d)\n", state); | ||
377 | } | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static int regs_open(struct inode *inode, struct file *file) | ||
383 | { | ||
384 | return single_open(file, regs_show, inode->i_private); | ||
385 | } | ||
386 | |||
387 | static const struct file_operations regs_fops = { | ||
388 | .open = regs_open, | ||
389 | .read = seq_read, | ||
390 | .llseek = seq_lseek, | ||
391 | .release = single_release, | ||
392 | }; | ||
393 | |||
394 | static void soctherm_debug_init(struct platform_device *pdev) | ||
395 | { | ||
396 | struct tegra_soctherm *tegra = platform_get_drvdata(pdev); | ||
397 | struct dentry *root, *file; | ||
398 | |||
399 | root = debugfs_create_dir("soctherm", NULL); | ||
400 | if (!root) { | ||
401 | dev_err(&pdev->dev, "failed to create debugfs directory\n"); | ||
402 | return; | ||
403 | } | ||
404 | |||
405 | tegra->debugfs_dir = root; | ||
406 | |||
407 | file = debugfs_create_file("reg_contents", 0644, root, | ||
408 | pdev, ®s_fops); | ||
409 | if (!file) { | ||
410 | dev_err(&pdev->dev, "failed to create debugfs file\n"); | ||
411 | debugfs_remove_recursive(tegra->debugfs_dir); | ||
412 | tegra->debugfs_dir = NULL; | ||
413 | } | ||
414 | } | ||
415 | #else | ||
416 | static inline void soctherm_debug_init(struct platform_device *pdev) {} | ||
417 | #endif | ||
418 | |||
419 | static int soctherm_clk_enable(struct platform_device *pdev, bool enable) | ||
420 | { | ||
421 | struct tegra_soctherm *tegra = platform_get_drvdata(pdev); | ||
422 | int err; | ||
423 | |||
424 | if (!tegra->clock_soctherm || !tegra->clock_tsensor) | ||
425 | return -EINVAL; | ||
426 | |||
427 | reset_control_assert(tegra->reset); | ||
428 | |||
429 | if (enable) { | ||
430 | err = clk_prepare_enable(tegra->clock_soctherm); | ||
431 | if (err) { | ||
432 | reset_control_deassert(tegra->reset); | ||
433 | return err; | ||
434 | } | ||
435 | |||
436 | err = clk_prepare_enable(tegra->clock_tsensor); | ||
437 | if (err) { | ||
438 | clk_disable_unprepare(tegra->clock_soctherm); | ||
439 | reset_control_deassert(tegra->reset); | ||
440 | return err; | ||
441 | } | ||
442 | } else { | ||
443 | clk_disable_unprepare(tegra->clock_tsensor); | ||
444 | clk_disable_unprepare(tegra->clock_soctherm); | ||
445 | } | ||
446 | |||
447 | reset_control_deassert(tegra->reset); | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static void soctherm_init(struct platform_device *pdev) | ||
453 | { | ||
454 | struct tegra_soctherm *tegra = platform_get_drvdata(pdev); | ||
455 | const struct tegra_tsensor_group **ttgs = tegra->soc->ttgs; | ||
456 | int i; | ||
457 | u32 pdiv, hotspot; | ||
458 | |||
459 | /* Initialize raw sensors */ | ||
460 | for (i = 0; i < tegra->soc->num_tsensors; ++i) | ||
461 | enable_tsensor(tegra, i); | ||
462 | |||
463 | /* program pdiv and hotspot offsets per THERM */ | ||
464 | pdiv = readl(tegra->regs + SENSOR_PDIV); | ||
465 | hotspot = readl(tegra->regs + SENSOR_HOTSPOT_OFF); | ||
466 | for (i = 0; i < tegra->soc->num_ttgs; ++i) { | ||
467 | pdiv = REG_SET_MASK(pdiv, ttgs[i]->pdiv_mask, | ||
468 | ttgs[i]->pdiv); | ||
469 | /* hotspot offset from PLLX, doesn't need to configure PLLX */ | ||
470 | if (ttgs[i]->id == TEGRA124_SOCTHERM_SENSOR_PLLX) | ||
471 | continue; | ||
472 | hotspot = REG_SET_MASK(hotspot, | ||
473 | ttgs[i]->pllx_hotspot_mask, | ||
474 | ttgs[i]->pllx_hotspot_diff); | ||
475 | } | ||
476 | writel(pdiv, tegra->regs + SENSOR_PDIV); | ||
477 | writel(hotspot, tegra->regs + SENSOR_HOTSPOT_OFF); | ||
478 | } | ||
479 | |||
480 | static const struct of_device_id tegra_soctherm_of_match[] = { | ||
481 | #ifdef CONFIG_ARCH_TEGRA_124_SOC | ||
482 | { | ||
483 | .compatible = "nvidia,tegra124-soctherm", | ||
484 | .data = &tegra124_soctherm, | ||
485 | }, | ||
486 | #endif | ||
487 | #ifdef CONFIG_ARCH_TEGRA_132_SOC | ||
488 | { | ||
489 | .compatible = "nvidia,tegra132-soctherm", | ||
490 | .data = &tegra132_soctherm, | ||
491 | }, | ||
492 | #endif | ||
493 | #ifdef CONFIG_ARCH_TEGRA_210_SOC | ||
494 | { | ||
495 | .compatible = "nvidia,tegra210-soctherm", | ||
496 | .data = &tegra210_soctherm, | ||
497 | }, | ||
498 | #endif | ||
499 | { }, | ||
500 | }; | ||
501 | MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match); | ||
502 | |||
503 | static int tegra_soctherm_probe(struct platform_device *pdev) | ||
504 | { | ||
505 | const struct of_device_id *match; | ||
506 | struct tegra_soctherm *tegra; | ||
507 | struct thermal_zone_device *z; | ||
508 | struct tsensor_shared_calib shared_calib; | ||
509 | struct resource *res; | ||
510 | struct tegra_soctherm_soc *soc; | ||
511 | unsigned int i; | ||
512 | int err; | ||
513 | |||
514 | match = of_match_node(tegra_soctherm_of_match, pdev->dev.of_node); | ||
515 | if (!match) | ||
516 | return -ENODEV; | ||
517 | |||
518 | soc = (struct tegra_soctherm_soc *)match->data; | ||
519 | if (soc->num_ttgs > TEGRA124_SOCTHERM_SENSOR_NUM) | ||
520 | return -EINVAL; | ||
521 | |||
522 | tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); | ||
523 | if (!tegra) | ||
524 | return -ENOMEM; | ||
525 | |||
526 | dev_set_drvdata(&pdev->dev, tegra); | ||
527 | |||
528 | tegra->soc = soc; | ||
529 | |||
530 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
531 | tegra->regs = devm_ioremap_resource(&pdev->dev, res); | ||
532 | if (IS_ERR(tegra->regs)) | ||
533 | return PTR_ERR(tegra->regs); | ||
534 | |||
535 | tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm"); | ||
536 | if (IS_ERR(tegra->reset)) { | ||
537 | dev_err(&pdev->dev, "can't get soctherm reset\n"); | ||
538 | return PTR_ERR(tegra->reset); | ||
539 | } | ||
540 | |||
541 | tegra->clock_tsensor = devm_clk_get(&pdev->dev, "tsensor"); | ||
542 | if (IS_ERR(tegra->clock_tsensor)) { | ||
543 | dev_err(&pdev->dev, "can't get tsensor clock\n"); | ||
544 | return PTR_ERR(tegra->clock_tsensor); | ||
545 | } | ||
546 | |||
547 | tegra->clock_soctherm = devm_clk_get(&pdev->dev, "soctherm"); | ||
548 | if (IS_ERR(tegra->clock_soctherm)) { | ||
549 | dev_err(&pdev->dev, "can't get soctherm clock\n"); | ||
550 | return PTR_ERR(tegra->clock_soctherm); | ||
551 | } | ||
552 | |||
553 | tegra->calib = devm_kzalloc(&pdev->dev, | ||
554 | sizeof(u32) * soc->num_tsensors, | ||
555 | GFP_KERNEL); | ||
556 | if (!tegra->calib) | ||
557 | return -ENOMEM; | ||
558 | |||
559 | /* calculate shared calibration data */ | ||
560 | err = tegra_calc_shared_calib(soc->tfuse, &shared_calib); | ||
561 | if (err) | ||
562 | return err; | ||
563 | |||
564 | /* calculate tsensor calibaration data */ | ||
565 | for (i = 0; i < soc->num_tsensors; ++i) { | ||
566 | err = tegra_calc_tsensor_calib(&soc->tsensors[i], | ||
567 | &shared_calib, | ||
568 | &tegra->calib[i]); | ||
569 | if (err) | ||
570 | return err; | ||
571 | } | ||
572 | |||
573 | tegra->thermctl_tzs = devm_kzalloc(&pdev->dev, | ||
574 | sizeof(*z) * soc->num_ttgs, | ||
575 | GFP_KERNEL); | ||
576 | if (!tegra->thermctl_tzs) | ||
577 | return -ENOMEM; | ||
578 | |||
579 | err = soctherm_clk_enable(pdev, true); | ||
580 | if (err) | ||
581 | return err; | ||
582 | |||
583 | soctherm_init(pdev); | ||
584 | |||
585 | for (i = 0; i < soc->num_ttgs; ++i) { | ||
586 | struct tegra_thermctl_zone *zone = | ||
587 | devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL); | ||
588 | if (!zone) { | ||
589 | err = -ENOMEM; | ||
590 | goto disable_clocks; | ||
591 | } | ||
592 | |||
593 | zone->reg = tegra->regs + soc->ttgs[i]->sensor_temp_offset; | ||
594 | zone->dev = &pdev->dev; | ||
595 | zone->sg = soc->ttgs[i]; | ||
596 | |||
597 | z = devm_thermal_zone_of_sensor_register(&pdev->dev, | ||
598 | soc->ttgs[i]->id, zone, | ||
599 | &tegra_of_thermal_ops); | ||
600 | if (IS_ERR(z)) { | ||
601 | err = PTR_ERR(z); | ||
602 | dev_err(&pdev->dev, "failed to register sensor: %d\n", | ||
603 | err); | ||
604 | goto disable_clocks; | ||
605 | } | ||
606 | |||
607 | zone->tz = z; | ||
608 | tegra->thermctl_tzs[soc->ttgs[i]->id] = z; | ||
609 | |||
610 | /* Configure hw trip points */ | ||
611 | tegra_soctherm_set_hwtrips(&pdev->dev, soc->ttgs[i], z); | ||
612 | } | ||
613 | |||
614 | soctherm_debug_init(pdev); | ||
615 | |||
616 | return 0; | ||
617 | |||
618 | disable_clocks: | ||
619 | soctherm_clk_enable(pdev, false); | ||
620 | |||
621 | return err; | ||
622 | } | ||
623 | |||
624 | static int tegra_soctherm_remove(struct platform_device *pdev) | ||
625 | { | ||
626 | struct tegra_soctherm *tegra = platform_get_drvdata(pdev); | ||
627 | |||
628 | debugfs_remove_recursive(tegra->debugfs_dir); | ||
629 | |||
630 | soctherm_clk_enable(pdev, false); | ||
631 | |||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | static int __maybe_unused soctherm_suspend(struct device *dev) | ||
636 | { | ||
637 | struct platform_device *pdev = to_platform_device(dev); | ||
638 | |||
639 | soctherm_clk_enable(pdev, false); | ||
640 | |||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static int __maybe_unused soctherm_resume(struct device *dev) | ||
645 | { | ||
646 | struct platform_device *pdev = to_platform_device(dev); | ||
647 | struct tegra_soctherm *tegra = platform_get_drvdata(pdev); | ||
648 | struct tegra_soctherm_soc *soc = tegra->soc; | ||
649 | int err, i; | ||
650 | |||
651 | err = soctherm_clk_enable(pdev, true); | ||
652 | if (err) { | ||
653 | dev_err(&pdev->dev, | ||
654 | "Resume failed: enable clocks failed\n"); | ||
655 | return err; | ||
656 | } | ||
657 | |||
658 | soctherm_init(pdev); | ||
659 | |||
660 | for (i = 0; i < soc->num_ttgs; ++i) { | ||
661 | struct thermal_zone_device *tz; | ||
662 | |||
663 | tz = tegra->thermctl_tzs[soc->ttgs[i]->id]; | ||
664 | tegra_soctherm_set_hwtrips(dev, soc->ttgs[i], tz); | ||
665 | } | ||
666 | |||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | static SIMPLE_DEV_PM_OPS(tegra_soctherm_pm, soctherm_suspend, soctherm_resume); | ||
671 | |||
672 | static struct platform_driver tegra_soctherm_driver = { | ||
673 | .probe = tegra_soctherm_probe, | ||
674 | .remove = tegra_soctherm_remove, | ||
675 | .driver = { | ||
676 | .name = "tegra_soctherm", | ||
677 | .pm = &tegra_soctherm_pm, | ||
678 | .of_match_table = tegra_soctherm_of_match, | ||
679 | }, | ||
680 | }; | ||
681 | module_platform_driver(tegra_soctherm_driver); | ||
682 | |||
683 | MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>"); | ||
684 | MODULE_DESCRIPTION("NVIDIA Tegra SOCTHERM thermal management driver"); | ||
685 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/thermal/tegra/soctherm.h b/drivers/thermal/tegra/soctherm.h new file mode 100644 index 000000000000..28e18ec4b4c3 --- /dev/null +++ b/drivers/thermal/tegra/soctherm.h | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This software is licensed under the terms of the GNU General Public | ||
5 | * License version 2, as published by the Free Software Foundation, and | ||
6 | * may be copied, distributed, and modified under those terms. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef __DRIVERS_THERMAL_TEGRA_SOCTHERM_H | ||
16 | #define __DRIVERS_THERMAL_TEGRA_SOCTHERM_H | ||
17 | |||
18 | #define SENSOR_CONFIG2 8 | ||
19 | #define SENSOR_CONFIG2_THERMA_MASK (0xffff << 16) | ||
20 | #define SENSOR_CONFIG2_THERMA_SHIFT 16 | ||
21 | #define SENSOR_CONFIG2_THERMB_MASK 0xffff | ||
22 | #define SENSOR_CONFIG2_THERMB_SHIFT 0 | ||
23 | |||
24 | #define THERMCTL_THERMTRIP_CTL 0x80 | ||
25 | /* BITs are defined in device file */ | ||
26 | |||
27 | #define SENSOR_PDIV 0x1c0 | ||
28 | #define SENSOR_PDIV_CPU_MASK (0xf << 12) | ||
29 | #define SENSOR_PDIV_GPU_MASK (0xf << 8) | ||
30 | #define SENSOR_PDIV_MEM_MASK (0xf << 4) | ||
31 | #define SENSOR_PDIV_PLLX_MASK (0xf << 0) | ||
32 | |||
33 | #define SENSOR_HOTSPOT_OFF 0x1c4 | ||
34 | #define SENSOR_HOTSPOT_CPU_MASK (0xff << 16) | ||
35 | #define SENSOR_HOTSPOT_GPU_MASK (0xff << 8) | ||
36 | #define SENSOR_HOTSPOT_MEM_MASK (0xff << 0) | ||
37 | |||
38 | #define SENSOR_TEMP1 0x1c8 | ||
39 | #define SENSOR_TEMP1_CPU_TEMP_MASK (0xffff << 16) | ||
40 | #define SENSOR_TEMP1_GPU_TEMP_MASK 0xffff | ||
41 | #define SENSOR_TEMP2 0x1cc | ||
42 | #define SENSOR_TEMP2_MEM_TEMP_MASK (0xffff << 16) | ||
43 | #define SENSOR_TEMP2_PLLX_TEMP_MASK 0xffff | ||
44 | |||
45 | /** | ||
46 | * struct tegra_tsensor_group - SOC_THERM sensor group data | ||
47 | * @name: short name of the temperature sensor group | ||
48 | * @id: numeric ID of the temperature sensor group | ||
49 | * @sensor_temp_offset: offset of the SENSOR_TEMP* register | ||
50 | * @sensor_temp_mask: bit mask for this sensor group in SENSOR_TEMP* register | ||
51 | * @pdiv: the sensor count post-divider to use during runtime | ||
52 | * @pdiv_ate: the sensor count post-divider used during automated test | ||
53 | * @pdiv_mask: register bitfield mask for the PDIV field for this sensor | ||
54 | * @pllx_hotspot_diff: hotspot offset from the PLLX sensor, must be 0 for | ||
55 | PLLX sensor group | ||
56 | * @pllx_hotspot_mask: register bitfield mask for the HOTSPOT field | ||
57 | */ | ||
58 | struct tegra_tsensor_group { | ||
59 | const char *name; | ||
60 | u8 id; | ||
61 | u16 sensor_temp_offset; | ||
62 | u32 sensor_temp_mask; | ||
63 | u32 pdiv, pdiv_ate, pdiv_mask; | ||
64 | u32 pllx_hotspot_diff, pllx_hotspot_mask; | ||
65 | u32 thermtrip_enable_mask; | ||
66 | u32 thermtrip_any_en_mask; | ||
67 | u32 thermtrip_threshold_mask; | ||
68 | }; | ||
69 | |||
70 | struct tegra_tsensor_configuration { | ||
71 | u32 tall, tiddq_en, ten_count, pdiv, pdiv_ate, tsample, tsample_ate; | ||
72 | }; | ||
73 | |||
74 | struct tegra_tsensor { | ||
75 | const char *name; | ||
76 | const u32 base; | ||
77 | const struct tegra_tsensor_configuration *config; | ||
78 | const u32 calib_fuse_offset; | ||
79 | /* | ||
80 | * Correction values used to modify values read from | ||
81 | * calibration fuses | ||
82 | */ | ||
83 | const s32 fuse_corr_alpha, fuse_corr_beta; | ||
84 | const struct tegra_tsensor_group *group; | ||
85 | }; | ||
86 | |||
87 | struct tegra_soctherm_fuse { | ||
88 | u32 fuse_base_cp_mask, fuse_base_cp_shift; | ||
89 | u32 fuse_base_ft_mask, fuse_base_ft_shift; | ||
90 | u32 fuse_shift_ft_mask, fuse_shift_ft_shift; | ||
91 | u32 fuse_spare_realignment; | ||
92 | }; | ||
93 | |||
94 | struct tsensor_shared_calib { | ||
95 | u32 base_cp, base_ft; | ||
96 | u32 actual_temp_cp, actual_temp_ft; | ||
97 | }; | ||
98 | |||
99 | struct tegra_soctherm_soc { | ||
100 | const struct tegra_tsensor *tsensors; | ||
101 | const unsigned int num_tsensors; | ||
102 | const struct tegra_tsensor_group **ttgs; | ||
103 | const unsigned int num_ttgs; | ||
104 | const struct tegra_soctherm_fuse *tfuse; | ||
105 | const int thresh_grain; | ||
106 | }; | ||
107 | |||
108 | int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse, | ||
109 | struct tsensor_shared_calib *shared); | ||
110 | int tegra_calc_tsensor_calib(const struct tegra_tsensor *sensor, | ||
111 | const struct tsensor_shared_calib *shared, | ||
112 | u32 *calib); | ||
113 | |||
114 | #ifdef CONFIG_ARCH_TEGRA_124_SOC | ||
115 | extern const struct tegra_soctherm_soc tegra124_soctherm; | ||
116 | #endif | ||
117 | |||
118 | #ifdef CONFIG_ARCH_TEGRA_132_SOC | ||
119 | extern const struct tegra_soctherm_soc tegra132_soctherm; | ||
120 | #endif | ||
121 | |||
122 | #ifdef CONFIG_ARCH_TEGRA_210_SOC | ||
123 | extern const struct tegra_soctherm_soc tegra210_soctherm; | ||
124 | #endif | ||
125 | |||
126 | #endif | ||
127 | |||
diff --git a/drivers/thermal/tegra/tegra124-soctherm.c b/drivers/thermal/tegra/tegra124-soctherm.c new file mode 100644 index 000000000000..beb9d36b9c8a --- /dev/null +++ b/drivers/thermal/tegra/tegra124-soctherm.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This software is licensed under the terms of the GNU General Public | ||
5 | * License version 2, as published by the Free Software Foundation, and | ||
6 | * may be copied, distributed, and modified under those terms. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | |||
18 | #include <dt-bindings/thermal/tegra124-soctherm.h> | ||
19 | |||
20 | #include "soctherm.h" | ||
21 | |||
22 | #define TEGRA124_THERMTRIP_ANY_EN_MASK (0x1 << 28) | ||
23 | #define TEGRA124_THERMTRIP_MEM_EN_MASK (0x1 << 27) | ||
24 | #define TEGRA124_THERMTRIP_GPU_EN_MASK (0x1 << 26) | ||
25 | #define TEGRA124_THERMTRIP_CPU_EN_MASK (0x1 << 25) | ||
26 | #define TEGRA124_THERMTRIP_TSENSE_EN_MASK (0x1 << 24) | ||
27 | #define TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK (0xff << 16) | ||
28 | #define TEGRA124_THERMTRIP_CPU_THRESH_MASK (0xff << 8) | ||
29 | #define TEGRA124_THERMTRIP_TSENSE_THRESH_MASK 0xff | ||
30 | |||
31 | #define TEGRA124_THRESH_GRAIN 1000 | ||
32 | |||
33 | static const struct tegra_tsensor_configuration tegra124_tsensor_config = { | ||
34 | .tall = 16300, | ||
35 | .tiddq_en = 1, | ||
36 | .ten_count = 1, | ||
37 | .tsample = 120, | ||
38 | .tsample_ate = 480, | ||
39 | }; | ||
40 | |||
41 | static const struct tegra_tsensor_group tegra124_tsensor_group_cpu = { | ||
42 | .id = TEGRA124_SOCTHERM_SENSOR_CPU, | ||
43 | .name = "cpu", | ||
44 | .sensor_temp_offset = SENSOR_TEMP1, | ||
45 | .sensor_temp_mask = SENSOR_TEMP1_CPU_TEMP_MASK, | ||
46 | .pdiv = 8, | ||
47 | .pdiv_ate = 8, | ||
48 | .pdiv_mask = SENSOR_PDIV_CPU_MASK, | ||
49 | .pllx_hotspot_diff = 10, | ||
50 | .pllx_hotspot_mask = SENSOR_HOTSPOT_CPU_MASK, | ||
51 | .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, | ||
52 | .thermtrip_enable_mask = TEGRA124_THERMTRIP_CPU_EN_MASK, | ||
53 | .thermtrip_threshold_mask = TEGRA124_THERMTRIP_CPU_THRESH_MASK, | ||
54 | }; | ||
55 | |||
56 | static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = { | ||
57 | .id = TEGRA124_SOCTHERM_SENSOR_GPU, | ||
58 | .name = "gpu", | ||
59 | .sensor_temp_offset = SENSOR_TEMP1, | ||
60 | .sensor_temp_mask = SENSOR_TEMP1_GPU_TEMP_MASK, | ||
61 | .pdiv = 8, | ||
62 | .pdiv_ate = 8, | ||
63 | .pdiv_mask = SENSOR_PDIV_GPU_MASK, | ||
64 | .pllx_hotspot_diff = 5, | ||
65 | .pllx_hotspot_mask = SENSOR_HOTSPOT_GPU_MASK, | ||
66 | .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, | ||
67 | .thermtrip_enable_mask = TEGRA124_THERMTRIP_GPU_EN_MASK, | ||
68 | .thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK, | ||
69 | }; | ||
70 | |||
71 | static const struct tegra_tsensor_group tegra124_tsensor_group_pll = { | ||
72 | .id = TEGRA124_SOCTHERM_SENSOR_PLLX, | ||
73 | .name = "pll", | ||
74 | .sensor_temp_offset = SENSOR_TEMP2, | ||
75 | .sensor_temp_mask = SENSOR_TEMP2_PLLX_TEMP_MASK, | ||
76 | .pdiv = 8, | ||
77 | .pdiv_ate = 8, | ||
78 | .pdiv_mask = SENSOR_PDIV_PLLX_MASK, | ||
79 | .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, | ||
80 | .thermtrip_enable_mask = TEGRA124_THERMTRIP_TSENSE_EN_MASK, | ||
81 | .thermtrip_threshold_mask = TEGRA124_THERMTRIP_TSENSE_THRESH_MASK, | ||
82 | }; | ||
83 | |||
84 | static const struct tegra_tsensor_group tegra124_tsensor_group_mem = { | ||
85 | .id = TEGRA124_SOCTHERM_SENSOR_MEM, | ||
86 | .name = "mem", | ||
87 | .sensor_temp_offset = SENSOR_TEMP2, | ||
88 | .sensor_temp_mask = SENSOR_TEMP2_MEM_TEMP_MASK, | ||
89 | .pdiv = 8, | ||
90 | .pdiv_ate = 8, | ||
91 | .pdiv_mask = SENSOR_PDIV_MEM_MASK, | ||
92 | .pllx_hotspot_diff = 0, | ||
93 | .pllx_hotspot_mask = SENSOR_HOTSPOT_MEM_MASK, | ||
94 | .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, | ||
95 | .thermtrip_enable_mask = TEGRA124_THERMTRIP_MEM_EN_MASK, | ||
96 | .thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK, | ||
97 | }; | ||
98 | |||
99 | static const struct tegra_tsensor_group *tegra124_tsensor_groups[] = { | ||
100 | &tegra124_tsensor_group_cpu, | ||
101 | &tegra124_tsensor_group_gpu, | ||
102 | &tegra124_tsensor_group_pll, | ||
103 | &tegra124_tsensor_group_mem, | ||
104 | }; | ||
105 | |||
106 | static const struct tegra_tsensor tegra124_tsensors[] = { | ||
107 | { | ||
108 | .name = "cpu0", | ||
109 | .base = 0xc0, | ||
110 | .config = &tegra124_tsensor_config, | ||
111 | .calib_fuse_offset = 0x098, | ||
112 | .fuse_corr_alpha = 1135400, | ||
113 | .fuse_corr_beta = -6266900, | ||
114 | .group = &tegra124_tsensor_group_cpu, | ||
115 | }, { | ||
116 | .name = "cpu1", | ||
117 | .base = 0xe0, | ||
118 | .config = &tegra124_tsensor_config, | ||
119 | .calib_fuse_offset = 0x084, | ||
120 | .fuse_corr_alpha = 1122220, | ||
121 | .fuse_corr_beta = -5700700, | ||
122 | .group = &tegra124_tsensor_group_cpu, | ||
123 | }, { | ||
124 | .name = "cpu2", | ||
125 | .base = 0x100, | ||
126 | .config = &tegra124_tsensor_config, | ||
127 | .calib_fuse_offset = 0x088, | ||
128 | .fuse_corr_alpha = 1127000, | ||
129 | .fuse_corr_beta = -6768200, | ||
130 | .group = &tegra124_tsensor_group_cpu, | ||
131 | }, { | ||
132 | .name = "cpu3", | ||
133 | .base = 0x120, | ||
134 | .config = &tegra124_tsensor_config, | ||
135 | .calib_fuse_offset = 0x12c, | ||
136 | .fuse_corr_alpha = 1110900, | ||
137 | .fuse_corr_beta = -6232000, | ||
138 | .group = &tegra124_tsensor_group_cpu, | ||
139 | }, { | ||
140 | .name = "mem0", | ||
141 | .base = 0x140, | ||
142 | .config = &tegra124_tsensor_config, | ||
143 | .calib_fuse_offset = 0x158, | ||
144 | .fuse_corr_alpha = 1122300, | ||
145 | .fuse_corr_beta = -5936400, | ||
146 | .group = &tegra124_tsensor_group_mem, | ||
147 | }, { | ||
148 | .name = "mem1", | ||
149 | .base = 0x160, | ||
150 | .config = &tegra124_tsensor_config, | ||
151 | .calib_fuse_offset = 0x15c, | ||
152 | .fuse_corr_alpha = 1145700, | ||
153 | .fuse_corr_beta = -7124600, | ||
154 | .group = &tegra124_tsensor_group_mem, | ||
155 | }, { | ||
156 | .name = "gpu", | ||
157 | .base = 0x180, | ||
158 | .config = &tegra124_tsensor_config, | ||
159 | .calib_fuse_offset = 0x154, | ||
160 | .fuse_corr_alpha = 1120100, | ||
161 | .fuse_corr_beta = -6000500, | ||
162 | .group = &tegra124_tsensor_group_gpu, | ||
163 | }, { | ||
164 | .name = "pllx", | ||
165 | .base = 0x1a0, | ||
166 | .config = &tegra124_tsensor_config, | ||
167 | .calib_fuse_offset = 0x160, | ||
168 | .fuse_corr_alpha = 1106500, | ||
169 | .fuse_corr_beta = -6729300, | ||
170 | .group = &tegra124_tsensor_group_pll, | ||
171 | }, | ||
172 | }; | ||
173 | |||
174 | /* | ||
175 | * Mask/shift bits in FUSE_TSENSOR_COMMON and | ||
176 | * FUSE_TSENSOR_COMMON, which are described in | ||
177 | * tegra_soctherm_fuse.c | ||
178 | */ | ||
179 | static const struct tegra_soctherm_fuse tegra124_soctherm_fuse = { | ||
180 | .fuse_base_cp_mask = 0x3ff, | ||
181 | .fuse_base_cp_shift = 0, | ||
182 | .fuse_base_ft_mask = 0x7ff << 10, | ||
183 | .fuse_base_ft_shift = 10, | ||
184 | .fuse_shift_ft_mask = 0x1f << 21, | ||
185 | .fuse_shift_ft_shift = 21, | ||
186 | .fuse_spare_realignment = 0x1fc, | ||
187 | }; | ||
188 | |||
189 | const struct tegra_soctherm_soc tegra124_soctherm = { | ||
190 | .tsensors = tegra124_tsensors, | ||
191 | .num_tsensors = ARRAY_SIZE(tegra124_tsensors), | ||
192 | .ttgs = tegra124_tsensor_groups, | ||
193 | .num_ttgs = ARRAY_SIZE(tegra124_tsensor_groups), | ||
194 | .tfuse = &tegra124_soctherm_fuse, | ||
195 | .thresh_grain = TEGRA124_THRESH_GRAIN, | ||
196 | }; | ||
diff --git a/drivers/thermal/tegra/tegra132-soctherm.c b/drivers/thermal/tegra/tegra132-soctherm.c new file mode 100644 index 000000000000..e2aa84e1b307 --- /dev/null +++ b/drivers/thermal/tegra/tegra132-soctherm.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This software is licensed under the terms of the GNU General Public | ||
5 | * License version 2, as published by the Free Software Foundation, and | ||
6 | * may be copied, distributed, and modified under those terms. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | |||
18 | #include <dt-bindings/thermal/tegra124-soctherm.h> | ||
19 | |||
20 | #include "soctherm.h" | ||
21 | |||
22 | #define TEGRA132_THERMTRIP_ANY_EN_MASK (0x1 << 28) | ||
23 | #define TEGRA132_THERMTRIP_MEM_EN_MASK (0x1 << 27) | ||
24 | #define TEGRA132_THERMTRIP_GPU_EN_MASK (0x1 << 26) | ||
25 | #define TEGRA132_THERMTRIP_CPU_EN_MASK (0x1 << 25) | ||
26 | #define TEGRA132_THERMTRIP_TSENSE_EN_MASK (0x1 << 24) | ||
27 | #define TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK (0xff << 16) | ||
28 | #define TEGRA132_THERMTRIP_CPU_THRESH_MASK (0xff << 8) | ||
29 | #define TEGRA132_THERMTRIP_TSENSE_THRESH_MASK 0xff | ||
30 | |||
31 | #define TEGRA132_THRESH_GRAIN 1000 | ||
32 | |||
33 | static const struct tegra_tsensor_configuration tegra132_tsensor_config = { | ||
34 | .tall = 16300, | ||
35 | .tiddq_en = 1, | ||
36 | .ten_count = 1, | ||
37 | .tsample = 120, | ||
38 | .tsample_ate = 480, | ||
39 | }; | ||
40 | |||
41 | static const struct tegra_tsensor_group tegra132_tsensor_group_cpu = { | ||
42 | .id = TEGRA124_SOCTHERM_SENSOR_CPU, | ||
43 | .name = "cpu", | ||
44 | .sensor_temp_offset = SENSOR_TEMP1, | ||
45 | .sensor_temp_mask = SENSOR_TEMP1_CPU_TEMP_MASK, | ||
46 | .pdiv = 8, | ||
47 | .pdiv_ate = 8, | ||
48 | .pdiv_mask = SENSOR_PDIV_CPU_MASK, | ||
49 | .pllx_hotspot_diff = 10, | ||
50 | .pllx_hotspot_mask = SENSOR_HOTSPOT_CPU_MASK, | ||
51 | .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, | ||
52 | .thermtrip_enable_mask = TEGRA132_THERMTRIP_CPU_EN_MASK, | ||
53 | .thermtrip_threshold_mask = TEGRA132_THERMTRIP_CPU_THRESH_MASK, | ||
54 | }; | ||
55 | |||
56 | static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = { | ||
57 | .id = TEGRA124_SOCTHERM_SENSOR_GPU, | ||
58 | .name = "gpu", | ||
59 | .sensor_temp_offset = SENSOR_TEMP1, | ||
60 | .sensor_temp_mask = SENSOR_TEMP1_GPU_TEMP_MASK, | ||
61 | .pdiv = 8, | ||
62 | .pdiv_ate = 8, | ||
63 | .pdiv_mask = SENSOR_PDIV_GPU_MASK, | ||
64 | .pllx_hotspot_diff = 5, | ||
65 | .pllx_hotspot_mask = SENSOR_HOTSPOT_GPU_MASK, | ||
66 | .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, | ||
67 | .thermtrip_enable_mask = TEGRA132_THERMTRIP_GPU_EN_MASK, | ||
68 | .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK, | ||
69 | }; | ||
70 | |||
71 | static const struct tegra_tsensor_group tegra132_tsensor_group_pll = { | ||
72 | .id = TEGRA124_SOCTHERM_SENSOR_PLLX, | ||
73 | .name = "pll", | ||
74 | .sensor_temp_offset = SENSOR_TEMP2, | ||
75 | .sensor_temp_mask = SENSOR_TEMP2_PLLX_TEMP_MASK, | ||
76 | .pdiv = 8, | ||
77 | .pdiv_ate = 8, | ||
78 | .pdiv_mask = SENSOR_PDIV_PLLX_MASK, | ||
79 | .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, | ||
80 | .thermtrip_enable_mask = TEGRA132_THERMTRIP_TSENSE_EN_MASK, | ||
81 | .thermtrip_threshold_mask = TEGRA132_THERMTRIP_TSENSE_THRESH_MASK, | ||
82 | }; | ||
83 | |||
84 | static const struct tegra_tsensor_group tegra132_tsensor_group_mem = { | ||
85 | .id = TEGRA124_SOCTHERM_SENSOR_MEM, | ||
86 | .name = "mem", | ||
87 | .sensor_temp_offset = SENSOR_TEMP2, | ||
88 | .sensor_temp_mask = SENSOR_TEMP2_MEM_TEMP_MASK, | ||
89 | .pdiv = 8, | ||
90 | .pdiv_ate = 8, | ||
91 | .pdiv_mask = SENSOR_PDIV_MEM_MASK, | ||
92 | .pllx_hotspot_diff = 0, | ||
93 | .pllx_hotspot_mask = SENSOR_HOTSPOT_MEM_MASK, | ||
94 | .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, | ||
95 | .thermtrip_enable_mask = TEGRA132_THERMTRIP_MEM_EN_MASK, | ||
96 | .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK, | ||
97 | }; | ||
98 | |||
99 | static const struct tegra_tsensor_group *tegra132_tsensor_groups[] = { | ||
100 | &tegra132_tsensor_group_cpu, | ||
101 | &tegra132_tsensor_group_gpu, | ||
102 | &tegra132_tsensor_group_pll, | ||
103 | &tegra132_tsensor_group_mem, | ||
104 | }; | ||
105 | |||
106 | static struct tegra_tsensor tegra132_tsensors[] = { | ||
107 | { | ||
108 | .name = "cpu0", | ||
109 | .base = 0xc0, | ||
110 | .config = &tegra132_tsensor_config, | ||
111 | .calib_fuse_offset = 0x098, | ||
112 | .fuse_corr_alpha = 1126600, | ||
113 | .fuse_corr_beta = -9433500, | ||
114 | .group = &tegra132_tsensor_group_cpu, | ||
115 | }, { | ||
116 | .name = "cpu1", | ||
117 | .base = 0xe0, | ||
118 | .config = &tegra132_tsensor_config, | ||
119 | .calib_fuse_offset = 0x084, | ||
120 | .fuse_corr_alpha = 1110800, | ||
121 | .fuse_corr_beta = -7383000, | ||
122 | .group = &tegra132_tsensor_group_cpu, | ||
123 | }, { | ||
124 | .name = "cpu2", | ||
125 | .base = 0x100, | ||
126 | .config = &tegra132_tsensor_config, | ||
127 | .calib_fuse_offset = 0x088, | ||
128 | .fuse_corr_alpha = 1113800, | ||
129 | .fuse_corr_beta = -6215200, | ||
130 | .group = &tegra132_tsensor_group_cpu, | ||
131 | }, { | ||
132 | .name = "cpu3", | ||
133 | .base = 0x120, | ||
134 | .config = &tegra132_tsensor_config, | ||
135 | .calib_fuse_offset = 0x12c, | ||
136 | .fuse_corr_alpha = 1129600, | ||
137 | .fuse_corr_beta = -8196100, | ||
138 | .group = &tegra132_tsensor_group_cpu, | ||
139 | }, { | ||
140 | .name = "mem0", | ||
141 | .base = 0x140, | ||
142 | .config = &tegra132_tsensor_config, | ||
143 | .calib_fuse_offset = 0x158, | ||
144 | .fuse_corr_alpha = 1132900, | ||
145 | .fuse_corr_beta = -6755300, | ||
146 | .group = &tegra132_tsensor_group_mem, | ||
147 | }, { | ||
148 | .name = "mem1", | ||
149 | .base = 0x160, | ||
150 | .config = &tegra132_tsensor_config, | ||
151 | .calib_fuse_offset = 0x15c, | ||
152 | .fuse_corr_alpha = 1142300, | ||
153 | .fuse_corr_beta = -7374200, | ||
154 | .group = &tegra132_tsensor_group_mem, | ||
155 | }, { | ||
156 | .name = "gpu", | ||
157 | .base = 0x180, | ||
158 | .config = &tegra132_tsensor_config, | ||
159 | .calib_fuse_offset = 0x154, | ||
160 | .fuse_corr_alpha = 1125100, | ||
161 | .fuse_corr_beta = -6350400, | ||
162 | .group = &tegra132_tsensor_group_gpu, | ||
163 | }, { | ||
164 | .name = "pllx", | ||
165 | .base = 0x1a0, | ||
166 | .config = &tegra132_tsensor_config, | ||
167 | .calib_fuse_offset = 0x160, | ||
168 | .fuse_corr_alpha = 1118100, | ||
169 | .fuse_corr_beta = -8208800, | ||
170 | .group = &tegra132_tsensor_group_pll, | ||
171 | }, | ||
172 | }; | ||
173 | |||
174 | /* | ||
175 | * Mask/shift bits in FUSE_TSENSOR_COMMON and | ||
176 | * FUSE_TSENSOR_COMMON, which are described in | ||
177 | * tegra_soctherm_fuse.c | ||
178 | */ | ||
179 | static const struct tegra_soctherm_fuse tegra132_soctherm_fuse = { | ||
180 | .fuse_base_cp_mask = 0x3ff, | ||
181 | .fuse_base_cp_shift = 0, | ||
182 | .fuse_base_ft_mask = 0x7ff << 10, | ||
183 | .fuse_base_ft_shift = 10, | ||
184 | .fuse_shift_ft_mask = 0x1f << 21, | ||
185 | .fuse_shift_ft_shift = 21, | ||
186 | .fuse_spare_realignment = 0x1fc, | ||
187 | }; | ||
188 | |||
189 | const struct tegra_soctherm_soc tegra132_soctherm = { | ||
190 | .tsensors = tegra132_tsensors, | ||
191 | .num_tsensors = ARRAY_SIZE(tegra132_tsensors), | ||
192 | .ttgs = tegra132_tsensor_groups, | ||
193 | .num_ttgs = ARRAY_SIZE(tegra132_tsensor_groups), | ||
194 | .tfuse = &tegra132_soctherm_fuse, | ||
195 | .thresh_grain = TEGRA132_THRESH_GRAIN, | ||
196 | }; | ||
diff --git a/drivers/thermal/tegra/tegra210-soctherm.c b/drivers/thermal/tegra/tegra210-soctherm.c new file mode 100644 index 000000000000..19cc0ab66f0e --- /dev/null +++ b/drivers/thermal/tegra/tegra210-soctherm.c | |||
@@ -0,0 +1,197 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This software is licensed under the terms of the GNU General Public | ||
5 | * License version 2, as published by the Free Software Foundation, and | ||
6 | * may be copied, distributed, and modified under those terms. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <soc/tegra/fuse.h> | ||
18 | |||
19 | #include <dt-bindings/thermal/tegra124-soctherm.h> | ||
20 | |||
21 | #include "soctherm.h" | ||
22 | |||
23 | #define TEGRA210_THERMTRIP_ANY_EN_MASK (0x1 << 31) | ||
24 | #define TEGRA210_THERMTRIP_MEM_EN_MASK (0x1 << 30) | ||
25 | #define TEGRA210_THERMTRIP_GPU_EN_MASK (0x1 << 29) | ||
26 | #define TEGRA210_THERMTRIP_CPU_EN_MASK (0x1 << 28) | ||
27 | #define TEGRA210_THERMTRIP_TSENSE_EN_MASK (0x1 << 27) | ||
28 | #define TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK (0x1ff << 18) | ||
29 | #define TEGRA210_THERMTRIP_CPU_THRESH_MASK (0x1ff << 9) | ||
30 | #define TEGRA210_THERMTRIP_TSENSE_THRESH_MASK 0x1ff | ||
31 | |||
32 | #define TEGRA210_THRESH_GRAIN 500 | ||
33 | |||
34 | static const struct tegra_tsensor_configuration tegra210_tsensor_config = { | ||
35 | .tall = 16300, | ||
36 | .tiddq_en = 1, | ||
37 | .ten_count = 1, | ||
38 | .tsample = 120, | ||
39 | .tsample_ate = 480, | ||
40 | }; | ||
41 | |||
42 | static const struct tegra_tsensor_group tegra210_tsensor_group_cpu = { | ||
43 | .id = TEGRA124_SOCTHERM_SENSOR_CPU, | ||
44 | .name = "cpu", | ||
45 | .sensor_temp_offset = SENSOR_TEMP1, | ||
46 | .sensor_temp_mask = SENSOR_TEMP1_CPU_TEMP_MASK, | ||
47 | .pdiv = 8, | ||
48 | .pdiv_ate = 8, | ||
49 | .pdiv_mask = SENSOR_PDIV_CPU_MASK, | ||
50 | .pllx_hotspot_diff = 10, | ||
51 | .pllx_hotspot_mask = SENSOR_HOTSPOT_CPU_MASK, | ||
52 | .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, | ||
53 | .thermtrip_enable_mask = TEGRA210_THERMTRIP_CPU_EN_MASK, | ||
54 | .thermtrip_threshold_mask = TEGRA210_THERMTRIP_CPU_THRESH_MASK, | ||
55 | }; | ||
56 | |||
57 | static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = { | ||
58 | .id = TEGRA124_SOCTHERM_SENSOR_GPU, | ||
59 | .name = "gpu", | ||
60 | .sensor_temp_offset = SENSOR_TEMP1, | ||
61 | .sensor_temp_mask = SENSOR_TEMP1_GPU_TEMP_MASK, | ||
62 | .pdiv = 8, | ||
63 | .pdiv_ate = 8, | ||
64 | .pdiv_mask = SENSOR_PDIV_GPU_MASK, | ||
65 | .pllx_hotspot_diff = 5, | ||
66 | .pllx_hotspot_mask = SENSOR_HOTSPOT_GPU_MASK, | ||
67 | .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, | ||
68 | .thermtrip_enable_mask = TEGRA210_THERMTRIP_GPU_EN_MASK, | ||
69 | .thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK, | ||
70 | }; | ||
71 | |||
72 | static const struct tegra_tsensor_group tegra210_tsensor_group_pll = { | ||
73 | .id = TEGRA124_SOCTHERM_SENSOR_PLLX, | ||
74 | .name = "pll", | ||
75 | .sensor_temp_offset = SENSOR_TEMP2, | ||
76 | .sensor_temp_mask = SENSOR_TEMP2_PLLX_TEMP_MASK, | ||
77 | .pdiv = 8, | ||
78 | .pdiv_ate = 8, | ||
79 | .pdiv_mask = SENSOR_PDIV_PLLX_MASK, | ||
80 | .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, | ||
81 | .thermtrip_enable_mask = TEGRA210_THERMTRIP_TSENSE_EN_MASK, | ||
82 | .thermtrip_threshold_mask = TEGRA210_THERMTRIP_TSENSE_THRESH_MASK, | ||
83 | }; | ||
84 | |||
85 | static const struct tegra_tsensor_group tegra210_tsensor_group_mem = { | ||
86 | .id = TEGRA124_SOCTHERM_SENSOR_MEM, | ||
87 | .name = "mem", | ||
88 | .sensor_temp_offset = SENSOR_TEMP2, | ||
89 | .sensor_temp_mask = SENSOR_TEMP2_MEM_TEMP_MASK, | ||
90 | .pdiv = 8, | ||
91 | .pdiv_ate = 8, | ||
92 | .pdiv_mask = SENSOR_PDIV_MEM_MASK, | ||
93 | .pllx_hotspot_diff = 0, | ||
94 | .pllx_hotspot_mask = SENSOR_HOTSPOT_MEM_MASK, | ||
95 | .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, | ||
96 | .thermtrip_enable_mask = TEGRA210_THERMTRIP_MEM_EN_MASK, | ||
97 | .thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK, | ||
98 | }; | ||
99 | |||
100 | static const struct tegra_tsensor_group *tegra210_tsensor_groups[] = { | ||
101 | &tegra210_tsensor_group_cpu, | ||
102 | &tegra210_tsensor_group_gpu, | ||
103 | &tegra210_tsensor_group_pll, | ||
104 | &tegra210_tsensor_group_mem, | ||
105 | }; | ||
106 | |||
107 | static const struct tegra_tsensor tegra210_tsensors[] = { | ||
108 | { | ||
109 | .name = "cpu0", | ||
110 | .base = 0xc0, | ||
111 | .config = &tegra210_tsensor_config, | ||
112 | .calib_fuse_offset = 0x098, | ||
113 | .fuse_corr_alpha = 1085000, | ||
114 | .fuse_corr_beta = 3244200, | ||
115 | .group = &tegra210_tsensor_group_cpu, | ||
116 | }, { | ||
117 | .name = "cpu1", | ||
118 | .base = 0xe0, | ||
119 | .config = &tegra210_tsensor_config, | ||
120 | .calib_fuse_offset = 0x084, | ||
121 | .fuse_corr_alpha = 1126200, | ||
122 | .fuse_corr_beta = -67500, | ||
123 | .group = &tegra210_tsensor_group_cpu, | ||
124 | }, { | ||
125 | .name = "cpu2", | ||
126 | .base = 0x100, | ||
127 | .config = &tegra210_tsensor_config, | ||
128 | .calib_fuse_offset = 0x088, | ||
129 | .fuse_corr_alpha = 1098400, | ||
130 | .fuse_corr_beta = 2251100, | ||
131 | .group = &tegra210_tsensor_group_cpu, | ||
132 | }, { | ||
133 | .name = "cpu3", | ||
134 | .base = 0x120, | ||
135 | .config = &tegra210_tsensor_config, | ||
136 | .calib_fuse_offset = 0x12c, | ||
137 | .fuse_corr_alpha = 1108000, | ||
138 | .fuse_corr_beta = 602700, | ||
139 | .group = &tegra210_tsensor_group_cpu, | ||
140 | }, { | ||
141 | .name = "mem0", | ||
142 | .base = 0x140, | ||
143 | .config = &tegra210_tsensor_config, | ||
144 | .calib_fuse_offset = 0x158, | ||
145 | .fuse_corr_alpha = 1069200, | ||
146 | .fuse_corr_beta = 3549900, | ||
147 | .group = &tegra210_tsensor_group_mem, | ||
148 | }, { | ||
149 | .name = "mem1", | ||
150 | .base = 0x160, | ||
151 | .config = &tegra210_tsensor_config, | ||
152 | .calib_fuse_offset = 0x15c, | ||
153 | .fuse_corr_alpha = 1173700, | ||
154 | .fuse_corr_beta = -6263600, | ||
155 | .group = &tegra210_tsensor_group_mem, | ||
156 | }, { | ||
157 | .name = "gpu", | ||
158 | .base = 0x180, | ||
159 | .config = &tegra210_tsensor_config, | ||
160 | .calib_fuse_offset = 0x154, | ||
161 | .fuse_corr_alpha = 1074300, | ||
162 | .fuse_corr_beta = 2734900, | ||
163 | .group = &tegra210_tsensor_group_gpu, | ||
164 | }, { | ||
165 | .name = "pllx", | ||
166 | .base = 0x1a0, | ||
167 | .config = &tegra210_tsensor_config, | ||
168 | .calib_fuse_offset = 0x160, | ||
169 | .fuse_corr_alpha = 1039700, | ||
170 | .fuse_corr_beta = 6829100, | ||
171 | .group = &tegra210_tsensor_group_pll, | ||
172 | }, | ||
173 | }; | ||
174 | |||
175 | /* | ||
176 | * Mask/shift bits in FUSE_TSENSOR_COMMON and | ||
177 | * FUSE_TSENSOR_COMMON, which are described in | ||
178 | * tegra_soctherm_fuse.c | ||
179 | */ | ||
180 | static const struct tegra_soctherm_fuse tegra210_soctherm_fuse = { | ||
181 | .fuse_base_cp_mask = 0x3ff << 11, | ||
182 | .fuse_base_cp_shift = 11, | ||
183 | .fuse_base_ft_mask = 0x7ff << 21, | ||
184 | .fuse_base_ft_shift = 21, | ||
185 | .fuse_shift_ft_mask = 0x1f << 6, | ||
186 | .fuse_shift_ft_shift = 6, | ||
187 | .fuse_spare_realignment = 0, | ||
188 | }; | ||
189 | |||
190 | const struct tegra_soctherm_soc tegra210_soctherm = { | ||
191 | .tsensors = tegra210_tsensors, | ||
192 | .num_tsensors = ARRAY_SIZE(tegra210_tsensors), | ||
193 | .ttgs = tegra210_tsensor_groups, | ||
194 | .num_ttgs = ARRAY_SIZE(tegra210_tsensor_groups), | ||
195 | .tfuse = &tegra210_soctherm_fuse, | ||
196 | .thresh_grain = TEGRA210_THRESH_GRAIN, | ||
197 | }; | ||
diff --git a/drivers/thermal/tegra_soctherm.c b/drivers/thermal/tegra_soctherm.c deleted file mode 100644 index 136975220c92..000000000000 --- a/drivers/thermal/tegra_soctherm.c +++ /dev/null | |||
@@ -1,476 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Author: | ||
5 | * Mikko Perttunen <mperttunen@nvidia.com> | ||
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 | */ | ||
17 | |||
18 | #include <linux/bitops.h> | ||
19 | #include <linux/clk.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/of.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/reset.h> | ||
28 | #include <linux/thermal.h> | ||
29 | |||
30 | #include <soc/tegra/fuse.h> | ||
31 | |||
32 | #define SENSOR_CONFIG0 0 | ||
33 | #define SENSOR_CONFIG0_STOP BIT(0) | ||
34 | #define SENSOR_CONFIG0_TALL_SHIFT 8 | ||
35 | #define SENSOR_CONFIG0_TCALC_OVER BIT(4) | ||
36 | #define SENSOR_CONFIG0_OVER BIT(3) | ||
37 | #define SENSOR_CONFIG0_CPTR_OVER BIT(2) | ||
38 | |||
39 | #define SENSOR_CONFIG1 4 | ||
40 | #define SENSOR_CONFIG1_TSAMPLE_SHIFT 0 | ||
41 | #define SENSOR_CONFIG1_TIDDQ_EN_SHIFT 15 | ||
42 | #define SENSOR_CONFIG1_TEN_COUNT_SHIFT 24 | ||
43 | #define SENSOR_CONFIG1_TEMP_ENABLE BIT(31) | ||
44 | |||
45 | #define SENSOR_CONFIG2 8 | ||
46 | #define SENSOR_CONFIG2_THERMA_SHIFT 16 | ||
47 | #define SENSOR_CONFIG2_THERMB_SHIFT 0 | ||
48 | |||
49 | #define SENSOR_PDIV 0x1c0 | ||
50 | #define SENSOR_PDIV_T124 0x8888 | ||
51 | #define SENSOR_HOTSPOT_OFF 0x1c4 | ||
52 | #define SENSOR_HOTSPOT_OFF_T124 0x00060600 | ||
53 | #define SENSOR_TEMP1 0x1c8 | ||
54 | #define SENSOR_TEMP2 0x1cc | ||
55 | |||
56 | #define SENSOR_TEMP_MASK 0xffff | ||
57 | #define READBACK_VALUE_MASK 0xff00 | ||
58 | #define READBACK_VALUE_SHIFT 8 | ||
59 | #define READBACK_ADD_HALF BIT(7) | ||
60 | #define READBACK_NEGATE BIT(0) | ||
61 | |||
62 | #define FUSE_TSENSOR8_CALIB 0x180 | ||
63 | #define FUSE_SPARE_REALIGNMENT_REG_0 0x1fc | ||
64 | |||
65 | #define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK 0x1fff | ||
66 | #define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK (0x1fff << 13) | ||
67 | #define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13 | ||
68 | |||
69 | #define FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK 0x3ff | ||
70 | #define FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK (0x7ff << 10) | ||
71 | #define FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT 10 | ||
72 | |||
73 | #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_MASK 0x3f | ||
74 | #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK (0x1f << 21) | ||
75 | #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT 21 | ||
76 | |||
77 | #define NOMINAL_CALIB_FT_T124 105 | ||
78 | #define NOMINAL_CALIB_CP_T124 25 | ||
79 | |||
80 | struct tegra_tsensor_configuration { | ||
81 | u32 tall, tsample, tiddq_en, ten_count, pdiv, tsample_ate, pdiv_ate; | ||
82 | }; | ||
83 | |||
84 | struct tegra_tsensor { | ||
85 | const struct tegra_tsensor_configuration *config; | ||
86 | u32 base, calib_fuse_offset; | ||
87 | /* Correction values used to modify values read from calibration fuses */ | ||
88 | s32 fuse_corr_alpha, fuse_corr_beta; | ||
89 | }; | ||
90 | |||
91 | struct tegra_thermctl_zone { | ||
92 | void __iomem *reg; | ||
93 | unsigned int shift; | ||
94 | }; | ||
95 | |||
96 | static const struct tegra_tsensor_configuration t124_tsensor_config = { | ||
97 | .tall = 16300, | ||
98 | .tsample = 120, | ||
99 | .tiddq_en = 1, | ||
100 | .ten_count = 1, | ||
101 | .pdiv = 8, | ||
102 | .tsample_ate = 480, | ||
103 | .pdiv_ate = 8 | ||
104 | }; | ||
105 | |||
106 | static const struct tegra_tsensor t124_tsensors[] = { | ||
107 | { | ||
108 | .config = &t124_tsensor_config, | ||
109 | .base = 0xc0, | ||
110 | .calib_fuse_offset = 0x098, | ||
111 | .fuse_corr_alpha = 1135400, | ||
112 | .fuse_corr_beta = -6266900, | ||
113 | }, | ||
114 | { | ||
115 | .config = &t124_tsensor_config, | ||
116 | .base = 0xe0, | ||
117 | .calib_fuse_offset = 0x084, | ||
118 | .fuse_corr_alpha = 1122220, | ||
119 | .fuse_corr_beta = -5700700, | ||
120 | }, | ||
121 | { | ||
122 | .config = &t124_tsensor_config, | ||
123 | .base = 0x100, | ||
124 | .calib_fuse_offset = 0x088, | ||
125 | .fuse_corr_alpha = 1127000, | ||
126 | .fuse_corr_beta = -6768200, | ||
127 | }, | ||
128 | { | ||
129 | .config = &t124_tsensor_config, | ||
130 | .base = 0x120, | ||
131 | .calib_fuse_offset = 0x12c, | ||
132 | .fuse_corr_alpha = 1110900, | ||
133 | .fuse_corr_beta = -6232000, | ||
134 | }, | ||
135 | { | ||
136 | .config = &t124_tsensor_config, | ||
137 | .base = 0x140, | ||
138 | .calib_fuse_offset = 0x158, | ||
139 | .fuse_corr_alpha = 1122300, | ||
140 | .fuse_corr_beta = -5936400, | ||
141 | }, | ||
142 | { | ||
143 | .config = &t124_tsensor_config, | ||
144 | .base = 0x160, | ||
145 | .calib_fuse_offset = 0x15c, | ||
146 | .fuse_corr_alpha = 1145700, | ||
147 | .fuse_corr_beta = -7124600, | ||
148 | }, | ||
149 | { | ||
150 | .config = &t124_tsensor_config, | ||
151 | .base = 0x180, | ||
152 | .calib_fuse_offset = 0x154, | ||
153 | .fuse_corr_alpha = 1120100, | ||
154 | .fuse_corr_beta = -6000500, | ||
155 | }, | ||
156 | { | ||
157 | .config = &t124_tsensor_config, | ||
158 | .base = 0x1a0, | ||
159 | .calib_fuse_offset = 0x160, | ||
160 | .fuse_corr_alpha = 1106500, | ||
161 | .fuse_corr_beta = -6729300, | ||
162 | }, | ||
163 | }; | ||
164 | |||
165 | struct tegra_soctherm { | ||
166 | struct reset_control *reset; | ||
167 | struct clk *clock_tsensor; | ||
168 | struct clk *clock_soctherm; | ||
169 | void __iomem *regs; | ||
170 | |||
171 | struct thermal_zone_device *thermctl_tzs[4]; | ||
172 | }; | ||
173 | |||
174 | struct tsensor_shared_calibration { | ||
175 | u32 base_cp, base_ft; | ||
176 | u32 actual_temp_cp, actual_temp_ft; | ||
177 | }; | ||
178 | |||
179 | static int calculate_shared_calibration(struct tsensor_shared_calibration *r) | ||
180 | { | ||
181 | u32 val, shifted_cp, shifted_ft; | ||
182 | int err; | ||
183 | |||
184 | err = tegra_fuse_readl(FUSE_TSENSOR8_CALIB, &val); | ||
185 | if (err) | ||
186 | return err; | ||
187 | r->base_cp = val & FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK; | ||
188 | r->base_ft = (val & FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK) | ||
189 | >> FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT; | ||
190 | val = ((val & FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK) | ||
191 | >> FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT); | ||
192 | shifted_ft = sign_extend32(val, 4); | ||
193 | |||
194 | err = tegra_fuse_readl(FUSE_SPARE_REALIGNMENT_REG_0, &val); | ||
195 | if (err) | ||
196 | return err; | ||
197 | shifted_cp = sign_extend32(val, 5); | ||
198 | |||
199 | r->actual_temp_cp = 2 * NOMINAL_CALIB_CP_T124 + shifted_cp; | ||
200 | r->actual_temp_ft = 2 * NOMINAL_CALIB_FT_T124 + shifted_ft; | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static s64 div64_s64_precise(s64 a, s64 b) | ||
206 | { | ||
207 | s64 r, al; | ||
208 | |||
209 | /* Scale up for increased precision division */ | ||
210 | al = a << 16; | ||
211 | |||
212 | r = div64_s64(al * 2 + 1, 2 * b); | ||
213 | return r >> 16; | ||
214 | } | ||
215 | |||
216 | static int | ||
217 | calculate_tsensor_calibration(const struct tegra_tsensor *sensor, | ||
218 | const struct tsensor_shared_calibration *shared, | ||
219 | u32 *calib) | ||
220 | { | ||
221 | u32 val; | ||
222 | s32 actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp, | ||
223 | mult, div; | ||
224 | s16 therma, thermb; | ||
225 | s64 tmp; | ||
226 | int err; | ||
227 | |||
228 | err = tegra_fuse_readl(sensor->calib_fuse_offset, &val); | ||
229 | if (err) | ||
230 | return err; | ||
231 | |||
232 | actual_tsensor_cp = (shared->base_cp * 64) + sign_extend32(val, 12); | ||
233 | val = (val & FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK) | ||
234 | >> FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT; | ||
235 | actual_tsensor_ft = (shared->base_ft * 32) + sign_extend32(val, 12); | ||
236 | |||
237 | delta_sens = actual_tsensor_ft - actual_tsensor_cp; | ||
238 | delta_temp = shared->actual_temp_ft - shared->actual_temp_cp; | ||
239 | |||
240 | mult = sensor->config->pdiv * sensor->config->tsample_ate; | ||
241 | div = sensor->config->tsample * sensor->config->pdiv_ate; | ||
242 | |||
243 | therma = div64_s64_precise((s64) delta_temp * (1LL << 13) * mult, | ||
244 | (s64) delta_sens * div); | ||
245 | |||
246 | tmp = (s64)actual_tsensor_ft * shared->actual_temp_cp - | ||
247 | (s64)actual_tsensor_cp * shared->actual_temp_ft; | ||
248 | thermb = div64_s64_precise(tmp, (s64)delta_sens); | ||
249 | |||
250 | therma = div64_s64_precise((s64)therma * sensor->fuse_corr_alpha, | ||
251 | (s64)1000000LL); | ||
252 | thermb = div64_s64_precise((s64)thermb * sensor->fuse_corr_alpha + | ||
253 | sensor->fuse_corr_beta, (s64)1000000LL); | ||
254 | |||
255 | *calib = ((u16)therma << SENSOR_CONFIG2_THERMA_SHIFT) | | ||
256 | ((u16)thermb << SENSOR_CONFIG2_THERMB_SHIFT); | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int enable_tsensor(struct tegra_soctherm *tegra, | ||
262 | const struct tegra_tsensor *sensor, | ||
263 | const struct tsensor_shared_calibration *shared) | ||
264 | { | ||
265 | void __iomem *base = tegra->regs + sensor->base; | ||
266 | unsigned int val; | ||
267 | u32 calib; | ||
268 | int err; | ||
269 | |||
270 | err = calculate_tsensor_calibration(sensor, shared, &calib); | ||
271 | if (err) | ||
272 | return err; | ||
273 | |||
274 | val = sensor->config->tall << SENSOR_CONFIG0_TALL_SHIFT; | ||
275 | writel(val, base + SENSOR_CONFIG0); | ||
276 | |||
277 | val = (sensor->config->tsample - 1) << SENSOR_CONFIG1_TSAMPLE_SHIFT; | ||
278 | val |= sensor->config->tiddq_en << SENSOR_CONFIG1_TIDDQ_EN_SHIFT; | ||
279 | val |= sensor->config->ten_count << SENSOR_CONFIG1_TEN_COUNT_SHIFT; | ||
280 | val |= SENSOR_CONFIG1_TEMP_ENABLE; | ||
281 | writel(val, base + SENSOR_CONFIG1); | ||
282 | |||
283 | writel(calib, base + SENSOR_CONFIG2); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | /* | ||
289 | * Translate from soctherm readback format to millicelsius. | ||
290 | * The soctherm readback format in bits is as follows: | ||
291 | * TTTTTTTT H______N | ||
292 | * where T's contain the temperature in Celsius, | ||
293 | * H denotes an addition of 0.5 Celsius and N denotes negation | ||
294 | * of the final value. | ||
295 | */ | ||
296 | static int translate_temp(u16 val) | ||
297 | { | ||
298 | long t; | ||
299 | |||
300 | t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000; | ||
301 | if (val & READBACK_ADD_HALF) | ||
302 | t += 500; | ||
303 | if (val & READBACK_NEGATE) | ||
304 | t *= -1; | ||
305 | |||
306 | return t; | ||
307 | } | ||
308 | |||
309 | static int tegra_thermctl_get_temp(void *data, int *out_temp) | ||
310 | { | ||
311 | struct tegra_thermctl_zone *zone = data; | ||
312 | u32 val; | ||
313 | |||
314 | val = (readl(zone->reg) >> zone->shift) & SENSOR_TEMP_MASK; | ||
315 | *out_temp = translate_temp(val); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = { | ||
321 | .get_temp = tegra_thermctl_get_temp, | ||
322 | }; | ||
323 | |||
324 | static const struct of_device_id tegra_soctherm_of_match[] = { | ||
325 | { .compatible = "nvidia,tegra124-soctherm" }, | ||
326 | { }, | ||
327 | }; | ||
328 | MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match); | ||
329 | |||
330 | struct thermctl_zone_desc { | ||
331 | unsigned int offset; | ||
332 | unsigned int shift; | ||
333 | }; | ||
334 | |||
335 | static const struct thermctl_zone_desc t124_thermctl_temp_zones[] = { | ||
336 | { SENSOR_TEMP1, 16 }, | ||
337 | { SENSOR_TEMP2, 16 }, | ||
338 | { SENSOR_TEMP1, 0 }, | ||
339 | { SENSOR_TEMP2, 0 } | ||
340 | }; | ||
341 | |||
342 | static int tegra_soctherm_probe(struct platform_device *pdev) | ||
343 | { | ||
344 | struct tegra_soctherm *tegra; | ||
345 | struct thermal_zone_device *tz; | ||
346 | struct tsensor_shared_calibration shared_calib; | ||
347 | struct resource *res; | ||
348 | unsigned int i; | ||
349 | int err; | ||
350 | |||
351 | const struct tegra_tsensor *tsensors = t124_tsensors; | ||
352 | |||
353 | tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); | ||
354 | if (!tegra) | ||
355 | return -ENOMEM; | ||
356 | |||
357 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
358 | tegra->regs = devm_ioremap_resource(&pdev->dev, res); | ||
359 | if (IS_ERR(tegra->regs)) | ||
360 | return PTR_ERR(tegra->regs); | ||
361 | |||
362 | tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm"); | ||
363 | if (IS_ERR(tegra->reset)) { | ||
364 | dev_err(&pdev->dev, "can't get soctherm reset\n"); | ||
365 | return PTR_ERR(tegra->reset); | ||
366 | } | ||
367 | |||
368 | tegra->clock_tsensor = devm_clk_get(&pdev->dev, "tsensor"); | ||
369 | if (IS_ERR(tegra->clock_tsensor)) { | ||
370 | dev_err(&pdev->dev, "can't get tsensor clock\n"); | ||
371 | return PTR_ERR(tegra->clock_tsensor); | ||
372 | } | ||
373 | |||
374 | tegra->clock_soctherm = devm_clk_get(&pdev->dev, "soctherm"); | ||
375 | if (IS_ERR(tegra->clock_soctherm)) { | ||
376 | dev_err(&pdev->dev, "can't get soctherm clock\n"); | ||
377 | return PTR_ERR(tegra->clock_soctherm); | ||
378 | } | ||
379 | |||
380 | reset_control_assert(tegra->reset); | ||
381 | |||
382 | err = clk_prepare_enable(tegra->clock_soctherm); | ||
383 | if (err) | ||
384 | return err; | ||
385 | |||
386 | err = clk_prepare_enable(tegra->clock_tsensor); | ||
387 | if (err) { | ||
388 | clk_disable_unprepare(tegra->clock_soctherm); | ||
389 | return err; | ||
390 | } | ||
391 | |||
392 | reset_control_deassert(tegra->reset); | ||
393 | |||
394 | /* Initialize raw sensors */ | ||
395 | |||
396 | err = calculate_shared_calibration(&shared_calib); | ||
397 | if (err) | ||
398 | goto disable_clocks; | ||
399 | |||
400 | for (i = 0; i < ARRAY_SIZE(t124_tsensors); ++i) { | ||
401 | err = enable_tsensor(tegra, tsensors + i, &shared_calib); | ||
402 | if (err) | ||
403 | goto disable_clocks; | ||
404 | } | ||
405 | |||
406 | writel(SENSOR_PDIV_T124, tegra->regs + SENSOR_PDIV); | ||
407 | writel(SENSOR_HOTSPOT_OFF_T124, tegra->regs + SENSOR_HOTSPOT_OFF); | ||
408 | |||
409 | /* Initialize thermctl sensors */ | ||
410 | |||
411 | for (i = 0; i < ARRAY_SIZE(tegra->thermctl_tzs); ++i) { | ||
412 | struct tegra_thermctl_zone *zone = | ||
413 | devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL); | ||
414 | if (!zone) { | ||
415 | err = -ENOMEM; | ||
416 | goto unregister_tzs; | ||
417 | } | ||
418 | |||
419 | zone->reg = tegra->regs + t124_thermctl_temp_zones[i].offset; | ||
420 | zone->shift = t124_thermctl_temp_zones[i].shift; | ||
421 | |||
422 | tz = thermal_zone_of_sensor_register(&pdev->dev, i, zone, | ||
423 | &tegra_of_thermal_ops); | ||
424 | if (IS_ERR(tz)) { | ||
425 | err = PTR_ERR(tz); | ||
426 | dev_err(&pdev->dev, "failed to register sensor: %d\n", | ||
427 | err); | ||
428 | goto unregister_tzs; | ||
429 | } | ||
430 | |||
431 | tegra->thermctl_tzs[i] = tz; | ||
432 | } | ||
433 | |||
434 | return 0; | ||
435 | |||
436 | unregister_tzs: | ||
437 | while (i--) | ||
438 | thermal_zone_of_sensor_unregister(&pdev->dev, | ||
439 | tegra->thermctl_tzs[i]); | ||
440 | |||
441 | disable_clocks: | ||
442 | clk_disable_unprepare(tegra->clock_tsensor); | ||
443 | clk_disable_unprepare(tegra->clock_soctherm); | ||
444 | |||
445 | return err; | ||
446 | } | ||
447 | |||
448 | static int tegra_soctherm_remove(struct platform_device *pdev) | ||
449 | { | ||
450 | struct tegra_soctherm *tegra = platform_get_drvdata(pdev); | ||
451 | unsigned int i; | ||
452 | |||
453 | for (i = 0; i < ARRAY_SIZE(tegra->thermctl_tzs); ++i) { | ||
454 | thermal_zone_of_sensor_unregister(&pdev->dev, | ||
455 | tegra->thermctl_tzs[i]); | ||
456 | } | ||
457 | |||
458 | clk_disable_unprepare(tegra->clock_tsensor); | ||
459 | clk_disable_unprepare(tegra->clock_soctherm); | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static struct platform_driver tegra_soctherm_driver = { | ||
465 | .probe = tegra_soctherm_probe, | ||
466 | .remove = tegra_soctherm_remove, | ||
467 | .driver = { | ||
468 | .name = "tegra-soctherm", | ||
469 | .of_match_table = tegra_soctherm_of_match, | ||
470 | }, | ||
471 | }; | ||
472 | module_platform_driver(tegra_soctherm_driver); | ||
473 | |||
474 | MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>"); | ||
475 | MODULE_DESCRIPTION("NVIDIA Tegra SOCTHERM thermal management driver"); | ||
476 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/thermal/thermal-generic-adc.c b/drivers/thermal/thermal-generic-adc.c new file mode 100644 index 000000000000..73f55d6a1721 --- /dev/null +++ b/drivers/thermal/thermal-generic-adc.c | |||
@@ -0,0 +1,182 @@ | |||
1 | /* | ||
2 | * Generic ADC thermal driver | ||
3 | * | ||
4 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Laxman Dewangan <ldewangan@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/iio/consumer.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/thermal.h> | ||
18 | |||
19 | struct gadc_thermal_info { | ||
20 | struct device *dev; | ||
21 | struct thermal_zone_device *tz_dev; | ||
22 | struct iio_channel *channel; | ||
23 | s32 *lookup_table; | ||
24 | int nlookup_table; | ||
25 | }; | ||
26 | |||
27 | static int gadc_thermal_adc_to_temp(struct gadc_thermal_info *gti, int val) | ||
28 | { | ||
29 | int temp, adc_hi, adc_lo; | ||
30 | int i; | ||
31 | |||
32 | for (i = 0; i < gti->nlookup_table; i++) { | ||
33 | if (val >= gti->lookup_table[2 * i + 1]) | ||
34 | break; | ||
35 | } | ||
36 | |||
37 | if (i == 0) { | ||
38 | temp = gti->lookup_table[0]; | ||
39 | } else if (i >= (gti->nlookup_table - 1)) { | ||
40 | temp = gti->lookup_table[2 * (gti->nlookup_table - 1)]; | ||
41 | } else { | ||
42 | adc_hi = gti->lookup_table[2 * i - 1]; | ||
43 | adc_lo = gti->lookup_table[2 * i + 1]; | ||
44 | temp = gti->lookup_table[2 * i]; | ||
45 | temp -= ((val - adc_lo) * 1000) / (adc_hi - adc_lo); | ||
46 | } | ||
47 | |||
48 | return temp; | ||
49 | } | ||
50 | |||
51 | static int gadc_thermal_get_temp(void *data, int *temp) | ||
52 | { | ||
53 | struct gadc_thermal_info *gti = data; | ||
54 | int val; | ||
55 | int ret; | ||
56 | |||
57 | ret = iio_read_channel_processed(gti->channel, &val); | ||
58 | if (ret < 0) { | ||
59 | dev_err(gti->dev, "IIO channel read failed %d\n", ret); | ||
60 | return ret; | ||
61 | } | ||
62 | *temp = gadc_thermal_adc_to_temp(gti, val); | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static const struct thermal_zone_of_device_ops gadc_thermal_ops = { | ||
68 | .get_temp = gadc_thermal_get_temp, | ||
69 | }; | ||
70 | |||
71 | static int gadc_thermal_read_linear_lookup_table(struct device *dev, | ||
72 | struct gadc_thermal_info *gti) | ||
73 | { | ||
74 | struct device_node *np = dev->of_node; | ||
75 | int ntable; | ||
76 | int ret; | ||
77 | |||
78 | ntable = of_property_count_elems_of_size(np, "temperature-lookup-table", | ||
79 | sizeof(u32)); | ||
80 | if (ntable < 0) { | ||
81 | dev_err(dev, "Lookup table is not provided\n"); | ||
82 | return ntable; | ||
83 | } | ||
84 | |||
85 | if (ntable % 2) { | ||
86 | dev_err(dev, "Pair of temperature vs ADC read value missing\n"); | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | |||
90 | gti->lookup_table = devm_kzalloc(dev, sizeof(*gti->lookup_table) * | ||
91 | ntable, GFP_KERNEL); | ||
92 | if (!gti->lookup_table) | ||
93 | return -ENOMEM; | ||
94 | |||
95 | ret = of_property_read_u32_array(np, "temperature-lookup-table", | ||
96 | (u32 *)gti->lookup_table, ntable); | ||
97 | if (ret < 0) { | ||
98 | dev_err(dev, "Failed to read temperature lookup table: %d\n", | ||
99 | ret); | ||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | gti->nlookup_table = ntable / 2; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int gadc_thermal_probe(struct platform_device *pdev) | ||
109 | { | ||
110 | struct gadc_thermal_info *gti; | ||
111 | int ret; | ||
112 | |||
113 | if (!pdev->dev.of_node) { | ||
114 | dev_err(&pdev->dev, "Only DT based supported\n"); | ||
115 | return -ENODEV; | ||
116 | } | ||
117 | |||
118 | gti = devm_kzalloc(&pdev->dev, sizeof(*gti), GFP_KERNEL); | ||
119 | if (!gti) | ||
120 | return -ENOMEM; | ||
121 | |||
122 | ret = gadc_thermal_read_linear_lookup_table(&pdev->dev, gti); | ||
123 | if (ret < 0) | ||
124 | return ret; | ||
125 | |||
126 | gti->dev = &pdev->dev; | ||
127 | platform_set_drvdata(pdev, gti); | ||
128 | |||
129 | gti->channel = iio_channel_get(&pdev->dev, "sensor-channel"); | ||
130 | if (IS_ERR(gti->channel)) { | ||
131 | ret = PTR_ERR(gti->channel); | ||
132 | dev_err(&pdev->dev, "IIO channel not found: %d\n", ret); | ||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | gti->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, 0, | ||
137 | gti, &gadc_thermal_ops); | ||
138 | if (IS_ERR(gti->tz_dev)) { | ||
139 | ret = PTR_ERR(gti->tz_dev); | ||
140 | dev_err(&pdev->dev, "Thermal zone sensor register failed: %d\n", | ||
141 | ret); | ||
142 | goto sensor_fail; | ||
143 | } | ||
144 | |||
145 | return 0; | ||
146 | |||
147 | sensor_fail: | ||
148 | iio_channel_release(gti->channel); | ||
149 | |||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | static int gadc_thermal_remove(struct platform_device *pdev) | ||
154 | { | ||
155 | struct gadc_thermal_info *gti = platform_get_drvdata(pdev); | ||
156 | |||
157 | thermal_zone_of_sensor_unregister(&pdev->dev, gti->tz_dev); | ||
158 | iio_channel_release(gti->channel); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static const struct of_device_id of_adc_thermal_match[] = { | ||
164 | { .compatible = "generic-adc-thermal", }, | ||
165 | {}, | ||
166 | }; | ||
167 | MODULE_DEVICE_TABLE(of, of_adc_thermal_match); | ||
168 | |||
169 | static struct platform_driver gadc_thermal_driver = { | ||
170 | .driver = { | ||
171 | .name = "generic-adc-thermal", | ||
172 | .of_match_table = of_adc_thermal_match, | ||
173 | }, | ||
174 | .probe = gadc_thermal_probe, | ||
175 | .remove = gadc_thermal_remove, | ||
176 | }; | ||
177 | |||
178 | module_platform_driver(gadc_thermal_driver); | ||
179 | |||
180 | MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); | ||
181 | MODULE_DESCRIPTION("Generic ADC thermal driver using IIO framework with DT"); | ||
182 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c index b213a1222295..15c0a9ac2209 100644 --- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c +++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c | |||
@@ -337,7 +337,7 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, | |||
337 | return -EINVAL; | 337 | return -EINVAL; |
338 | 338 | ||
339 | /* in case this is specified by DT */ | 339 | /* in case this is specified by DT */ |
340 | data->ti_thermal = thermal_zone_of_sensor_register(bgp->dev, id, | 340 | data->ti_thermal = devm_thermal_zone_of_sensor_register(bgp->dev, id, |
341 | data, &ti_of_thermal_ops); | 341 | data, &ti_of_thermal_ops); |
342 | if (IS_ERR(data->ti_thermal)) { | 342 | if (IS_ERR(data->ti_thermal)) { |
343 | /* Create thermal zone */ | 343 | /* Create thermal zone */ |
@@ -368,9 +368,6 @@ int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id) | |||
368 | if (data && data->ti_thermal) { | 368 | if (data && data->ti_thermal) { |
369 | if (data->our_zone) | 369 | if (data->our_zone) |
370 | thermal_zone_device_unregister(data->ti_thermal); | 370 | thermal_zone_device_unregister(data->ti_thermal); |
371 | else | ||
372 | thermal_zone_of_sensor_unregister(bgp->dev, | ||
373 | data->ti_thermal); | ||
374 | } | 371 | } |
375 | 372 | ||
376 | return 0; | 373 | return 0; |
diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c index 7fc919f7da4d..97f0a2bd93ed 100644 --- a/drivers/thermal/x86_pkg_temp_thermal.c +++ b/drivers/thermal/x86_pkg_temp_thermal.c | |||
@@ -555,7 +555,7 @@ static int pkg_temp_thermal_cpu_callback(struct notifier_block *nfb, | |||
555 | { | 555 | { |
556 | unsigned int cpu = (unsigned long) hcpu; | 556 | unsigned int cpu = (unsigned long) hcpu; |
557 | 557 | ||
558 | switch (action) { | 558 | switch (action & ~CPU_TASKS_FROZEN) { |
559 | case CPU_ONLINE: | 559 | case CPU_ONLINE: |
560 | case CPU_DOWN_FAILED: | 560 | case CPU_DOWN_FAILED: |
561 | get_core_online(cpu); | 561 | get_core_online(cpu); |
diff --git a/include/dt-bindings/thermal/tegra124-soctherm.h b/include/dt-bindings/thermal/tegra124-soctherm.h index 85aaf66690f9..729ab9fc325e 100644 --- a/include/dt-bindings/thermal/tegra124-soctherm.h +++ b/include/dt-bindings/thermal/tegra124-soctherm.h | |||
@@ -9,5 +9,6 @@ | |||
9 | #define TEGRA124_SOCTHERM_SENSOR_MEM 1 | 9 | #define TEGRA124_SOCTHERM_SENSOR_MEM 1 |
10 | #define TEGRA124_SOCTHERM_SENSOR_GPU 2 | 10 | #define TEGRA124_SOCTHERM_SENSOR_GPU 2 |
11 | #define TEGRA124_SOCTHERM_SENSOR_PLLX 3 | 11 | #define TEGRA124_SOCTHERM_SENSOR_PLLX 3 |
12 | #define TEGRA124_SOCTHERM_SENSOR_NUM 4 | ||
12 | 13 | ||
13 | #endif | 14 | #endif |
diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 1b8a5a7876ce..e45abe7db9a6 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h | |||
@@ -340,6 +340,7 @@ struct thermal_zone_of_device_ops { | |||
340 | int (*get_temp)(void *, int *); | 340 | int (*get_temp)(void *, int *); |
341 | int (*get_trend)(void *, long *); | 341 | int (*get_trend)(void *, long *); |
342 | int (*set_emul_temp)(void *, int); | 342 | int (*set_emul_temp)(void *, int); |
343 | int (*set_trip_temp)(void *, int, int); | ||
343 | }; | 344 | }; |
344 | 345 | ||
345 | /** | 346 | /** |