aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhang Rui <rui.zhang@intel.com>2013-04-14 21:26:58 -0400
committerZhang Rui <rui.zhang@intel.com>2013-04-14 21:26:58 -0400
commitd13cb03aef0c062dcdd16b411bd4c02c1574ff08 (patch)
tree0ee1d535ddf0ca49cd88484f042d12996f689e1c
parent2fd1db8819fbf73b5f74b4b4a205ab7be0957944 (diff)
parentbbf7fc88c78f7317e2cdcf77e974c8a9a8312641 (diff)
Merge branch 'thermal' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux into next
Conflicts: drivers/thermal/cpu_cooling.c
-rw-r--r--Documentation/devicetree/bindings/thermal/armada-thermal.txt22
-rw-r--r--Documentation/thermal/exynos_thermal_emulation8
-rw-r--r--Documentation/thermal/sysfs-api.txt12
-rw-r--r--drivers/thermal/Kconfig23
-rw-r--r--drivers/thermal/Makefile10
-rw-r--r--drivers/thermal/armada_thermal.c232
-rw-r--r--drivers/thermal/cpu_cooling.c154
-rw-r--r--drivers/thermal/exynos_thermal.c184
-rw-r--r--drivers/thermal/fair_share.c15
-rw-r--r--drivers/thermal/rcar_thermal.c34
-rw-r--r--drivers/thermal/step_wise.c26
-rw-r--r--drivers/thermal/thermal_core.c (renamed from drivers/thermal/thermal_sys.c)59
-rw-r--r--drivers/thermal/thermal_core.h27
-rw-r--r--drivers/thermal/user_space.c15
-rw-r--r--include/linux/cpu_cooling.h9
-rw-r--r--include/linux/thermal.h9
16 files changed, 578 insertions, 261 deletions
diff --git a/Documentation/devicetree/bindings/thermal/armada-thermal.txt b/Documentation/devicetree/bindings/thermal/armada-thermal.txt
new file mode 100644
index 000000000000..fff93d5f92de
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/armada-thermal.txt
@@ -0,0 +1,22 @@
1* Marvell Armada 370/XP thermal management
2
3Required properties:
4
5- compatible: Should be set to one of the following:
6 marvell,armada370-thermal
7 marvell,armadaxp-thermal
8
9- reg: Device's register space.
10 Two entries are expected, see the examples below.
11 The first one is required for the sensor register;
12 the second one is required for the control register
13 to be used for sensor initialization (a.k.a. calibration).
14
15Example:
16
17 thermal@d0018300 {
18 compatible = "marvell,armada370-thermal";
19 reg = <0xd0018300 0x4
20 0xd0018304 0x4>;
21 status = "okay";
22 };
diff --git a/Documentation/thermal/exynos_thermal_emulation b/Documentation/thermal/exynos_thermal_emulation
index b73bbfb697bb..36a3e79c1203 100644
--- a/Documentation/thermal/exynos_thermal_emulation
+++ b/Documentation/thermal/exynos_thermal_emulation
@@ -13,11 +13,11 @@ Thermal emulation mode supports software debug for TMU's operation. User can set
13manually with software code and TMU will read current temperature from user value not from 13manually with software code and TMU will read current temperature from user value not from
14sensor's value. 14sensor's value.
15 15
16Enabling CONFIG_EXYNOS_THERMAL_EMUL option will make this support in available. 16Enabling CONFIG_THERMAL_EMULATION option will make this support available.
17When it's enabled, sysfs node will be created under 17When it's enabled, sysfs node will be created as
18/sys/bus/platform/devices/'exynos device name'/ with name of 'emulation'. 18/sys/devices/virtual/thermal/thermal_zone'zone id'/emul_temp.
19 19
20The sysfs node, 'emulation', will contain value 0 for the initial state. When you input any 20The sysfs node, 'emul_node', will contain value 0 for the initial state. When you input any
21temperature you want to update to sysfs node, it automatically enable emulation mode and 21temperature you want to update to sysfs node, it automatically enable emulation mode and
22current temperature will be changed into it. 22current temperature will be changed into it.
23(Exynos also supports user changable delay time which would be used to delay of 23(Exynos also supports user changable delay time which would be used to delay of
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index 6859661c9d31..b2ffe98cf469 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -265,6 +265,10 @@ emul_temp
265 Unit: millidegree Celsius 265 Unit: millidegree Celsius
266 WO, Optional 266 WO, Optional
267 267
268 WARNING: Be careful while enabling this option on production systems,
269 because userland can easily disable the thermal policy by simply
270 flooding this sysfs node with low temperature values.
271
268***************************** 272*****************************
269* Cooling device attributes * 273* Cooling device attributes *
270***************************** 274*****************************
@@ -375,11 +379,3 @@ platform data is provided, this uses the step_wise throttling policy.
375This function serves as an arbitrator to set the state of a cooling 379This function serves as an arbitrator to set the state of a cooling
376device. It sets the cooling device to the deepest cooling state if 380device. It sets the cooling device to the deepest cooling state if
377possible. 381possible.
378
3795.5:thermal_register_governor:
380This function lets the various thermal governors to register themselves
381with the Thermal framework. At run time, depending on a zone's platform
382data, a particular governor is used for throttling.
383
3845.6:thermal_unregister_governor:
385This function unregisters a governor from the thermal framework.
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index a764f165b589..d1c2160492aa 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -67,7 +67,7 @@ config THERMAL_GOV_USER_SPACE
67 Enable this to let the user space manage the platform thermals. 67 Enable this to let the user space manage the platform thermals.
68 68
69config CPU_THERMAL 69config CPU_THERMAL
70 tristate "generic cpu cooling support" 70 bool "generic cpu cooling support"
71 depends on CPU_FREQ 71 depends on CPU_FREQ
72 select CPU_FREQ_TABLE 72 select CPU_FREQ_TABLE
73 help 73 help
@@ -86,6 +86,10 @@ config THERMAL_EMULATION
86 user can manually input temperature and test the different trip 86 user can manually input temperature and test the different trip
87 threshold behaviour for simulation purpose. 87 threshold behaviour for simulation purpose.
88 88
89 WARNING: Be careful while enabling this option on production systems,
90 because userland can easily disable the thermal policy by simply
91 flooding this sysfs node with low temperature values.
92
89config SPEAR_THERMAL 93config SPEAR_THERMAL
90 bool "SPEAr thermal sensor driver" 94 bool "SPEAr thermal sensor driver"
91 depends on PLAT_SPEAR 95 depends on PLAT_SPEAR
@@ -117,15 +121,6 @@ config EXYNOS_THERMAL
117 If you say yes here you get support for TMU (Thermal Management 121 If you say yes here you get support for TMU (Thermal Management
118 Unit) on SAMSUNG EXYNOS series of SoC. 122 Unit) on SAMSUNG EXYNOS series of SoC.
119 123
120config EXYNOS_THERMAL_EMUL
121 bool "EXYNOS TMU emulation mode support"
122 depends on EXYNOS_THERMAL
123 help
124 Exynos 4412 and 4414 and 5 series has emulation mode on TMU.
125 Enable this option will be make sysfs node in exynos thermal platform
126 device directory to support emulation mode. With emulation mode sysfs
127 node, you can manually input temperature to TMU for simulation purpose.
128
129config DOVE_THERMAL 124config DOVE_THERMAL
130 tristate "Temperature sensor on Marvell Dove SoCs" 125 tristate "Temperature sensor on Marvell Dove SoCs"
131 depends on ARCH_DOVE 126 depends on ARCH_DOVE
@@ -144,6 +139,14 @@ config DB8500_THERMAL
144 created. Cooling devices can be bound to the trip points to cool this 139 created. Cooling devices can be bound to the trip points to cool this
145 thermal zone if trip points reached. 140 thermal zone if trip points reached.
146 141
142config ARMADA_THERMAL
143 tristate "Armada 370/XP thermal management"
144 depends on ARCH_MVEBU
145 depends on OF
146 help
147 Enable this option if you want to have support for thermal management
148 controller present in Armada 370 and Armada XP SoC.
149
147config DB8500_CPUFREQ_COOLING 150config DB8500_CPUFREQ_COOLING
148 tristate "DB8500 cpufreq cooling" 151 tristate "DB8500 cpufreq cooling"
149 depends on ARCH_U8500 152 depends on ARCH_U8500
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index d3a2b38c31e8..c054d410ac3f 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -3,14 +3,15 @@
3# 3#
4 4
5obj-$(CONFIG_THERMAL) += thermal_sys.o 5obj-$(CONFIG_THERMAL) += thermal_sys.o
6thermal_sys-y += thermal_core.o
6 7
7# governors 8# governors
8obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o 9thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o
9obj-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o 10thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o
10obj-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o 11thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o
11 12
12# cpufreq cooling 13# cpufreq cooling
13obj-$(CONFIG_CPU_THERMAL) += cpu_cooling.o 14thermal_sys-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
14 15
15# platform thermal drivers 16# platform thermal drivers
16obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o 17obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o
19obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o 20obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
20obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o 21obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o
21obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o 22obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
23obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
22obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o 24obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
23obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o 25obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
24 26
diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c
new file mode 100644
index 000000000000..5b4d75fd7b49
--- /dev/null
+++ b/drivers/thermal/armada_thermal.c
@@ -0,0 +1,232 @@
1/*
2 * Marvell Armada 370/XP thermal sensor driver
3 *
4 * Copyright (C) 2013 Marvell
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16#include <linux/device.h>
17#include <linux/err.h>
18#include <linux/io.h>
19#include <linux/kernel.h>
20#include <linux/of.h>
21#include <linux/module.h>
22#include <linux/delay.h>
23#include <linux/platform_device.h>
24#include <linux/of_device.h>
25#include <linux/thermal.h>
26
27#define THERMAL_VALID_OFFSET 9
28#define THERMAL_VALID_MASK 0x1
29#define THERMAL_TEMP_OFFSET 10
30#define THERMAL_TEMP_MASK 0x1ff
31
32/* Thermal Manager Control and Status Register */
33#define PMU_TDC0_SW_RST_MASK (0x1 << 1)
34#define PMU_TM_DISABLE_OFFS 0
35#define PMU_TM_DISABLE_MASK (0x1 << PMU_TM_DISABLE_OFFS)
36#define PMU_TDC0_REF_CAL_CNT_OFFS 11
37#define PMU_TDC0_REF_CAL_CNT_MASK (0x1ff << PMU_TDC0_REF_CAL_CNT_OFFS)
38#define PMU_TDC0_OTF_CAL_MASK (0x1 << 30)
39#define PMU_TDC0_START_CAL_MASK (0x1 << 25)
40
41struct armada_thermal_ops;
42
43/* Marvell EBU Thermal Sensor Dev Structure */
44struct armada_thermal_priv {
45 void __iomem *sensor;
46 void __iomem *control;
47 struct armada_thermal_ops *ops;
48};
49
50struct armada_thermal_ops {
51 /* Initialize the sensor */
52 void (*init_sensor)(struct armada_thermal_priv *);
53
54 /* Test for a valid sensor value (optional) */
55 bool (*is_valid)(struct armada_thermal_priv *);
56};
57
58static void armadaxp_init_sensor(struct armada_thermal_priv *priv)
59{
60 unsigned long reg;
61
62 reg = readl_relaxed(priv->control);
63 reg |= PMU_TDC0_OTF_CAL_MASK;
64 writel(reg, priv->control);
65
66 /* Reference calibration value */
67 reg &= ~PMU_TDC0_REF_CAL_CNT_MASK;
68 reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS);
69 writel(reg, priv->control);
70
71 /* Reset the sensor */
72 reg = readl_relaxed(priv->control);
73 writel((reg | PMU_TDC0_SW_RST_MASK), priv->control);
74
75 writel(reg, priv->control);
76
77 /* Enable the sensor */
78 reg = readl_relaxed(priv->sensor);
79 reg &= ~PMU_TM_DISABLE_MASK;
80 writel(reg, priv->sensor);
81}
82
83static void armada370_init_sensor(struct armada_thermal_priv *priv)
84{
85 unsigned long reg;
86
87 reg = readl_relaxed(priv->control);
88 reg |= PMU_TDC0_OTF_CAL_MASK;
89 writel(reg, priv->control);
90
91 /* Reference calibration value */
92 reg &= ~PMU_TDC0_REF_CAL_CNT_MASK;
93 reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS);
94 writel(reg, priv->control);
95
96 reg &= ~PMU_TDC0_START_CAL_MASK;
97 writel(reg, priv->control);
98
99 mdelay(10);
100}
101
102static bool armada_is_valid(struct armada_thermal_priv *priv)
103{
104 unsigned long reg = readl_relaxed(priv->sensor);
105
106 return (reg >> THERMAL_VALID_OFFSET) & THERMAL_VALID_MASK;
107}
108
109static int armada_get_temp(struct thermal_zone_device *thermal,
110 unsigned long *temp)
111{
112 struct armada_thermal_priv *priv = thermal->devdata;
113 unsigned long reg;
114
115 /* Valid check */
116 if (priv->ops->is_valid && !priv->ops->is_valid(priv)) {
117 dev_err(&thermal->device,
118 "Temperature sensor reading not valid\n");
119 return -EIO;
120 }
121
122 reg = readl_relaxed(priv->sensor);
123 reg = (reg >> THERMAL_TEMP_OFFSET) & THERMAL_TEMP_MASK;
124 *temp = (3153000000UL - (10000000UL*reg)) / 13825;
125 return 0;
126}
127
128static struct thermal_zone_device_ops ops = {
129 .get_temp = armada_get_temp,
130};
131
132static const struct armada_thermal_ops armadaxp_ops = {
133 .init_sensor = armadaxp_init_sensor,
134};
135
136static const struct armada_thermal_ops armada370_ops = {
137 .is_valid = armada_is_valid,
138 .init_sensor = armada370_init_sensor,
139};
140
141static const struct of_device_id armada_thermal_id_table[] = {
142 {
143 .compatible = "marvell,armadaxp-thermal",
144 .data = &armadaxp_ops,
145 },
146 {
147 .compatible = "marvell,armada370-thermal",
148 .data = &armada370_ops,
149 },
150 {
151 /* sentinel */
152 },
153};
154MODULE_DEVICE_TABLE(of, armada_thermal_id_table);
155
156static int armada_thermal_probe(struct platform_device *pdev)
157{
158 struct thermal_zone_device *thermal;
159 const struct of_device_id *match;
160 struct armada_thermal_priv *priv;
161 struct resource *res;
162
163 match = of_match_device(armada_thermal_id_table, &pdev->dev);
164 if (!match)
165 return -ENODEV;
166
167 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
168 if (!priv)
169 return -ENOMEM;
170
171 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
172 if (!res) {
173 dev_err(&pdev->dev, "Failed to get platform resource\n");
174 return -ENODEV;
175 }
176
177 priv->sensor = devm_ioremap_resource(&pdev->dev, res);
178 if (IS_ERR(priv->sensor))
179 return PTR_ERR(priv->sensor);
180
181 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
182 if (!res) {
183 dev_err(&pdev->dev, "Failed to get platform resource\n");
184 return -ENODEV;
185 }
186
187 priv->control = devm_ioremap_resource(&pdev->dev, res);
188 if (IS_ERR(priv->control))
189 return PTR_ERR(priv->control);
190
191 priv->ops = (struct armada_thermal_ops *)match->data;
192 priv->ops->init_sensor(priv);
193
194 thermal = thermal_zone_device_register("armada_thermal", 0, 0,
195 priv, &ops, NULL, 0, 0);
196 if (IS_ERR(thermal)) {
197 dev_err(&pdev->dev,
198 "Failed to register thermal zone device\n");
199 return PTR_ERR(thermal);
200 }
201
202 platform_set_drvdata(pdev, thermal);
203
204 return 0;
205}
206
207static int armada_thermal_exit(struct platform_device *pdev)
208{
209 struct thermal_zone_device *armada_thermal =
210 platform_get_drvdata(pdev);
211
212 thermal_zone_device_unregister(armada_thermal);
213 platform_set_drvdata(pdev, NULL);
214
215 return 0;
216}
217
218static struct platform_driver armada_thermal_driver = {
219 .probe = armada_thermal_probe,
220 .remove = armada_thermal_exit,
221 .driver = {
222 .name = "armada_thermal",
223 .owner = THIS_MODULE,
224 .of_match_table = of_match_ptr(armada_thermal_id_table),
225 },
226};
227
228module_platform_driver(armada_thermal_driver);
229
230MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>");
231MODULE_DESCRIPTION("Armada 370/XP thermal driver");
232MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index be2e6b0e5349..5f5c780bcd90 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -108,54 +108,120 @@ static int is_cpufreq_valid(int cpu)
108 return !cpufreq_get_policy(&policy, cpu); 108 return !cpufreq_get_policy(&policy, cpu);
109} 109}
110 110
111/** 111enum cpufreq_cooling_property {
112 * get_cpu_frequency - get the absolute value of frequency from level. 112 GET_LEVEL,
113 * @cpu: cpu for which frequency is fetched. 113 GET_FREQ,
114 * @level: level of frequency, equals cooling state of cpu cooling device 114 GET_MAXL,
115 * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc 115};
116 */ 116
117static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) 117/*
118 * this is the common function to
119 * 1. get maximum cpu cooling states
120 * 2. translate frequency to cooling state
121 * 3. translate cooling state to frequency
122 * Note that the code may be not in good shape
123 * but it is written in this way in order to:
124 * a) reduce duplicate code as most of the code can be shared.
125 * b) make sure the logic is consistent when translating between
126 * cooling states and frequencies.
127*/
128static int get_property(unsigned int cpu, unsigned long input,
129 unsigned int* output, enum cpufreq_cooling_property property)
118{ 130{
119 int ret = 0, i = 0; 131 int i, j;
120 unsigned long level_index; 132 unsigned long max_level = 0, level;
121 bool descend = false; 133 unsigned int freq = CPUFREQ_ENTRY_INVALID;
134 int descend = -1;
122 struct cpufreq_frequency_table *table = 135 struct cpufreq_frequency_table *table =
123 cpufreq_frequency_get_table(cpu); 136 cpufreq_frequency_get_table(cpu);
137
138 if (!output)
139 return -EINVAL;
140
124 if (!table) 141 if (!table)
125 return ret; 142 return -EINVAL;
126 143
127 while (table[i].frequency != CPUFREQ_TABLE_END) { 144
145 for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
146 /* ignore invalid entries */
128 if (table[i].frequency == CPUFREQ_ENTRY_INVALID) 147 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
129 continue; 148 continue;
130 149
131 /*check if table in ascending or descending order*/ 150 /* ignore duplicate entry */
132 if ((table[i + 1].frequency != CPUFREQ_TABLE_END) && 151 if (freq == table[i].frequency)
133 (table[i + 1].frequency < table[i].frequency) 152 continue;
134 && !descend) { 153
135 descend = true; 154 /* get the frequency order */
136 } 155 if (freq != CPUFREQ_ENTRY_INVALID && descend != -1)
156 descend = !!(freq > table[i].frequency);
137 157
138 /*return if level matched and table in descending order*/ 158 freq = table[i].frequency;
139 if (descend && i == level) 159 max_level++;
140 return table[i].frequency;
141 i++;
142 } 160 }
143 i--;
144 161
145 if (level > i || descend) 162 /* get max level */
146 return ret; 163 if (property == GET_MAXL) {
147 level_index = i - level; 164 *output = (unsigned int)max_level;
165 return 0;
166 }
167
168 if (property == GET_FREQ)
169 level = descend ? input : (max_level - input -1);
170
148 171
149 /*Scan the table in reverse order and match the level*/ 172 for (i = 0, j = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
150 while (i >= 0) { 173 /* ignore invalid entry */
151 if (table[i].frequency == CPUFREQ_ENTRY_INVALID) 174 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
152 continue; 175 continue;
153 /*return if level matched*/ 176
154 if (i == level_index) 177 /* ignore duplicate entry */
155 return table[i].frequency; 178 if (freq == table[i].frequency)
156 i--; 179 continue;
180
181 /* now we have a valid frequency entry */
182 freq = table[i].frequency;
183
184 if (property == GET_LEVEL && (unsigned int)input == freq) {
185 /* get level by frequency */
186 *output = descend ? j : (max_level - j - 1);
187 return 0;
188 }
189 if (property == GET_FREQ && level == j) {
190 /* get frequency by level */
191 *output = freq;
192 return 0;
193 }
194 j++;
157 } 195 }
158 return ret; 196 return -EINVAL;
197}
198
199unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
200{
201 unsigned int val;
202
203 if (get_property(cpu, (unsigned long)freq, &val, GET_LEVEL))
204 return THERMAL_CSTATE_INVALID;
205 return (unsigned long)val;
206}
207
208EXPORT_SYMBOL(cpufreq_cooling_get_level);
209
210/**
211 * get_cpu_frequency - get the absolute value of frequency from level.
212 * @cpu: cpu for which frequency is fetched.
213 * @level: level of frequency, equals cooling state of cpu cooling device
214 * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc
215 */
216static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level)
217{
218 int ret = 0;
219 unsigned int freq;
220
221 ret = get_property(cpu, level, &freq, GET_FREQ);
222 if (ret)
223 return 0;
224 return freq;
159} 225}
160 226
161/** 227/**
@@ -237,29 +303,17 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
237 struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; 303 struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
238 struct cpumask *mask = &cpufreq_device->allowed_cpus; 304 struct cpumask *mask = &cpufreq_device->allowed_cpus;
239 unsigned int cpu; 305 unsigned int cpu;
240 struct cpufreq_frequency_table *table;
241 unsigned long count = 0; 306 unsigned long count = 0;
242 int i = 0; 307 int ret;
243 308
244 cpu = cpumask_any(mask); 309 cpu = cpumask_any(mask);
245 table = cpufreq_frequency_get_table(cpu);
246 if (!table) {
247 *state = 0;
248 return 0;
249 }
250 310
251 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 311 ret = get_property(cpu, 0, (unsigned int *)&count, GET_MAXL);
252 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
253 continue;
254 count++;
255 }
256 312
257 if (count > 0) { 313 if (count > 0)
258 *state = --count; 314 *state = count;
259 return 0;
260 }
261 315
262 return -EINVAL; 316 return ret;
263} 317}
264 318
265/** 319/**
diff --git a/drivers/thermal/exynos_thermal.c b/drivers/thermal/exynos_thermal.c
index 46568c078dee..e34d842cc675 100644
--- a/drivers/thermal/exynos_thermal.c
+++ b/drivers/thermal/exynos_thermal.c
@@ -39,8 +39,6 @@
39#include <linux/cpu_cooling.h> 39#include <linux/cpu_cooling.h>
40#include <linux/of.h> 40#include <linux/of.h>
41 41
42#include <plat/cpu.h>
43
44/* Exynos generic registers */ 42/* Exynos generic registers */
45#define EXYNOS_TMU_REG_TRIMINFO 0x0 43#define EXYNOS_TMU_REG_TRIMINFO 0x0
46#define EXYNOS_TMU_REG_CONTROL 0x20 44#define EXYNOS_TMU_REG_CONTROL 0x20
@@ -100,13 +98,13 @@
100#define IDLE_INTERVAL 10000 98#define IDLE_INTERVAL 10000
101#define MCELSIUS 1000 99#define MCELSIUS 1000
102 100
103#ifdef CONFIG_EXYNOS_THERMAL_EMUL 101#ifdef CONFIG_THERMAL_EMULATION
104#define EXYNOS_EMUL_TIME 0x57F0 102#define EXYNOS_EMUL_TIME 0x57F0
105#define EXYNOS_EMUL_TIME_SHIFT 16 103#define EXYNOS_EMUL_TIME_SHIFT 16
106#define EXYNOS_EMUL_DATA_SHIFT 8 104#define EXYNOS_EMUL_DATA_SHIFT 8
107#define EXYNOS_EMUL_DATA_MASK 0xFF 105#define EXYNOS_EMUL_DATA_MASK 0xFF
108#define EXYNOS_EMUL_ENABLE 0x1 106#define EXYNOS_EMUL_ENABLE 0x1
109#endif /* CONFIG_EXYNOS_THERMAL_EMUL */ 107#endif /* CONFIG_THERMAL_EMULATION */
110 108
111/* CPU Zone information */ 109/* CPU Zone information */
112#define PANIC_ZONE 4 110#define PANIC_ZONE 4
@@ -145,6 +143,7 @@ struct thermal_cooling_conf {
145struct thermal_sensor_conf { 143struct thermal_sensor_conf {
146 char name[SENSOR_NAME_LEN]; 144 char name[SENSOR_NAME_LEN];
147 int (*read_temperature)(void *data); 145 int (*read_temperature)(void *data);
146 int (*write_emul_temp)(void *drv_data, unsigned long temp);
148 struct thermal_trip_point_conf trip_data; 147 struct thermal_trip_point_conf trip_data;
149 struct thermal_cooling_conf cooling_data; 148 struct thermal_cooling_conf cooling_data;
150 void *private_data; 149 void *private_data;
@@ -242,26 +241,6 @@ static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
242 return ret; 241 return ret;
243} 242}
244 243
245static int exynos_get_frequency_level(unsigned int cpu, unsigned int freq)
246{
247 int i = 0, ret = -EINVAL;
248 struct cpufreq_frequency_table *table = NULL;
249#ifdef CONFIG_CPU_FREQ
250 table = cpufreq_frequency_get_table(cpu);
251#endif
252 if (!table)
253 return ret;
254
255 while (table[i].frequency != CPUFREQ_TABLE_END) {
256 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
257 continue;
258 if (table[i].frequency == freq)
259 return i;
260 i++;
261 }
262 return ret;
263}
264
265/* Bind callback functions for thermal zone */ 244/* Bind callback functions for thermal zone */
266static int exynos_bind(struct thermal_zone_device *thermal, 245static int exynos_bind(struct thermal_zone_device *thermal,
267 struct thermal_cooling_device *cdev) 246 struct thermal_cooling_device *cdev)
@@ -288,8 +267,8 @@ static int exynos_bind(struct thermal_zone_device *thermal,
288 /* Bind the thermal zone to the cpufreq cooling device */ 267 /* Bind the thermal zone to the cpufreq cooling device */
289 for (i = 0; i < tab_size; i++) { 268 for (i = 0; i < tab_size; i++) {
290 clip_data = (struct freq_clip_table *)&(tab_ptr[i]); 269 clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
291 level = exynos_get_frequency_level(0, clip_data->freq_clip_max); 270 level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
292 if (level < 0) 271 if (level == THERMAL_CSTATE_INVALID)
293 return 0; 272 return 0;
294 switch (GET_ZONE(i)) { 273 switch (GET_ZONE(i)) {
295 case MONITOR_ZONE: 274 case MONITOR_ZONE:
@@ -369,6 +348,23 @@ static int exynos_get_temp(struct thermal_zone_device *thermal,
369 return 0; 348 return 0;
370} 349}
371 350
351/* Get temperature callback functions for thermal zone */
352static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
353 unsigned long temp)
354{
355 void *data;
356 int ret = -EINVAL;
357
358 if (!th_zone->sensor_conf) {
359 pr_info("Temperature sensor not initialised\n");
360 return -EINVAL;
361 }
362 data = th_zone->sensor_conf->private_data;
363 if (th_zone->sensor_conf->write_emul_temp)
364 ret = th_zone->sensor_conf->write_emul_temp(data, temp);
365 return ret;
366}
367
372/* Get the temperature trend */ 368/* Get the temperature trend */
373static int exynos_get_trend(struct thermal_zone_device *thermal, 369static int exynos_get_trend(struct thermal_zone_device *thermal,
374 int trip, enum thermal_trend *trend) 370 int trip, enum thermal_trend *trend)
@@ -392,6 +388,7 @@ static struct thermal_zone_device_ops const exynos_dev_ops = {
392 .bind = exynos_bind, 388 .bind = exynos_bind,
393 .unbind = exynos_unbind, 389 .unbind = exynos_unbind,
394 .get_temp = exynos_get_temp, 390 .get_temp = exynos_get_temp,
391 .set_emul_temp = exynos_set_emul_temp,
395 .get_trend = exynos_get_trend, 392 .get_trend = exynos_get_trend,
396 .get_mode = exynos_get_mode, 393 .get_mode = exynos_get_mode,
397 .set_mode = exynos_set_mode, 394 .set_mode = exynos_set_mode,
@@ -714,6 +711,47 @@ static int exynos_tmu_read(struct exynos_tmu_data *data)
714 return temp; 711 return temp;
715} 712}
716 713
714#ifdef CONFIG_THERMAL_EMULATION
715static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
716{
717 struct exynos_tmu_data *data = drv_data;
718 unsigned int reg;
719 int ret = -EINVAL;
720
721 if (data->soc == SOC_ARCH_EXYNOS4210)
722 goto out;
723
724 if (temp && temp < MCELSIUS)
725 goto out;
726
727 mutex_lock(&data->lock);
728 clk_enable(data->clk);
729
730 reg = readl(data->base + EXYNOS_EMUL_CON);
731
732 if (temp) {
733 temp /= MCELSIUS;
734
735 reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
736 (temp_to_code(data, temp)
737 << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
738 } else {
739 reg &= ~EXYNOS_EMUL_ENABLE;
740 }
741
742 writel(reg, data->base + EXYNOS_EMUL_CON);
743
744 clk_disable(data->clk);
745 mutex_unlock(&data->lock);
746 return 0;
747out:
748 return ret;
749}
750#else
751static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
752 { return -EINVAL; }
753#endif/*CONFIG_THERMAL_EMULATION*/
754
717static void exynos_tmu_work(struct work_struct *work) 755static void exynos_tmu_work(struct work_struct *work)
718{ 756{
719 struct exynos_tmu_data *data = container_of(work, 757 struct exynos_tmu_data *data = container_of(work,
@@ -747,6 +785,7 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id)
747static struct thermal_sensor_conf exynos_sensor_conf = { 785static struct thermal_sensor_conf exynos_sensor_conf = {
748 .name = "exynos-therm", 786 .name = "exynos-therm",
749 .read_temperature = (int (*)(void *))exynos_tmu_read, 787 .read_temperature = (int (*)(void *))exynos_tmu_read,
788 .write_emul_temp = exynos_tmu_set_emulation,
750}; 789};
751 790
752#if defined(CONFIG_CPU_EXYNOS4210) 791#if defined(CONFIG_CPU_EXYNOS4210)
@@ -853,93 +892,6 @@ static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
853 platform_get_device_id(pdev)->driver_data; 892 platform_get_device_id(pdev)->driver_data;
854} 893}
855 894
856#ifdef CONFIG_EXYNOS_THERMAL_EMUL
857static ssize_t exynos_tmu_emulation_show(struct device *dev,
858 struct device_attribute *attr,
859 char *buf)
860{
861 struct platform_device *pdev = container_of(dev,
862 struct platform_device, dev);
863 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
864 unsigned int reg;
865 u8 temp_code;
866 int temp = 0;
867
868 if (data->soc == SOC_ARCH_EXYNOS4210)
869 goto out;
870
871 mutex_lock(&data->lock);
872 clk_enable(data->clk);
873 reg = readl(data->base + EXYNOS_EMUL_CON);
874 clk_disable(data->clk);
875 mutex_unlock(&data->lock);
876
877 if (reg & EXYNOS_EMUL_ENABLE) {
878 reg >>= EXYNOS_EMUL_DATA_SHIFT;
879 temp_code = reg & EXYNOS_EMUL_DATA_MASK;
880 temp = code_to_temp(data, temp_code);
881 }
882out:
883 return sprintf(buf, "%d\n", temp * MCELSIUS);
884}
885
886static ssize_t exynos_tmu_emulation_store(struct device *dev,
887 struct device_attribute *attr,
888 const char *buf, size_t count)
889{
890 struct platform_device *pdev = container_of(dev,
891 struct platform_device, dev);
892 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
893 unsigned int reg;
894 int temp;
895
896 if (data->soc == SOC_ARCH_EXYNOS4210)
897 goto out;
898
899 if (!sscanf(buf, "%d\n", &temp) || temp < 0)
900 return -EINVAL;
901
902 mutex_lock(&data->lock);
903 clk_enable(data->clk);
904
905 reg = readl(data->base + EXYNOS_EMUL_CON);
906
907 if (temp) {
908 /* Both CELSIUS and MCELSIUS type are available for input */
909 if (temp > MCELSIUS)
910 temp /= MCELSIUS;
911
912 reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
913 (temp_to_code(data, (temp / MCELSIUS))
914 << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
915 } else {
916 reg &= ~EXYNOS_EMUL_ENABLE;
917 }
918
919 writel(reg, data->base + EXYNOS_EMUL_CON);
920
921 clk_disable(data->clk);
922 mutex_unlock(&data->lock);
923
924out:
925 return count;
926}
927
928static DEVICE_ATTR(emulation, 0644, exynos_tmu_emulation_show,
929 exynos_tmu_emulation_store);
930static int create_emulation_sysfs(struct device *dev)
931{
932 return device_create_file(dev, &dev_attr_emulation);
933}
934static void remove_emulation_sysfs(struct device *dev)
935{
936 device_remove_file(dev, &dev_attr_emulation);
937}
938#else
939static inline int create_emulation_sysfs(struct device *dev) { return 0; }
940static inline void remove_emulation_sysfs(struct device *dev) {}
941#endif
942
943static int exynos_tmu_probe(struct platform_device *pdev) 895static int exynos_tmu_probe(struct platform_device *pdev)
944{ 896{
945 struct exynos_tmu_data *data; 897 struct exynos_tmu_data *data;
@@ -1039,10 +991,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
1039 goto err_clk; 991 goto err_clk;
1040 } 992 }
1041 993
1042 ret = create_emulation_sysfs(&pdev->dev);
1043 if (ret)
1044 dev_err(&pdev->dev, "Failed to create emulation mode sysfs node\n");
1045
1046 return 0; 994 return 0;
1047err_clk: 995err_clk:
1048 platform_set_drvdata(pdev, NULL); 996 platform_set_drvdata(pdev, NULL);
@@ -1054,8 +1002,6 @@ static int exynos_tmu_remove(struct platform_device *pdev)
1054{ 1002{
1055 struct exynos_tmu_data *data = platform_get_drvdata(pdev); 1003 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
1056 1004
1057 remove_emulation_sysfs(&pdev->dev);
1058
1059 exynos_tmu_control(pdev, false); 1005 exynos_tmu_control(pdev, false);
1060 1006
1061 exynos_unregister_thermal(); 1007 exynos_unregister_thermal();
diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c
index 792479f2b64b..944ba2f340c8 100644
--- a/drivers/thermal/fair_share.c
+++ b/drivers/thermal/fair_share.c
@@ -22,9 +22,6 @@
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 */ 23 */
24 24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
27#include <linux/module.h>
28#include <linux/thermal.h> 25#include <linux/thermal.h>
29 26
30#include "thermal_core.h" 27#include "thermal_core.h"
@@ -111,23 +108,15 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
111static struct thermal_governor thermal_gov_fair_share = { 108static struct thermal_governor thermal_gov_fair_share = {
112 .name = "fair_share", 109 .name = "fair_share",
113 .throttle = fair_share_throttle, 110 .throttle = fair_share_throttle,
114 .owner = THIS_MODULE,
115}; 111};
116 112
117static int __init thermal_gov_fair_share_init(void) 113int thermal_gov_fair_share_register(void)
118{ 114{
119 return thermal_register_governor(&thermal_gov_fair_share); 115 return thermal_register_governor(&thermal_gov_fair_share);
120} 116}
121 117
122static void __exit thermal_gov_fair_share_exit(void) 118void thermal_gov_fair_share_unregister(void)
123{ 119{
124 thermal_unregister_governor(&thermal_gov_fair_share); 120 thermal_unregister_governor(&thermal_gov_fair_share);
125} 121}
126 122
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 2cc5b6115e3e..8d7edd4c8228 100644
--- a/drivers/thermal/rcar_thermal.c
+++ b/drivers/thermal/rcar_thermal.c
@@ -24,6 +24,7 @@
24#include <linux/io.h> 24#include <linux/io.h>
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/platform_device.h> 26#include <linux/platform_device.h>
27#include <linux/pm_runtime.h>
27#include <linux/reboot.h> 28#include <linux/reboot.h>
28#include <linux/slab.h> 29#include <linux/slab.h>
29#include <linux/spinlock.h> 30#include <linux/spinlock.h>
@@ -377,6 +378,9 @@ static int rcar_thermal_probe(struct platform_device *pdev)
377 spin_lock_init(&common->lock); 378 spin_lock_init(&common->lock);
378 common->dev = dev; 379 common->dev = dev;
379 380
381 pm_runtime_enable(dev);
382 pm_runtime_get_sync(dev);
383
380 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 384 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
381 if (irq) { 385 if (irq) {
382 int ret; 386 int ret;
@@ -419,12 +423,15 @@ static int rcar_thermal_probe(struct platform_device *pdev)
419 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 423 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
420 if (!priv) { 424 if (!priv) {
421 dev_err(dev, "Could not allocate priv\n"); 425 dev_err(dev, "Could not allocate priv\n");
422 return -ENOMEM; 426 ret = -ENOMEM;
427 goto error_unregister;
423 } 428 }
424 429
425 priv->base = devm_ioremap_resource(dev, res); 430 priv->base = devm_ioremap_resource(dev, res);
426 if (IS_ERR(priv->base)) 431 if (IS_ERR(priv->base)) {
427 return PTR_ERR(priv->base); 432 ret = PTR_ERR(priv->base);
433 goto error_unregister;
434 }
428 435
429 priv->common = common; 436 priv->common = common;
430 priv->id = i; 437 priv->id = i;
@@ -443,10 +450,10 @@ static int rcar_thermal_probe(struct platform_device *pdev)
443 goto error_unregister; 450 goto error_unregister;
444 } 451 }
445 452
446 list_move_tail(&priv->list, &common->head);
447
448 if (rcar_has_irq_support(priv)) 453 if (rcar_has_irq_support(priv))
449 rcar_thermal_irq_enable(priv); 454 rcar_thermal_irq_enable(priv);
455
456 list_move_tail(&priv->list, &common->head);
450 } 457 }
451 458
452 platform_set_drvdata(pdev, common); 459 platform_set_drvdata(pdev, common);
@@ -456,8 +463,14 @@ static int rcar_thermal_probe(struct platform_device *pdev)
456 return 0; 463 return 0;
457 464
458error_unregister: 465error_unregister:
459 rcar_thermal_for_each_priv(priv, common) 466 rcar_thermal_for_each_priv(priv, common) {
460 thermal_zone_device_unregister(priv->zone); 467 thermal_zone_device_unregister(priv->zone);
468 if (rcar_has_irq_support(priv))
469 rcar_thermal_irq_disable(priv);
470 }
471
472 pm_runtime_put_sync(dev);
473 pm_runtime_disable(dev);
461 474
462 return ret; 475 return ret;
463} 476}
@@ -465,13 +478,20 @@ error_unregister:
465static int rcar_thermal_remove(struct platform_device *pdev) 478static int rcar_thermal_remove(struct platform_device *pdev)
466{ 479{
467 struct rcar_thermal_common *common = platform_get_drvdata(pdev); 480 struct rcar_thermal_common *common = platform_get_drvdata(pdev);
481 struct device *dev = &pdev->dev;
468 struct rcar_thermal_priv *priv; 482 struct rcar_thermal_priv *priv;
469 483
470 rcar_thermal_for_each_priv(priv, common) 484 rcar_thermal_for_each_priv(priv, common) {
471 thermal_zone_device_unregister(priv->zone); 485 thermal_zone_device_unregister(priv->zone);
486 if (rcar_has_irq_support(priv))
487 rcar_thermal_irq_disable(priv);
488 }
472 489
473 platform_set_drvdata(pdev, NULL); 490 platform_set_drvdata(pdev, NULL);
474 491
492 pm_runtime_put_sync(dev);
493 pm_runtime_disable(dev);
494
475 return 0; 495 return 0;
476} 496}
477 497
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
index 407cde3211c1..4d4ddae1a991 100644
--- a/drivers/thermal/step_wise.c
+++ b/drivers/thermal/step_wise.c
@@ -22,9 +22,6 @@
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 */ 23 */
24 24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
27#include <linux/module.h>
28#include <linux/thermal.h> 25#include <linux/thermal.h>
29 26
30#include "thermal_core.h" 27#include "thermal_core.h"
@@ -59,9 +56,12 @@ static unsigned long get_target_state(struct thermal_instance *instance,
59 56
60 switch (trend) { 57 switch (trend) {
61 case THERMAL_TREND_RAISING: 58 case THERMAL_TREND_RAISING:
62 if (throttle) 59 if (throttle) {
63 cur_state = cur_state < instance->upper ? 60 cur_state = cur_state < instance->upper ?
64 (cur_state + 1) : instance->upper; 61 (cur_state + 1) : instance->upper;
62 if (cur_state < instance->lower)
63 cur_state = instance->lower;
64 }
65 break; 65 break;
66 case THERMAL_TREND_RAISE_FULL: 66 case THERMAL_TREND_RAISE_FULL:
67 if (throttle) 67 if (throttle)
@@ -71,8 +71,11 @@ static unsigned long get_target_state(struct thermal_instance *instance,
71 if (cur_state == instance->lower) { 71 if (cur_state == instance->lower) {
72 if (!throttle) 72 if (!throttle)
73 cur_state = -1; 73 cur_state = -1;
74 } else 74 } else {
75 cur_state -= 1; 75 cur_state -= 1;
76 if (cur_state > instance->upper)
77 cur_state = instance->upper;
78 }
76 break; 79 break;
77 case THERMAL_TREND_DROP_FULL: 80 case THERMAL_TREND_DROP_FULL:
78 if (cur_state == instance->lower) { 81 if (cur_state == instance->lower) {
@@ -180,23 +183,14 @@ static int step_wise_throttle(struct thermal_zone_device *tz, int trip)
180static struct thermal_governor thermal_gov_step_wise = { 183static struct thermal_governor thermal_gov_step_wise = {
181 .name = "step_wise", 184 .name = "step_wise",
182 .throttle = step_wise_throttle, 185 .throttle = step_wise_throttle,
183 .owner = THIS_MODULE,
184}; 186};
185 187
186static int __init thermal_gov_step_wise_init(void) 188int thermal_gov_step_wise_register(void)
187{ 189{
188 return thermal_register_governor(&thermal_gov_step_wise); 190 return thermal_register_governor(&thermal_gov_step_wise);
189} 191}
190 192
191static void __exit thermal_gov_step_wise_exit(void) 193void thermal_gov_step_wise_unregister(void)
192{ 194{
193 thermal_unregister_governor(&thermal_gov_step_wise); 195 thermal_unregister_governor(&thermal_gov_step_wise);
194} 196}
195
196/* This should load after thermal framework */
197fs_initcall(thermal_gov_step_wise_init);
198module_exit(thermal_gov_step_wise_exit);
199
200MODULE_AUTHOR("Durgadoss R");
201MODULE_DESCRIPTION("A step-by-step thermal throttling governor");
202MODULE_LICENSE("GPL");
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_core.c
index 5b7863a03f98..4cdc3e327222 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_core.c
@@ -99,7 +99,6 @@ int thermal_register_governor(struct thermal_governor *governor)
99 99
100 return err; 100 return err;
101} 101}
102EXPORT_SYMBOL_GPL(thermal_register_governor);
103 102
104void thermal_unregister_governor(struct thermal_governor *governor) 103void thermal_unregister_governor(struct thermal_governor *governor)
105{ 104{
@@ -127,7 +126,6 @@ exit:
127 mutex_unlock(&thermal_governor_lock); 126 mutex_unlock(&thermal_governor_lock);
128 return; 127 return;
129} 128}
130EXPORT_SYMBOL_GPL(thermal_unregister_governor);
131 129
132static int get_idr(struct idr *idr, struct mutex *lock, int *id) 130static int get_idr(struct idr *idr, struct mutex *lock, int *id)
133{ 131{
@@ -1858,30 +1856,69 @@ static inline int genetlink_init(void) { return 0; }
1858static inline void genetlink_exit(void) {} 1856static inline void genetlink_exit(void) {}
1859#endif /* !CONFIG_NET */ 1857#endif /* !CONFIG_NET */
1860 1858
1859static int __init thermal_register_governors(void)
1860{
1861 int result;
1862
1863 result = thermal_gov_step_wise_register();
1864 if (result)
1865 return result;
1866
1867 result = thermal_gov_fair_share_register();
1868 if (result)
1869 return result;
1870
1871 return thermal_gov_user_space_register();
1872}
1873
1874static void thermal_unregister_governors(void)
1875{
1876 thermal_gov_step_wise_unregister();
1877 thermal_gov_fair_share_unregister();
1878 thermal_gov_user_space_unregister();
1879}
1880
1861static int __init thermal_init(void) 1881static int __init thermal_init(void)
1862{ 1882{
1863 int result = 0; 1883 int result;
1884
1885 result = thermal_register_governors();
1886 if (result)
1887 goto error;
1864 1888
1865 result = class_register(&thermal_class); 1889 result = class_register(&thermal_class);
1866 if (result) { 1890 if (result)
1867 idr_destroy(&thermal_tz_idr); 1891 goto unregister_governors;
1868 idr_destroy(&thermal_cdev_idr); 1892
1869 mutex_destroy(&thermal_idr_lock);
1870 mutex_destroy(&thermal_list_lock);
1871 return result;
1872 }
1873 result = genetlink_init(); 1893 result = genetlink_init();
1894 if (result)
1895 goto unregister_class;
1896
1897 return 0;
1898
1899unregister_governors:
1900 thermal_unregister_governors();
1901unregister_class:
1902 class_unregister(&thermal_class);
1903error:
1904 idr_destroy(&thermal_tz_idr);
1905 idr_destroy(&thermal_cdev_idr);
1906 mutex_destroy(&thermal_idr_lock);
1907 mutex_destroy(&thermal_list_lock);
1908 mutex_destroy(&thermal_governor_lock);
1874 return result; 1909 return result;
1875} 1910}
1876 1911
1877static void __exit thermal_exit(void) 1912static void __exit thermal_exit(void)
1878{ 1913{
1914 genetlink_exit();
1879 class_unregister(&thermal_class); 1915 class_unregister(&thermal_class);
1916 thermal_unregister_governors();
1880 idr_destroy(&thermal_tz_idr); 1917 idr_destroy(&thermal_tz_idr);
1881 idr_destroy(&thermal_cdev_idr); 1918 idr_destroy(&thermal_cdev_idr);
1882 mutex_destroy(&thermal_idr_lock); 1919 mutex_destroy(&thermal_idr_lock);
1883 mutex_destroy(&thermal_list_lock); 1920 mutex_destroy(&thermal_list_lock);
1884 genetlink_exit(); 1921 mutex_destroy(&thermal_governor_lock);
1885} 1922}
1886 1923
1887fs_initcall(thermal_init); 1924fs_initcall(thermal_init);
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index 0d3205a18112..7cf2f6626251 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -50,4 +50,31 @@ struct thermal_instance {
50 struct list_head cdev_node; /* node in cdev->thermal_instances */ 50 struct list_head cdev_node; /* node in cdev->thermal_instances */
51}; 51};
52 52
53int thermal_register_governor(struct thermal_governor *);
54void thermal_unregister_governor(struct thermal_governor *);
55
56#ifdef CONFIG_THERMAL_GOV_STEP_WISE
57int thermal_gov_step_wise_register(void);
58void thermal_gov_step_wise_unregister(void);
59#else
60static inline int thermal_gov_step_wise_register(void) { return 0; }
61static inline void thermal_gov_step_wise_unregister(void) {}
62#endif /* CONFIG_THERMAL_GOV_STEP_WISE */
63
64#ifdef CONFIG_THERMAL_GOV_FAIR_SHARE
65int thermal_gov_fair_share_register(void);
66void thermal_gov_fair_share_unregister(void);
67#else
68static inline int thermal_gov_fair_share_register(void) { return 0; }
69static inline void thermal_gov_fair_share_unregister(void) {}
70#endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */
71
72#ifdef CONFIG_THERMAL_GOV_USER_SPACE
73int thermal_gov_user_space_register(void);
74void thermal_gov_user_space_unregister(void);
75#else
76static inline int thermal_gov_user_space_register(void) { return 0; }
77static inline void thermal_gov_user_space_unregister(void) {}
78#endif /* CONFIG_THERMAL_GOV_USER_SPACE */
79
53#endif /* __THERMAL_CORE_H__ */ 80#endif /* __THERMAL_CORE_H__ */
diff --git a/drivers/thermal/user_space.c b/drivers/thermal/user_space.c
index 6bbb380b6d19..10adcddc8821 100644
--- a/drivers/thermal/user_space.c
+++ b/drivers/thermal/user_space.c
@@ -22,9 +22,6 @@
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 */ 23 */
24 24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
27#include <linux/module.h>
28#include <linux/thermal.h> 25#include <linux/thermal.h>
29 26
30#include "thermal_core.h" 27#include "thermal_core.h"
@@ -46,23 +43,15 @@ static int notify_user_space(struct thermal_zone_device *tz, int trip)
46static struct thermal_governor thermal_gov_user_space = { 43static struct thermal_governor thermal_gov_user_space = {
47 .name = "user_space", 44 .name = "user_space",
48 .throttle = notify_user_space, 45 .throttle = notify_user_space,
49 .owner = THIS_MODULE,
50}; 46};
51 47
52static int __init thermal_gov_user_space_init(void) 48int thermal_gov_user_space_register(void)
53{ 49{
54 return thermal_register_governor(&thermal_gov_user_space); 50 return thermal_register_governor(&thermal_gov_user_space);
55} 51}
56 52
57static void __exit thermal_gov_user_space_exit(void) 53void thermal_gov_user_space_unregister(void)
58{ 54{
59 thermal_unregister_governor(&thermal_gov_user_space); 55 thermal_unregister_governor(&thermal_gov_user_space);
60} 56}
61 57
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 40b4ef54cc7d..77c87c9d0193 100644
--- a/include/linux/cpu_cooling.h
+++ b/include/linux/cpu_cooling.h
@@ -29,7 +29,7 @@
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#if defined(CONFIG_CPU_THERMAL) || defined(CONFIG_CPU_THERMAL_MODULE) 32#ifdef CONFIG_CPU_THERMAL
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
@@ -42,6 +42,8 @@ struct thermal_cooling_device *cpufreq_cooling_register(
42 * @cdev: thermal cooling device pointer. 42 * @cdev: thermal cooling device pointer.
43 */ 43 */
44void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev); 44void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
45
46unsigned long cpufreq_cooling_get_level(unsigned int, unsigned int);
45#else /* !CONFIG_CPU_THERMAL */ 47#else /* !CONFIG_CPU_THERMAL */
46static inline struct thermal_cooling_device *cpufreq_cooling_register( 48static inline struct thermal_cooling_device *cpufreq_cooling_register(
47 const struct cpumask *clip_cpus) 49 const struct cpumask *clip_cpus)
@@ -53,6 +55,11 @@ static inline void cpufreq_cooling_unregister(
53{ 55{
54 return; 56 return;
55} 57}
58static inline unsigned long cpufreq_cooling_get_level(unsigned int,
59 unsigned int)
60{
61 return THERMAL_CSTATE_INVALID;
62}
56#endif /* CONFIG_CPU_THERMAL */ 63#endif /* CONFIG_CPU_THERMAL */
57 64
58#endif /* __CPU_COOLING_H__ */ 65#endif /* __CPU_COOLING_H__ */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index fd7b8f3e6f42..3bda306f7a50 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -33,8 +33,11 @@
33#define THERMAL_MAX_TRIPS 12 33#define THERMAL_MAX_TRIPS 12
34#define THERMAL_NAME_LENGTH 20 34#define THERMAL_NAME_LENGTH 20
35 35
36/* invalid cooling state */
37#define THERMAL_CSTATE_INVALID -1UL
38
36/* No upper/lower limit requirement */ 39/* No upper/lower limit requirement */
37#define THERMAL_NO_LIMIT -1UL 40#define THERMAL_NO_LIMIT THERMAL_CSTATE_INVALID
38 41
39/* Unit conversion macros */ 42/* Unit conversion macros */
40#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \ 43#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \
@@ -184,7 +187,6 @@ struct thermal_governor {
184 char name[THERMAL_NAME_LENGTH]; 187 char name[THERMAL_NAME_LENGTH];
185 int (*throttle)(struct thermal_zone_device *tz, int trip); 188 int (*throttle)(struct thermal_zone_device *tz, int trip);
186 struct list_head governor_list; 189 struct list_head governor_list;
187 struct module *owner;
188}; 190};
189 191
190/* Structure that holds binding parameters for a zone */ 192/* Structure that holds binding parameters for a zone */
@@ -244,9 +246,6 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
244void thermal_cdev_update(struct thermal_cooling_device *); 246void thermal_cdev_update(struct thermal_cooling_device *);
245void notify_thermal_framework(struct thermal_zone_device *, int); 247void notify_thermal_framework(struct thermal_zone_device *, int);
246 248
247int thermal_register_governor(struct thermal_governor *);
248void thermal_unregister_governor(struct thermal_governor *);
249
250#ifdef CONFIG_NET 249#ifdef CONFIG_NET
251extern int thermal_generate_netlink_event(struct thermal_zone_device *tz, 250extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
252 enum events event); 251 enum events event);