summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/thermal/db8500-thermal.txt44
-rw-r--r--Documentation/thermal/sysfs-api.txt64
-rw-r--r--arch/arm/boot/dts/dbx5x0.dtsi14
-rw-r--r--arch/arm/boot/dts/snowball.dts31
-rw-r--r--arch/arm/configs/u8500_defconfig2
-rw-r--r--arch/arm/mach-ux500/board-mop500.c64
-rw-r--r--drivers/acpi/thermal.c6
-rw-r--r--drivers/platform/x86/acerhdf.c2
-rw-r--r--drivers/platform/x86/intel_mid_thermal.c2
-rw-r--r--drivers/power/power_supply_core.c2
-rw-r--r--drivers/staging/omap-thermal/omap-thermal-common.c2
-rw-r--r--drivers/thermal/Kconfig82
-rw-r--r--drivers/thermal/Makefile17
-rw-r--r--drivers/thermal/cpu_cooling.c107
-rw-r--r--drivers/thermal/db8500_cpufreq_cooling.c108
-rw-r--r--drivers/thermal/db8500_thermal.c531
-rw-r--r--drivers/thermal/exynos_thermal.c2
-rw-r--r--drivers/thermal/fair_share.c133
-rw-r--r--drivers/thermal/rcar_thermal.c27
-rw-r--r--drivers/thermal/spear_thermal.c2
-rw-r--r--drivers/thermal/step_wise.c194
-rw-r--r--drivers/thermal/thermal_core.h53
-rw-r--r--drivers/thermal/thermal_sys.c701
-rw-r--r--drivers/thermal/user_space.c68
-rw-r--r--include/linux/cpu_cooling.h6
-rw-r--r--include/linux/platform_data/db8500_thermal.h38
-rw-r--r--include/linux/thermal.h134
27 files changed, 2038 insertions, 398 deletions
diff --git a/Documentation/devicetree/bindings/thermal/db8500-thermal.txt b/Documentation/devicetree/bindings/thermal/db8500-thermal.txt
new file mode 100644
index 000000000000..2e1c06fad81f
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/db8500-thermal.txt
@@ -0,0 +1,44 @@
1* ST-Ericsson DB8500 Thermal
2
3** Thermal node properties:
4
5- compatible : "stericsson,db8500-thermal";
6- reg : address range of the thermal sensor registers;
7- interrupts : interrupts generated from PRCMU;
8- interrupt-names : "IRQ_HOTMON_LOW" and "IRQ_HOTMON_HIGH";
9- num-trips : number of total trip points, this is required, set it 0 if none,
10 if greater than 0, the following properties must be defined;
11- tripN-temp : temperature of trip point N, should be in ascending order;
12- tripN-type : type of trip point N, should be one of "active" "passive" "hot"
13 "critical";
14- tripN-cdev-num : number of the cooling devices which can be bound to trip
15 point N, this is required if trip point N is defined, set it 0 if none,
16 otherwise the following cooling device names must be defined;
17- tripN-cdev-nameM : name of the No. M cooling device of trip point N;
18
19Usually the num-trips and tripN-*** are separated in board related dts files.
20
21Example:
22thermal@801573c0 {
23 compatible = "stericsson,db8500-thermal";
24 reg = <0x801573c0 0x40>;
25 interrupts = <21 0x4>, <22 0x4>;
26 interrupt-names = "IRQ_HOTMON_LOW", "IRQ_HOTMON_HIGH";
27
28 num-trips = <3>;
29
30 trip0-temp = <75000>;
31 trip0-type = "active";
32 trip0-cdev-num = <1>;
33 trip0-cdev-name0 = "thermal-cpufreq-0";
34
35 trip1-temp = <80000>;
36 trip1-type = "active";
37 trip1-cdev-num = <2>;
38 trip1-cdev-name0 = "thermal-cpufreq-0";
39 trip1-cdev-name1 = "thermal-fan";
40
41 trip2-temp = <85000>;
42 trip2-type = "critical";
43 trip2-cdev-num = <0>;
44}
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index ca1a1a34970e..88c02334e356 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -112,6 +112,29 @@ temperature) and throttle appropriate devices.
112 trip: indicates which trip point the cooling devices is associated with 112 trip: indicates which trip point the cooling devices is associated with
113 in this thermal zone. 113 in this thermal zone.
114 114
1151.4 Thermal Zone Parameters
1161.4.1 struct thermal_bind_params
117 This structure defines the following parameters that are used to bind
118 a zone with a cooling device for a particular trip point.
119 .cdev: The cooling device pointer
120 .weight: The 'influence' of a particular cooling device on this zone.
121 This is on a percentage scale. The sum of all these weights
122 (for a particular zone) cannot exceed 100.
123 .trip_mask:This is a bit mask that gives the binding relation between
124 this thermal zone and cdev, for a particular trip point.
125 If nth bit is set, then the cdev and thermal zone are bound
126 for trip point n.
127 .match: This call back returns success(0) if the 'tz and cdev' need to
128 be bound, as per platform data.
1291.4.2 struct thermal_zone_params
130 This structure defines the platform level parameters for a thermal zone.
131 This data, for each thermal zone should come from the platform layer.
132 This is an optional feature where some platforms can choose not to
133 provide this data.
134 .governor_name: Name of the thermal governor used for this zone
135 .num_tbps: Number of thermal_bind_params entries for this zone
136 .tbp: thermal_bind_params entries
137
1152. sysfs attributes structure 1382. sysfs attributes structure
116 139
117RO read only value 140RO read only value
@@ -126,6 +149,7 @@ Thermal zone device sys I/F, created once it's registered:
126 |---type: Type of the thermal zone 149 |---type: Type of the thermal zone
127 |---temp: Current temperature 150 |---temp: Current temperature
128 |---mode: Working mode of the thermal zone 151 |---mode: Working mode of the thermal zone
152 |---policy: Thermal governor used for this zone
129 |---trip_point_[0-*]_temp: Trip point temperature 153 |---trip_point_[0-*]_temp: Trip point temperature
130 |---trip_point_[0-*]_type: Trip point type 154 |---trip_point_[0-*]_type: Trip point type
131 |---trip_point_[0-*]_hyst: Hysteresis value for this trip point 155 |---trip_point_[0-*]_hyst: Hysteresis value for this trip point
@@ -187,6 +211,10 @@ mode
187 charge of the thermal management. 211 charge of the thermal management.
188 RW, Optional 212 RW, Optional
189 213
214policy
215 One of the various thermal governors used for a particular zone.
216 RW, Required
217
190trip_point_[0-*]_temp 218trip_point_[0-*]_temp
191 The temperature above which trip point will be fired. 219 The temperature above which trip point will be fired.
192 Unit: millidegree Celsius 220 Unit: millidegree Celsius
@@ -264,6 +292,7 @@ method, the sys I/F structure will be built like this:
264 |---type: acpitz 292 |---type: acpitz
265 |---temp: 37000 293 |---temp: 37000
266 |---mode: enabled 294 |---mode: enabled
295 |---policy: step_wise
267 |---trip_point_0_temp: 100000 296 |---trip_point_0_temp: 100000
268 |---trip_point_0_type: critical 297 |---trip_point_0_type: critical
269 |---trip_point_1_temp: 80000 298 |---trip_point_1_temp: 80000
@@ -305,3 +334,38 @@ to a thermal_zone_device when it registers itself with the framework. The
305event will be one of:{THERMAL_AUX0, THERMAL_AUX1, THERMAL_CRITICAL, 334event will be one of:{THERMAL_AUX0, THERMAL_AUX1, THERMAL_CRITICAL,
306THERMAL_DEV_FAULT}. Notification can be sent when the current temperature 335THERMAL_DEV_FAULT}. Notification can be sent when the current temperature
307crosses any of the configured thresholds. 336crosses any of the configured thresholds.
337
3385. Export Symbol APIs:
339
3405.1: get_tz_trend:
341This function returns the trend of a thermal zone, i.e the rate of change
342of temperature of the thermal zone. Ideally, the thermal sensor drivers
343are supposed to implement the callback. If they don't, the thermal
344framework calculated the trend by comparing the previous and the current
345temperature values.
346
3475.2:get_thermal_instance:
348This function returns the thermal_instance corresponding to a given
349{thermal_zone, cooling_device, trip_point} combination. Returns NULL
350if such an instance does not exist.
351
3525.3:notify_thermal_framework:
353This function handles the trip events from sensor drivers. It starts
354throttling the cooling devices according to the policy configured.
355For CRITICAL and HOT trip points, this notifies the respective drivers,
356and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
357The throttling policy is based on the configured platform data; if no
358platform data is provided, this uses the step_wise throttling policy.
359
3605.4:thermal_cdev_update:
361This function serves as an arbitrator to set the state of a cooling
362device. It sets the cooling device to the deepest cooling state if
363possible.
364
3655.5:thermal_register_governor:
366This function lets the various thermal governors to register themselves
367with the Thermal framework. At run time, depending on a zone's platform
368data, a particular governor is used for throttling.
369
3705.6:thermal_unregister_governor:
371This function unregisters a governor from the thermal framework.
diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
index 4b0e0ca08f40..731086b2fca2 100644
--- a/arch/arm/boot/dts/dbx5x0.dtsi
+++ b/arch/arm/boot/dts/dbx5x0.dtsi
@@ -203,6 +203,14 @@
203 reg = <0x80157450 0xC>; 203 reg = <0x80157450 0xC>;
204 }; 204 };
205 205
206 thermal@801573c0 {
207 compatible = "stericsson,db8500-thermal";
208 reg = <0x801573c0 0x40>;
209 interrupts = <21 0x4>, <22 0x4>;
210 interrupt-names = "IRQ_HOTMON_LOW", "IRQ_HOTMON_HIGH";
211 status = "disabled";
212 };
213
206 db8500-prcmu-regulators { 214 db8500-prcmu-regulators {
207 compatible = "stericsson,db8500-prcmu-regulator"; 215 compatible = "stericsson,db8500-prcmu-regulator";
208 216
@@ -660,5 +668,11 @@
660 ranges = <0 0x50000000 0x4000000>; 668 ranges = <0 0x50000000 0x4000000>;
661 status = "disabled"; 669 status = "disabled";
662 }; 670 };
671
672 cpufreq-cooling {
673 compatible = "stericsson,db8500-cpufreq-cooling";
674 status = "disabled";
675 };
676
663 }; 677 };
664}; 678};
diff --git a/arch/arm/boot/dts/snowball.dts b/arch/arm/boot/dts/snowball.dts
index 702c0baa6004..c6f85f0bc531 100644
--- a/arch/arm/boot/dts/snowball.dts
+++ b/arch/arm/boot/dts/snowball.dts
@@ -99,6 +99,33 @@
99 status = "okay"; 99 status = "okay";
100 }; 100 };
101 101
102 prcmu@80157000 {
103 thermal@801573c0 {
104 num-trips = <4>;
105
106 trip0-temp = <70000>;
107 trip0-type = "active";
108 trip0-cdev-num = <1>;
109 trip0-cdev-name0 = "thermal-cpufreq-0";
110
111 trip1-temp = <75000>;
112 trip1-type = "active";
113 trip1-cdev-num = <1>;
114 trip1-cdev-name0 = "thermal-cpufreq-0";
115
116 trip2-temp = <80000>;
117 trip2-type = "active";
118 trip2-cdev-num = <1>;
119 trip2-cdev-name0 = "thermal-cpufreq-0";
120
121 trip3-temp = <85000>;
122 trip3-type = "critical";
123 trip3-cdev-num = <0>;
124
125 status = "okay";
126 };
127 };
128
102 external-bus@50000000 { 129 external-bus@50000000 {
103 status = "okay"; 130 status = "okay";
104 131
@@ -183,5 +210,9 @@
183 reg = <0x33>; 210 reg = <0x33>;
184 }; 211 };
185 }; 212 };
213
214 cpufreq-cooling {
215 status = "okay";
216 };
186 }; 217 };
187}; 218};
diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig
index da6845493caa..250625d5223f 100644
--- a/arch/arm/configs/u8500_defconfig
+++ b/arch/arm/configs/u8500_defconfig
@@ -69,6 +69,8 @@ CONFIG_GPIO_TC3589X=y
69CONFIG_POWER_SUPPLY=y 69CONFIG_POWER_SUPPLY=y
70CONFIG_AB8500_BM=y 70CONFIG_AB8500_BM=y
71CONFIG_AB8500_BATTERY_THERM_ON_BATCTRL=y 71CONFIG_AB8500_BATTERY_THERM_ON_BATCTRL=y
72CONFIG_THERMAL=y
73CONFIG_CPU_THERMAL=y
72CONFIG_MFD_STMPE=y 74CONFIG_MFD_STMPE=y
73CONFIG_MFD_TC3589X=y 75CONFIG_MFD_TC3589X=y
74CONFIG_AB5500_CORE=y 76CONFIG_AB5500_CORE=y
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index 0a3dd601a400..2d16b1dd5fec 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -16,6 +16,7 @@
16#include <linux/io.h> 16#include <linux/io.h>
17#include <linux/i2c.h> 17#include <linux/i2c.h>
18#include <linux/platform_data/i2c-nomadik.h> 18#include <linux/platform_data/i2c-nomadik.h>
19#include <linux/platform_data/db8500_thermal.h>
19#include <linux/gpio.h> 20#include <linux/gpio.h>
20#include <linux/amba/bus.h> 21#include <linux/amba/bus.h>
21#include <linux/amba/pl022.h> 22#include <linux/amba/pl022.h>
@@ -229,6 +230,67 @@ static struct ab8500_platform_data ab8500_platdata = {
229}; 230};
230 231
231/* 232/*
233 * Thermal Sensor
234 */
235
236static struct resource db8500_thsens_resources[] = {
237 {
238 .name = "IRQ_HOTMON_LOW",
239 .start = IRQ_PRCMU_HOTMON_LOW,
240 .end = IRQ_PRCMU_HOTMON_LOW,
241 .flags = IORESOURCE_IRQ,
242 },
243 {
244 .name = "IRQ_HOTMON_HIGH",
245 .start = IRQ_PRCMU_HOTMON_HIGH,
246 .end = IRQ_PRCMU_HOTMON_HIGH,
247 .flags = IORESOURCE_IRQ,
248 },
249};
250
251static struct db8500_thsens_platform_data db8500_thsens_data = {
252 .trip_points[0] = {
253 .temp = 70000,
254 .type = THERMAL_TRIP_ACTIVE,
255 .cdev_name = {
256 [0] = "thermal-cpufreq-0",
257 },
258 },
259 .trip_points[1] = {
260 .temp = 75000,
261 .type = THERMAL_TRIP_ACTIVE,
262 .cdev_name = {
263 [0] = "thermal-cpufreq-0",
264 },
265 },
266 .trip_points[2] = {
267 .temp = 80000,
268 .type = THERMAL_TRIP_ACTIVE,
269 .cdev_name = {
270 [0] = "thermal-cpufreq-0",
271 },
272 },
273 .trip_points[3] = {
274 .temp = 85000,
275 .type = THERMAL_TRIP_CRITICAL,
276 },
277 .num_trips = 4,
278};
279
280static struct platform_device u8500_thsens_device = {
281 .name = "db8500-thermal",
282 .resource = db8500_thsens_resources,
283 .num_resources = ARRAY_SIZE(db8500_thsens_resources),
284 .dev = {
285 .platform_data = &db8500_thsens_data,
286 },
287};
288
289static struct platform_device u8500_cpufreq_cooling_device = {
290 .name = "db8500-cpufreq-cooling",
291};
292
293/*
232 * TPS61052 294 * TPS61052
233 */ 295 */
234 296
@@ -583,6 +645,8 @@ static struct platform_device *snowball_platform_devs[] __initdata = {
583 &snowball_key_dev, 645 &snowball_key_dev,
584 &snowball_sbnet_dev, 646 &snowball_sbnet_dev,
585 &snowball_gpio_en_3v3_regulator_dev, 647 &snowball_gpio_en_3v3_regulator_dev,
648 &u8500_thsens_device,
649 &u8500_cpufreq_cooling_device,
586}; 650};
587 651
588static void __init mop500_init_machine(void) 652static void __init mop500_init_machine(void)
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 6e8cc16b54c1..506fbd4b5733 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -900,14 +900,14 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
900 if (tz->trips.passive.flags.valid) 900 if (tz->trips.passive.flags.valid)
901 tz->thermal_zone = 901 tz->thermal_zone =
902 thermal_zone_device_register("acpitz", trips, 0, tz, 902 thermal_zone_device_register("acpitz", trips, 0, tz,
903 &acpi_thermal_zone_ops, 903 &acpi_thermal_zone_ops, NULL,
904 tz->trips.passive.tsp*100, 904 tz->trips.passive.tsp*100,
905 tz->polling_frequency*100); 905 tz->polling_frequency*100);
906 else 906 else
907 tz->thermal_zone = 907 tz->thermal_zone =
908 thermal_zone_device_register("acpitz", trips, 0, tz, 908 thermal_zone_device_register("acpitz", trips, 0, tz,
909 &acpi_thermal_zone_ops, 0, 909 &acpi_thermal_zone_ops, NULL,
910 tz->polling_frequency*100); 910 0, tz->polling_frequency*100);
911 if (IS_ERR(tz->thermal_zone)) 911 if (IS_ERR(tz->thermal_zone))
912 return -ENODEV; 912 return -ENODEV;
913 913
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 84c56881ba80..c2e3e63d2c15 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -662,7 +662,7 @@ static int acerhdf_register_thermal(void)
662 return -EINVAL; 662 return -EINVAL;
663 663
664 thz_dev = thermal_zone_device_register("acerhdf", 1, 0, NULL, 664 thz_dev = thermal_zone_device_register("acerhdf", 1, 0, NULL,
665 &acerhdf_dev_ops, 0, 665 &acerhdf_dev_ops, NULL, 0,
666 (kernelmode) ? interval*1000 : 0); 666 (kernelmode) ? interval*1000 : 0);
667 if (IS_ERR(thz_dev)) 667 if (IS_ERR(thz_dev))
668 return -EINVAL; 668 return -EINVAL;
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
index c8097616dd62..93de09019d1d 100644
--- a/drivers/platform/x86/intel_mid_thermal.c
+++ b/drivers/platform/x86/intel_mid_thermal.c
@@ -502,7 +502,7 @@ static int mid_thermal_probe(struct platform_device *pdev)
502 goto err; 502 goto err;
503 } 503 }
504 pinfo->tzd[i] = thermal_zone_device_register(name[i], 504 pinfo->tzd[i] = thermal_zone_device_register(name[i],
505 0, 0, td_info, &tzd_ops, 0, 0); 505 0, 0, td_info, &tzd_ops, NULL, 0, 0);
506 if (IS_ERR(pinfo->tzd[i])) { 506 if (IS_ERR(pinfo->tzd[i])) {
507 kfree(td_info); 507 kfree(td_info);
508 ret = PTR_ERR(pinfo->tzd[i]); 508 ret = PTR_ERR(pinfo->tzd[i]);
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 2436f1350013..f77a41272e5d 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -201,7 +201,7 @@ static int psy_register_thermal(struct power_supply *psy)
201 for (i = 0; i < psy->num_properties; i++) { 201 for (i = 0; i < psy->num_properties; i++) {
202 if (psy->properties[i] == POWER_SUPPLY_PROP_TEMP) { 202 if (psy->properties[i] == POWER_SUPPLY_PROP_TEMP) {
203 psy->tzd = thermal_zone_device_register(psy->name, 0, 0, 203 psy->tzd = thermal_zone_device_register(psy->name, 0, 0,
204 psy, &psy_tzd_ops, 0, 0); 204 psy, &psy_tzd_ops, NULL, 0, 0);
205 if (IS_ERR(psy->tzd)) 205 if (IS_ERR(psy->tzd))
206 return PTR_ERR(psy->tzd); 206 return PTR_ERR(psy->tzd);
207 break; 207 break;
diff --git a/drivers/staging/omap-thermal/omap-thermal-common.c b/drivers/staging/omap-thermal/omap-thermal-common.c
index 15e9723ba4d6..61f1070c6667 100644
--- a/drivers/staging/omap-thermal/omap-thermal-common.c
+++ b/drivers/staging/omap-thermal/omap-thermal-common.c
@@ -270,7 +270,7 @@ int omap_thermal_expose_sensor(struct omap_bandgap *bg_ptr, int id,
270 /* Create thermal zone */ 270 /* Create thermal zone */
271 data->omap_thermal = thermal_zone_device_register(domain, 271 data->omap_thermal = thermal_zone_device_register(domain,
272 OMAP_TRIP_NUMBER, 0, data, &omap_thermal_ops, 272 OMAP_TRIP_NUMBER, 0, data, &omap_thermal_ops,
273 FAST_TEMP_MONITORING_RATE, 273 NULL, FAST_TEMP_MONITORING_RATE,
274 FAST_TEMP_MONITORING_RATE); 274 FAST_TEMP_MONITORING_RATE);
275 if (IS_ERR_OR_NULL(data->omap_thermal)) { 275 if (IS_ERR_OR_NULL(data->omap_thermal)) {
276 dev_err(bg_ptr->dev, "thermal zone device is NULL\n"); 276 dev_err(bg_ptr->dev, "thermal zone device is NULL\n");
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index e1cb6bd75f60..8636fae1f7ec 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -13,15 +13,62 @@ menuconfig THERMAL
13 All platforms with ACPI thermal support can use this driver. 13 All platforms with ACPI thermal support can use this driver.
14 If you want this support, you should say Y or M here. 14 If you want this support, you should say Y or M here.
15 15
16if THERMAL
17
16config THERMAL_HWMON 18config THERMAL_HWMON
17 bool 19 bool
18 depends on THERMAL
19 depends on HWMON=y || HWMON=THERMAL 20 depends on HWMON=y || HWMON=THERMAL
20 default y 21 default y
21 22
23choice
24 prompt "Default Thermal governor"
25 default THERMAL_DEFAULT_GOV_STEP_WISE
26 help
27 This option sets which thermal governor shall be loaded at
28 startup. If in doubt, select 'step_wise'.
29
30config THERMAL_DEFAULT_GOV_STEP_WISE
31 bool "step_wise"
32 select STEP_WISE
33 help
34 Use the step_wise governor as default. This throttles the
35 devices one step at a time.
36
37config THERMAL_DEFAULT_GOV_FAIR_SHARE
38 bool "fair_share"
39 select FAIR_SHARE
40 help
41 Use the fair_share governor as default. This throttles the
42 devices based on their 'contribution' to a zone. The
43 contribution should be provided through platform data.
44
45config THERMAL_DEFAULT_GOV_USER_SPACE
46 bool "user_space"
47 select USER_SPACE
48 help
49 Select this if you want to let the user space manage the
50 lpatform thermals.
51
52endchoice
53
54config FAIR_SHARE
55 bool "Fair-share thermal governor"
56 help
57 Enable this to manage platform thermals using fair-share governor.
58
59config STEP_WISE
60 bool "Step_wise thermal governor"
61 help
62 Enable this to manage platform thermals using a simple linear
63
64config USER_SPACE
65 bool "User_space thermal governor"
66 help
67 Enable this to let the user space manage the platform thermals.
68
22config CPU_THERMAL 69config CPU_THERMAL
23 bool "generic cpu cooling support" 70 tristate "generic cpu cooling support"
24 depends on THERMAL && CPU_FREQ 71 depends on CPU_FREQ
25 select CPU_FREQ_TABLE 72 select CPU_FREQ_TABLE
26 help 73 help
27 This implements the generic cpu cooling mechanism through frequency 74 This implements the generic cpu cooling mechanism through frequency
@@ -33,7 +80,6 @@ config CPU_THERMAL
33 80
34config SPEAR_THERMAL 81config SPEAR_THERMAL
35 bool "SPEAr thermal sensor driver" 82 bool "SPEAr thermal sensor driver"
36 depends on THERMAL
37 depends on PLAT_SPEAR 83 depends on PLAT_SPEAR
38 depends on OF 84 depends on OF
39 help 85 help
@@ -42,7 +88,6 @@ config SPEAR_THERMAL
42 88
43config RCAR_THERMAL 89config RCAR_THERMAL
44 tristate "Renesas R-Car thermal driver" 90 tristate "Renesas R-Car thermal driver"
45 depends on THERMAL
46 depends on ARCH_SHMOBILE 91 depends on ARCH_SHMOBILE
47 help 92 help
48 Enable this to plug the R-Car thermal sensor driver into the Linux 93 Enable this to plug the R-Car thermal sensor driver into the Linux
@@ -50,8 +95,31 @@ config RCAR_THERMAL
50 95
51config EXYNOS_THERMAL 96config EXYNOS_THERMAL
52 tristate "Temperature sensor on Samsung EXYNOS" 97 tristate "Temperature sensor on Samsung EXYNOS"
53 depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5) && THERMAL 98 depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5)
54 select CPU_FREQ_TABLE 99 depends on CPU_THERMAL
55 help 100 help
56 If you say yes here you get support for TMU (Thermal Managment 101 If you say yes here you get support for TMU (Thermal Managment
57 Unit) on SAMSUNG EXYNOS series of SoC. 102 Unit) on SAMSUNG EXYNOS series of SoC.
103
104config DB8500_THERMAL
105 bool "DB8500 thermal management"
106 depends on ARCH_U8500
107 default y
108 help
109 Adds DB8500 thermal management implementation according to the thermal
110 management framework. A thermal zone with several trip points will be
111 created. Cooling devices can be bound to the trip points to cool this
112 thermal zone if trip points reached.
113
114config DB8500_CPUFREQ_COOLING
115 tristate "DB8500 cpufreq cooling"
116 depends on ARCH_U8500
117 depends on CPU_THERMAL
118 default y
119 help
120 Adds DB8500 cpufreq cooling devices, and these cooling devices can be
121 bound to thermal zone trip points. When a trip point reached, the
122 bound cpufreq cooling device turns active to set CPU frequency low to
123 cool down the CPU.
124
125endif
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 885550dc64b7..d8da683245fc 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -3,7 +3,18 @@
3# 3#
4 4
5obj-$(CONFIG_THERMAL) += thermal_sys.o 5obj-$(CONFIG_THERMAL) += thermal_sys.o
6obj-$(CONFIG_CPU_THERMAL) += cpu_cooling.o 6
7obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o 7# governors
8obj-$(CONFIG_FAIR_SHARE) += fair_share.o
9obj-$(CONFIG_STEP_WISE) += step_wise.o
10obj-$(CONFIG_USER_SPACE) += user_space.o
11
12# cpufreq cooling
13obj-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
14
15# platform thermal drivers
16obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
8obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o 17obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o
9obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o 18obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
19obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
20obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index cc1c930a90e4..836828e29a87 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -58,12 +58,13 @@ struct cpufreq_cooling_device {
58}; 58};
59static LIST_HEAD(cooling_cpufreq_list); 59static LIST_HEAD(cooling_cpufreq_list);
60static DEFINE_IDR(cpufreq_idr); 60static DEFINE_IDR(cpufreq_idr);
61static DEFINE_MUTEX(cooling_cpufreq_lock);
61 62
62static struct mutex cooling_cpufreq_lock; 63static unsigned int cpufreq_dev_count;
63 64
64/* notify_table passes value to the CPUFREQ_ADJUST callback function. */ 65/* notify_table passes value to the CPUFREQ_ADJUST callback function. */
65#define NOTIFY_INVALID NULL 66#define NOTIFY_INVALID NULL
66struct cpufreq_cooling_device *notify_device; 67static struct cpufreq_cooling_device *notify_device;
67 68
68/** 69/**
69 * get_idr - function to get a unique id. 70 * get_idr - function to get a unique id.
@@ -240,42 +241,32 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
240static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, 241static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
241 unsigned long *state) 242 unsigned long *state)
242{ 243{
243 int ret = -EINVAL, i = 0; 244 struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
244 struct cpufreq_cooling_device *cpufreq_device; 245 struct cpumask *maskPtr = &cpufreq_device->allowed_cpus;
245 struct cpumask *maskPtr;
246 unsigned int cpu; 246 unsigned int cpu;
247 struct cpufreq_frequency_table *table; 247 struct cpufreq_frequency_table *table;
248 unsigned long count = 0;
249 int i = 0;
248 250
249 mutex_lock(&cooling_cpufreq_lock);
250 list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
251 if (cpufreq_device && cpufreq_device->cool_dev == cdev)
252 break;
253 }
254 if (cpufreq_device == NULL)
255 goto return_get_max_state;
256
257 maskPtr = &cpufreq_device->allowed_cpus;
258 cpu = cpumask_any(maskPtr); 251 cpu = cpumask_any(maskPtr);
259 table = cpufreq_frequency_get_table(cpu); 252 table = cpufreq_frequency_get_table(cpu);
260 if (!table) { 253 if (!table) {
261 *state = 0; 254 *state = 0;
262 ret = 0; 255 return 0;
263 goto return_get_max_state;
264 } 256 }
265 257
266 while (table[i].frequency != CPUFREQ_TABLE_END) { 258 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
267 if (table[i].frequency == CPUFREQ_ENTRY_INVALID) 259 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
268 continue; 260 continue;
269 i++; 261 count++;
270 } 262 }
271 if (i > 0) { 263
272 *state = --i; 264 if (count > 0) {
273 ret = 0; 265 *state = --count;
266 return 0;
274 } 267 }
275 268
276return_get_max_state: 269 return -EINVAL;
277 mutex_unlock(&cooling_cpufreq_lock);
278 return ret;
279} 270}
280 271
281/** 272/**
@@ -286,20 +277,10 @@ return_get_max_state:
286static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, 277static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
287 unsigned long *state) 278 unsigned long *state)
288{ 279{
289 int ret = -EINVAL; 280 struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
290 struct cpufreq_cooling_device *cpufreq_device;
291 281
292 mutex_lock(&cooling_cpufreq_lock); 282 *state = cpufreq_device->cpufreq_state;
293 list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) { 283 return 0;
294 if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
295 *state = cpufreq_device->cpufreq_state;
296 ret = 0;
297 break;
298 }
299 }
300 mutex_unlock(&cooling_cpufreq_lock);
301
302 return ret;
303} 284}
304 285
305/** 286/**
@@ -310,22 +291,9 @@ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
310static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, 291static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
311 unsigned long state) 292 unsigned long state)
312{ 293{
313 int ret = -EINVAL; 294 struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
314 struct cpufreq_cooling_device *cpufreq_device;
315 295
316 mutex_lock(&cooling_cpufreq_lock); 296 return cpufreq_apply_cooling(cpufreq_device, state);
317 list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
318 if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
319 ret = 0;
320 break;
321 }
322 }
323 if (!ret)
324 ret = cpufreq_apply_cooling(cpufreq_device, state);
325
326 mutex_unlock(&cooling_cpufreq_lock);
327
328 return ret;
329} 297}
330 298
331/* Bind cpufreq callbacks to thermal cooling device ops */ 299/* Bind cpufreq callbacks to thermal cooling device ops */
@@ -345,18 +313,15 @@ static struct notifier_block thermal_cpufreq_notifier_block = {
345 * @clip_cpus: cpumask of cpus where the frequency constraints will happen. 313 * @clip_cpus: cpumask of cpus where the frequency constraints will happen.
346 */ 314 */
347struct thermal_cooling_device *cpufreq_cooling_register( 315struct thermal_cooling_device *cpufreq_cooling_register(
348 struct cpumask *clip_cpus) 316 const struct cpumask *clip_cpus)
349{ 317{
350 struct thermal_cooling_device *cool_dev; 318 struct thermal_cooling_device *cool_dev;
351 struct cpufreq_cooling_device *cpufreq_dev = NULL; 319 struct cpufreq_cooling_device *cpufreq_dev = NULL;
352 unsigned int cpufreq_dev_count = 0, min = 0, max = 0; 320 unsigned int min = 0, max = 0;
353 char dev_name[THERMAL_NAME_LENGTH]; 321 char dev_name[THERMAL_NAME_LENGTH];
354 int ret = 0, i; 322 int ret = 0, i;
355 struct cpufreq_policy policy; 323 struct cpufreq_policy policy;
356 324
357 list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node)
358 cpufreq_dev_count++;
359
360 /*Verify that all the clip cpus have same freq_min, freq_max limit*/ 325 /*Verify that all the clip cpus have same freq_min, freq_max limit*/
361 for_each_cpu(i, clip_cpus) { 326 for_each_cpu(i, clip_cpus) {
362 /*continue if cpufreq policy not found and not return error*/ 327 /*continue if cpufreq policy not found and not return error*/
@@ -369,7 +334,7 @@ struct thermal_cooling_device *cpufreq_cooling_register(
369 if (min != policy.cpuinfo.min_freq || 334 if (min != policy.cpuinfo.min_freq ||
370 max != policy.cpuinfo.max_freq) 335 max != policy.cpuinfo.max_freq)
371 return ERR_PTR(-EINVAL); 336 return ERR_PTR(-EINVAL);
372} 337 }
373 } 338 }
374 cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device), 339 cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device),
375 GFP_KERNEL); 340 GFP_KERNEL);
@@ -378,9 +343,6 @@ struct thermal_cooling_device *cpufreq_cooling_register(
378 343
379 cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus); 344 cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus);
380 345
381 if (cpufreq_dev_count == 0)
382 mutex_init(&cooling_cpufreq_lock);
383
384 ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); 346 ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
385 if (ret) { 347 if (ret) {
386 kfree(cpufreq_dev); 348 kfree(cpufreq_dev);
@@ -399,12 +361,12 @@ struct thermal_cooling_device *cpufreq_cooling_register(
399 cpufreq_dev->cool_dev = cool_dev; 361 cpufreq_dev->cool_dev = cool_dev;
400 cpufreq_dev->cpufreq_state = 0; 362 cpufreq_dev->cpufreq_state = 0;
401 mutex_lock(&cooling_cpufreq_lock); 363 mutex_lock(&cooling_cpufreq_lock);
402 list_add_tail(&cpufreq_dev->node, &cooling_cpufreq_list);
403 364
404 /* Register the notifier for first cpufreq cooling device */ 365 /* Register the notifier for first cpufreq cooling device */
405 if (cpufreq_dev_count == 0) 366 if (cpufreq_dev_count == 0)
406 cpufreq_register_notifier(&thermal_cpufreq_notifier_block, 367 cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
407 CPUFREQ_POLICY_NOTIFIER); 368 CPUFREQ_POLICY_NOTIFIER);
369 cpufreq_dev_count++;
408 370
409 mutex_unlock(&cooling_cpufreq_lock); 371 mutex_unlock(&cooling_cpufreq_lock);
410 return cool_dev; 372 return cool_dev;
@@ -417,33 +379,20 @@ EXPORT_SYMBOL(cpufreq_cooling_register);
417 */ 379 */
418void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) 380void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
419{ 381{
420 struct cpufreq_cooling_device *cpufreq_dev = NULL; 382 struct cpufreq_cooling_device *cpufreq_dev = cdev->devdata;
421 unsigned int cpufreq_dev_count = 0;
422 383
423 mutex_lock(&cooling_cpufreq_lock); 384 mutex_lock(&cooling_cpufreq_lock);
424 list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node) { 385 cpufreq_dev_count--;
425 if (cpufreq_dev && cpufreq_dev->cool_dev == cdev)
426 break;
427 cpufreq_dev_count++;
428 }
429
430 if (!cpufreq_dev || cpufreq_dev->cool_dev != cdev) {
431 mutex_unlock(&cooling_cpufreq_lock);
432 return;
433 }
434
435 list_del(&cpufreq_dev->node);
436 386
437 /* Unregister the notifier for the last cpufreq cooling device */ 387 /* Unregister the notifier for the last cpufreq cooling device */
438 if (cpufreq_dev_count == 1) { 388 if (cpufreq_dev_count == 0) {
439 cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, 389 cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
440 CPUFREQ_POLICY_NOTIFIER); 390 CPUFREQ_POLICY_NOTIFIER);
441 } 391 }
442 mutex_unlock(&cooling_cpufreq_lock); 392 mutex_unlock(&cooling_cpufreq_lock);
393
443 thermal_cooling_device_unregister(cpufreq_dev->cool_dev); 394 thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
444 release_idr(&cpufreq_idr, cpufreq_dev->id); 395 release_idr(&cpufreq_idr, cpufreq_dev->id);
445 if (cpufreq_dev_count == 1)
446 mutex_destroy(&cooling_cpufreq_lock);
447 kfree(cpufreq_dev); 396 kfree(cpufreq_dev);
448} 397}
449EXPORT_SYMBOL(cpufreq_cooling_unregister); 398EXPORT_SYMBOL(cpufreq_cooling_unregister);
diff --git a/drivers/thermal/db8500_cpufreq_cooling.c b/drivers/thermal/db8500_cpufreq_cooling.c
new file mode 100644
index 000000000000..4cf8e72af90a
--- /dev/null
+++ b/drivers/thermal/db8500_cpufreq_cooling.c
@@ -0,0 +1,108 @@
1/*
2 * db8500_cpufreq_cooling.c - DB8500 cpufreq works as cooling device.
3 *
4 * Copyright (C) 2012 ST-Ericsson
5 * Copyright (C) 2012 Linaro Ltd.
6 *
7 * Author: Hongbo Zhang <hongbo.zhang@linaro.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19
20#include <linux/cpu_cooling.h>
21#include <linux/cpufreq.h>
22#include <linux/err.h>
23#include <linux/module.h>
24#include <linux/platform_device.h>
25#include <linux/slab.h>
26
27static int db8500_cpufreq_cooling_probe(struct platform_device *pdev)
28{
29 struct thermal_cooling_device *cdev;
30 struct cpumask mask_val;
31
32 /* make sure cpufreq driver has been initialized */
33 if (!cpufreq_frequency_get_table(0))
34 return -EPROBE_DEFER;
35
36 cpumask_set_cpu(0, &mask_val);
37 cdev = cpufreq_cooling_register(&mask_val);
38
39 if (IS_ERR_OR_NULL(cdev)) {
40 dev_err(&pdev->dev, "Failed to register cooling device\n");
41 return PTR_ERR(cdev);
42 }
43
44 platform_set_drvdata(pdev, cdev);
45
46 dev_info(&pdev->dev, "Cooling device registered: %s\n", cdev->type);
47
48 return 0;
49}
50
51static int db8500_cpufreq_cooling_remove(struct platform_device *pdev)
52{
53 struct thermal_cooling_device *cdev = platform_get_drvdata(pdev);
54
55 cpufreq_cooling_unregister(cdev);
56
57 return 0;
58}
59
60static int db8500_cpufreq_cooling_suspend(struct platform_device *pdev,
61 pm_message_t state)
62{
63 return -ENOSYS;
64}
65
66static int db8500_cpufreq_cooling_resume(struct platform_device *pdev)
67{
68 return -ENOSYS;
69}
70
71#ifdef CONFIG_OF
72static const struct of_device_id db8500_cpufreq_cooling_match[] = {
73 { .compatible = "stericsson,db8500-cpufreq-cooling" },
74 {},
75};
76#else
77#define db8500_cpufreq_cooling_match NULL
78#endif
79
80static struct platform_driver db8500_cpufreq_cooling_driver = {
81 .driver = {
82 .owner = THIS_MODULE,
83 .name = "db8500-cpufreq-cooling",
84 .of_match_table = db8500_cpufreq_cooling_match,
85 },
86 .probe = db8500_cpufreq_cooling_probe,
87 .suspend = db8500_cpufreq_cooling_suspend,
88 .resume = db8500_cpufreq_cooling_resume,
89 .remove = db8500_cpufreq_cooling_remove,
90};
91
92static int __init db8500_cpufreq_cooling_init(void)
93{
94 return platform_driver_register(&db8500_cpufreq_cooling_driver);
95}
96
97static void __exit db8500_cpufreq_cooling_exit(void)
98{
99 platform_driver_unregister(&db8500_cpufreq_cooling_driver);
100}
101
102/* Should be later than db8500_cpufreq_register */
103late_initcall(db8500_cpufreq_cooling_init);
104module_exit(db8500_cpufreq_cooling_exit);
105
106MODULE_AUTHOR("Hongbo Zhang <hongbo.zhang@stericsson.com>");
107MODULE_DESCRIPTION("DB8500 cpufreq cooling driver");
108MODULE_LICENSE("GPL");
diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c
new file mode 100644
index 000000000000..ec71ade3e317
--- /dev/null
+++ b/drivers/thermal/db8500_thermal.c
@@ -0,0 +1,531 @@
1/*
2 * db8500_thermal.c - DB8500 Thermal Management Implementation
3 *
4 * Copyright (C) 2012 ST-Ericsson
5 * Copyright (C) 2012 Linaro Ltd.
6 *
7 * Author: Hongbo Zhang <hongbo.zhang@linaro.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19
20#include <linux/cpu_cooling.h>
21#include <linux/interrupt.h>
22#include <linux/mfd/dbx500-prcmu.h>
23#include <linux/module.h>
24#include <linux/of.h>
25#include <linux/platform_data/db8500_thermal.h>
26#include <linux/platform_device.h>
27#include <linux/slab.h>
28#include <linux/thermal.h>
29
30#define PRCMU_DEFAULT_MEASURE_TIME 0xFFF
31#define PRCMU_DEFAULT_LOW_TEMP 0
32
33struct db8500_thermal_zone {
34 struct thermal_zone_device *therm_dev;
35 struct mutex th_lock;
36 struct work_struct therm_work;
37 struct db8500_thsens_platform_data *trip_tab;
38 enum thermal_device_mode mode;
39 enum thermal_trend trend;
40 unsigned long cur_temp_pseudo;
41 unsigned int cur_index;
42};
43
44/* Local function to check if thermal zone matches cooling devices */
45static int db8500_thermal_match_cdev(struct thermal_cooling_device *cdev,
46 struct db8500_trip_point *trip_point)
47{
48 int i;
49
50 if (!strlen(cdev->type))
51 return -EINVAL;
52
53 for (i = 0; i < COOLING_DEV_MAX; i++) {
54 if (!strcmp(trip_point->cdev_name[i], cdev->type))
55 return 0;
56 }
57
58 return -ENODEV;
59}
60
61/* Callback to bind cooling device to thermal zone */
62static int db8500_cdev_bind(struct thermal_zone_device *thermal,
63 struct thermal_cooling_device *cdev)
64{
65 struct db8500_thermal_zone *pzone = thermal->devdata;
66 struct db8500_thsens_platform_data *ptrips = pzone->trip_tab;
67 unsigned long max_state, upper, lower;
68 int i, ret = -EINVAL;
69
70 cdev->ops->get_max_state(cdev, &max_state);
71
72 for (i = 0; i < ptrips->num_trips; i++) {
73 if (db8500_thermal_match_cdev(cdev, &ptrips->trip_points[i]))
74 continue;
75
76 upper = lower = i > max_state ? max_state : i;
77
78 ret = thermal_zone_bind_cooling_device(thermal, i, cdev,
79 upper, lower);
80
81 dev_info(&cdev->device, "%s bind to %d: %d-%s\n", cdev->type,
82 i, ret, ret ? "fail" : "succeed");
83 }
84
85 return ret;
86}
87
88/* Callback to unbind cooling device from thermal zone */
89static int db8500_cdev_unbind(struct thermal_zone_device *thermal,
90 struct thermal_cooling_device *cdev)
91{
92 struct db8500_thermal_zone *pzone = thermal->devdata;
93 struct db8500_thsens_platform_data *ptrips = pzone->trip_tab;
94 int i, ret = -EINVAL;
95
96 for (i = 0; i < ptrips->num_trips; i++) {
97 if (db8500_thermal_match_cdev(cdev, &ptrips->trip_points[i]))
98 continue;
99
100 ret = thermal_zone_unbind_cooling_device(thermal, i, cdev);
101
102 dev_info(&cdev->device, "%s unbind from %d: %s\n", cdev->type,
103 i, ret ? "fail" : "succeed");
104 }
105
106 return ret;
107}
108
109/* Callback to get current temperature */
110static int db8500_sys_get_temp(struct thermal_zone_device *thermal,
111 unsigned long *temp)
112{
113 struct db8500_thermal_zone *pzone = thermal->devdata;
114
115 /*
116 * TODO: There is no PRCMU interface to get temperature data currently,
117 * so a pseudo temperature is returned , it works for thermal framework
118 * and this will be fixed when the PRCMU interface is available.
119 */
120 *temp = pzone->cur_temp_pseudo;
121
122 return 0;
123}
124
125/* Callback to get temperature changing trend */
126static int db8500_sys_get_trend(struct thermal_zone_device *thermal,
127 int trip, enum thermal_trend *trend)
128{
129 struct db8500_thermal_zone *pzone = thermal->devdata;
130
131 *trend = pzone->trend;
132
133 return 0;
134}
135
136/* Callback to get thermal zone mode */
137static int db8500_sys_get_mode(struct thermal_zone_device *thermal,
138 enum thermal_device_mode *mode)
139{
140 struct db8500_thermal_zone *pzone = thermal->devdata;
141
142 mutex_lock(&pzone->th_lock);
143 *mode = pzone->mode;
144 mutex_unlock(&pzone->th_lock);
145
146 return 0;
147}
148
149/* Callback to set thermal zone mode */
150static int db8500_sys_set_mode(struct thermal_zone_device *thermal,
151 enum thermal_device_mode mode)
152{
153 struct db8500_thermal_zone *pzone = thermal->devdata;
154
155 mutex_lock(&pzone->th_lock);
156
157 pzone->mode = mode;
158 if (mode == THERMAL_DEVICE_ENABLED)
159 schedule_work(&pzone->therm_work);
160
161 mutex_unlock(&pzone->th_lock);
162
163 return 0;
164}
165
166/* Callback to get trip point type */
167static int db8500_sys_get_trip_type(struct thermal_zone_device *thermal,
168 int trip, enum thermal_trip_type *type)
169{
170 struct db8500_thermal_zone *pzone = thermal->devdata;
171 struct db8500_thsens_platform_data *ptrips = pzone->trip_tab;
172
173 if (trip >= ptrips->num_trips)
174 return -EINVAL;
175
176 *type = ptrips->trip_points[trip].type;
177
178 return 0;
179}
180
181/* Callback to get trip point temperature */
182static int db8500_sys_get_trip_temp(struct thermal_zone_device *thermal,
183 int trip, unsigned long *temp)
184{
185 struct db8500_thermal_zone *pzone = thermal->devdata;
186 struct db8500_thsens_platform_data *ptrips = pzone->trip_tab;
187
188 if (trip >= ptrips->num_trips)
189 return -EINVAL;
190
191 *temp = ptrips->trip_points[trip].temp;
192
193 return 0;
194}
195
196/* Callback to get critical trip point temperature */
197static int db8500_sys_get_crit_temp(struct thermal_zone_device *thermal,
198 unsigned long *temp)
199{
200 struct db8500_thermal_zone *pzone = thermal->devdata;
201 struct db8500_thsens_platform_data *ptrips = pzone->trip_tab;
202 int i;
203
204 for (i = ptrips->num_trips - 1; i > 0; i--) {
205 if (ptrips->trip_points[i].type == THERMAL_TRIP_CRITICAL) {
206 *temp = ptrips->trip_points[i].temp;
207 return 0;
208 }
209 }
210
211 return -EINVAL;
212}
213
214static struct thermal_zone_device_ops thdev_ops = {
215 .bind = db8500_cdev_bind,
216 .unbind = db8500_cdev_unbind,
217 .get_temp = db8500_sys_get_temp,
218 .get_trend = db8500_sys_get_trend,
219 .get_mode = db8500_sys_get_mode,
220 .set_mode = db8500_sys_set_mode,
221 .get_trip_type = db8500_sys_get_trip_type,
222 .get_trip_temp = db8500_sys_get_trip_temp,
223 .get_crit_temp = db8500_sys_get_crit_temp,
224};
225
226static void db8500_thermal_update_config(struct db8500_thermal_zone *pzone,
227 unsigned int idx, enum thermal_trend trend,
228 unsigned long next_low, unsigned long next_high)
229{
230 prcmu_stop_temp_sense();
231
232 pzone->cur_index = idx;
233 pzone->cur_temp_pseudo = (next_low + next_high)/2;
234 pzone->trend = trend;
235
236 prcmu_config_hotmon((u8)(next_low/1000), (u8)(next_high/1000));
237 prcmu_start_temp_sense(PRCMU_DEFAULT_MEASURE_TIME);
238}
239
240static irqreturn_t prcmu_low_irq_handler(int irq, void *irq_data)
241{
242 struct db8500_thermal_zone *pzone = irq_data;
243 struct db8500_thsens_platform_data *ptrips = pzone->trip_tab;
244 unsigned int idx = pzone->cur_index;
245 unsigned long next_low, next_high;
246
247 if (unlikely(idx == 0))
248 /* Meaningless for thermal management, ignoring it */
249 return IRQ_HANDLED;
250
251 if (idx == 1) {
252 next_high = ptrips->trip_points[0].temp;
253 next_low = PRCMU_DEFAULT_LOW_TEMP;
254 } else {
255 next_high = ptrips->trip_points[idx-1].temp;
256 next_low = ptrips->trip_points[idx-2].temp;
257 }
258 idx -= 1;
259
260 db8500_thermal_update_config(pzone, idx, THERMAL_TREND_DROPPING,
261 next_low, next_high);
262
263 dev_dbg(&pzone->therm_dev->device,
264 "PRCMU set max %ld, min %ld\n", next_high, next_low);
265
266 schedule_work(&pzone->therm_work);
267
268 return IRQ_HANDLED;
269}
270
271static irqreturn_t prcmu_high_irq_handler(int irq, void *irq_data)
272{
273 struct db8500_thermal_zone *pzone = irq_data;
274 struct db8500_thsens_platform_data *ptrips = pzone->trip_tab;
275 unsigned int idx = pzone->cur_index;
276 unsigned long next_low, next_high;
277
278 if (idx < ptrips->num_trips - 1) {
279 next_high = ptrips->trip_points[idx+1].temp;
280 next_low = ptrips->trip_points[idx].temp;
281 idx += 1;
282
283 db8500_thermal_update_config(pzone, idx, THERMAL_TREND_RAISING,
284 next_low, next_high);
285
286 dev_dbg(&pzone->therm_dev->device,
287 "PRCMU set max %ld, min %ld\n", next_high, next_low);
288 } else if (idx == ptrips->num_trips - 1)
289 pzone->cur_temp_pseudo = ptrips->trip_points[idx].temp + 1;
290
291 schedule_work(&pzone->therm_work);
292
293 return IRQ_HANDLED;
294}
295
296static void db8500_thermal_work(struct work_struct *work)
297{
298 enum thermal_device_mode cur_mode;
299 struct db8500_thermal_zone *pzone;
300
301 pzone = container_of(work, struct db8500_thermal_zone, therm_work);
302
303 mutex_lock(&pzone->th_lock);
304 cur_mode = pzone->mode;
305 mutex_unlock(&pzone->th_lock);
306
307 if (cur_mode == THERMAL_DEVICE_DISABLED)
308 return;
309
310 thermal_zone_device_update(pzone->therm_dev);
311 dev_dbg(&pzone->therm_dev->device, "thermal work finished.\n");
312}
313
314#ifdef CONFIG_OF
315static struct db8500_thsens_platform_data*
316 db8500_thermal_parse_dt(struct platform_device *pdev)
317{
318 struct db8500_thsens_platform_data *ptrips;
319 struct device_node *np = pdev->dev.of_node;
320 char prop_name[32];
321 const char *tmp_str;
322 u32 tmp_data;
323 int i, j;
324
325 ptrips = devm_kzalloc(&pdev->dev, sizeof(*ptrips), GFP_KERNEL);
326 if (!ptrips)
327 return NULL;
328
329 if (of_property_read_u32(np, "num-trips", &tmp_data))
330 goto err_parse_dt;
331
332 if (tmp_data > THERMAL_MAX_TRIPS)
333 goto err_parse_dt;
334
335 ptrips->num_trips = tmp_data;
336
337 for (i = 0; i < ptrips->num_trips; i++) {
338 sprintf(prop_name, "trip%d-temp", i);
339 if (of_property_read_u32(np, prop_name, &tmp_data))
340 goto err_parse_dt;
341
342 ptrips->trip_points[i].temp = tmp_data;
343
344 sprintf(prop_name, "trip%d-type", i);
345 if (of_property_read_string(np, prop_name, &tmp_str))
346 goto err_parse_dt;
347
348 if (!strcmp(tmp_str, "active"))
349 ptrips->trip_points[i].type = THERMAL_TRIP_ACTIVE;
350 else if (!strcmp(tmp_str, "passive"))
351 ptrips->trip_points[i].type = THERMAL_TRIP_PASSIVE;
352 else if (!strcmp(tmp_str, "hot"))
353 ptrips->trip_points[i].type = THERMAL_TRIP_HOT;
354 else if (!strcmp(tmp_str, "critical"))
355 ptrips->trip_points[i].type = THERMAL_TRIP_CRITICAL;
356 else
357 goto err_parse_dt;
358
359 sprintf(prop_name, "trip%d-cdev-num", i);
360 if (of_property_read_u32(np, prop_name, &tmp_data))
361 goto err_parse_dt;
362
363 if (tmp_data > COOLING_DEV_MAX)
364 goto err_parse_dt;
365
366 for (j = 0; j < tmp_data; j++) {
367 sprintf(prop_name, "trip%d-cdev-name%d", i, j);
368 if (of_property_read_string(np, prop_name, &tmp_str))
369 goto err_parse_dt;
370
371 if (strlen(tmp_str) >= THERMAL_NAME_LENGTH)
372 goto err_parse_dt;
373
374 strcpy(ptrips->trip_points[i].cdev_name[j], tmp_str);
375 }
376 }
377 return ptrips;
378
379err_parse_dt:
380 dev_err(&pdev->dev, "Parsing device tree data error.\n");
381 return NULL;
382}
383#else
384static inline struct db8500_thsens_platform_data*
385 db8500_thermal_parse_dt(struct platform_device *pdev)
386{
387 return NULL;
388}
389#endif
390
391static int db8500_thermal_probe(struct platform_device *pdev)
392{
393 struct db8500_thermal_zone *pzone = NULL;
394 struct db8500_thsens_platform_data *ptrips = NULL;
395 struct device_node *np = pdev->dev.of_node;
396 int low_irq, high_irq, ret = 0;
397 unsigned long dft_low, dft_high;
398
399 if (np)
400 ptrips = db8500_thermal_parse_dt(pdev);
401 else
402 ptrips = dev_get_platdata(&pdev->dev);
403
404 if (!ptrips)
405 return -EINVAL;
406
407 pzone = devm_kzalloc(&pdev->dev, sizeof(*pzone), GFP_KERNEL);
408 if (!pzone)
409 return -ENOMEM;
410
411 mutex_init(&pzone->th_lock);
412 mutex_lock(&pzone->th_lock);
413
414 pzone->mode = THERMAL_DEVICE_DISABLED;
415 pzone->trip_tab = ptrips;
416
417 INIT_WORK(&pzone->therm_work, db8500_thermal_work);
418
419 low_irq = platform_get_irq_byname(pdev, "IRQ_HOTMON_LOW");
420 if (low_irq < 0) {
421 dev_err(&pdev->dev, "Get IRQ_HOTMON_LOW failed.\n");
422 return low_irq;
423 }
424
425 ret = devm_request_threaded_irq(&pdev->dev, low_irq, NULL,
426 prcmu_low_irq_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT,
427 "dbx500_temp_low", pzone);
428 if (ret < 0) {
429 dev_err(&pdev->dev, "Failed to allocate temp low irq.\n");
430 return ret;
431 }
432
433 high_irq = platform_get_irq_byname(pdev, "IRQ_HOTMON_HIGH");
434 if (high_irq < 0) {
435 dev_err(&pdev->dev, "Get IRQ_HOTMON_HIGH failed.\n");
436 return high_irq;
437 }
438
439 ret = devm_request_threaded_irq(&pdev->dev, high_irq, NULL,
440 prcmu_high_irq_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT,
441 "dbx500_temp_high", pzone);
442 if (ret < 0) {
443 dev_err(&pdev->dev, "Failed to allocate temp high irq.\n");
444 return ret;
445 }
446
447 pzone->therm_dev = thermal_zone_device_register("db8500_thermal_zone",
448 ptrips->num_trips, 0, pzone, &thdev_ops, NULL, 0, 0);
449
450 if (IS_ERR_OR_NULL(pzone->therm_dev)) {
451 dev_err(&pdev->dev, "Register thermal zone device failed.\n");
452 return PTR_ERR(pzone->therm_dev);
453 }
454 dev_info(&pdev->dev, "Thermal zone device registered.\n");
455
456 dft_low = PRCMU_DEFAULT_LOW_TEMP;
457 dft_high = ptrips->trip_points[0].temp;
458
459 db8500_thermal_update_config(pzone, 0, THERMAL_TREND_STABLE,
460 dft_low, dft_high);
461
462 platform_set_drvdata(pdev, pzone);
463 pzone->mode = THERMAL_DEVICE_ENABLED;
464 mutex_unlock(&pzone->th_lock);
465
466 return 0;
467}
468
469static int db8500_thermal_remove(struct platform_device *pdev)
470{
471 struct db8500_thermal_zone *pzone = platform_get_drvdata(pdev);
472
473 thermal_zone_device_unregister(pzone->therm_dev);
474 cancel_work_sync(&pzone->therm_work);
475 mutex_destroy(&pzone->th_lock);
476
477 return 0;
478}
479
480static int db8500_thermal_suspend(struct platform_device *pdev,
481 pm_message_t state)
482{
483 struct db8500_thermal_zone *pzone = platform_get_drvdata(pdev);
484
485 flush_work(&pzone->therm_work);
486 prcmu_stop_temp_sense();
487
488 return 0;
489}
490
491static int db8500_thermal_resume(struct platform_device *pdev)
492{
493 struct db8500_thermal_zone *pzone = platform_get_drvdata(pdev);
494 struct db8500_thsens_platform_data *ptrips = pzone->trip_tab;
495 unsigned long dft_low, dft_high;
496
497 dft_low = PRCMU_DEFAULT_LOW_TEMP;
498 dft_high = ptrips->trip_points[0].temp;
499
500 db8500_thermal_update_config(pzone, 0, THERMAL_TREND_STABLE,
501 dft_low, dft_high);
502
503 return 0;
504}
505
506#ifdef CONFIG_OF
507static const struct of_device_id db8500_thermal_match[] = {
508 { .compatible = "stericsson,db8500-thermal" },
509 {},
510};
511#else
512#define db8500_thermal_match NULL
513#endif
514
515static struct platform_driver db8500_thermal_driver = {
516 .driver = {
517 .owner = THIS_MODULE,
518 .name = "db8500-thermal",
519 .of_match_table = db8500_thermal_match,
520 },
521 .probe = db8500_thermal_probe,
522 .suspend = db8500_thermal_suspend,
523 .resume = db8500_thermal_resume,
524 .remove = db8500_thermal_remove,
525};
526
527module_platform_driver(db8500_thermal_driver);
528
529MODULE_AUTHOR("Hongbo Zhang <hongbo.zhang@stericsson.com>");
530MODULE_DESCRIPTION("DB8500 thermal driver");
531MODULE_LICENSE("GPL");
diff --git a/drivers/thermal/exynos_thermal.c b/drivers/thermal/exynos_thermal.c
index 6dd29e4ce36b..7772d1603769 100644
--- a/drivers/thermal/exynos_thermal.c
+++ b/drivers/thermal/exynos_thermal.c
@@ -451,7 +451,7 @@ static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
451 th_zone->cool_dev_size++; 451 th_zone->cool_dev_size++;
452 452
453 th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name, 453 th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
454 EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, 0, 454 EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
455 IDLE_INTERVAL); 455 IDLE_INTERVAL);
456 456
457 if (IS_ERR(th_zone->therm_dev)) { 457 if (IS_ERR(th_zone->therm_dev)) {
diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c
new file mode 100644
index 000000000000..792479f2b64b
--- /dev/null
+++ b/drivers/thermal/fair_share.c
@@ -0,0 +1,133 @@
1/*
2 * fair_share.c - A simple weight based Thermal governor
3 *
4 * Copyright (C) 2012 Intel Corp
5 * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
6 *
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 */
24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
27#include <linux/module.h>
28#include <linux/thermal.h>
29
30#include "thermal_core.h"
31
32/**
33 * get_trip_level: - obtains the current trip level for a zone
34 * @tz: thermal zone device
35 */
36static int get_trip_level(struct thermal_zone_device *tz)
37{
38 int count = 0;
39 unsigned long trip_temp;
40
41 if (tz->trips == 0 || !tz->ops->get_trip_temp)
42 return 0;
43
44 for (count = 0; count < tz->trips; count++) {
45 tz->ops->get_trip_temp(tz, count, &trip_temp);
46 if (tz->temperature < trip_temp)
47 break;
48 }
49 return count;
50}
51
52static long get_target_state(struct thermal_zone_device *tz,
53 struct thermal_cooling_device *cdev, int weight, int level)
54{
55 unsigned long max_state;
56
57 cdev->ops->get_max_state(cdev, &max_state);
58
59 return (long)(weight * level * max_state) / (100 * tz->trips);
60}
61
62/**
63 * fair_share_throttle - throttles devices asscciated with the given zone
64 * @tz - thermal_zone_device
65 *
66 * Throttling Logic: This uses three parameters to calculate the new
67 * throttle state of the cooling devices associated with the given zone.
68 *
69 * Parameters used for Throttling:
70 * P1. max_state: Maximum throttle state exposed by the cooling device.
71 * P2. weight[i]/100:
72 * How 'effective' the 'i'th device is, in cooling the given zone.
73 * P3. cur_trip_level/max_no_of_trips:
74 * This describes the extent to which the devices should be throttled.
75 * We do not want to throttle too much when we trip a lower temperature,
76 * whereas the throttling is at full swing if we trip critical levels.
77 * (Heavily assumes the trip points are in ascending order)
78 * new_state of cooling device = P3 * P2 * P1
79 */
80static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
81{
82 const struct thermal_zone_params *tzp;
83 struct thermal_cooling_device *cdev;
84 struct thermal_instance *instance;
85 int i;
86 int cur_trip_level = get_trip_level(tz);
87
88 if (!tz->tzp || !tz->tzp->tbp)
89 return -EINVAL;
90
91 tzp = tz->tzp;
92
93 for (i = 0; i < tzp->num_tbps; i++) {
94 if (!tzp->tbp[i].cdev)
95 continue;
96
97 cdev = tzp->tbp[i].cdev;
98 instance = get_thermal_instance(tz, cdev, trip);
99 if (!instance)
100 continue;
101
102 instance->target = get_target_state(tz, cdev,
103 tzp->tbp[i].weight, cur_trip_level);
104
105 instance->cdev->updated = false;
106 thermal_cdev_update(cdev);
107 }
108 return 0;
109}
110
111static struct thermal_governor thermal_gov_fair_share = {
112 .name = "fair_share",
113 .throttle = fair_share_throttle,
114 .owner = THIS_MODULE,
115};
116
117static int __init thermal_gov_fair_share_init(void)
118{
119 return thermal_register_governor(&thermal_gov_fair_share);
120}
121
122static void __exit thermal_gov_fair_share_exit(void)
123{
124 thermal_unregister_governor(&thermal_gov_fair_share);
125}
126
127/* This should load after thermal framework */
128fs_initcall(thermal_gov_fair_share_init);
129module_exit(thermal_gov_fair_share_exit);
130
131MODULE_AUTHOR("Durgadoss R");
132MODULE_DESCRIPTION("A simple weight based thermal throttling governor");
133MODULE_LICENSE("GPL");
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
index f7a1b574a304..90db951725da 100644
--- a/drivers/thermal/rcar_thermal.c
+++ b/drivers/thermal/rcar_thermal.c
@@ -43,6 +43,9 @@ struct rcar_thermal_priv {
43 u32 comp; 43 u32 comp;
44}; 44};
45 45
46#define MCELSIUS(temp) ((temp) * 1000)
47#define rcar_zone_to_priv(zone) (zone->devdata)
48
46/* 49/*
47 * basic functions 50 * basic functions
48 */ 51 */
@@ -96,7 +99,7 @@ static void rcar_thermal_bset(struct rcar_thermal_priv *priv, u32 reg,
96static int rcar_thermal_get_temp(struct thermal_zone_device *zone, 99static int rcar_thermal_get_temp(struct thermal_zone_device *zone,
97 unsigned long *temp) 100 unsigned long *temp)
98{ 101{
99 struct rcar_thermal_priv *priv = zone->devdata; 102 struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
100 int val, min, max, tmp; 103 int val, min, max, tmp;
101 104
102 tmp = -200; /* default */ 105 tmp = -200; /* default */
@@ -169,7 +172,7 @@ static int rcar_thermal_get_temp(struct thermal_zone_device *zone,
169 } 172 }
170 } 173 }
171 174
172 *temp = tmp; 175 *temp = MCELSIUS(tmp);
173 return 0; 176 return 0;
174} 177}
175 178
@@ -185,7 +188,6 @@ static int rcar_thermal_probe(struct platform_device *pdev)
185 struct thermal_zone_device *zone; 188 struct thermal_zone_device *zone;
186 struct rcar_thermal_priv *priv; 189 struct rcar_thermal_priv *priv;
187 struct resource *res; 190 struct resource *res;
188 int ret;
189 191
190 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 192 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
191 if (!res) { 193 if (!res) {
@@ -206,16 +208,14 @@ static int rcar_thermal_probe(struct platform_device *pdev)
206 res->start, resource_size(res)); 208 res->start, resource_size(res));
207 if (!priv->base) { 209 if (!priv->base) {
208 dev_err(&pdev->dev, "Unable to ioremap thermal register\n"); 210 dev_err(&pdev->dev, "Unable to ioremap thermal register\n");
209 ret = -ENOMEM; 211 return -ENOMEM;
210 goto error_free_priv;
211 } 212 }
212 213
213 zone = thermal_zone_device_register("rcar_thermal", 0, 0, priv, 214 zone = thermal_zone_device_register("rcar_thermal", 0, 0, priv,
214 &rcar_thermal_zone_ops, 0, 0); 215 &rcar_thermal_zone_ops, NULL, 0, 0);
215 if (IS_ERR(zone)) { 216 if (IS_ERR(zone)) {
216 dev_err(&pdev->dev, "thermal zone device is NULL\n"); 217 dev_err(&pdev->dev, "thermal zone device is NULL\n");
217 ret = PTR_ERR(zone); 218 return PTR_ERR(zone);
218 goto error_iounmap;
219 } 219 }
220 220
221 platform_set_drvdata(pdev, zone); 221 platform_set_drvdata(pdev, zone);
@@ -223,26 +223,15 @@ static int rcar_thermal_probe(struct platform_device *pdev)
223 dev_info(&pdev->dev, "proved\n"); 223 dev_info(&pdev->dev, "proved\n");
224 224
225 return 0; 225 return 0;
226
227error_iounmap:
228 devm_iounmap(&pdev->dev, priv->base);
229error_free_priv:
230 devm_kfree(&pdev->dev, priv);
231
232 return ret;
233} 226}
234 227
235static int rcar_thermal_remove(struct platform_device *pdev) 228static int rcar_thermal_remove(struct platform_device *pdev)
236{ 229{
237 struct thermal_zone_device *zone = platform_get_drvdata(pdev); 230 struct thermal_zone_device *zone = platform_get_drvdata(pdev);
238 struct rcar_thermal_priv *priv = zone->devdata;
239 231
240 thermal_zone_device_unregister(zone); 232 thermal_zone_device_unregister(zone);
241 platform_set_drvdata(pdev, NULL); 233 platform_set_drvdata(pdev, NULL);
242 234
243 devm_iounmap(&pdev->dev, priv->base);
244 devm_kfree(&pdev->dev, priv);
245
246 return 0; 235 return 0;
247} 236}
248 237
diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c
index 9bc969261d01..6b2d8b21aaee 100644
--- a/drivers/thermal/spear_thermal.c
+++ b/drivers/thermal/spear_thermal.c
@@ -147,7 +147,7 @@ static int spear_thermal_probe(struct platform_device *pdev)
147 writel_relaxed(stdev->flags, stdev->thermal_base); 147 writel_relaxed(stdev->flags, stdev->thermal_base);
148 148
149 spear_thermal = thermal_zone_device_register("spear_thermal", 0, 0, 149 spear_thermal = thermal_zone_device_register("spear_thermal", 0, 0,
150 stdev, &ops, 0, 0); 150 stdev, &ops, NULL, 0, 0);
151 if (IS_ERR(spear_thermal)) { 151 if (IS_ERR(spear_thermal)) {
152 dev_err(&pdev->dev, "thermal zone device is NULL\n"); 152 dev_err(&pdev->dev, "thermal zone device is NULL\n");
153 ret = PTR_ERR(spear_thermal); 153 ret = PTR_ERR(spear_thermal);
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
new file mode 100644
index 000000000000..0cd5e9fbab1c
--- /dev/null
+++ b/drivers/thermal/step_wise.c
@@ -0,0 +1,194 @@
1/*
2 * step_wise.c - A step-by-step Thermal throttling governor
3 *
4 * Copyright (C) 2012 Intel Corp
5 * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
6 *
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 */
24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
27#include <linux/module.h>
28#include <linux/thermal.h>
29
30#include "thermal_core.h"
31
32/*
33 * If the temperature is higher than a trip point,
34 * a. if the trend is THERMAL_TREND_RAISING, use higher cooling
35 * state for this trip point
36 * b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
37 * state for this trip point
38 */
39static unsigned long get_target_state(struct thermal_instance *instance,
40 enum thermal_trend trend)
41{
42 struct thermal_cooling_device *cdev = instance->cdev;
43 unsigned long cur_state;
44
45 cdev->ops->get_cur_state(cdev, &cur_state);
46
47 if (trend == THERMAL_TREND_RAISING) {
48 cur_state = cur_state < instance->upper ?
49 (cur_state + 1) : instance->upper;
50 } else if (trend == THERMAL_TREND_DROPPING) {
51 cur_state = cur_state > instance->lower ?
52 (cur_state - 1) : instance->lower;
53 }
54
55 return cur_state;
56}
57
58static void update_passive_instance(struct thermal_zone_device *tz,
59 enum thermal_trip_type type, int value)
60{
61 /*
62 * If value is +1, activate a passive instance.
63 * If value is -1, deactivate a passive instance.
64 */
65 if (type == THERMAL_TRIP_PASSIVE || type == THERMAL_TRIPS_NONE)
66 tz->passive += value;
67}
68
69static void update_instance_for_throttle(struct thermal_zone_device *tz,
70 int trip, enum thermal_trip_type trip_type,
71 enum thermal_trend trend)
72{
73 struct thermal_instance *instance;
74
75 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
76 if (instance->trip != trip)
77 continue;
78
79 instance->target = get_target_state(instance, trend);
80
81 /* Activate a passive thermal instance */
82 if (instance->target == THERMAL_NO_TARGET)
83 update_passive_instance(tz, trip_type, 1);
84
85 instance->cdev->updated = false; /* cdev needs update */
86 }
87}
88
89static void update_instance_for_dethrottle(struct thermal_zone_device *tz,
90 int trip, enum thermal_trip_type trip_type)
91{
92 struct thermal_instance *instance;
93 struct thermal_cooling_device *cdev;
94 unsigned long cur_state;
95
96 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
97 if (instance->trip != trip ||
98 instance->target == THERMAL_NO_TARGET)
99 continue;
100
101 cdev = instance->cdev;
102 cdev->ops->get_cur_state(cdev, &cur_state);
103
104 instance->target = cur_state > instance->lower ?
105 (cur_state - 1) : THERMAL_NO_TARGET;
106
107 /* Deactivate a passive thermal instance */
108 if (instance->target == THERMAL_NO_TARGET)
109 update_passive_instance(tz, trip_type, -1);
110
111 cdev->updated = false; /* cdev needs update */
112 }
113}
114
115static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
116{
117 long trip_temp;
118 enum thermal_trip_type trip_type;
119 enum thermal_trend trend;
120
121 if (trip == THERMAL_TRIPS_NONE) {
122 trip_temp = tz->forced_passive;
123 trip_type = THERMAL_TRIPS_NONE;
124 } else {
125 tz->ops->get_trip_temp(tz, trip, &trip_temp);
126 tz->ops->get_trip_type(tz, trip, &trip_type);
127 }
128
129 trend = get_tz_trend(tz, trip);
130
131 mutex_lock(&tz->lock);
132
133 if (tz->temperature >= trip_temp)
134 update_instance_for_throttle(tz, trip, trip_type, trend);
135 else
136 update_instance_for_dethrottle(tz, trip, trip_type);
137
138 mutex_unlock(&tz->lock);
139}
140
141/**
142 * step_wise_throttle - throttles devices asscciated with the given zone
143 * @tz - thermal_zone_device
144 * @trip - the trip point
145 * @trip_type - type of the trip point
146 *
147 * Throttling Logic: This uses the trend of the thermal zone to throttle.
148 * If the thermal zone is 'heating up' this throttles all the cooling
149 * devices associated with the zone and its particular trip point, by one
150 * step. If the zone is 'cooling down' it brings back the performance of
151 * the devices by one step.
152 */
153static int step_wise_throttle(struct thermal_zone_device *tz, int trip)
154{
155 struct thermal_instance *instance;
156
157 thermal_zone_trip_update(tz, trip);
158
159 if (tz->forced_passive)
160 thermal_zone_trip_update(tz, THERMAL_TRIPS_NONE);
161
162 mutex_lock(&tz->lock);
163
164 list_for_each_entry(instance, &tz->thermal_instances, tz_node)
165 thermal_cdev_update(instance->cdev);
166
167 mutex_unlock(&tz->lock);
168
169 return 0;
170}
171
172static struct thermal_governor thermal_gov_step_wise = {
173 .name = "step_wise",
174 .throttle = step_wise_throttle,
175 .owner = THIS_MODULE,
176};
177
178static int __init thermal_gov_step_wise_init(void)
179{
180 return thermal_register_governor(&thermal_gov_step_wise);
181}
182
183static void __exit thermal_gov_step_wise_exit(void)
184{
185 thermal_unregister_governor(&thermal_gov_step_wise);
186}
187
188/* This should load after thermal framework */
189fs_initcall(thermal_gov_step_wise_init);
190module_exit(thermal_gov_step_wise_exit);
191
192MODULE_AUTHOR("Durgadoss R");
193MODULE_DESCRIPTION("A step-by-step thermal throttling governor");
194MODULE_LICENSE("GPL");
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
new file mode 100644
index 000000000000..0d3205a18112
--- /dev/null
+++ b/drivers/thermal/thermal_core.h
@@ -0,0 +1,53 @@
1/*
2 * thermal_core.h
3 *
4 * Copyright (C) 2012 Intel Corp
5 * Author: Durgadoss R <durgadoss.r@intel.com>
6 *
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 as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 *
21 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22 */
23
24#ifndef __THERMAL_CORE_H__
25#define __THERMAL_CORE_H__
26
27#include <linux/device.h>
28#include <linux/thermal.h>
29
30/* Initial state of a cooling device during binding */
31#define THERMAL_NO_TARGET -1UL
32
33/*
34 * This structure is used to describe the behavior of
35 * a certain cooling device on a certain trip point
36 * in a certain thermal zone
37 */
38struct thermal_instance {
39 int id;
40 char name[THERMAL_NAME_LENGTH];
41 struct thermal_zone_device *tz;
42 struct thermal_cooling_device *cdev;
43 int trip;
44 unsigned long upper; /* Highest cooling state for this trip point */
45 unsigned long lower; /* Lowest cooling state for this trip point */
46 unsigned long target; /* expected cooling state */
47 char attr_name[THERMAL_NAME_LENGTH];
48 struct device_attribute attr;
49 struct list_head tz_node; /* node in tz->thermal_instances */
50 struct list_head cdev_node; /* node in cdev->thermal_instances */
51};
52
53#endif /* __THERMAL_CORE_H__ */
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 9ee42ca4d289..8c8ce806180f 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -37,38 +37,98 @@
37#include <net/netlink.h> 37#include <net/netlink.h>
38#include <net/genetlink.h> 38#include <net/genetlink.h>
39 39
40#include "thermal_core.h"
41
40MODULE_AUTHOR("Zhang Rui"); 42MODULE_AUTHOR("Zhang Rui");
41MODULE_DESCRIPTION("Generic thermal management sysfs support"); 43MODULE_DESCRIPTION("Generic thermal management sysfs support");
42MODULE_LICENSE("GPL"); 44MODULE_LICENSE("GPL");
43 45
44#define THERMAL_NO_TARGET -1UL
45/*
46 * This structure is used to describe the behavior of
47 * a certain cooling device on a certain trip point
48 * in a certain thermal zone
49 */
50struct thermal_instance {
51 int id;
52 char name[THERMAL_NAME_LENGTH];
53 struct thermal_zone_device *tz;
54 struct thermal_cooling_device *cdev;
55 int trip;
56 unsigned long upper; /* Highest cooling state for this trip point */
57 unsigned long lower; /* Lowest cooling state for this trip point */
58 unsigned long target; /* expected cooling state */
59 char attr_name[THERMAL_NAME_LENGTH];
60 struct device_attribute attr;
61 struct list_head tz_node; /* node in tz->thermal_instances */
62 struct list_head cdev_node; /* node in cdev->thermal_instances */
63};
64
65static DEFINE_IDR(thermal_tz_idr); 46static DEFINE_IDR(thermal_tz_idr);
66static DEFINE_IDR(thermal_cdev_idr); 47static DEFINE_IDR(thermal_cdev_idr);
67static DEFINE_MUTEX(thermal_idr_lock); 48static DEFINE_MUTEX(thermal_idr_lock);
68 49
69static LIST_HEAD(thermal_tz_list); 50static LIST_HEAD(thermal_tz_list);
70static LIST_HEAD(thermal_cdev_list); 51static LIST_HEAD(thermal_cdev_list);
52static LIST_HEAD(thermal_governor_list);
53
71static DEFINE_MUTEX(thermal_list_lock); 54static DEFINE_MUTEX(thermal_list_lock);
55static DEFINE_MUTEX(thermal_governor_lock);
56
57static struct thermal_governor *__find_governor(const char *name)
58{
59 struct thermal_governor *pos;
60
61 list_for_each_entry(pos, &thermal_governor_list, governor_list)
62 if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
63 return pos;
64
65 return NULL;
66}
67
68int thermal_register_governor(struct thermal_governor *governor)
69{
70 int err;
71 const char *name;
72 struct thermal_zone_device *pos;
73
74 if (!governor)
75 return -EINVAL;
76
77 mutex_lock(&thermal_governor_lock);
78
79 err = -EBUSY;
80 if (__find_governor(governor->name) == NULL) {
81 err = 0;
82 list_add(&governor->governor_list, &thermal_governor_list);
83 }
84
85 mutex_lock(&thermal_list_lock);
86
87 list_for_each_entry(pos, &thermal_tz_list, node) {
88 if (pos->governor)
89 continue;
90 if (pos->tzp)
91 name = pos->tzp->governor_name;
92 else
93 name = DEFAULT_THERMAL_GOVERNOR;
94 if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
95 pos->governor = governor;
96 }
97
98 mutex_unlock(&thermal_list_lock);
99 mutex_unlock(&thermal_governor_lock);
100
101 return err;
102}
103EXPORT_SYMBOL_GPL(thermal_register_governor);
104
105void thermal_unregister_governor(struct thermal_governor *governor)
106{
107 struct thermal_zone_device *pos;
108
109 if (!governor)
110 return;
111
112 mutex_lock(&thermal_governor_lock);
113
114 if (__find_governor(governor->name) == NULL)
115 goto exit;
116
117 mutex_lock(&thermal_list_lock);
118
119 list_for_each_entry(pos, &thermal_tz_list, node) {
120 if (!strnicmp(pos->governor->name, governor->name,
121 THERMAL_NAME_LENGTH))
122 pos->governor = NULL;
123 }
124
125 mutex_unlock(&thermal_list_lock);
126 list_del(&governor->governor_list);
127exit:
128 mutex_unlock(&thermal_governor_lock);
129 return;
130}
131EXPORT_SYMBOL_GPL(thermal_unregister_governor);
72 132
73static int get_idr(struct idr *idr, struct mutex *lock, int *id) 133static int get_idr(struct idr *idr, struct mutex *lock, int *id)
74{ 134{
@@ -101,6 +161,262 @@ static void release_idr(struct idr *idr, struct mutex *lock, int id)
101 mutex_unlock(lock); 161 mutex_unlock(lock);
102} 162}
103 163
164int get_tz_trend(struct thermal_zone_device *tz, int trip)
165{
166 enum thermal_trend trend;
167
168 if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
169 if (tz->temperature > tz->last_temperature)
170 trend = THERMAL_TREND_RAISING;
171 else if (tz->temperature < tz->last_temperature)
172 trend = THERMAL_TREND_DROPPING;
173 else
174 trend = THERMAL_TREND_STABLE;
175 }
176
177 return trend;
178}
179EXPORT_SYMBOL(get_tz_trend);
180
181struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
182 struct thermal_cooling_device *cdev, int trip)
183{
184 struct thermal_instance *pos = NULL;
185 struct thermal_instance *target_instance = NULL;
186
187 mutex_lock(&tz->lock);
188 mutex_lock(&cdev->lock);
189
190 list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
191 if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
192 target_instance = pos;
193 break;
194 }
195 }
196
197 mutex_unlock(&cdev->lock);
198 mutex_unlock(&tz->lock);
199
200 return target_instance;
201}
202EXPORT_SYMBOL(get_thermal_instance);
203
204static void print_bind_err_msg(struct thermal_zone_device *tz,
205 struct thermal_cooling_device *cdev, int ret)
206{
207 dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
208 tz->type, cdev->type, ret);
209}
210
211static void __bind(struct thermal_zone_device *tz, int mask,
212 struct thermal_cooling_device *cdev)
213{
214 int i, ret;
215
216 for (i = 0; i < tz->trips; i++) {
217 if (mask & (1 << i)) {
218 ret = thermal_zone_bind_cooling_device(tz, i, cdev,
219 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
220 if (ret)
221 print_bind_err_msg(tz, cdev, ret);
222 }
223 }
224}
225
226static void __unbind(struct thermal_zone_device *tz, int mask,
227 struct thermal_cooling_device *cdev)
228{
229 int i;
230
231 for (i = 0; i < tz->trips; i++)
232 if (mask & (1 << i))
233 thermal_zone_unbind_cooling_device(tz, i, cdev);
234}
235
236static void bind_cdev(struct thermal_cooling_device *cdev)
237{
238 int i, ret;
239 const struct thermal_zone_params *tzp;
240 struct thermal_zone_device *pos = NULL;
241
242 mutex_lock(&thermal_list_lock);
243
244 list_for_each_entry(pos, &thermal_tz_list, node) {
245 if (!pos->tzp && !pos->ops->bind)
246 continue;
247
248 if (!pos->tzp && pos->ops->bind) {
249 ret = pos->ops->bind(pos, cdev);
250 if (ret)
251 print_bind_err_msg(pos, cdev, ret);
252 }
253
254 tzp = pos->tzp;
255 if (!tzp || !tzp->tbp)
256 continue;
257
258 for (i = 0; i < tzp->num_tbps; i++) {
259 if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
260 continue;
261 if (tzp->tbp[i].match(pos, cdev))
262 continue;
263 tzp->tbp[i].cdev = cdev;
264 __bind(pos, tzp->tbp[i].trip_mask, cdev);
265 }
266 }
267
268 mutex_unlock(&thermal_list_lock);
269}
270
271static void bind_tz(struct thermal_zone_device *tz)
272{
273 int i, ret;
274 struct thermal_cooling_device *pos = NULL;
275 const struct thermal_zone_params *tzp = tz->tzp;
276
277 if (!tzp && !tz->ops->bind)
278 return;
279
280 mutex_lock(&thermal_list_lock);
281
282 /* If there is no platform data, try to use ops->bind */
283 if (!tzp && tz->ops->bind) {
284 list_for_each_entry(pos, &thermal_cdev_list, node) {
285 ret = tz->ops->bind(tz, pos);
286 if (ret)
287 print_bind_err_msg(tz, pos, ret);
288 }
289 goto exit;
290 }
291
292 if (!tzp || !tzp->tbp)
293 goto exit;
294
295 list_for_each_entry(pos, &thermal_cdev_list, node) {
296 for (i = 0; i < tzp->num_tbps; i++) {
297 if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
298 continue;
299 if (tzp->tbp[i].match(tz, pos))
300 continue;
301 tzp->tbp[i].cdev = pos;
302 __bind(tz, tzp->tbp[i].trip_mask, pos);
303 }
304 }
305exit:
306 mutex_unlock(&thermal_list_lock);
307}
308
309static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
310 int delay)
311{
312 if (delay > 1000)
313 mod_delayed_work(system_freezable_wq, &tz->poll_queue,
314 round_jiffies(msecs_to_jiffies(delay)));
315 else if (delay)
316 mod_delayed_work(system_freezable_wq, &tz->poll_queue,
317 msecs_to_jiffies(delay));
318 else
319 cancel_delayed_work(&tz->poll_queue);
320}
321
322static void monitor_thermal_zone(struct thermal_zone_device *tz)
323{
324 mutex_lock(&tz->lock);
325
326 if (tz->passive)
327 thermal_zone_device_set_polling(tz, tz->passive_delay);
328 else if (tz->polling_delay)
329 thermal_zone_device_set_polling(tz, tz->polling_delay);
330 else
331 thermal_zone_device_set_polling(tz, 0);
332
333 mutex_unlock(&tz->lock);
334}
335
336static void handle_non_critical_trips(struct thermal_zone_device *tz,
337 int trip, enum thermal_trip_type trip_type)
338{
339 if (tz->governor)
340 tz->governor->throttle(tz, trip);
341}
342
343static void handle_critical_trips(struct thermal_zone_device *tz,
344 int trip, enum thermal_trip_type trip_type)
345{
346 long trip_temp;
347
348 tz->ops->get_trip_temp(tz, trip, &trip_temp);
349
350 /* If we have not crossed the trip_temp, we do not care. */
351 if (tz->temperature < trip_temp)
352 return;
353
354 if (tz->ops->notify)
355 tz->ops->notify(tz, trip, trip_type);
356
357 if (trip_type == THERMAL_TRIP_CRITICAL) {
358 pr_emerg("Critical temperature reached(%d C),shutting down\n",
359 tz->temperature / 1000);
360 orderly_poweroff(true);
361 }
362}
363
364static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
365{
366 enum thermal_trip_type type;
367
368 tz->ops->get_trip_type(tz, trip, &type);
369
370 if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
371 handle_critical_trips(tz, trip, type);
372 else
373 handle_non_critical_trips(tz, trip, type);
374 /*
375 * Alright, we handled this trip successfully.
376 * So, start monitoring again.
377 */
378 monitor_thermal_zone(tz);
379}
380
381static void update_temperature(struct thermal_zone_device *tz)
382{
383 long temp;
384 int ret;
385
386 mutex_lock(&tz->lock);
387
388 ret = tz->ops->get_temp(tz, &temp);
389 if (ret) {
390 pr_warn("failed to read out thermal zone %d\n", tz->id);
391 goto exit;
392 }
393
394 tz->last_temperature = tz->temperature;
395 tz->temperature = temp;
396
397exit:
398 mutex_unlock(&tz->lock);
399}
400
401void thermal_zone_device_update(struct thermal_zone_device *tz)
402{
403 int count;
404
405 update_temperature(tz);
406
407 for (count = 0; count < tz->trips; count++)
408 handle_thermal_trip(tz, count);
409}
410EXPORT_SYMBOL(thermal_zone_device_update);
411
412static void thermal_zone_device_check(struct work_struct *work)
413{
414 struct thermal_zone_device *tz = container_of(work, struct
415 thermal_zone_device,
416 poll_queue.work);
417 thermal_zone_device_update(tz);
418}
419
104/* sys I/F for thermal zone */ 420/* sys I/F for thermal zone */
105 421
106#define to_thermal_zone(_dev) \ 422#define to_thermal_zone(_dev) \
@@ -354,10 +670,41 @@ passive_show(struct device *dev, struct device_attribute *attr,
354 return sprintf(buf, "%d\n", tz->forced_passive); 670 return sprintf(buf, "%d\n", tz->forced_passive);
355} 671}
356 672
673static ssize_t
674policy_store(struct device *dev, struct device_attribute *attr,
675 const char *buf, size_t count)
676{
677 int ret = -EINVAL;
678 struct thermal_zone_device *tz = to_thermal_zone(dev);
679 struct thermal_governor *gov;
680
681 mutex_lock(&thermal_governor_lock);
682
683 gov = __find_governor(buf);
684 if (!gov)
685 goto exit;
686
687 tz->governor = gov;
688 ret = count;
689
690exit:
691 mutex_unlock(&thermal_governor_lock);
692 return ret;
693}
694
695static ssize_t
696policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
697{
698 struct thermal_zone_device *tz = to_thermal_zone(dev);
699
700 return sprintf(buf, "%s\n", tz->governor->name);
701}
702
357static DEVICE_ATTR(type, 0444, type_show, NULL); 703static DEVICE_ATTR(type, 0444, type_show, NULL);
358static DEVICE_ATTR(temp, 0444, temp_show, NULL); 704static DEVICE_ATTR(temp, 0444, temp_show, NULL);
359static DEVICE_ATTR(mode, 0644, mode_show, mode_store); 705static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
360static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store); 706static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
707static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
361 708
362/* sys I/F for cooling device */ 709/* sys I/F for cooling device */
363#define to_cooling_device(_dev) \ 710#define to_cooling_device(_dev) \
@@ -700,27 +1047,6 @@ thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
700} 1047}
701#endif 1048#endif
702 1049
703static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
704 int delay)
705{
706 if (delay > 1000)
707 mod_delayed_work(system_freezable_wq, &tz->poll_queue,
708 round_jiffies(msecs_to_jiffies(delay)));
709 else if (delay)
710 mod_delayed_work(system_freezable_wq, &tz->poll_queue,
711 msecs_to_jiffies(delay));
712 else
713 cancel_delayed_work(&tz->poll_queue);
714}
715
716static void thermal_zone_device_check(struct work_struct *work)
717{
718 struct thermal_zone_device *tz = container_of(work, struct
719 thermal_zone_device,
720 poll_queue.work);
721 thermal_zone_device_update(tz);
722}
723
724/** 1050/**
725 * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone 1051 * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
726 * @tz: thermal zone device 1052 * @tz: thermal zone device
@@ -895,7 +1221,6 @@ thermal_cooling_device_register(char *type, void *devdata,
895 const struct thermal_cooling_device_ops *ops) 1221 const struct thermal_cooling_device_ops *ops)
896{ 1222{
897 struct thermal_cooling_device *cdev; 1223 struct thermal_cooling_device *cdev;
898 struct thermal_zone_device *pos;
899 int result; 1224 int result;
900 1225
901 if (type && strlen(type) >= THERMAL_NAME_LENGTH) 1226 if (type && strlen(type) >= THERMAL_NAME_LENGTH)
@@ -945,20 +1270,15 @@ thermal_cooling_device_register(char *type, void *devdata,
945 if (result) 1270 if (result)
946 goto unregister; 1271 goto unregister;
947 1272
1273 /* Add 'this' new cdev to the global cdev list */
948 mutex_lock(&thermal_list_lock); 1274 mutex_lock(&thermal_list_lock);
949 list_add(&cdev->node, &thermal_cdev_list); 1275 list_add(&cdev->node, &thermal_cdev_list);
950 list_for_each_entry(pos, &thermal_tz_list, node) {
951 if (!pos->ops->bind)
952 continue;
953 result = pos->ops->bind(pos, cdev);
954 if (result)
955 break;
956
957 }
958 mutex_unlock(&thermal_list_lock); 1276 mutex_unlock(&thermal_list_lock);
959 1277
960 if (!result) 1278 /* Update binding information for 'this' new cdev */
961 return cdev; 1279 bind_cdev(cdev);
1280
1281 return cdev;
962 1282
963unregister: 1283unregister:
964 release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); 1284 release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
@@ -974,10 +1294,10 @@ EXPORT_SYMBOL(thermal_cooling_device_register);
974 * thermal_cooling_device_unregister() must be called when the device is no 1294 * thermal_cooling_device_unregister() must be called when the device is no
975 * longer needed. 1295 * longer needed.
976 */ 1296 */
977void thermal_cooling_device_unregister(struct 1297void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
978 thermal_cooling_device
979 *cdev)
980{ 1298{
1299 int i;
1300 const struct thermal_zone_params *tzp;
981 struct thermal_zone_device *tz; 1301 struct thermal_zone_device *tz;
982 struct thermal_cooling_device *pos = NULL; 1302 struct thermal_cooling_device *pos = NULL;
983 1303
@@ -994,12 +1314,28 @@ void thermal_cooling_device_unregister(struct
994 return; 1314 return;
995 } 1315 }
996 list_del(&cdev->node); 1316 list_del(&cdev->node);
1317
1318 /* Unbind all thermal zones associated with 'this' cdev */
997 list_for_each_entry(tz, &thermal_tz_list, node) { 1319 list_for_each_entry(tz, &thermal_tz_list, node) {
998 if (!tz->ops->unbind) 1320 if (tz->ops->unbind) {
1321 tz->ops->unbind(tz, cdev);
999 continue; 1322 continue;
1000 tz->ops->unbind(tz, cdev); 1323 }
1324
1325 if (!tz->tzp || !tz->tzp->tbp)
1326 continue;
1327
1328 tzp = tz->tzp;
1329 for (i = 0; i < tzp->num_tbps; i++) {
1330 if (tzp->tbp[i].cdev == cdev) {
1331 __unbind(tz, tzp->tbp[i].trip_mask, cdev);
1332 tzp->tbp[i].cdev = NULL;
1333 }
1334 }
1001 } 1335 }
1336
1002 mutex_unlock(&thermal_list_lock); 1337 mutex_unlock(&thermal_list_lock);
1338
1003 if (cdev->type[0]) 1339 if (cdev->type[0])
1004 device_remove_file(&cdev->device, &dev_attr_cdev_type); 1340 device_remove_file(&cdev->device, &dev_attr_cdev_type);
1005 device_remove_file(&cdev->device, &dev_attr_max_state); 1341 device_remove_file(&cdev->device, &dev_attr_max_state);
@@ -1011,7 +1347,7 @@ void thermal_cooling_device_unregister(struct
1011} 1347}
1012EXPORT_SYMBOL(thermal_cooling_device_unregister); 1348EXPORT_SYMBOL(thermal_cooling_device_unregister);
1013 1349
1014static void thermal_cdev_do_update(struct thermal_cooling_device *cdev) 1350void thermal_cdev_update(struct thermal_cooling_device *cdev)
1015{ 1351{
1016 struct thermal_instance *instance; 1352 struct thermal_instance *instance;
1017 unsigned long target = 0; 1353 unsigned long target = 0;
@@ -1032,183 +1368,25 @@ static void thermal_cdev_do_update(struct thermal_cooling_device *cdev)
1032 cdev->ops->set_cur_state(cdev, target); 1368 cdev->ops->set_cur_state(cdev, target);
1033 cdev->updated = true; 1369 cdev->updated = true;
1034} 1370}
1371EXPORT_SYMBOL(thermal_cdev_update);
1035 1372
1036static void thermal_zone_do_update(struct thermal_zone_device *tz)
1037{
1038 struct thermal_instance *instance;
1039
1040 list_for_each_entry(instance, &tz->thermal_instances, tz_node)
1041 thermal_cdev_do_update(instance->cdev);
1042}
1043
1044/*
1045 * Cooling algorithm for both active and passive cooling
1046 *
1047 * 1. if the temperature is higher than a trip point,
1048 * a. if the trend is THERMAL_TREND_RAISING, use higher cooling
1049 * state for this trip point
1050 * b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
1051 * state for this trip point
1052 *
1053 * 2. if the temperature is lower than a trip point, use lower
1054 * cooling state for this trip point
1055 *
1056 * Note that this behaves the same as the previous passive cooling
1057 * algorithm.
1058 */
1059
1060static void thermal_zone_trip_update(struct thermal_zone_device *tz,
1061 int trip, long temp)
1062{
1063 struct thermal_instance *instance;
1064 struct thermal_cooling_device *cdev = NULL;
1065 unsigned long cur_state, max_state;
1066 long trip_temp;
1067 enum thermal_trip_type trip_type;
1068 enum thermal_trend trend;
1069
1070 if (trip == THERMAL_TRIPS_NONE) {
1071 trip_temp = tz->forced_passive;
1072 trip_type = THERMAL_TRIPS_NONE;
1073 } else {
1074 tz->ops->get_trip_temp(tz, trip, &trip_temp);
1075 tz->ops->get_trip_type(tz, trip, &trip_type);
1076 }
1077
1078 if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
1079 /*
1080 * compare the current temperature and previous temperature
1081 * to get the thermal trend, if no special requirement
1082 */
1083 if (tz->temperature > tz->last_temperature)
1084 trend = THERMAL_TREND_RAISING;
1085 else if (tz->temperature < tz->last_temperature)
1086 trend = THERMAL_TREND_DROPPING;
1087 else
1088 trend = THERMAL_TREND_STABLE;
1089 }
1090
1091 if (temp >= trip_temp) {
1092 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
1093 if (instance->trip != trip)
1094 continue;
1095
1096 cdev = instance->cdev;
1097
1098 cdev->ops->get_cur_state(cdev, &cur_state);
1099 cdev->ops->get_max_state(cdev, &max_state);
1100
1101 if (trend == THERMAL_TREND_RAISING) {
1102 cur_state = cur_state < instance->upper ?
1103 (cur_state + 1) : instance->upper;
1104 } else if (trend == THERMAL_TREND_DROPPING) {
1105 cur_state = cur_state > instance->lower ?
1106 (cur_state - 1) : instance->lower;
1107 }
1108
1109 /* activate a passive thermal instance */
1110 if ((trip_type == THERMAL_TRIP_PASSIVE ||
1111 trip_type == THERMAL_TRIPS_NONE) &&
1112 instance->target == THERMAL_NO_TARGET)
1113 tz->passive++;
1114
1115 instance->target = cur_state;
1116 cdev->updated = false; /* cooling device needs update */
1117 }
1118 } else { /* below trip */
1119 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
1120 if (instance->trip != trip)
1121 continue;
1122
1123 /* Do not use the inactive thermal instance */
1124 if (instance->target == THERMAL_NO_TARGET)
1125 continue;
1126 cdev = instance->cdev;
1127 cdev->ops->get_cur_state(cdev, &cur_state);
1128
1129 cur_state = cur_state > instance->lower ?
1130 (cur_state - 1) : THERMAL_NO_TARGET;
1131
1132 /* deactivate a passive thermal instance */
1133 if ((trip_type == THERMAL_TRIP_PASSIVE ||
1134 trip_type == THERMAL_TRIPS_NONE) &&
1135 cur_state == THERMAL_NO_TARGET)
1136 tz->passive--;
1137 instance->target = cur_state;
1138 cdev->updated = false; /* cooling device needs update */
1139 }
1140 }
1141
1142 return;
1143}
1144/** 1373/**
1145 * thermal_zone_device_update - force an update of a thermal zone's state 1374 * notify_thermal_framework - Sensor drivers use this API to notify framework
1146 * @ttz: the thermal zone to update 1375 * @tz: thermal zone device
1376 * @trip: indicates which trip point has been crossed
1377 *
1378 * This function handles the trip events from sensor drivers. It starts
1379 * throttling the cooling devices according to the policy configured.
1380 * For CRITICAL and HOT trip points, this notifies the respective drivers,
1381 * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
1382 * The throttling policy is based on the configured platform data; if no
1383 * platform data is provided, this uses the step_wise throttling policy.
1147 */ 1384 */
1148 1385void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
1149void thermal_zone_device_update(struct thermal_zone_device *tz)
1150{ 1386{
1151 int count, ret = 0; 1387 handle_thermal_trip(tz, trip);
1152 long temp, trip_temp;
1153 enum thermal_trip_type trip_type;
1154
1155 mutex_lock(&tz->lock);
1156
1157 if (tz->ops->get_temp(tz, &temp)) {
1158 /* get_temp failed - retry it later */
1159 pr_warn("failed to read out thermal zone %d\n", tz->id);
1160 goto leave;
1161 }
1162
1163 tz->last_temperature = tz->temperature;
1164 tz->temperature = temp;
1165
1166 for (count = 0; count < tz->trips; count++) {
1167 tz->ops->get_trip_type(tz, count, &trip_type);
1168 tz->ops->get_trip_temp(tz, count, &trip_temp);
1169
1170 switch (trip_type) {
1171 case THERMAL_TRIP_CRITICAL:
1172 if (temp >= trip_temp) {
1173 if (tz->ops->notify)
1174 ret = tz->ops->notify(tz, count,
1175 trip_type);
1176 if (!ret) {
1177 pr_emerg("Critical temperature reached (%ld C), shutting down\n",
1178 temp/1000);
1179 orderly_poweroff(true);
1180 }
1181 }
1182 break;
1183 case THERMAL_TRIP_HOT:
1184 if (temp >= trip_temp)
1185 if (tz->ops->notify)
1186 tz->ops->notify(tz, count, trip_type);
1187 break;
1188 case THERMAL_TRIP_ACTIVE:
1189 thermal_zone_trip_update(tz, count, temp);
1190 break;
1191 case THERMAL_TRIP_PASSIVE:
1192 if (temp >= trip_temp || tz->passive)
1193 thermal_zone_trip_update(tz, count, temp);
1194 break;
1195 }
1196 }
1197
1198 if (tz->forced_passive)
1199 thermal_zone_trip_update(tz, THERMAL_TRIPS_NONE, temp);
1200 thermal_zone_do_update(tz);
1201
1202leave:
1203 if (tz->passive)
1204 thermal_zone_device_set_polling(tz, tz->passive_delay);
1205 else if (tz->polling_delay)
1206 thermal_zone_device_set_polling(tz, tz->polling_delay);
1207 else
1208 thermal_zone_device_set_polling(tz, 0);
1209 mutex_unlock(&tz->lock);
1210} 1388}
1211EXPORT_SYMBOL(thermal_zone_device_update); 1389EXPORT_SYMBOL(notify_thermal_framework);
1212 1390
1213/** 1391/**
1214 * create_trip_attrs - create attributes for trip points 1392 * create_trip_attrs - create attributes for trip points
@@ -1320,6 +1498,7 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
1320 * @mask: a bit string indicating the writeablility of trip points 1498 * @mask: a bit string indicating the writeablility of trip points
1321 * @devdata: private device data 1499 * @devdata: private device data
1322 * @ops: standard thermal zone device callbacks 1500 * @ops: standard thermal zone device callbacks
1501 * @tzp: thermal zone platform parameters
1323 * @passive_delay: number of milliseconds to wait between polls when 1502 * @passive_delay: number of milliseconds to wait between polls when
1324 * performing passive cooling 1503 * performing passive cooling
1325 * @polling_delay: number of milliseconds to wait between polls when checking 1504 * @polling_delay: number of milliseconds to wait between polls when checking
@@ -1332,10 +1511,10 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
1332struct thermal_zone_device *thermal_zone_device_register(const char *type, 1511struct thermal_zone_device *thermal_zone_device_register(const char *type,
1333 int trips, int mask, void *devdata, 1512 int trips, int mask, void *devdata,
1334 const struct thermal_zone_device_ops *ops, 1513 const struct thermal_zone_device_ops *ops,
1514 const struct thermal_zone_params *tzp,
1335 int passive_delay, int polling_delay) 1515 int passive_delay, int polling_delay)
1336{ 1516{
1337 struct thermal_zone_device *tz; 1517 struct thermal_zone_device *tz;
1338 struct thermal_cooling_device *pos;
1339 enum thermal_trip_type trip_type; 1518 enum thermal_trip_type trip_type;
1340 int result; 1519 int result;
1341 int count; 1520 int count;
@@ -1365,6 +1544,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
1365 1544
1366 strcpy(tz->type, type ? : ""); 1545 strcpy(tz->type, type ? : "");
1367 tz->ops = ops; 1546 tz->ops = ops;
1547 tz->tzp = tzp;
1368 tz->device.class = &thermal_class; 1548 tz->device.class = &thermal_class;
1369 tz->devdata = devdata; 1549 tz->devdata = devdata;
1370 tz->trips = trips; 1550 tz->trips = trips;
@@ -1406,27 +1586,38 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
1406 passive = 1; 1586 passive = 1;
1407 } 1587 }
1408 1588
1409 if (!passive) 1589 if (!passive) {
1410 result = device_create_file(&tz->device, 1590 result = device_create_file(&tz->device, &dev_attr_passive);
1411 &dev_attr_passive); 1591 if (result)
1592 goto unregister;
1593 }
1412 1594
1595 /* Create policy attribute */
1596 result = device_create_file(&tz->device, &dev_attr_policy);
1413 if (result) 1597 if (result)
1414 goto unregister; 1598 goto unregister;
1415 1599
1600 /* Update 'this' zone's governor information */
1601 mutex_lock(&thermal_governor_lock);
1602
1603 if (tz->tzp)
1604 tz->governor = __find_governor(tz->tzp->governor_name);
1605 else
1606 tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
1607
1608 mutex_unlock(&thermal_governor_lock);
1609
1416 result = thermal_add_hwmon_sysfs(tz); 1610 result = thermal_add_hwmon_sysfs(tz);
1417 if (result) 1611 if (result)
1418 goto unregister; 1612 goto unregister;
1419 1613
1420 mutex_lock(&thermal_list_lock); 1614 mutex_lock(&thermal_list_lock);
1421 list_add_tail(&tz->node, &thermal_tz_list); 1615 list_add_tail(&tz->node, &thermal_tz_list);
1422 if (ops->bind)
1423 list_for_each_entry(pos, &thermal_cdev_list, node) {
1424 result = ops->bind(tz, pos);
1425 if (result)
1426 break;
1427 }
1428 mutex_unlock(&thermal_list_lock); 1616 mutex_unlock(&thermal_list_lock);
1429 1617
1618 /* Bind cooling devices for this zone */
1619 bind_tz(tz);
1620
1430 INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check); 1621 INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
1431 1622
1432 thermal_zone_device_update(tz); 1623 thermal_zone_device_update(tz);
@@ -1447,12 +1638,16 @@ EXPORT_SYMBOL(thermal_zone_device_register);
1447 */ 1638 */
1448void thermal_zone_device_unregister(struct thermal_zone_device *tz) 1639void thermal_zone_device_unregister(struct thermal_zone_device *tz)
1449{ 1640{
1641 int i;
1642 const struct thermal_zone_params *tzp;
1450 struct thermal_cooling_device *cdev; 1643 struct thermal_cooling_device *cdev;
1451 struct thermal_zone_device *pos = NULL; 1644 struct thermal_zone_device *pos = NULL;
1452 1645
1453 if (!tz) 1646 if (!tz)
1454 return; 1647 return;
1455 1648
1649 tzp = tz->tzp;
1650
1456 mutex_lock(&thermal_list_lock); 1651 mutex_lock(&thermal_list_lock);
1457 list_for_each_entry(pos, &thermal_tz_list, node) 1652 list_for_each_entry(pos, &thermal_tz_list, node)
1458 if (pos == tz) 1653 if (pos == tz)
@@ -1463,9 +1658,25 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
1463 return; 1658 return;
1464 } 1659 }
1465 list_del(&tz->node); 1660 list_del(&tz->node);
1466 if (tz->ops->unbind) 1661
1467 list_for_each_entry(cdev, &thermal_cdev_list, node) 1662 /* Unbind all cdevs associated with 'this' thermal zone */
1468 tz->ops->unbind(tz, cdev); 1663 list_for_each_entry(cdev, &thermal_cdev_list, node) {
1664 if (tz->ops->unbind) {
1665 tz->ops->unbind(tz, cdev);
1666 continue;
1667 }
1668
1669 if (!tzp || !tzp->tbp)
1670 break;
1671
1672 for (i = 0; i < tzp->num_tbps; i++) {
1673 if (tzp->tbp[i].cdev == cdev) {
1674 __unbind(tz, tzp->tbp[i].trip_mask, cdev);
1675 tzp->tbp[i].cdev = NULL;
1676 }
1677 }
1678 }
1679
1469 mutex_unlock(&thermal_list_lock); 1680 mutex_unlock(&thermal_list_lock);
1470 1681
1471 thermal_zone_device_set_polling(tz, 0); 1682 thermal_zone_device_set_polling(tz, 0);
@@ -1475,7 +1686,9 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
1475 device_remove_file(&tz->device, &dev_attr_temp); 1686 device_remove_file(&tz->device, &dev_attr_temp);
1476 if (tz->ops->get_mode) 1687 if (tz->ops->get_mode)
1477 device_remove_file(&tz->device, &dev_attr_mode); 1688 device_remove_file(&tz->device, &dev_attr_mode);
1689 device_remove_file(&tz->device, &dev_attr_policy);
1478 remove_trip_attrs(tz); 1690 remove_trip_attrs(tz);
1691 tz->governor = NULL;
1479 1692
1480 thermal_remove_hwmon_sysfs(tz); 1693 thermal_remove_hwmon_sysfs(tz);
1481 release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); 1694 release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
diff --git a/drivers/thermal/user_space.c b/drivers/thermal/user_space.c
new file mode 100644
index 000000000000..6bbb380b6d19
--- /dev/null
+++ b/drivers/thermal/user_space.c
@@ -0,0 +1,68 @@
1/*
2 * user_space.c - A simple user space Thermal events notifier
3 *
4 * Copyright (C) 2012 Intel Corp
5 * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
6 *
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 */
24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
27#include <linux/module.h>
28#include <linux/thermal.h>
29
30#include "thermal_core.h"
31
32/**
33 * notify_user_space - Notifies user space about thermal events
34 * @tz - thermal_zone_device
35 *
36 * This function notifies the user space through UEvents.
37 */
38static int notify_user_space(struct thermal_zone_device *tz, int trip)
39{
40 mutex_lock(&tz->lock);
41 kobject_uevent(&tz->device.kobj, KOBJ_CHANGE);
42 mutex_unlock(&tz->lock);
43 return 0;
44}
45
46static struct thermal_governor thermal_gov_user_space = {
47 .name = "user_space",
48 .throttle = notify_user_space,
49 .owner = THIS_MODULE,
50};
51
52static int __init thermal_gov_user_space_init(void)
53{
54 return thermal_register_governor(&thermal_gov_user_space);
55}
56
57static void __exit thermal_gov_user_space_exit(void)
58{
59 thermal_unregister_governor(&thermal_gov_user_space);
60}
61
62/* This should load after thermal framework */
63fs_initcall(thermal_gov_user_space_init);
64module_exit(thermal_gov_user_space_exit);
65
66MODULE_AUTHOR("Durgadoss R");
67MODULE_DESCRIPTION("A user space Thermal notifier");
68MODULE_LICENSE("GPL");
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
index 851530128e65..40b4ef54cc7d 100644
--- a/include/linux/cpu_cooling.h
+++ b/include/linux/cpu_cooling.h
@@ -29,13 +29,13 @@
29#define CPUFREQ_COOLING_START 0 29#define CPUFREQ_COOLING_START 0
30#define CPUFREQ_COOLING_STOP 1 30#define CPUFREQ_COOLING_STOP 1
31 31
32#ifdef CONFIG_CPU_THERMAL 32#if defined(CONFIG_CPU_THERMAL) || defined(CONFIG_CPU_THERMAL_MODULE)
33/** 33/**
34 * cpufreq_cooling_register - function to create cpufreq cooling device. 34 * cpufreq_cooling_register - function to create cpufreq cooling device.
35 * @clip_cpus: cpumask of cpus where the frequency constraints will happen 35 * @clip_cpus: cpumask of cpus where the frequency constraints will happen
36 */ 36 */
37struct thermal_cooling_device *cpufreq_cooling_register( 37struct thermal_cooling_device *cpufreq_cooling_register(
38 struct cpumask *clip_cpus); 38 const struct cpumask *clip_cpus);
39 39
40/** 40/**
41 * cpufreq_cooling_unregister - function to remove cpufreq cooling device. 41 * cpufreq_cooling_unregister - function to remove cpufreq cooling device.
@@ -44,7 +44,7 @@ struct thermal_cooling_device *cpufreq_cooling_register(
44void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev); 44void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
45#else /* !CONFIG_CPU_THERMAL */ 45#else /* !CONFIG_CPU_THERMAL */
46static inline struct thermal_cooling_device *cpufreq_cooling_register( 46static inline struct thermal_cooling_device *cpufreq_cooling_register(
47 struct cpumask *clip_cpus) 47 const struct cpumask *clip_cpus)
48{ 48{
49 return NULL; 49 return NULL;
50} 50}
diff --git a/include/linux/platform_data/db8500_thermal.h b/include/linux/platform_data/db8500_thermal.h
new file mode 100644
index 000000000000..3bf60902e902
--- /dev/null
+++ b/include/linux/platform_data/db8500_thermal.h
@@ -0,0 +1,38 @@
1/*
2 * db8500_thermal.h - DB8500 Thermal Management Implementation
3 *
4 * Copyright (C) 2012 ST-Ericsson
5 * Copyright (C) 2012 Linaro Ltd.
6 *
7 * Author: Hongbo Zhang <hongbo.zhang@linaro.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19
20#ifndef _DB8500_THERMAL_H_
21#define _DB8500_THERMAL_H_
22
23#include <linux/thermal.h>
24
25#define COOLING_DEV_MAX 8
26
27struct db8500_trip_point {
28 unsigned long temp;
29 enum thermal_trip_type type;
30 char cdev_name[COOLING_DEV_MAX][THERMAL_NAME_LENGTH];
31};
32
33struct db8500_thsens_platform_data {
34 struct db8500_trip_point trip_points[THERMAL_MAX_TRIPS];
35 int num_trips;
36};
37
38#endif /* _DB8500_THERMAL_H_ */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 91b34812cd84..fe82022478e7 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -29,6 +29,32 @@
29#include <linux/device.h> 29#include <linux/device.h>
30#include <linux/workqueue.h> 30#include <linux/workqueue.h>
31 31
32#define THERMAL_TRIPS_NONE -1
33#define THERMAL_MAX_TRIPS 12
34#define THERMAL_NAME_LENGTH 20
35
36/* No upper/lower limit requirement */
37#define THERMAL_NO_LIMIT -1UL
38
39/* Unit conversion macros */
40#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \
41 ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
42#define CELSIUS_TO_KELVIN(t) ((t)*10+2732)
43
44/* Adding event notification support elements */
45#define THERMAL_GENL_FAMILY_NAME "thermal_event"
46#define THERMAL_GENL_VERSION 0x01
47#define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_group"
48
49/* Default Thermal Governor */
50#if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE)
51#define DEFAULT_THERMAL_GOVERNOR "step_wise"
52#elif defined(CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE)
53#define DEFAULT_THERMAL_GOVERNOR "fair_share"
54#elif defined(CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE)
55#define DEFAULT_THERMAL_GOVERNOR "user_space"
56#endif
57
32struct thermal_zone_device; 58struct thermal_zone_device;
33struct thermal_cooling_device; 59struct thermal_cooling_device;
34 60
@@ -50,6 +76,30 @@ enum thermal_trend {
50 THERMAL_TREND_DROPPING, /* temperature is dropping */ 76 THERMAL_TREND_DROPPING, /* temperature is dropping */
51}; 77};
52 78
79/* Events supported by Thermal Netlink */
80enum events {
81 THERMAL_AUX0,
82 THERMAL_AUX1,
83 THERMAL_CRITICAL,
84 THERMAL_DEV_FAULT,
85};
86
87/* attributes of thermal_genl_family */
88enum {
89 THERMAL_GENL_ATTR_UNSPEC,
90 THERMAL_GENL_ATTR_EVENT,
91 __THERMAL_GENL_ATTR_MAX,
92};
93#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)
94
95/* commands supported by the thermal_genl_family */
96enum {
97 THERMAL_GENL_CMD_UNSPEC,
98 THERMAL_GENL_CMD_EVENT,
99 __THERMAL_GENL_CMD_MAX,
100};
101#define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1)
102
53struct thermal_zone_device_ops { 103struct thermal_zone_device_ops {
54 int (*bind) (struct thermal_zone_device *, 104 int (*bind) (struct thermal_zone_device *,
55 struct thermal_cooling_device *); 105 struct thermal_cooling_device *);
@@ -83,11 +133,6 @@ struct thermal_cooling_device_ops {
83 int (*set_cur_state) (struct thermal_cooling_device *, unsigned long); 133 int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
84}; 134};
85 135
86#define THERMAL_NO_LIMIT -1UL /* no upper/lower limit requirement */
87
88#define THERMAL_TRIPS_NONE -1
89#define THERMAL_MAX_TRIPS 12
90#define THERMAL_NAME_LENGTH 20
91struct thermal_cooling_device { 136struct thermal_cooling_device {
92 int id; 137 int id;
93 char type[THERMAL_NAME_LENGTH]; 138 char type[THERMAL_NAME_LENGTH];
@@ -100,10 +145,6 @@ struct thermal_cooling_device {
100 struct list_head node; 145 struct list_head node;
101}; 146};
102 147
103#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \
104 ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
105#define CELSIUS_TO_KELVIN(t) ((t)*10+2732)
106
107struct thermal_attr { 148struct thermal_attr {
108 struct device_attribute attr; 149 struct device_attribute attr;
109 char name[THERMAL_NAME_LENGTH]; 150 char name[THERMAL_NAME_LENGTH];
@@ -125,46 +166,61 @@ struct thermal_zone_device {
125 int passive; 166 int passive;
126 unsigned int forced_passive; 167 unsigned int forced_passive;
127 const struct thermal_zone_device_ops *ops; 168 const struct thermal_zone_device_ops *ops;
169 const struct thermal_zone_params *tzp;
170 struct thermal_governor *governor;
128 struct list_head thermal_instances; 171 struct list_head thermal_instances;
129 struct idr idr; 172 struct idr idr;
130 struct mutex lock; /* protect thermal_instances list */ 173 struct mutex lock; /* protect thermal_instances list */
131 struct list_head node; 174 struct list_head node;
132 struct delayed_work poll_queue; 175 struct delayed_work poll_queue;
133}; 176};
134/* Adding event notification support elements */
135#define THERMAL_GENL_FAMILY_NAME "thermal_event"
136#define THERMAL_GENL_VERSION 0x01
137#define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_group"
138 177
139enum events { 178/* Structure that holds thermal governor information */
140 THERMAL_AUX0, 179struct thermal_governor {
141 THERMAL_AUX1, 180 char name[THERMAL_NAME_LENGTH];
142 THERMAL_CRITICAL, 181 int (*throttle)(struct thermal_zone_device *tz, int trip);
143 THERMAL_DEV_FAULT, 182 struct list_head governor_list;
183 struct module *owner;
144}; 184};
145 185
146struct thermal_genl_event { 186/* Structure that holds binding parameters for a zone */
147 u32 orig; 187struct thermal_bind_params {
148 enum events event; 188 struct thermal_cooling_device *cdev;
189
190 /*
191 * This is a measure of 'how effectively these devices can
192 * cool 'this' thermal zone. The shall be determined by platform
193 * characterization. This is on a 'percentage' scale.
194 * See Documentation/thermal/sysfs-api.txt for more information.
195 */
196 int weight;
197
198 /*
199 * This is a bit mask that gives the binding relation between this
200 * thermal zone and cdev, for a particular trip point.
201 * See Documentation/thermal/sysfs-api.txt for more information.
202 */
203 int trip_mask;
204 int (*match) (struct thermal_zone_device *tz,
205 struct thermal_cooling_device *cdev);
149}; 206};
150/* attributes of thermal_genl_family */ 207
151enum { 208/* Structure to define Thermal Zone parameters */
152 THERMAL_GENL_ATTR_UNSPEC, 209struct thermal_zone_params {
153 THERMAL_GENL_ATTR_EVENT, 210 char governor_name[THERMAL_NAME_LENGTH];
154 __THERMAL_GENL_ATTR_MAX, 211 int num_tbps; /* Number of tbp entries */
212 struct thermal_bind_params *tbp;
155}; 213};
156#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)
157 214
158/* commands supported by the thermal_genl_family */ 215struct thermal_genl_event {
159enum { 216 u32 orig;
160 THERMAL_GENL_CMD_UNSPEC, 217 enum events event;
161 THERMAL_GENL_CMD_EVENT,
162 __THERMAL_GENL_CMD_MAX,
163}; 218};
164#define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1)
165 219
220/* Function declarations */
166struct thermal_zone_device *thermal_zone_device_register(const char *, int, int, 221struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
167 void *, const struct thermal_zone_device_ops *, int, int); 222 void *, const struct thermal_zone_device_ops *,
223 const struct thermal_zone_params *, int, int);
168void thermal_zone_device_unregister(struct thermal_zone_device *); 224void thermal_zone_device_unregister(struct thermal_zone_device *);
169 225
170int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int, 226int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
@@ -173,10 +229,20 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
173int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int, 229int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
174 struct thermal_cooling_device *); 230 struct thermal_cooling_device *);
175void thermal_zone_device_update(struct thermal_zone_device *); 231void thermal_zone_device_update(struct thermal_zone_device *);
232
176struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, 233struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
177 const struct thermal_cooling_device_ops *); 234 const struct thermal_cooling_device_ops *);
178void thermal_cooling_device_unregister(struct thermal_cooling_device *); 235void thermal_cooling_device_unregister(struct thermal_cooling_device *);
179 236
237int get_tz_trend(struct thermal_zone_device *, int);
238struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
239 struct thermal_cooling_device *, int);
240void thermal_cdev_update(struct thermal_cooling_device *);
241void notify_thermal_framework(struct thermal_zone_device *, int);
242
243int thermal_register_governor(struct thermal_governor *);
244void thermal_unregister_governor(struct thermal_governor *);
245
180#ifdef CONFIG_NET 246#ifdef CONFIG_NET
181extern int thermal_generate_netlink_event(u32 orig, enum events event); 247extern int thermal_generate_netlink_event(u32 orig, enum events event);
182#else 248#else