aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-12 10:42:59 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-12 10:42:59 -0400
commitb9b42eeb88d36cc7400925302f1587aaaa348905 (patch)
treef5260ad8013adeca9f86c85c096099844238c725
parent7b7a2f0a31c6c1ff53a3c87c0bca4f8d01471391 (diff)
parent50e66c7ed8a1cd7e933628f9f5cf2617394adf5a (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
Pull thermal management updates from Zhang Rui: "We have a lot of SOC changes and a few thermal core fixes this time. The biggest change is about exynos thermal driver restructure. The patch set adds TMU (Thermal management Unit) driver support for exynos5440 platform. There are 3 instances of the TMU controllers so necessary cleanup/re-structure is done to handle multiple thermal zone. The next biggest change is the introduction of the imx thermal driver. It adds the imx thermal support using Temperature Monitor (TEMPMON) block found on some Freescale i.MX SoCs. The driver uses syscon regmap interface to access TEMPMON control registers and calibration data, and supports cpufreq as the cooling device. Highlights: - restructure exynos thermal driver. - introduce new imx thermal driver. - fix a bug in thermal core, which powers on the fans unexpectedly after resume from suspend" * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: (46 commits) drivers: thermal: add check when unregistering cpu cooling thermal: thermal_core: allow binding with limits on bind_params drivers: thermal: make usage of CONFIG_THERMAL_HWMON optional drivers: thermal: parent virtual hwmon with thermal zone thermal: hwmon: move hwmon support to single file thermal: exynos: Clean up non-DT remnants thermal: exynos: Fix potential NULL pointer dereference thermal: exynos: Fix typos in Kconfig thermal: ti-soc-thermal: Ensure to compute thermal trend thermal: ti-soc-thermal: Set the bandgap mask counter delay value thermal: ti-soc-thermal: Initialize counter_delay field for TI DRA752 sensors thermal: step_wise: return instance->target by default thermal: step_wise: cdev only needs update on a new target state Thermal/cpu_cooling: Return directly for the cpu out of allowed_cpus in the cpufreq_thermal_notifier() thermal: exynos_tmu: fix wrong error check for mapped memory thermal: imx: implement thermal alarm interrupt handling thermal: imx: dynamic passive and SoC specific critical trip points Documentation: thermal: Explain the exynos thermal driver model ARM: dts: thermal: exynos: Add documentation for Exynos SoC thermal bindings thermal: exynos: Support for TMU regulator defined at device tree ...
-rw-r--r--Documentation/devicetree/bindings/thermal/exynos-thermal.txt55
-rw-r--r--Documentation/devicetree/bindings/thermal/imx-thermal.txt17
-rw-r--r--Documentation/thermal/exynos_thermal43
-rw-r--r--Documentation/thermal/sysfs-api.txt12
-rw-r--r--drivers/thermal/Kconfig33
-rw-r--r--drivers/thermal/Makefile6
-rw-r--r--drivers/thermal/cpu_cooling.c8
-rw-r--r--drivers/thermal/exynos_thermal.c1059
-rw-r--r--drivers/thermal/imx_thermal.c541
-rw-r--r--drivers/thermal/samsung/Kconfig18
-rw-r--r--drivers/thermal/samsung/Makefile7
-rw-r--r--drivers/thermal/samsung/exynos_thermal_common.c432
-rw-r--r--drivers/thermal/samsung/exynos_thermal_common.h107
-rw-r--r--drivers/thermal/samsung/exynos_tmu.c762
-rw-r--r--drivers/thermal/samsung/exynos_tmu.h311
-rw-r--r--drivers/thermal/samsung/exynos_tmu_data.c250
-rw-r--r--drivers/thermal/samsung/exynos_tmu_data.h155
-rw-r--r--drivers/thermal/step_wise.c32
-rw-r--r--drivers/thermal/thermal_core.c282
-rw-r--r--drivers/thermal/thermal_hwmon.c269
-rw-r--r--drivers/thermal/thermal_hwmon.h49
-rw-r--r--drivers/thermal/ti-soc-thermal/dra752-thermal-data.c5
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-bandgap.c6
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-thermal-common.c7
-rw-r--r--include/linux/platform_data/exynos_thermal.h119
-rw-r--r--include/linux/thermal.h18
26 files changed, 3133 insertions, 1470 deletions
diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
new file mode 100644
index 000000000000..284f5300fd8b
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
@@ -0,0 +1,55 @@
1* Exynos Thermal Management Unit (TMU)
2
3** Required properties:
4
5- compatible : One of the following:
6 "samsung,exynos4412-tmu"
7 "samsung,exynos4210-tmu"
8 "samsung,exynos5250-tmu"
9 "samsung,exynos5440-tmu"
10- interrupt-parent : The phandle for the interrupt controller
11- reg : Address range of the thermal registers. For soc's which has multiple
12 instances of TMU and some registers are shared across all TMU's like
13 interrupt related then 2 set of register has to supplied. First set
14 belongs to each instance of TMU and second set belongs to common TMU
15 registers.
16- interrupts : Should contain interrupt for thermal system
17- clocks : The main clock for TMU device
18- clock-names : Thermal system clock name
19- vtmu-supply: This entry is optional and provides the regulator node supplying
20 voltage to TMU. If needed this entry can be placed inside
21 board/platform specific dts file.
22
23Example 1):
24
25 tmu@100C0000 {
26 compatible = "samsung,exynos4412-tmu";
27 interrupt-parent = <&combiner>;
28 reg = <0x100C0000 0x100>;
29 interrupts = <2 4>;
30 clocks = <&clock 383>;
31 clock-names = "tmu_apbif";
32 status = "disabled";
33 vtmu-supply = <&tmu_regulator_node>;
34 };
35
36Example 2):
37
38 tmuctrl_0: tmuctrl@160118 {
39 compatible = "samsung,exynos5440-tmu";
40 reg = <0x160118 0x230>, <0x160368 0x10>;
41 interrupts = <0 58 0>;
42 clocks = <&clock 21>;
43 clock-names = "tmu_apbif";
44 };
45
46Note: For multi-instance tmu each instance should have an alias correctly
47numbered in "aliases" node.
48
49Example:
50
51aliases {
52 tmuctrl0 = &tmuctrl_0;
53 tmuctrl1 = &tmuctrl_1;
54 tmuctrl2 = &tmuctrl_2;
55};
diff --git a/Documentation/devicetree/bindings/thermal/imx-thermal.txt b/Documentation/devicetree/bindings/thermal/imx-thermal.txt
new file mode 100644
index 000000000000..541c25e49abf
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/imx-thermal.txt
@@ -0,0 +1,17 @@
1* Temperature Monitor (TEMPMON) on Freescale i.MX SoCs
2
3Required properties:
4- compatible : "fsl,imx6q-thermal"
5- fsl,tempmon : phandle pointer to system controller that contains TEMPMON
6 control registers, e.g. ANATOP on imx6q.
7- fsl,tempmon-data : phandle pointer to fuse controller that contains TEMPMON
8 calibration data, e.g. OCOTP on imx6q. The details about calibration data
9 can be found in SoC Reference Manual.
10
11Example:
12
13tempmon {
14 compatible = "fsl,imx6q-tempmon";
15 fsl,tempmon = <&anatop>;
16 fsl,tempmon-data = <&ocotp>;
17};
diff --git a/Documentation/thermal/exynos_thermal b/Documentation/thermal/exynos_thermal
index 2b46f67b1ccb..9010c4416967 100644
--- a/Documentation/thermal/exynos_thermal
+++ b/Documentation/thermal/exynos_thermal
@@ -1,17 +1,17 @@
1Kernel driver exynos4_tmu 1Kernel driver exynos_tmu
2================= 2=================
3 3
4Supported chips: 4Supported chips:
5* ARM SAMSUNG EXYNOS4 series of SoC 5* ARM SAMSUNG EXYNOS4, EXYNOS5 series of SoC
6 Prefix: 'exynos4-tmu'
7 Datasheet: Not publicly available 6 Datasheet: Not publicly available
8 7
9Authors: Donggeun Kim <dg77.kim@samsung.com> 8Authors: Donggeun Kim <dg77.kim@samsung.com>
9Authors: Amit Daniel <amit.daniel@samsung.com>
10 10
11Description 11TMU controller Description:
12----------- 12---------------------------
13 13
14This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC. 14This driver allows to read temperature inside SAMSUNG EXYNOS4/5 series of SoC.
15 15
16The chip only exposes the measured 8-bit temperature code value 16The chip only exposes the measured 8-bit temperature code value
17through a register. 17through a register.
@@ -34,9 +34,9 @@ The three equations are:
34 TI2: Trimming info for 85 degree Celsius (stored at TRIMINFO register) 34 TI2: Trimming info for 85 degree Celsius (stored at TRIMINFO register)
35 Temperature code measured at 85 degree Celsius which is unchanged 35 Temperature code measured at 85 degree Celsius which is unchanged
36 36
37TMU(Thermal Management Unit) in EXYNOS4 generates interrupt 37TMU(Thermal Management Unit) in EXYNOS4/5 generates interrupt
38when temperature exceeds pre-defined levels. 38when temperature exceeds pre-defined levels.
39The maximum number of configurable threshold is four. 39The maximum number of configurable threshold is five.
40The threshold levels are defined as follows: 40The threshold levels are defined as follows:
41 Level_0: current temperature > trigger_level_0 + threshold 41 Level_0: current temperature > trigger_level_0 + threshold
42 Level_1: current temperature > trigger_level_1 + threshold 42 Level_1: current temperature > trigger_level_1 + threshold
@@ -47,6 +47,31 @@ The threshold levels are defined as follows:
47 through the corresponding registers. 47 through the corresponding registers.
48 48
49When an interrupt occurs, this driver notify kernel thermal framework 49When an interrupt occurs, this driver notify kernel thermal framework
50with the function exynos4_report_trigger. 50with the function exynos_report_trigger.
51Although an interrupt condition for level_0 can be set, 51Although an interrupt condition for level_0 can be set,
52it can be used to synchronize the cooling action. 52it can be used to synchronize the cooling action.
53
54TMU driver description:
55-----------------------
56
57The exynos thermal driver is structured as,
58
59 Kernel Core thermal framework
60 (thermal_core.c, step_wise.c, cpu_cooling.c)
61 ^
62 |
63 |
64TMU configuration data -------> TMU Driver <------> Exynos Core thermal wrapper
65(exynos_tmu_data.c) (exynos_tmu.c) (exynos_thermal_common.c)
66(exynos_tmu_data.h) (exynos_tmu.h) (exynos_thermal_common.h)
67
68a) TMU configuration data: This consist of TMU register offsets/bitfields
69 described through structure exynos_tmu_registers. Also several
70 other platform data (struct exynos_tmu_platform_data) members
71 are used to configure the TMU.
72b) TMU driver: This component initialises the TMU controller and sets different
73 thresholds. It invokes core thermal implementation with the call
74 exynos_report_trigger.
75c) Exynos Core thermal wrapper: This provides 3 wrapper function to use the
76 Kernel core thermal framework. They are exynos_unregister_thermal,
77 exynos_register_thermal and exynos_report_trigger.
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index a71bd5b90fe8..87519cb379ee 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -134,6 +134,13 @@ temperature) and throttle appropriate devices.
134 this thermal zone and cdev, for a particular trip point. 134 this thermal zone and cdev, for a particular trip point.
135 If nth bit is set, then the cdev and thermal zone are bound 135 If nth bit is set, then the cdev and thermal zone are bound
136 for trip point n. 136 for trip point n.
137 .limits: This is an array of cooling state limits. Must have exactly
138 2 * thermal_zone.number_of_trip_points. It is an array consisting
139 of tuples <lower-state upper-state> of state limits. Each trip
140 will be associated with one state limit tuple when binding.
141 A NULL pointer means <THERMAL_NO_LIMITS THERMAL_NO_LIMITS>
142 on all trips. These limits are used when binding a cdev to a
143 trip point.
137 .match: This call back returns success(0) if the 'tz and cdev' need to 144 .match: This call back returns success(0) if the 'tz and cdev' need to
138 be bound, as per platform data. 145 be bound, as per platform data.
1391.4.2 struct thermal_zone_params 1461.4.2 struct thermal_zone_params
@@ -142,6 +149,11 @@ temperature) and throttle appropriate devices.
142 This is an optional feature where some platforms can choose not to 149 This is an optional feature where some platforms can choose not to
143 provide this data. 150 provide this data.
144 .governor_name: Name of the thermal governor used for this zone 151 .governor_name: Name of the thermal governor used for this zone
152 .no_hwmon: a boolean to indicate if the thermal to hwmon sysfs interface
153 is required. when no_hwmon == false, a hwmon sysfs interface
154 will be created. when no_hwmon == true, nothing will be done.
155 In case the thermal_zone_params is NULL, the hwmon interface
156 will be created (for backward compatibility).
145 .num_tbps: Number of thermal_bind_params entries for this zone 157 .num_tbps: Number of thermal_bind_params entries for this zone
146 .tbp: thermal_bind_params entries 158 .tbp: thermal_bind_params entries
147 159
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index e988c81d763c..dbfc390330ac 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -17,8 +17,17 @@ if THERMAL
17 17
18config THERMAL_HWMON 18config THERMAL_HWMON
19 bool 19 bool
20 prompt "Expose thermal sensors as hwmon device"
20 depends on HWMON=y || HWMON=THERMAL 21 depends on HWMON=y || HWMON=THERMAL
21 default y 22 default y
23 help
24 In case a sensor is registered with the thermal
25 framework, this option will also register it
26 as a hwmon. The sensor will then have the common
27 hwmon sysfs interface.
28
29 Say 'Y' here if you want all thermal sensors to
30 have hwmon sysfs interface too.
22 31
23choice 32choice
24 prompt "Default Thermal governor" 33 prompt "Default Thermal governor"
@@ -91,6 +100,17 @@ config THERMAL_EMULATION
91 because userland can easily disable the thermal policy by simply 100 because userland can easily disable the thermal policy by simply
92 flooding this sysfs node with low temperature values. 101 flooding this sysfs node with low temperature values.
93 102
103config IMX_THERMAL
104 tristate "Temperature sensor driver for Freescale i.MX SoCs"
105 depends on CPU_THERMAL
106 depends on MFD_SYSCON
107 depends on OF
108 help
109 Support for Temperature Monitor (TEMPMON) found on Freescale i.MX SoCs.
110 It supports one critical trip point and one passive trip point. The
111 cpufreq is used as the cooling device to throttle CPUs when the
112 passive trip is crossed.
113
94config SPEAR_THERMAL 114config SPEAR_THERMAL
95 bool "SPEAr thermal sensor driver" 115 bool "SPEAr thermal sensor driver"
96 depends on PLAT_SPEAR 116 depends on PLAT_SPEAR
@@ -114,14 +134,6 @@ config KIRKWOOD_THERMAL
114 Support for the Kirkwood thermal sensor driver into the Linux thermal 134 Support for the Kirkwood thermal sensor driver into the Linux thermal
115 framework. Only kirkwood 88F6282 and 88F6283 have this sensor. 135 framework. Only kirkwood 88F6282 and 88F6283 have this sensor.
116 136
117config EXYNOS_THERMAL
118 tristate "Temperature sensor on Samsung EXYNOS"
119 depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5)
120 depends on CPU_THERMAL
121 help
122 If you say yes here you get support for TMU (Thermal Management
123 Unit) on SAMSUNG EXYNOS series of SoC.
124
125config DOVE_THERMAL 137config DOVE_THERMAL
126 tristate "Temperature sensor on Marvell Dove SoCs" 138 tristate "Temperature sensor on Marvell Dove SoCs"
127 depends on ARCH_DOVE 139 depends on ARCH_DOVE
@@ -184,4 +196,9 @@ menu "Texas Instruments thermal drivers"
184source "drivers/thermal/ti-soc-thermal/Kconfig" 196source "drivers/thermal/ti-soc-thermal/Kconfig"
185endmenu 197endmenu
186 198
199menu "Samsung thermal drivers"
200depends on PLAT_SAMSUNG
201source "drivers/thermal/samsung/Kconfig"
202endmenu
203
187endif 204endif
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 67184a293e3f..584b36319d51 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -5,6 +5,9 @@
5obj-$(CONFIG_THERMAL) += thermal_sys.o 5obj-$(CONFIG_THERMAL) += thermal_sys.o
6thermal_sys-y += thermal_core.o 6thermal_sys-y += thermal_core.o
7 7
8# interface to/from other layers providing sensors
9thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o
10
8# governors 11# governors
9thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o 12thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o
10thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o 13thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o
@@ -17,10 +20,11 @@ thermal_sys-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
17obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o 20obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
18obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o 21obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o
19obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o 22obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o
20obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o 23obj-y += samsung/
21obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o 24obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o
22obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o 25obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
23obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o 26obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
27obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
24obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o 28obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
25obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o 29obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
26obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o 30obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 82e15dbb3ac7..d17902886c3f 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -322,6 +322,8 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
322 322
323 if (cpumask_test_cpu(policy->cpu, &notify_device->allowed_cpus)) 323 if (cpumask_test_cpu(policy->cpu, &notify_device->allowed_cpus))
324 max_freq = notify_device->cpufreq_val; 324 max_freq = notify_device->cpufreq_val;
325 else
326 return 0;
325 327
326 /* Never exceed user_policy.max */ 328 /* Never exceed user_policy.max */
327 if (max_freq > policy->user_policy.max) 329 if (max_freq > policy->user_policy.max)
@@ -496,8 +498,12 @@ EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
496 */ 498 */
497void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) 499void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
498{ 500{
499 struct cpufreq_cooling_device *cpufreq_dev = cdev->devdata; 501 struct cpufreq_cooling_device *cpufreq_dev;
502
503 if (!cdev)
504 return;
500 505
506 cpufreq_dev = cdev->devdata;
501 mutex_lock(&cooling_cpufreq_lock); 507 mutex_lock(&cooling_cpufreq_lock);
502 cpufreq_dev_count--; 508 cpufreq_dev_count--;
503 509
diff --git a/drivers/thermal/exynos_thermal.c b/drivers/thermal/exynos_thermal.c
deleted file mode 100644
index 9af4b93c9f86..000000000000
--- a/drivers/thermal/exynos_thermal.c
+++ /dev/null
@@ -1,1059 +0,0 @@
1/*
2 * exynos_thermal.c - Samsung EXYNOS TMU (Thermal Management Unit)
3 *
4 * Copyright (C) 2011 Samsung Electronics
5 * Donggeun Kim <dg77.kim@samsung.com>
6 * Amit Daniel Kachhap <amit.kachhap@linaro.org>
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; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <linux/module.h>
25#include <linux/err.h>
26#include <linux/kernel.h>
27#include <linux/slab.h>
28#include <linux/platform_device.h>
29#include <linux/interrupt.h>
30#include <linux/clk.h>
31#include <linux/workqueue.h>
32#include <linux/sysfs.h>
33#include <linux/kobject.h>
34#include <linux/io.h>
35#include <linux/mutex.h>
36#include <linux/platform_data/exynos_thermal.h>
37#include <linux/thermal.h>
38#include <linux/cpufreq.h>
39#include <linux/cpu_cooling.h>
40#include <linux/of.h>
41
42/* Exynos generic registers */
43#define EXYNOS_TMU_REG_TRIMINFO 0x0
44#define EXYNOS_TMU_REG_CONTROL 0x20
45#define EXYNOS_TMU_REG_STATUS 0x28
46#define EXYNOS_TMU_REG_CURRENT_TEMP 0x40
47#define EXYNOS_TMU_REG_INTEN 0x70
48#define EXYNOS_TMU_REG_INTSTAT 0x74
49#define EXYNOS_TMU_REG_INTCLEAR 0x78
50
51#define EXYNOS_TMU_TRIM_TEMP_MASK 0xff
52#define EXYNOS_TMU_GAIN_SHIFT 8
53#define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24
54#define EXYNOS_TMU_CORE_ON 3
55#define EXYNOS_TMU_CORE_OFF 2
56#define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET 50
57
58/* Exynos4210 specific registers */
59#define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44
60#define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50
61#define EXYNOS4210_TMU_REG_TRIG_LEVEL1 0x54
62#define EXYNOS4210_TMU_REG_TRIG_LEVEL2 0x58
63#define EXYNOS4210_TMU_REG_TRIG_LEVEL3 0x5C
64#define EXYNOS4210_TMU_REG_PAST_TEMP0 0x60
65#define EXYNOS4210_TMU_REG_PAST_TEMP1 0x64
66#define EXYNOS4210_TMU_REG_PAST_TEMP2 0x68
67#define EXYNOS4210_TMU_REG_PAST_TEMP3 0x6C
68
69#define EXYNOS4210_TMU_TRIG_LEVEL0_MASK 0x1
70#define EXYNOS4210_TMU_TRIG_LEVEL1_MASK 0x10
71#define EXYNOS4210_TMU_TRIG_LEVEL2_MASK 0x100
72#define EXYNOS4210_TMU_TRIG_LEVEL3_MASK 0x1000
73#define EXYNOS4210_TMU_INTCLEAR_VAL 0x1111
74
75/* Exynos5250 and Exynos4412 specific registers */
76#define EXYNOS_TMU_TRIMINFO_CON 0x14
77#define EXYNOS_THD_TEMP_RISE 0x50
78#define EXYNOS_THD_TEMP_FALL 0x54
79#define EXYNOS_EMUL_CON 0x80
80
81#define EXYNOS_TRIMINFO_RELOAD 0x1
82#define EXYNOS_TMU_CLEAR_RISE_INT 0x111
83#define EXYNOS_TMU_CLEAR_FALL_INT (0x111 << 12)
84#define EXYNOS_MUX_ADDR_VALUE 6
85#define EXYNOS_MUX_ADDR_SHIFT 20
86#define EXYNOS_TMU_TRIP_MODE_SHIFT 13
87
88#define EFUSE_MIN_VALUE 40
89#define EFUSE_MAX_VALUE 100
90
91/* In-kernel thermal framework related macros & definations */
92#define SENSOR_NAME_LEN 16
93#define MAX_TRIP_COUNT 8
94#define MAX_COOLING_DEVICE 4
95#define MAX_THRESHOLD_LEVS 4
96
97#define ACTIVE_INTERVAL 500
98#define IDLE_INTERVAL 10000
99#define MCELSIUS 1000
100
101#ifdef CONFIG_THERMAL_EMULATION
102#define EXYNOS_EMUL_TIME 0x57F0
103#define EXYNOS_EMUL_TIME_SHIFT 16
104#define EXYNOS_EMUL_DATA_SHIFT 8
105#define EXYNOS_EMUL_DATA_MASK 0xFF
106#define EXYNOS_EMUL_ENABLE 0x1
107#endif /* CONFIG_THERMAL_EMULATION */
108
109/* CPU Zone information */
110#define PANIC_ZONE 4
111#define WARN_ZONE 3
112#define MONITOR_ZONE 2
113#define SAFE_ZONE 1
114
115#define GET_ZONE(trip) (trip + 2)
116#define GET_TRIP(zone) (zone - 2)
117
118#define EXYNOS_ZONE_COUNT 3
119
120struct exynos_tmu_data {
121 struct exynos_tmu_platform_data *pdata;
122 struct resource *mem;
123 void __iomem *base;
124 int irq;
125 enum soc_type soc;
126 struct work_struct irq_work;
127 struct mutex lock;
128 struct clk *clk;
129 u8 temp_error1, temp_error2;
130};
131
132struct thermal_trip_point_conf {
133 int trip_val[MAX_TRIP_COUNT];
134 int trip_count;
135 u8 trigger_falling;
136};
137
138struct thermal_cooling_conf {
139 struct freq_clip_table freq_data[MAX_TRIP_COUNT];
140 int freq_clip_count;
141};
142
143struct thermal_sensor_conf {
144 char name[SENSOR_NAME_LEN];
145 int (*read_temperature)(void *data);
146 int (*write_emul_temp)(void *drv_data, unsigned long temp);
147 struct thermal_trip_point_conf trip_data;
148 struct thermal_cooling_conf cooling_data;
149 void *private_data;
150};
151
152struct exynos_thermal_zone {
153 enum thermal_device_mode mode;
154 struct thermal_zone_device *therm_dev;
155 struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
156 unsigned int cool_dev_size;
157 struct platform_device *exynos4_dev;
158 struct thermal_sensor_conf *sensor_conf;
159 bool bind;
160};
161
162static struct exynos_thermal_zone *th_zone;
163static void exynos_unregister_thermal(void);
164static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
165
166/* Get mode callback functions for thermal zone */
167static int exynos_get_mode(struct thermal_zone_device *thermal,
168 enum thermal_device_mode *mode)
169{
170 if (th_zone)
171 *mode = th_zone->mode;
172 return 0;
173}
174
175/* Set mode callback functions for thermal zone */
176static int exynos_set_mode(struct thermal_zone_device *thermal,
177 enum thermal_device_mode mode)
178{
179 if (!th_zone->therm_dev) {
180 pr_notice("thermal zone not registered\n");
181 return 0;
182 }
183
184 mutex_lock(&th_zone->therm_dev->lock);
185
186 if (mode == THERMAL_DEVICE_ENABLED &&
187 !th_zone->sensor_conf->trip_data.trigger_falling)
188 th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
189 else
190 th_zone->therm_dev->polling_delay = 0;
191
192 mutex_unlock(&th_zone->therm_dev->lock);
193
194 th_zone->mode = mode;
195 thermal_zone_device_update(th_zone->therm_dev);
196 pr_info("thermal polling set for duration=%d msec\n",
197 th_zone->therm_dev->polling_delay);
198 return 0;
199}
200
201
202/* Get trip type callback functions for thermal zone */
203static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
204 enum thermal_trip_type *type)
205{
206 switch (GET_ZONE(trip)) {
207 case MONITOR_ZONE:
208 case WARN_ZONE:
209 *type = THERMAL_TRIP_ACTIVE;
210 break;
211 case PANIC_ZONE:
212 *type = THERMAL_TRIP_CRITICAL;
213 break;
214 default:
215 return -EINVAL;
216 }
217 return 0;
218}
219
220/* Get trip temperature callback functions for thermal zone */
221static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
222 unsigned long *temp)
223{
224 if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
225 return -EINVAL;
226
227 *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
228 /* convert the temperature into millicelsius */
229 *temp = *temp * MCELSIUS;
230
231 return 0;
232}
233
234/* Get critical temperature callback functions for thermal zone */
235static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
236 unsigned long *temp)
237{
238 int ret;
239 /* Panic zone */
240 ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
241 return ret;
242}
243
244/* Bind callback functions for thermal zone */
245static int exynos_bind(struct thermal_zone_device *thermal,
246 struct thermal_cooling_device *cdev)
247{
248 int ret = 0, i, tab_size, level;
249 struct freq_clip_table *tab_ptr, *clip_data;
250 struct thermal_sensor_conf *data = th_zone->sensor_conf;
251
252 tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
253 tab_size = data->cooling_data.freq_clip_count;
254
255 if (tab_ptr == NULL || tab_size == 0)
256 return -EINVAL;
257
258 /* find the cooling device registered*/
259 for (i = 0; i < th_zone->cool_dev_size; i++)
260 if (cdev == th_zone->cool_dev[i])
261 break;
262
263 /* No matching cooling device */
264 if (i == th_zone->cool_dev_size)
265 return 0;
266
267 /* Bind the thermal zone to the cpufreq cooling device */
268 for (i = 0; i < tab_size; i++) {
269 clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
270 level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
271 if (level == THERMAL_CSTATE_INVALID)
272 return 0;
273 switch (GET_ZONE(i)) {
274 case MONITOR_ZONE:
275 case WARN_ZONE:
276 if (thermal_zone_bind_cooling_device(thermal, i, cdev,
277 level, 0)) {
278 pr_err("error binding cdev inst %d\n", i);
279 ret = -EINVAL;
280 }
281 th_zone->bind = true;
282 break;
283 default:
284 ret = -EINVAL;
285 }
286 }
287
288 return ret;
289}
290
291/* Unbind callback functions for thermal zone */
292static int exynos_unbind(struct thermal_zone_device *thermal,
293 struct thermal_cooling_device *cdev)
294{
295 int ret = 0, i, tab_size;
296 struct thermal_sensor_conf *data = th_zone->sensor_conf;
297
298 if (th_zone->bind == false)
299 return 0;
300
301 tab_size = data->cooling_data.freq_clip_count;
302
303 if (tab_size == 0)
304 return -EINVAL;
305
306 /* find the cooling device registered*/
307 for (i = 0; i < th_zone->cool_dev_size; i++)
308 if (cdev == th_zone->cool_dev[i])
309 break;
310
311 /* No matching cooling device */
312 if (i == th_zone->cool_dev_size)
313 return 0;
314
315 /* Bind the thermal zone to the cpufreq cooling device */
316 for (i = 0; i < tab_size; i++) {
317 switch (GET_ZONE(i)) {
318 case MONITOR_ZONE:
319 case WARN_ZONE:
320 if (thermal_zone_unbind_cooling_device(thermal, i,
321 cdev)) {
322 pr_err("error unbinding cdev inst=%d\n", i);
323 ret = -EINVAL;
324 }
325 th_zone->bind = false;
326 break;
327 default:
328 ret = -EINVAL;
329 }
330 }
331 return ret;
332}
333
334/* Get temperature callback functions for thermal zone */
335static int exynos_get_temp(struct thermal_zone_device *thermal,
336 unsigned long *temp)
337{
338 void *data;
339
340 if (!th_zone->sensor_conf) {
341 pr_info("Temperature sensor not initialised\n");
342 return -EINVAL;
343 }
344 data = th_zone->sensor_conf->private_data;
345 *temp = th_zone->sensor_conf->read_temperature(data);
346 /* convert the temperature into millicelsius */
347 *temp = *temp * MCELSIUS;
348 return 0;
349}
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
368/* Get the temperature trend */
369static int exynos_get_trend(struct thermal_zone_device *thermal,
370 int trip, enum thermal_trend *trend)
371{
372 int ret;
373 unsigned long trip_temp;
374
375 ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
376 if (ret < 0)
377 return ret;
378
379 if (thermal->temperature >= trip_temp)
380 *trend = THERMAL_TREND_RAISE_FULL;
381 else
382 *trend = THERMAL_TREND_DROP_FULL;
383
384 return 0;
385}
386/* Operation callback functions for thermal zone */
387static struct thermal_zone_device_ops const exynos_dev_ops = {
388 .bind = exynos_bind,
389 .unbind = exynos_unbind,
390 .get_temp = exynos_get_temp,
391 .set_emul_temp = exynos_set_emul_temp,
392 .get_trend = exynos_get_trend,
393 .get_mode = exynos_get_mode,
394 .set_mode = exynos_set_mode,
395 .get_trip_type = exynos_get_trip_type,
396 .get_trip_temp = exynos_get_trip_temp,
397 .get_crit_temp = exynos_get_crit_temp,
398};
399
400/*
401 * This function may be called from interrupt based temperature sensor
402 * when threshold is changed.
403 */
404static void exynos_report_trigger(void)
405{
406 unsigned int i;
407 char data[10];
408 char *envp[] = { data, NULL };
409
410 if (!th_zone || !th_zone->therm_dev)
411 return;
412 if (th_zone->bind == false) {
413 for (i = 0; i < th_zone->cool_dev_size; i++) {
414 if (!th_zone->cool_dev[i])
415 continue;
416 exynos_bind(th_zone->therm_dev,
417 th_zone->cool_dev[i]);
418 }
419 }
420
421 thermal_zone_device_update(th_zone->therm_dev);
422
423 mutex_lock(&th_zone->therm_dev->lock);
424 /* Find the level for which trip happened */
425 for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
426 if (th_zone->therm_dev->last_temperature <
427 th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
428 break;
429 }
430
431 if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
432 !th_zone->sensor_conf->trip_data.trigger_falling) {
433 if (i > 0)
434 th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
435 else
436 th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
437 }
438
439 snprintf(data, sizeof(data), "%u", i);
440 kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
441 mutex_unlock(&th_zone->therm_dev->lock);
442}
443
444/* Register with the in-kernel thermal management */
445static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
446{
447 int ret;
448 struct cpumask mask_val;
449
450 if (!sensor_conf || !sensor_conf->read_temperature) {
451 pr_err("Temperature sensor not initialised\n");
452 return -EINVAL;
453 }
454
455 th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
456 if (!th_zone)
457 return -ENOMEM;
458
459 th_zone->sensor_conf = sensor_conf;
460 cpumask_set_cpu(0, &mask_val);
461 th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
462 if (IS_ERR(th_zone->cool_dev[0])) {
463 pr_err("Failed to register cpufreq cooling device\n");
464 ret = -EINVAL;
465 goto err_unregister;
466 }
467 th_zone->cool_dev_size++;
468
469 th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
470 EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
471 sensor_conf->trip_data.trigger_falling ?
472 0 : IDLE_INTERVAL);
473
474 if (IS_ERR(th_zone->therm_dev)) {
475 pr_err("Failed to register thermal zone device\n");
476 ret = PTR_ERR(th_zone->therm_dev);
477 goto err_unregister;
478 }
479 th_zone->mode = THERMAL_DEVICE_ENABLED;
480
481 pr_info("Exynos: Kernel Thermal management registered\n");
482
483 return 0;
484
485err_unregister:
486 exynos_unregister_thermal();
487 return ret;
488}
489
490/* Un-Register with the in-kernel thermal management */
491static void exynos_unregister_thermal(void)
492{
493 int i;
494
495 if (!th_zone)
496 return;
497
498 if (th_zone->therm_dev)
499 thermal_zone_device_unregister(th_zone->therm_dev);
500
501 for (i = 0; i < th_zone->cool_dev_size; i++) {
502 if (th_zone->cool_dev[i])
503 cpufreq_cooling_unregister(th_zone->cool_dev[i]);
504 }
505
506 kfree(th_zone);
507 pr_info("Exynos: Kernel Thermal management unregistered\n");
508}
509
510/*
511 * TMU treats temperature as a mapped temperature code.
512 * The temperature is converted differently depending on the calibration type.
513 */
514static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
515{
516 struct exynos_tmu_platform_data *pdata = data->pdata;
517 int temp_code;
518
519 if (data->soc == SOC_ARCH_EXYNOS4210)
520 /* temp should range between 25 and 125 */
521 if (temp < 25 || temp > 125) {
522 temp_code = -EINVAL;
523 goto out;
524 }
525
526 switch (pdata->cal_type) {
527 case TYPE_TWO_POINT_TRIMMING:
528 temp_code = (temp - 25) *
529 (data->temp_error2 - data->temp_error1) /
530 (85 - 25) + data->temp_error1;
531 break;
532 case TYPE_ONE_POINT_TRIMMING:
533 temp_code = temp + data->temp_error1 - 25;
534 break;
535 default:
536 temp_code = temp + EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
537 break;
538 }
539out:
540 return temp_code;
541}
542
543/*
544 * Calculate a temperature value from a temperature code.
545 * The unit of the temperature is degree Celsius.
546 */
547static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
548{
549 struct exynos_tmu_platform_data *pdata = data->pdata;
550 int temp;
551
552 if (data->soc == SOC_ARCH_EXYNOS4210)
553 /* temp_code should range between 75 and 175 */
554 if (temp_code < 75 || temp_code > 175) {
555 temp = -ENODATA;
556 goto out;
557 }
558
559 switch (pdata->cal_type) {
560 case TYPE_TWO_POINT_TRIMMING:
561 temp = (temp_code - data->temp_error1) * (85 - 25) /
562 (data->temp_error2 - data->temp_error1) + 25;
563 break;
564 case TYPE_ONE_POINT_TRIMMING:
565 temp = temp_code - data->temp_error1 + 25;
566 break;
567 default:
568 temp = temp_code - EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
569 break;
570 }
571out:
572 return temp;
573}
574
575static int exynos_tmu_initialize(struct platform_device *pdev)
576{
577 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
578 struct exynos_tmu_platform_data *pdata = data->pdata;
579 unsigned int status, trim_info;
580 unsigned int rising_threshold = 0, falling_threshold = 0;
581 int ret = 0, threshold_code, i, trigger_levs = 0;
582
583 mutex_lock(&data->lock);
584 clk_enable(data->clk);
585
586 status = readb(data->base + EXYNOS_TMU_REG_STATUS);
587 if (!status) {
588 ret = -EBUSY;
589 goto out;
590 }
591
592 if (data->soc == SOC_ARCH_EXYNOS) {
593 __raw_writel(EXYNOS_TRIMINFO_RELOAD,
594 data->base + EXYNOS_TMU_TRIMINFO_CON);
595 }
596 /* Save trimming info in order to perform calibration */
597 trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
598 data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
599 data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);
600
601 if ((EFUSE_MIN_VALUE > data->temp_error1) ||
602 (data->temp_error1 > EFUSE_MAX_VALUE) ||
603 (data->temp_error2 != 0))
604 data->temp_error1 = pdata->efuse_value;
605
606 /* Count trigger levels to be enabled */
607 for (i = 0; i < MAX_THRESHOLD_LEVS; i++)
608 if (pdata->trigger_levels[i])
609 trigger_levs++;
610
611 if (data->soc == SOC_ARCH_EXYNOS4210) {
612 /* Write temperature code for threshold */
613 threshold_code = temp_to_code(data, pdata->threshold);
614 if (threshold_code < 0) {
615 ret = threshold_code;
616 goto out;
617 }
618 writeb(threshold_code,
619 data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
620 for (i = 0; i < trigger_levs; i++)
621 writeb(pdata->trigger_levels[i],
622 data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
623
624 writel(EXYNOS4210_TMU_INTCLEAR_VAL,
625 data->base + EXYNOS_TMU_REG_INTCLEAR);
626 } else if (data->soc == SOC_ARCH_EXYNOS) {
627 /* Write temperature code for rising and falling threshold */
628 for (i = 0; i < trigger_levs; i++) {
629 threshold_code = temp_to_code(data,
630 pdata->trigger_levels[i]);
631 if (threshold_code < 0) {
632 ret = threshold_code;
633 goto out;
634 }
635 rising_threshold |= threshold_code << 8 * i;
636 if (pdata->threshold_falling) {
637 threshold_code = temp_to_code(data,
638 pdata->trigger_levels[i] -
639 pdata->threshold_falling);
640 if (threshold_code > 0)
641 falling_threshold |=
642 threshold_code << 8 * i;
643 }
644 }
645
646 writel(rising_threshold,
647 data->base + EXYNOS_THD_TEMP_RISE);
648 writel(falling_threshold,
649 data->base + EXYNOS_THD_TEMP_FALL);
650
651 writel(EXYNOS_TMU_CLEAR_RISE_INT | EXYNOS_TMU_CLEAR_FALL_INT,
652 data->base + EXYNOS_TMU_REG_INTCLEAR);
653 }
654out:
655 clk_disable(data->clk);
656 mutex_unlock(&data->lock);
657
658 return ret;
659}
660
661static void exynos_tmu_control(struct platform_device *pdev, bool on)
662{
663 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
664 struct exynos_tmu_platform_data *pdata = data->pdata;
665 unsigned int con, interrupt_en;
666
667 mutex_lock(&data->lock);
668 clk_enable(data->clk);
669
670 con = pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT |
671 pdata->gain << EXYNOS_TMU_GAIN_SHIFT;
672
673 if (data->soc == SOC_ARCH_EXYNOS) {
674 con |= pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT;
675 con |= (EXYNOS_MUX_ADDR_VALUE << EXYNOS_MUX_ADDR_SHIFT);
676 }
677
678 if (on) {
679 con |= EXYNOS_TMU_CORE_ON;
680 interrupt_en = pdata->trigger_level3_en << 12 |
681 pdata->trigger_level2_en << 8 |
682 pdata->trigger_level1_en << 4 |
683 pdata->trigger_level0_en;
684 if (pdata->threshold_falling)
685 interrupt_en |= interrupt_en << 16;
686 } else {
687 con |= EXYNOS_TMU_CORE_OFF;
688 interrupt_en = 0; /* Disable all interrupts */
689 }
690 writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN);
691 writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
692
693 clk_disable(data->clk);
694 mutex_unlock(&data->lock);
695}
696
697static int exynos_tmu_read(struct exynos_tmu_data *data)
698{
699 u8 temp_code;
700 int temp;
701
702 mutex_lock(&data->lock);
703 clk_enable(data->clk);
704
705 temp_code = readb(data->base + EXYNOS_TMU_REG_CURRENT_TEMP);
706 temp = code_to_temp(data, temp_code);
707
708 clk_disable(data->clk);
709 mutex_unlock(&data->lock);
710
711 return temp;
712}
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
755static void exynos_tmu_work(struct work_struct *work)
756{
757 struct exynos_tmu_data *data = container_of(work,
758 struct exynos_tmu_data, irq_work);
759
760 exynos_report_trigger();
761 mutex_lock(&data->lock);
762 clk_enable(data->clk);
763 if (data->soc == SOC_ARCH_EXYNOS)
764 writel(EXYNOS_TMU_CLEAR_RISE_INT |
765 EXYNOS_TMU_CLEAR_FALL_INT,
766 data->base + EXYNOS_TMU_REG_INTCLEAR);
767 else
768 writel(EXYNOS4210_TMU_INTCLEAR_VAL,
769 data->base + EXYNOS_TMU_REG_INTCLEAR);
770 clk_disable(data->clk);
771 mutex_unlock(&data->lock);
772
773 enable_irq(data->irq);
774}
775
776static irqreturn_t exynos_tmu_irq(int irq, void *id)
777{
778 struct exynos_tmu_data *data = id;
779
780 disable_irq_nosync(irq);
781 schedule_work(&data->irq_work);
782
783 return IRQ_HANDLED;
784}
785static struct thermal_sensor_conf exynos_sensor_conf = {
786 .name = "exynos-therm",
787 .read_temperature = (int (*)(void *))exynos_tmu_read,
788 .write_emul_temp = exynos_tmu_set_emulation,
789};
790
791#if defined(CONFIG_CPU_EXYNOS4210)
792static struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
793 .threshold = 80,
794 .trigger_levels[0] = 5,
795 .trigger_levels[1] = 20,
796 .trigger_levels[2] = 30,
797 .trigger_level0_en = 1,
798 .trigger_level1_en = 1,
799 .trigger_level2_en = 1,
800 .trigger_level3_en = 0,
801 .gain = 15,
802 .reference_voltage = 7,
803 .cal_type = TYPE_ONE_POINT_TRIMMING,
804 .freq_tab[0] = {
805 .freq_clip_max = 800 * 1000,
806 .temp_level = 85,
807 },
808 .freq_tab[1] = {
809 .freq_clip_max = 200 * 1000,
810 .temp_level = 100,
811 },
812 .freq_tab_count = 2,
813 .type = SOC_ARCH_EXYNOS4210,
814};
815#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
816#else
817#define EXYNOS4210_TMU_DRV_DATA (NULL)
818#endif
819
820#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412) || \
821 defined(CONFIG_SOC_EXYNOS4212)
822static struct exynos_tmu_platform_data const exynos_default_tmu_data = {
823 .threshold_falling = 10,
824 .trigger_levels[0] = 85,
825 .trigger_levels[1] = 103,
826 .trigger_levels[2] = 110,
827 .trigger_level0_en = 1,
828 .trigger_level1_en = 1,
829 .trigger_level2_en = 1,
830 .trigger_level3_en = 0,
831 .gain = 8,
832 .reference_voltage = 16,
833 .noise_cancel_mode = 4,
834 .cal_type = TYPE_ONE_POINT_TRIMMING,
835 .efuse_value = 55,
836 .freq_tab[0] = {
837 .freq_clip_max = 800 * 1000,
838 .temp_level = 85,
839 },
840 .freq_tab[1] = {
841 .freq_clip_max = 200 * 1000,
842 .temp_level = 103,
843 },
844 .freq_tab_count = 2,
845 .type = SOC_ARCH_EXYNOS,
846};
847#define EXYNOS_TMU_DRV_DATA (&exynos_default_tmu_data)
848#else
849#define EXYNOS_TMU_DRV_DATA (NULL)
850#endif
851
852#ifdef CONFIG_OF
853static const struct of_device_id exynos_tmu_match[] = {
854 {
855 .compatible = "samsung,exynos4210-tmu",
856 .data = (void *)EXYNOS4210_TMU_DRV_DATA,
857 },
858 {
859 .compatible = "samsung,exynos4412-tmu",
860 .data = (void *)EXYNOS_TMU_DRV_DATA,
861 },
862 {
863 .compatible = "samsung,exynos5250-tmu",
864 .data = (void *)EXYNOS_TMU_DRV_DATA,
865 },
866 {},
867};
868MODULE_DEVICE_TABLE(of, exynos_tmu_match);
869#endif
870
871static struct platform_device_id exynos_tmu_driver_ids[] = {
872 {
873 .name = "exynos4210-tmu",
874 .driver_data = (kernel_ulong_t)EXYNOS4210_TMU_DRV_DATA,
875 },
876 {
877 .name = "exynos5250-tmu",
878 .driver_data = (kernel_ulong_t)EXYNOS_TMU_DRV_DATA,
879 },
880 { },
881};
882MODULE_DEVICE_TABLE(platform, exynos_tmu_driver_ids);
883
884static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
885 struct platform_device *pdev)
886{
887#ifdef CONFIG_OF
888 if (pdev->dev.of_node) {
889 const struct of_device_id *match;
890 match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
891 if (!match)
892 return NULL;
893 return (struct exynos_tmu_platform_data *) match->data;
894 }
895#endif
896 return (struct exynos_tmu_platform_data *)
897 platform_get_device_id(pdev)->driver_data;
898}
899
900static int exynos_tmu_probe(struct platform_device *pdev)
901{
902 struct exynos_tmu_data *data;
903 struct exynos_tmu_platform_data *pdata = pdev->dev.platform_data;
904 int ret, i;
905
906 if (!pdata)
907 pdata = exynos_get_driver_data(pdev);
908
909 if (!pdata) {
910 dev_err(&pdev->dev, "No platform init data supplied.\n");
911 return -ENODEV;
912 }
913 data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data),
914 GFP_KERNEL);
915 if (!data) {
916 dev_err(&pdev->dev, "Failed to allocate driver structure\n");
917 return -ENOMEM;
918 }
919
920 data->irq = platform_get_irq(pdev, 0);
921 if (data->irq < 0) {
922 dev_err(&pdev->dev, "Failed to get platform irq\n");
923 return data->irq;
924 }
925
926 INIT_WORK(&data->irq_work, exynos_tmu_work);
927
928 data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
929 data->base = devm_ioremap_resource(&pdev->dev, data->mem);
930 if (IS_ERR(data->base))
931 return PTR_ERR(data->base);
932
933 ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
934 IRQF_TRIGGER_RISING, "exynos-tmu", data);
935 if (ret) {
936 dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
937 return ret;
938 }
939
940 data->clk = devm_clk_get(&pdev->dev, "tmu_apbif");
941 if (IS_ERR(data->clk)) {
942 dev_err(&pdev->dev, "Failed to get clock\n");
943 return PTR_ERR(data->clk);
944 }
945
946 ret = clk_prepare(data->clk);
947 if (ret)
948 return ret;
949
950 if (pdata->type == SOC_ARCH_EXYNOS ||
951 pdata->type == SOC_ARCH_EXYNOS4210)
952 data->soc = pdata->type;
953 else {
954 ret = -EINVAL;
955 dev_err(&pdev->dev, "Platform not supported\n");
956 goto err_clk;
957 }
958
959 data->pdata = pdata;
960 platform_set_drvdata(pdev, data);
961 mutex_init(&data->lock);
962
963 ret = exynos_tmu_initialize(pdev);
964 if (ret) {
965 dev_err(&pdev->dev, "Failed to initialize TMU\n");
966 goto err_clk;
967 }
968
969 exynos_tmu_control(pdev, true);
970
971 /* Register the sensor with thermal management interface */
972 (&exynos_sensor_conf)->private_data = data;
973 exynos_sensor_conf.trip_data.trip_count = pdata->trigger_level0_en +
974 pdata->trigger_level1_en + pdata->trigger_level2_en +
975 pdata->trigger_level3_en;
976
977 for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
978 exynos_sensor_conf.trip_data.trip_val[i] =
979 pdata->threshold + pdata->trigger_levels[i];
980
981 exynos_sensor_conf.trip_data.trigger_falling = pdata->threshold_falling;
982
983 exynos_sensor_conf.cooling_data.freq_clip_count =
984 pdata->freq_tab_count;
985 for (i = 0; i < pdata->freq_tab_count; i++) {
986 exynos_sensor_conf.cooling_data.freq_data[i].freq_clip_max =
987 pdata->freq_tab[i].freq_clip_max;
988 exynos_sensor_conf.cooling_data.freq_data[i].temp_level =
989 pdata->freq_tab[i].temp_level;
990 }
991
992 ret = exynos_register_thermal(&exynos_sensor_conf);
993 if (ret) {
994 dev_err(&pdev->dev, "Failed to register thermal interface\n");
995 goto err_clk;
996 }
997
998 return 0;
999err_clk:
1000 clk_unprepare(data->clk);
1001 return ret;
1002}
1003
1004static int exynos_tmu_remove(struct platform_device *pdev)
1005{
1006 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
1007
1008 exynos_tmu_control(pdev, false);
1009
1010 exynos_unregister_thermal();
1011
1012 clk_unprepare(data->clk);
1013
1014 return 0;
1015}
1016
1017#ifdef CONFIG_PM_SLEEP
1018static int exynos_tmu_suspend(struct device *dev)
1019{
1020 exynos_tmu_control(to_platform_device(dev), false);
1021
1022 return 0;
1023}
1024
1025static int exynos_tmu_resume(struct device *dev)
1026{
1027 struct platform_device *pdev = to_platform_device(dev);
1028
1029 exynos_tmu_initialize(pdev);
1030 exynos_tmu_control(pdev, true);
1031
1032 return 0;
1033}
1034
1035static SIMPLE_DEV_PM_OPS(exynos_tmu_pm,
1036 exynos_tmu_suspend, exynos_tmu_resume);
1037#define EXYNOS_TMU_PM (&exynos_tmu_pm)
1038#else
1039#define EXYNOS_TMU_PM NULL
1040#endif
1041
1042static struct platform_driver exynos_tmu_driver = {
1043 .driver = {
1044 .name = "exynos-tmu",
1045 .owner = THIS_MODULE,
1046 .pm = EXYNOS_TMU_PM,
1047 .of_match_table = of_match_ptr(exynos_tmu_match),
1048 },
1049 .probe = exynos_tmu_probe,
1050 .remove = exynos_tmu_remove,
1051 .id_table = exynos_tmu_driver_ids,
1052};
1053
1054module_platform_driver(exynos_tmu_driver);
1055
1056MODULE_DESCRIPTION("EXYNOS TMU Driver");
1057MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
1058MODULE_LICENSE("GPL");
1059MODULE_ALIAS("platform:exynos-tmu");
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
new file mode 100644
index 000000000000..1d6c801c1eb9
--- /dev/null
+++ b/drivers/thermal/imx_thermal.c
@@ -0,0 +1,541 @@
1/*
2 * Copyright 2013 Freescale Semiconductor, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include <linux/cpu_cooling.h>
11#include <linux/cpufreq.h>
12#include <linux/delay.h>
13#include <linux/device.h>
14#include <linux/init.h>
15#include <linux/interrupt.h>
16#include <linux/io.h>
17#include <linux/kernel.h>
18#include <linux/mfd/syscon.h>
19#include <linux/module.h>
20#include <linux/of.h>
21#include <linux/platform_device.h>
22#include <linux/regmap.h>
23#include <linux/slab.h>
24#include <linux/thermal.h>
25#include <linux/types.h>
26
27#define REG_SET 0x4
28#define REG_CLR 0x8
29#define REG_TOG 0xc
30
31#define MISC0 0x0150
32#define MISC0_REFTOP_SELBIASOFF (1 << 3)
33
34#define TEMPSENSE0 0x0180
35#define TEMPSENSE0_ALARM_VALUE_SHIFT 20
36#define TEMPSENSE0_ALARM_VALUE_MASK (0xfff << TEMPSENSE0_ALARM_VALUE_SHIFT)
37#define TEMPSENSE0_TEMP_CNT_SHIFT 8
38#define TEMPSENSE0_TEMP_CNT_MASK (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT)
39#define TEMPSENSE0_FINISHED (1 << 2)
40#define TEMPSENSE0_MEASURE_TEMP (1 << 1)
41#define TEMPSENSE0_POWER_DOWN (1 << 0)
42
43#define TEMPSENSE1 0x0190
44#define TEMPSENSE1_MEASURE_FREQ 0xffff
45
46#define OCOTP_ANA1 0x04e0
47
48/* The driver supports 1 passive trip point and 1 critical trip point */
49enum imx_thermal_trip {
50 IMX_TRIP_PASSIVE,
51 IMX_TRIP_CRITICAL,
52 IMX_TRIP_NUM,
53};
54
55/*
56 * It defines the temperature in millicelsius for passive trip point
57 * that will trigger cooling action when crossed.
58 */
59#define IMX_TEMP_PASSIVE 85000
60
61#define IMX_POLLING_DELAY 2000 /* millisecond */
62#define IMX_PASSIVE_DELAY 1000
63
64struct imx_thermal_data {
65 struct thermal_zone_device *tz;
66 struct thermal_cooling_device *cdev;
67 enum thermal_device_mode mode;
68 struct regmap *tempmon;
69 int c1, c2; /* See formula in imx_get_sensor_data() */
70 unsigned long temp_passive;
71 unsigned long temp_critical;
72 unsigned long alarm_temp;
73 unsigned long last_temp;
74 bool irq_enabled;
75 int irq;
76};
77
78static void imx_set_alarm_temp(struct imx_thermal_data *data,
79 signed long alarm_temp)
80{
81 struct regmap *map = data->tempmon;
82 int alarm_value;
83
84 data->alarm_temp = alarm_temp;
85 alarm_value = (alarm_temp - data->c2) / data->c1;
86 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_ALARM_VALUE_MASK);
87 regmap_write(map, TEMPSENSE0 + REG_SET, alarm_value <<
88 TEMPSENSE0_ALARM_VALUE_SHIFT);
89}
90
91static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
92{
93 struct imx_thermal_data *data = tz->devdata;
94 struct regmap *map = data->tempmon;
95 unsigned int n_meas;
96 bool wait;
97 u32 val;
98
99 if (data->mode == THERMAL_DEVICE_ENABLED) {
100 /* Check if a measurement is currently in progress */
101 regmap_read(map, TEMPSENSE0, &val);
102 wait = !(val & TEMPSENSE0_FINISHED);
103 } else {
104 /*
105 * Every time we measure the temperature, we will power on the
106 * temperature sensor, enable measurements, take a reading,
107 * disable measurements, power off the temperature sensor.
108 */
109 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
110 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
111
112 wait = true;
113 }
114
115 /*
116 * According to the temp sensor designers, it may require up to ~17us
117 * to complete a measurement.
118 */
119 if (wait)
120 usleep_range(20, 50);
121
122 regmap_read(map, TEMPSENSE0, &val);
123
124 if (data->mode != THERMAL_DEVICE_ENABLED) {
125 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
126 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
127 }
128
129 if ((val & TEMPSENSE0_FINISHED) == 0) {
130 dev_dbg(&tz->device, "temp measurement never finished\n");
131 return -EAGAIN;
132 }
133
134 n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT;
135
136 /* See imx_get_sensor_data() for formula derivation */
137 *temp = data->c2 + data->c1 * n_meas;
138
139 /* Update alarm value to next higher trip point */
140 if (data->alarm_temp == data->temp_passive && *temp >= data->temp_passive)
141 imx_set_alarm_temp(data, data->temp_critical);
142 if (data->alarm_temp == data->temp_critical && *temp < data->temp_passive) {
143 imx_set_alarm_temp(data, data->temp_passive);
144 dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
145 data->alarm_temp / 1000);
146 }
147
148 if (*temp != data->last_temp) {
149 dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
150 data->last_temp = *temp;
151 }
152
153 /* Reenable alarm IRQ if temperature below alarm temperature */
154 if (!data->irq_enabled && *temp < data->alarm_temp) {
155 data->irq_enabled = true;
156 enable_irq(data->irq);
157 }
158
159 return 0;
160}
161
162static int imx_get_mode(struct thermal_zone_device *tz,
163 enum thermal_device_mode *mode)
164{
165 struct imx_thermal_data *data = tz->devdata;
166
167 *mode = data->mode;
168
169 return 0;
170}
171
172static int imx_set_mode(struct thermal_zone_device *tz,
173 enum thermal_device_mode mode)
174{
175 struct imx_thermal_data *data = tz->devdata;
176 struct regmap *map = data->tempmon;
177
178 if (mode == THERMAL_DEVICE_ENABLED) {
179 tz->polling_delay = IMX_POLLING_DELAY;
180 tz->passive_delay = IMX_PASSIVE_DELAY;
181
182 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
183 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
184
185 if (!data->irq_enabled) {
186 data->irq_enabled = true;
187 enable_irq(data->irq);
188 }
189 } else {
190 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
191 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
192
193 tz->polling_delay = 0;
194 tz->passive_delay = 0;
195
196 if (data->irq_enabled) {
197 disable_irq(data->irq);
198 data->irq_enabled = false;
199 }
200 }
201
202 data->mode = mode;
203 thermal_zone_device_update(tz);
204
205 return 0;
206}
207
208static int imx_get_trip_type(struct thermal_zone_device *tz, int trip,
209 enum thermal_trip_type *type)
210{
211 *type = (trip == IMX_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
212 THERMAL_TRIP_CRITICAL;
213 return 0;
214}
215
216static int imx_get_crit_temp(struct thermal_zone_device *tz,
217 unsigned long *temp)
218{
219 struct imx_thermal_data *data = tz->devdata;
220
221 *temp = data->temp_critical;
222 return 0;
223}
224
225static int imx_get_trip_temp(struct thermal_zone_device *tz, int trip,
226 unsigned long *temp)
227{
228 struct imx_thermal_data *data = tz->devdata;
229
230 *temp = (trip == IMX_TRIP_PASSIVE) ? data->temp_passive :
231 data->temp_critical;
232 return 0;
233}
234
235static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
236 unsigned long temp)
237{
238 struct imx_thermal_data *data = tz->devdata;
239
240 if (trip == IMX_TRIP_CRITICAL)
241 return -EPERM;
242
243 if (temp > IMX_TEMP_PASSIVE)
244 return -EINVAL;
245
246 data->temp_passive = temp;
247
248 imx_set_alarm_temp(data, temp);
249
250 return 0;
251}
252
253static int imx_bind(struct thermal_zone_device *tz,
254 struct thermal_cooling_device *cdev)
255{
256 int ret;
257
258 ret = thermal_zone_bind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev,
259 THERMAL_NO_LIMIT,
260 THERMAL_NO_LIMIT);
261 if (ret) {
262 dev_err(&tz->device,
263 "binding zone %s with cdev %s failed:%d\n",
264 tz->type, cdev->type, ret);
265 return ret;
266 }
267
268 return 0;
269}
270
271static int imx_unbind(struct thermal_zone_device *tz,
272 struct thermal_cooling_device *cdev)
273{
274 int ret;
275
276 ret = thermal_zone_unbind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev);
277 if (ret) {
278 dev_err(&tz->device,
279 "unbinding zone %s with cdev %s failed:%d\n",
280 tz->type, cdev->type, ret);
281 return ret;
282 }
283
284 return 0;
285}
286
287static const struct thermal_zone_device_ops imx_tz_ops = {
288 .bind = imx_bind,
289 .unbind = imx_unbind,
290 .get_temp = imx_get_temp,
291 .get_mode = imx_get_mode,
292 .set_mode = imx_set_mode,
293 .get_trip_type = imx_get_trip_type,
294 .get_trip_temp = imx_get_trip_temp,
295 .get_crit_temp = imx_get_crit_temp,
296 .set_trip_temp = imx_set_trip_temp,
297};
298
299static int imx_get_sensor_data(struct platform_device *pdev)
300{
301 struct imx_thermal_data *data = platform_get_drvdata(pdev);
302 struct regmap *map;
303 int t1, t2, n1, n2;
304 int ret;
305 u32 val;
306
307 map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
308 "fsl,tempmon-data");
309 if (IS_ERR(map)) {
310 ret = PTR_ERR(map);
311 dev_err(&pdev->dev, "failed to get sensor regmap: %d\n", ret);
312 return ret;
313 }
314
315 ret = regmap_read(map, OCOTP_ANA1, &val);
316 if (ret) {
317 dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
318 return ret;
319 }
320
321 if (val == 0 || val == ~0) {
322 dev_err(&pdev->dev, "invalid sensor calibration data\n");
323 return -EINVAL;
324 }
325
326 /*
327 * Sensor data layout:
328 * [31:20] - sensor value @ 25C
329 * [19:8] - sensor value of hot
330 * [7:0] - hot temperature value
331 */
332 n1 = val >> 20;
333 n2 = (val & 0xfff00) >> 8;
334 t2 = val & 0xff;
335 t1 = 25; /* t1 always 25C */
336
337 /*
338 * Derived from linear interpolation,
339 * Tmeas = T2 + (Nmeas - N2) * (T1 - T2) / (N1 - N2)
340 * We want to reduce this down to the minimum computation necessary
341 * for each temperature read. Also, we want Tmeas in millicelsius
342 * and we don't want to lose precision from integer division. So...
343 * milli_Tmeas = 1000 * T2 + 1000 * (Nmeas - N2) * (T1 - T2) / (N1 - N2)
344 * Let constant c1 = 1000 * (T1 - T2) / (N1 - N2)
345 * milli_Tmeas = (1000 * T2) + c1 * (Nmeas - N2)
346 * milli_Tmeas = (1000 * T2) + (c1 * Nmeas) - (c1 * N2)
347 * Let constant c2 = (1000 * T2) - (c1 * N2)
348 * milli_Tmeas = c2 + (c1 * Nmeas)
349 */
350 data->c1 = 1000 * (t1 - t2) / (n1 - n2);
351 data->c2 = 1000 * t2 - data->c1 * n2;
352
353 /*
354 * Set the default passive cooling trip point to 20 °C below the
355 * maximum die temperature. Can be changed from userspace.
356 */
357 data->temp_passive = 1000 * (t2 - 20);
358
359 /*
360 * The maximum die temperature is t2, let's give 5 °C cushion
361 * for noise and possible temperature rise between measurements.
362 */
363 data->temp_critical = 1000 * (t2 - 5);
364
365 return 0;
366}
367
368static irqreturn_t imx_thermal_alarm_irq(int irq, void *dev)
369{
370 struct imx_thermal_data *data = dev;
371
372 disable_irq_nosync(irq);
373 data->irq_enabled = false;
374
375 return IRQ_WAKE_THREAD;
376}
377
378static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev)
379{
380 struct imx_thermal_data *data = dev;
381
382 dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
383 data->alarm_temp / 1000);
384
385 thermal_zone_device_update(data->tz);
386
387 return IRQ_HANDLED;
388}
389
390static int imx_thermal_probe(struct platform_device *pdev)
391{
392 struct imx_thermal_data *data;
393 struct cpumask clip_cpus;
394 struct regmap *map;
395 int measure_freq;
396 int ret;
397
398 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
399 if (!data)
400 return -ENOMEM;
401
402 map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "fsl,tempmon");
403 if (IS_ERR(map)) {
404 ret = PTR_ERR(map);
405 dev_err(&pdev->dev, "failed to get tempmon regmap: %d\n", ret);
406 return ret;
407 }
408 data->tempmon = map;
409
410 data->irq = platform_get_irq(pdev, 0);
411 if (data->irq < 0)
412 return data->irq;
413
414 ret = devm_request_threaded_irq(&pdev->dev, data->irq,
415 imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
416 0, "imx_thermal", data);
417 if (ret < 0) {
418 dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
419 return ret;
420 }
421
422 platform_set_drvdata(pdev, data);
423
424 ret = imx_get_sensor_data(pdev);
425 if (ret) {
426 dev_err(&pdev->dev, "failed to get sensor data\n");
427 return ret;
428 }
429
430 /* Make sure sensor is in known good state for measurements */
431 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
432 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
433 regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
434 regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF);
435 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
436
437 cpumask_set_cpu(0, &clip_cpus);
438 data->cdev = cpufreq_cooling_register(&clip_cpus);
439 if (IS_ERR(data->cdev)) {
440 ret = PTR_ERR(data->cdev);
441 dev_err(&pdev->dev,
442 "failed to register cpufreq cooling device: %d\n", ret);
443 return ret;
444 }
445
446 data->tz = thermal_zone_device_register("imx_thermal_zone",
447 IMX_TRIP_NUM,
448 BIT(IMX_TRIP_PASSIVE), data,
449 &imx_tz_ops, NULL,
450 IMX_PASSIVE_DELAY,
451 IMX_POLLING_DELAY);
452 if (IS_ERR(data->tz)) {
453 ret = PTR_ERR(data->tz);
454 dev_err(&pdev->dev,
455 "failed to register thermal zone device %d\n", ret);
456 cpufreq_cooling_unregister(data->cdev);
457 return ret;
458 }
459
460 /* Enable measurements at ~ 10 Hz */
461 regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
462 measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
463 regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq);
464 imx_set_alarm_temp(data, data->temp_passive);
465 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
466 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
467
468 data->irq_enabled = true;
469 data->mode = THERMAL_DEVICE_ENABLED;
470
471 return 0;
472}
473
474static int imx_thermal_remove(struct platform_device *pdev)
475{
476 struct imx_thermal_data *data = platform_get_drvdata(pdev);
477 struct regmap *map = data->tempmon;
478
479 /* Disable measurements */
480 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
481
482 thermal_zone_device_unregister(data->tz);
483 cpufreq_cooling_unregister(data->cdev);
484
485 return 0;
486}
487
488#ifdef CONFIG_PM_SLEEP
489static int imx_thermal_suspend(struct device *dev)
490{
491 struct imx_thermal_data *data = dev_get_drvdata(dev);
492 struct regmap *map = data->tempmon;
493 u32 val;
494
495 regmap_read(map, TEMPSENSE0, &val);
496 if ((val & TEMPSENSE0_POWER_DOWN) == 0) {
497 /*
498 * If a measurement is taking place, wait for a long enough
499 * time for it to finish, and then check again. If it still
500 * does not finish, something must go wrong.
501 */
502 udelay(50);
503 regmap_read(map, TEMPSENSE0, &val);
504 if ((val & TEMPSENSE0_POWER_DOWN) == 0)
505 return -ETIMEDOUT;
506 }
507
508 return 0;
509}
510
511static int imx_thermal_resume(struct device *dev)
512{
513 /* Nothing to do for now */
514 return 0;
515}
516#endif
517
518static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops,
519 imx_thermal_suspend, imx_thermal_resume);
520
521static const struct of_device_id of_imx_thermal_match[] = {
522 { .compatible = "fsl,imx6q-tempmon", },
523 { /* end */ }
524};
525
526static struct platform_driver imx_thermal = {
527 .driver = {
528 .name = "imx_thermal",
529 .owner = THIS_MODULE,
530 .pm = &imx_thermal_pm_ops,
531 .of_match_table = of_imx_thermal_match,
532 },
533 .probe = imx_thermal_probe,
534 .remove = imx_thermal_remove,
535};
536module_platform_driver(imx_thermal);
537
538MODULE_AUTHOR("Freescale Semiconductor, Inc.");
539MODULE_DESCRIPTION("Thermal driver for Freescale i.MX SoCs");
540MODULE_LICENSE("GPL v2");
541MODULE_ALIAS("platform:imx-thermal");
diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
new file mode 100644
index 000000000000..f760389a204c
--- /dev/null
+++ b/drivers/thermal/samsung/Kconfig
@@ -0,0 +1,18 @@
1config EXYNOS_THERMAL
2 tristate "Exynos thermal management unit driver"
3 depends on ARCH_HAS_BANDGAP && OF
4 help
5 If you say yes here you get support for the TMU (Thermal Management
6 Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises
7 the TMU, reports temperature and handles cooling action if defined.
8 This driver uses the Exynos core thermal APIs and TMU configuration
9 data from the supported SoCs.
10
11config EXYNOS_THERMAL_CORE
12 bool "Core thermal framework support for EXYNOS SOCs"
13 depends on EXYNOS_THERMAL
14 help
15 If you say yes here you get support for EXYNOS TMU
16 (Thermal Management Unit) common registration/unregistration
17 functions to the core thermal layer and also to use the generic
18 CPU cooling APIs.
diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
new file mode 100644
index 000000000000..c09d83095dc2
--- /dev/null
+++ b/drivers/thermal/samsung/Makefile
@@ -0,0 +1,7 @@
1#
2# Samsung thermal specific Makefile
3#
4obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
5exynos_thermal-y := exynos_tmu.o
6exynos_thermal-y += exynos_tmu_data.o
7exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
new file mode 100644
index 000000000000..f10a6ad37c06
--- /dev/null
+++ b/drivers/thermal/samsung/exynos_thermal_common.c
@@ -0,0 +1,432 @@
1/*
2 * exynos_thermal_common.c - Samsung EXYNOS common thermal file
3 *
4 * Copyright (C) 2013 Samsung Electronics
5 * Amit Daniel Kachhap <amit.daniel@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <linux/cpu_cooling.h>
24#include <linux/err.h>
25#include <linux/slab.h>
26#include <linux/thermal.h>
27
28#include "exynos_thermal_common.h"
29
30struct exynos_thermal_zone {
31 enum thermal_device_mode mode;
32 struct thermal_zone_device *therm_dev;
33 struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
34 unsigned int cool_dev_size;
35 struct platform_device *exynos4_dev;
36 struct thermal_sensor_conf *sensor_conf;
37 bool bind;
38};
39
40/* Get mode callback functions for thermal zone */
41static int exynos_get_mode(struct thermal_zone_device *thermal,
42 enum thermal_device_mode *mode)
43{
44 struct exynos_thermal_zone *th_zone = thermal->devdata;
45 if (th_zone)
46 *mode = th_zone->mode;
47 return 0;
48}
49
50/* Set mode callback functions for thermal zone */
51static int exynos_set_mode(struct thermal_zone_device *thermal,
52 enum thermal_device_mode mode)
53{
54 struct exynos_thermal_zone *th_zone = thermal->devdata;
55 if (!th_zone) {
56 dev_err(&thermal->device,
57 "thermal zone not registered\n");
58 return 0;
59 }
60
61 mutex_lock(&thermal->lock);
62
63 if (mode == THERMAL_DEVICE_ENABLED &&
64 !th_zone->sensor_conf->trip_data.trigger_falling)
65 thermal->polling_delay = IDLE_INTERVAL;
66 else
67 thermal->polling_delay = 0;
68
69 mutex_unlock(&thermal->lock);
70
71 th_zone->mode = mode;
72 thermal_zone_device_update(thermal);
73 dev_dbg(th_zone->sensor_conf->dev,
74 "thermal polling set for duration=%d msec\n",
75 thermal->polling_delay);
76 return 0;
77}
78
79
80/* Get trip type callback functions for thermal zone */
81static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
82 enum thermal_trip_type *type)
83{
84 struct exynos_thermal_zone *th_zone = thermal->devdata;
85 int max_trip = th_zone->sensor_conf->trip_data.trip_count;
86 int trip_type;
87
88 if (trip < 0 || trip >= max_trip)
89 return -EINVAL;
90
91 trip_type = th_zone->sensor_conf->trip_data.trip_type[trip];
92
93 if (trip_type == SW_TRIP)
94 *type = THERMAL_TRIP_CRITICAL;
95 else if (trip_type == THROTTLE_ACTIVE)
96 *type = THERMAL_TRIP_ACTIVE;
97 else if (trip_type == THROTTLE_PASSIVE)
98 *type = THERMAL_TRIP_PASSIVE;
99 else
100 return -EINVAL;
101
102 return 0;
103}
104
105/* Get trip temperature callback functions for thermal zone */
106static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
107 unsigned long *temp)
108{
109 struct exynos_thermal_zone *th_zone = thermal->devdata;
110 int max_trip = th_zone->sensor_conf->trip_data.trip_count;
111
112 if (trip < 0 || trip >= max_trip)
113 return -EINVAL;
114
115 *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
116 /* convert the temperature into millicelsius */
117 *temp = *temp * MCELSIUS;
118
119 return 0;
120}
121
122/* Get critical temperature callback functions for thermal zone */
123static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
124 unsigned long *temp)
125{
126 struct exynos_thermal_zone *th_zone = thermal->devdata;
127 int max_trip = th_zone->sensor_conf->trip_data.trip_count;
128 /* Get the temp of highest trip*/
129 return exynos_get_trip_temp(thermal, max_trip - 1, temp);
130}
131
132/* Bind callback functions for thermal zone */
133static int exynos_bind(struct thermal_zone_device *thermal,
134 struct thermal_cooling_device *cdev)
135{
136 int ret = 0, i, tab_size, level;
137 struct freq_clip_table *tab_ptr, *clip_data;
138 struct exynos_thermal_zone *th_zone = thermal->devdata;
139 struct thermal_sensor_conf *data = th_zone->sensor_conf;
140
141 tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
142 tab_size = data->cooling_data.freq_clip_count;
143
144 if (tab_ptr == NULL || tab_size == 0)
145 return 0;
146
147 /* find the cooling device registered*/
148 for (i = 0; i < th_zone->cool_dev_size; i++)
149 if (cdev == th_zone->cool_dev[i])
150 break;
151
152 /* No matching cooling device */
153 if (i == th_zone->cool_dev_size)
154 return 0;
155
156 /* Bind the thermal zone to the cpufreq cooling device */
157 for (i = 0; i < tab_size; i++) {
158 clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
159 level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
160 if (level == THERMAL_CSTATE_INVALID)
161 return 0;
162 switch (GET_ZONE(i)) {
163 case MONITOR_ZONE:
164 case WARN_ZONE:
165 if (thermal_zone_bind_cooling_device(thermal, i, cdev,
166 level, 0)) {
167 dev_err(data->dev,
168 "error unbinding cdev inst=%d\n", i);
169 ret = -EINVAL;
170 }
171 th_zone->bind = true;
172 break;
173 default:
174 ret = -EINVAL;
175 }
176 }
177
178 return ret;
179}
180
181/* Unbind callback functions for thermal zone */
182static int exynos_unbind(struct thermal_zone_device *thermal,
183 struct thermal_cooling_device *cdev)
184{
185 int ret = 0, i, tab_size;
186 struct exynos_thermal_zone *th_zone = thermal->devdata;
187 struct thermal_sensor_conf *data = th_zone->sensor_conf;
188
189 if (th_zone->bind == false)
190 return 0;
191
192 tab_size = data->cooling_data.freq_clip_count;
193
194 if (tab_size == 0)
195 return 0;
196
197 /* find the cooling device registered*/
198 for (i = 0; i < th_zone->cool_dev_size; i++)
199 if (cdev == th_zone->cool_dev[i])
200 break;
201
202 /* No matching cooling device */
203 if (i == th_zone->cool_dev_size)
204 return 0;
205
206 /* Bind the thermal zone to the cpufreq cooling device */
207 for (i = 0; i < tab_size; i++) {
208 switch (GET_ZONE(i)) {
209 case MONITOR_ZONE:
210 case WARN_ZONE:
211 if (thermal_zone_unbind_cooling_device(thermal, i,
212 cdev)) {
213 dev_err(data->dev,
214 "error unbinding cdev inst=%d\n", i);
215 ret = -EINVAL;
216 }
217 th_zone->bind = false;
218 break;
219 default:
220 ret = -EINVAL;
221 }
222 }
223 return ret;
224}
225
226/* Get temperature callback functions for thermal zone */
227static int exynos_get_temp(struct thermal_zone_device *thermal,
228 unsigned long *temp)
229{
230 struct exynos_thermal_zone *th_zone = thermal->devdata;
231 void *data;
232
233 if (!th_zone->sensor_conf) {
234 dev_err(&thermal->device,
235 "Temperature sensor not initialised\n");
236 return -EINVAL;
237 }
238 data = th_zone->sensor_conf->driver_data;
239 *temp = th_zone->sensor_conf->read_temperature(data);
240 /* convert the temperature into millicelsius */
241 *temp = *temp * MCELSIUS;
242 return 0;
243}
244
245/* Get temperature callback functions for thermal zone */
246static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
247 unsigned long temp)
248{
249 void *data;
250 int ret = -EINVAL;
251 struct exynos_thermal_zone *th_zone = thermal->devdata;
252
253 if (!th_zone->sensor_conf) {
254 dev_err(&thermal->device,
255 "Temperature sensor not initialised\n");
256 return -EINVAL;
257 }
258 data = th_zone->sensor_conf->driver_data;
259 if (th_zone->sensor_conf->write_emul_temp)
260 ret = th_zone->sensor_conf->write_emul_temp(data, temp);
261 return ret;
262}
263
264/* Get the temperature trend */
265static int exynos_get_trend(struct thermal_zone_device *thermal,
266 int trip, enum thermal_trend *trend)
267{
268 int ret;
269 unsigned long trip_temp;
270
271 ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
272 if (ret < 0)
273 return ret;
274
275 if (thermal->temperature >= trip_temp)
276 *trend = THERMAL_TREND_RAISE_FULL;
277 else
278 *trend = THERMAL_TREND_DROP_FULL;
279
280 return 0;
281}
282/* Operation callback functions for thermal zone */
283static struct thermal_zone_device_ops const exynos_dev_ops = {
284 .bind = exynos_bind,
285 .unbind = exynos_unbind,
286 .get_temp = exynos_get_temp,
287 .set_emul_temp = exynos_set_emul_temp,
288 .get_trend = exynos_get_trend,
289 .get_mode = exynos_get_mode,
290 .set_mode = exynos_set_mode,
291 .get_trip_type = exynos_get_trip_type,
292 .get_trip_temp = exynos_get_trip_temp,
293 .get_crit_temp = exynos_get_crit_temp,
294};
295
296/*
297 * This function may be called from interrupt based temperature sensor
298 * when threshold is changed.
299 */
300void exynos_report_trigger(struct thermal_sensor_conf *conf)
301{
302 unsigned int i;
303 char data[10];
304 char *envp[] = { data, NULL };
305 struct exynos_thermal_zone *th_zone;
306
307 if (!conf || !conf->pzone_data) {
308 pr_err("Invalid temperature sensor configuration data\n");
309 return;
310 }
311
312 th_zone = conf->pzone_data;
313 if (th_zone->therm_dev)
314 return;
315
316 if (th_zone->bind == false) {
317 for (i = 0; i < th_zone->cool_dev_size; i++) {
318 if (!th_zone->cool_dev[i])
319 continue;
320 exynos_bind(th_zone->therm_dev,
321 th_zone->cool_dev[i]);
322 }
323 }
324
325 thermal_zone_device_update(th_zone->therm_dev);
326
327 mutex_lock(&th_zone->therm_dev->lock);
328 /* Find the level for which trip happened */
329 for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
330 if (th_zone->therm_dev->last_temperature <
331 th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
332 break;
333 }
334
335 if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
336 !th_zone->sensor_conf->trip_data.trigger_falling) {
337 if (i > 0)
338 th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
339 else
340 th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
341 }
342
343 snprintf(data, sizeof(data), "%u", i);
344 kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
345 mutex_unlock(&th_zone->therm_dev->lock);
346}
347
348/* Register with the in-kernel thermal management */
349int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
350{
351 int ret;
352 struct cpumask mask_val;
353 struct exynos_thermal_zone *th_zone;
354
355 if (!sensor_conf || !sensor_conf->read_temperature) {
356 pr_err("Temperature sensor not initialised\n");
357 return -EINVAL;
358 }
359
360 th_zone = devm_kzalloc(sensor_conf->dev,
361 sizeof(struct exynos_thermal_zone), GFP_KERNEL);
362 if (!th_zone)
363 return -ENOMEM;
364
365 th_zone->sensor_conf = sensor_conf;
366 /*
367 * TODO: 1) Handle multiple cooling devices in a thermal zone
368 * 2) Add a flag/name in cooling info to map to specific
369 * sensor
370 */
371 if (sensor_conf->cooling_data.freq_clip_count > 0) {
372 cpumask_set_cpu(0, &mask_val);
373 th_zone->cool_dev[th_zone->cool_dev_size] =
374 cpufreq_cooling_register(&mask_val);
375 if (IS_ERR(th_zone->cool_dev[th_zone->cool_dev_size])) {
376 dev_err(sensor_conf->dev,
377 "Failed to register cpufreq cooling device\n");
378 ret = -EINVAL;
379 goto err_unregister;
380 }
381 th_zone->cool_dev_size++;
382 }
383
384 th_zone->therm_dev = thermal_zone_device_register(
385 sensor_conf->name, sensor_conf->trip_data.trip_count,
386 0, th_zone, &exynos_dev_ops, NULL, 0,
387 sensor_conf->trip_data.trigger_falling ? 0 :
388 IDLE_INTERVAL);
389
390 if (IS_ERR(th_zone->therm_dev)) {
391 dev_err(sensor_conf->dev,
392 "Failed to register thermal zone device\n");
393 ret = PTR_ERR(th_zone->therm_dev);
394 goto err_unregister;
395 }
396 th_zone->mode = THERMAL_DEVICE_ENABLED;
397 sensor_conf->pzone_data = th_zone;
398
399 dev_info(sensor_conf->dev,
400 "Exynos: Thermal zone(%s) registered\n", sensor_conf->name);
401
402 return 0;
403
404err_unregister:
405 exynos_unregister_thermal(sensor_conf);
406 return ret;
407}
408
409/* Un-Register with the in-kernel thermal management */
410void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf)
411{
412 int i;
413 struct exynos_thermal_zone *th_zone;
414
415 if (!sensor_conf || !sensor_conf->pzone_data) {
416 pr_err("Invalid temperature sensor configuration data\n");
417 return;
418 }
419
420 th_zone = sensor_conf->pzone_data;
421
422 if (th_zone->therm_dev)
423 thermal_zone_device_unregister(th_zone->therm_dev);
424
425 for (i = 0; i < th_zone->cool_dev_size; i++) {
426 if (th_zone->cool_dev[i])
427 cpufreq_cooling_unregister(th_zone->cool_dev[i]);
428 }
429
430 dev_info(sensor_conf->dev,
431 "Exynos: Kernel Thermal management unregistered\n");
432}
diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
new file mode 100644
index 000000000000..3eb2ed9ea3a4
--- /dev/null
+++ b/drivers/thermal/samsung/exynos_thermal_common.h
@@ -0,0 +1,107 @@
1/*
2 * exynos_thermal_common.h - Samsung EXYNOS common header file
3 *
4 * Copyright (C) 2013 Samsung Electronics
5 * Amit Daniel Kachhap <amit.daniel@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#ifndef _EXYNOS_THERMAL_COMMON_H
24#define _EXYNOS_THERMAL_COMMON_H
25
26/* In-kernel thermal framework related macros & definations */
27#define SENSOR_NAME_LEN 16
28#define MAX_TRIP_COUNT 8
29#define MAX_COOLING_DEVICE 4
30#define MAX_THRESHOLD_LEVS 5
31
32#define ACTIVE_INTERVAL 500
33#define IDLE_INTERVAL 10000
34#define MCELSIUS 1000
35
36/* CPU Zone information */
37#define PANIC_ZONE 4
38#define WARN_ZONE 3
39#define MONITOR_ZONE 2
40#define SAFE_ZONE 1
41
42#define GET_ZONE(trip) (trip + 2)
43#define GET_TRIP(zone) (zone - 2)
44
45enum trigger_type {
46 THROTTLE_ACTIVE = 1,
47 THROTTLE_PASSIVE,
48 SW_TRIP,
49 HW_TRIP,
50};
51
52/**
53 * struct freq_clip_table
54 * @freq_clip_max: maximum frequency allowed for this cooling state.
55 * @temp_level: Temperature level at which the temperature clipping will
56 * happen.
57 * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
58 *
59 * This structure is required to be filled and passed to the
60 * cpufreq_cooling_unregister function.
61 */
62struct freq_clip_table {
63 unsigned int freq_clip_max;
64 unsigned int temp_level;
65 const struct cpumask *mask_val;
66};
67
68struct thermal_trip_point_conf {
69 int trip_val[MAX_TRIP_COUNT];
70 int trip_type[MAX_TRIP_COUNT];
71 int trip_count;
72 unsigned char trigger_falling;
73};
74
75struct thermal_cooling_conf {
76 struct freq_clip_table freq_data[MAX_TRIP_COUNT];
77 int freq_clip_count;
78};
79
80struct thermal_sensor_conf {
81 char name[SENSOR_NAME_LEN];
82 int (*read_temperature)(void *data);
83 int (*write_emul_temp)(void *drv_data, unsigned long temp);
84 struct thermal_trip_point_conf trip_data;
85 struct thermal_cooling_conf cooling_data;
86 void *driver_data;
87 void *pzone_data;
88 struct device *dev;
89};
90
91/*Functions used exynos based thermal sensor driver*/
92#ifdef CONFIG_EXYNOS_THERMAL_CORE
93void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf);
94int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
95void exynos_report_trigger(struct thermal_sensor_conf *sensor_conf);
96#else
97static inline void
98exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf) { return; }
99
100static inline int
101exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; }
102
103static inline void
104exynos_report_trigger(struct thermal_sensor_conf *sensor_conf) { return; }
105
106#endif /* CONFIG_EXYNOS_THERMAL_CORE */
107#endif /* _EXYNOS_THERMAL_COMMON_H */
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
new file mode 100644
index 000000000000..b43afda8acd1
--- /dev/null
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -0,0 +1,762 @@
1/*
2 * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit)
3 *
4 * Copyright (C) 2011 Samsung Electronics
5 * Donggeun Kim <dg77.kim@samsung.com>
6 * Amit Daniel Kachhap <amit.kachhap@linaro.org>
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; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <linux/clk.h>
25#include <linux/io.h>
26#include <linux/interrupt.h>
27#include <linux/module.h>
28#include <linux/of.h>
29#include <linux/of_address.h>
30#include <linux/of_irq.h>
31#include <linux/platform_device.h>
32#include <linux/regulator/consumer.h>
33
34#include "exynos_thermal_common.h"
35#include "exynos_tmu.h"
36#include "exynos_tmu_data.h"
37
38/**
39 * struct exynos_tmu_data : A structure to hold the private data of the TMU
40 driver
41 * @id: identifier of the one instance of the TMU controller.
42 * @pdata: pointer to the tmu platform/configuration data
43 * @base: base address of the single instance of the TMU controller.
44 * @base_common: base address of the common registers of the TMU controller.
45 * @irq: irq number of the TMU controller.
46 * @soc: id of the SOC type.
47 * @irq_work: pointer to the irq work structure.
48 * @lock: lock to implement synchronization.
49 * @clk: pointer to the clock structure.
50 * @temp_error1: fused value of the first point trim.
51 * @temp_error2: fused value of the second point trim.
52 * @regulator: pointer to the TMU regulator structure.
53 * @reg_conf: pointer to structure to register with core thermal.
54 */
55struct exynos_tmu_data {
56 int id;
57 struct exynos_tmu_platform_data *pdata;
58 void __iomem *base;
59 void __iomem *base_common;
60 int irq;
61 enum soc_type soc;
62 struct work_struct irq_work;
63 struct mutex lock;
64 struct clk *clk;
65 u8 temp_error1, temp_error2;
66 struct regulator *regulator;
67 struct thermal_sensor_conf *reg_conf;
68};
69
70/*
71 * TMU treats temperature as a mapped temperature code.
72 * The temperature is converted differently depending on the calibration type.
73 */
74static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
75{
76 struct exynos_tmu_platform_data *pdata = data->pdata;
77 int temp_code;
78
79 if (pdata->cal_mode == HW_MODE)
80 return temp;
81
82 if (data->soc == SOC_ARCH_EXYNOS4210)
83 /* temp should range between 25 and 125 */
84 if (temp < 25 || temp > 125) {
85 temp_code = -EINVAL;
86 goto out;
87 }
88
89 switch (pdata->cal_type) {
90 case TYPE_TWO_POINT_TRIMMING:
91 temp_code = (temp - pdata->first_point_trim) *
92 (data->temp_error2 - data->temp_error1) /
93 (pdata->second_point_trim - pdata->first_point_trim) +
94 data->temp_error1;
95 break;
96 case TYPE_ONE_POINT_TRIMMING:
97 temp_code = temp + data->temp_error1 - pdata->first_point_trim;
98 break;
99 default:
100 temp_code = temp + pdata->default_temp_offset;
101 break;
102 }
103out:
104 return temp_code;
105}
106
107/*
108 * Calculate a temperature value from a temperature code.
109 * The unit of the temperature is degree Celsius.
110 */
111static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
112{
113 struct exynos_tmu_platform_data *pdata = data->pdata;
114 int temp;
115
116 if (pdata->cal_mode == HW_MODE)
117 return temp_code;
118
119 if (data->soc == SOC_ARCH_EXYNOS4210)
120 /* temp_code should range between 75 and 175 */
121 if (temp_code < 75 || temp_code > 175) {
122 temp = -ENODATA;
123 goto out;
124 }
125
126 switch (pdata->cal_type) {
127 case TYPE_TWO_POINT_TRIMMING:
128 temp = (temp_code - data->temp_error1) *
129 (pdata->second_point_trim - pdata->first_point_trim) /
130 (data->temp_error2 - data->temp_error1) +
131 pdata->first_point_trim;
132 break;
133 case TYPE_ONE_POINT_TRIMMING:
134 temp = temp_code - data->temp_error1 + pdata->first_point_trim;
135 break;
136 default:
137 temp = temp_code - pdata->default_temp_offset;
138 break;
139 }
140out:
141 return temp;
142}
143
144static int exynos_tmu_initialize(struct platform_device *pdev)
145{
146 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
147 struct exynos_tmu_platform_data *pdata = data->pdata;
148 const struct exynos_tmu_registers *reg = pdata->registers;
149 unsigned int status, trim_info = 0, con;
150 unsigned int rising_threshold = 0, falling_threshold = 0;
151 int ret = 0, threshold_code, i, trigger_levs = 0;
152
153 mutex_lock(&data->lock);
154 clk_enable(data->clk);
155
156 if (TMU_SUPPORTS(pdata, READY_STATUS)) {
157 status = readb(data->base + reg->tmu_status);
158 if (!status) {
159 ret = -EBUSY;
160 goto out;
161 }
162 }
163
164 if (TMU_SUPPORTS(pdata, TRIM_RELOAD))
165 __raw_writel(1, data->base + reg->triminfo_ctrl);
166
167 if (pdata->cal_mode == HW_MODE)
168 goto skip_calib_data;
169
170 /* Save trimming info in order to perform calibration */
171 if (data->soc == SOC_ARCH_EXYNOS5440) {
172 /*
173 * For exynos5440 soc triminfo value is swapped between TMU0 and
174 * TMU2, so the below logic is needed.
175 */
176 switch (data->id) {
177 case 0:
178 trim_info = readl(data->base +
179 EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data);
180 break;
181 case 1:
182 trim_info = readl(data->base + reg->triminfo_data);
183 break;
184 case 2:
185 trim_info = readl(data->base -
186 EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data);
187 }
188 } else {
189 trim_info = readl(data->base + reg->triminfo_data);
190 }
191 data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK;
192 data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) &
193 EXYNOS_TMU_TEMP_MASK);
194
195 if (!data->temp_error1 ||
196 (pdata->min_efuse_value > data->temp_error1) ||
197 (data->temp_error1 > pdata->max_efuse_value))
198 data->temp_error1 = pdata->efuse_value & EXYNOS_TMU_TEMP_MASK;
199
200 if (!data->temp_error2)
201 data->temp_error2 =
202 (pdata->efuse_value >> reg->triminfo_85_shift) &
203 EXYNOS_TMU_TEMP_MASK;
204
205skip_calib_data:
206 if (pdata->max_trigger_level > MAX_THRESHOLD_LEVS) {
207 dev_err(&pdev->dev, "Invalid max trigger level\n");
208 goto out;
209 }
210
211 for (i = 0; i < pdata->max_trigger_level; i++) {
212 if (!pdata->trigger_levels[i])
213 continue;
214
215 if ((pdata->trigger_type[i] == HW_TRIP) &&
216 (!pdata->trigger_levels[pdata->max_trigger_level - 1])) {
217 dev_err(&pdev->dev, "Invalid hw trigger level\n");
218 ret = -EINVAL;
219 goto out;
220 }
221
222 /* Count trigger levels except the HW trip*/
223 if (!(pdata->trigger_type[i] == HW_TRIP))
224 trigger_levs++;
225 }
226
227 if (data->soc == SOC_ARCH_EXYNOS4210) {
228 /* Write temperature code for threshold */
229 threshold_code = temp_to_code(data, pdata->threshold);
230 if (threshold_code < 0) {
231 ret = threshold_code;
232 goto out;
233 }
234 writeb(threshold_code,
235 data->base + reg->threshold_temp);
236 for (i = 0; i < trigger_levs; i++)
237 writeb(pdata->trigger_levels[i], data->base +
238 reg->threshold_th0 + i * sizeof(reg->threshold_th0));
239
240 writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
241 } else {
242 /* Write temperature code for rising and falling threshold */
243 for (i = 0;
244 i < trigger_levs && i < EXYNOS_MAX_TRIGGER_PER_REG; i++) {
245 threshold_code = temp_to_code(data,
246 pdata->trigger_levels[i]);
247 if (threshold_code < 0) {
248 ret = threshold_code;
249 goto out;
250 }
251 rising_threshold |= threshold_code << 8 * i;
252 if (pdata->threshold_falling) {
253 threshold_code = temp_to_code(data,
254 pdata->trigger_levels[i] -
255 pdata->threshold_falling);
256 if (threshold_code > 0)
257 falling_threshold |=
258 threshold_code << 8 * i;
259 }
260 }
261
262 writel(rising_threshold,
263 data->base + reg->threshold_th0);
264 writel(falling_threshold,
265 data->base + reg->threshold_th1);
266
267 writel((reg->inten_rise_mask << reg->inten_rise_shift) |
268 (reg->inten_fall_mask << reg->inten_fall_shift),
269 data->base + reg->tmu_intclear);
270
271 /* if last threshold limit is also present */
272 i = pdata->max_trigger_level - 1;
273 if (pdata->trigger_levels[i] &&
274 (pdata->trigger_type[i] == HW_TRIP)) {
275 threshold_code = temp_to_code(data,
276 pdata->trigger_levels[i]);
277 if (threshold_code < 0) {
278 ret = threshold_code;
279 goto out;
280 }
281 if (i == EXYNOS_MAX_TRIGGER_PER_REG - 1) {
282 /* 1-4 level to be assigned in th0 reg */
283 rising_threshold |= threshold_code << 8 * i;
284 writel(rising_threshold,
285 data->base + reg->threshold_th0);
286 } else if (i == EXYNOS_MAX_TRIGGER_PER_REG) {
287 /* 5th level to be assigned in th2 reg */
288 rising_threshold =
289 threshold_code << reg->threshold_th3_l0_shift;
290 writel(rising_threshold,
291 data->base + reg->threshold_th2);
292 }
293 con = readl(data->base + reg->tmu_ctrl);
294 con |= (1 << reg->therm_trip_en_shift);
295 writel(con, data->base + reg->tmu_ctrl);
296 }
297 }
298 /*Clear the PMIN in the common TMU register*/
299 if (reg->tmu_pmin && !data->id)
300 writel(0, data->base_common + reg->tmu_pmin);
301out:
302 clk_disable(data->clk);
303 mutex_unlock(&data->lock);
304
305 return ret;
306}
307
308static void exynos_tmu_control(struct platform_device *pdev, bool on)
309{
310 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
311 struct exynos_tmu_platform_data *pdata = data->pdata;
312 const struct exynos_tmu_registers *reg = pdata->registers;
313 unsigned int con, interrupt_en, cal_val;
314
315 mutex_lock(&data->lock);
316 clk_enable(data->clk);
317
318 con = readl(data->base + reg->tmu_ctrl);
319
320 if (pdata->reference_voltage) {
321 con &= ~(reg->buf_vref_sel_mask << reg->buf_vref_sel_shift);
322 con |= pdata->reference_voltage << reg->buf_vref_sel_shift;
323 }
324
325 if (pdata->gain) {
326 con &= ~(reg->buf_slope_sel_mask << reg->buf_slope_sel_shift);
327 con |= (pdata->gain << reg->buf_slope_sel_shift);
328 }
329
330 if (pdata->noise_cancel_mode) {
331 con &= ~(reg->therm_trip_mode_mask <<
332 reg->therm_trip_mode_shift);
333 con |= (pdata->noise_cancel_mode << reg->therm_trip_mode_shift);
334 }
335
336 if (pdata->cal_mode == HW_MODE) {
337 con &= ~(reg->calib_mode_mask << reg->calib_mode_shift);
338 cal_val = 0;
339 switch (pdata->cal_type) {
340 case TYPE_TWO_POINT_TRIMMING:
341 cal_val = 3;
342 break;
343 case TYPE_ONE_POINT_TRIMMING_85:
344 cal_val = 2;
345 break;
346 case TYPE_ONE_POINT_TRIMMING_25:
347 cal_val = 1;
348 break;
349 case TYPE_NONE:
350 break;
351 default:
352 dev_err(&pdev->dev, "Invalid calibration type, using none\n");
353 }
354 con |= cal_val << reg->calib_mode_shift;
355 }
356
357 if (on) {
358 con |= (1 << reg->core_en_shift);
359 interrupt_en =
360 pdata->trigger_enable[3] << reg->inten_rise3_shift |
361 pdata->trigger_enable[2] << reg->inten_rise2_shift |
362 pdata->trigger_enable[1] << reg->inten_rise1_shift |
363 pdata->trigger_enable[0] << reg->inten_rise0_shift;
364 if (TMU_SUPPORTS(pdata, FALLING_TRIP))
365 interrupt_en |=
366 interrupt_en << reg->inten_fall0_shift;
367 } else {
368 con &= ~(1 << reg->core_en_shift);
369 interrupt_en = 0; /* Disable all interrupts */
370 }
371 writel(interrupt_en, data->base + reg->tmu_inten);
372 writel(con, data->base + reg->tmu_ctrl);
373
374 clk_disable(data->clk);
375 mutex_unlock(&data->lock);
376}
377
378static int exynos_tmu_read(struct exynos_tmu_data *data)
379{
380 struct exynos_tmu_platform_data *pdata = data->pdata;
381 const struct exynos_tmu_registers *reg = pdata->registers;
382 u8 temp_code;
383 int temp;
384
385 mutex_lock(&data->lock);
386 clk_enable(data->clk);
387
388 temp_code = readb(data->base + reg->tmu_cur_temp);
389 temp = code_to_temp(data, temp_code);
390
391 clk_disable(data->clk);
392 mutex_unlock(&data->lock);
393
394 return temp;
395}
396
397#ifdef CONFIG_THERMAL_EMULATION
398static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
399{
400 struct exynos_tmu_data *data = drv_data;
401 struct exynos_tmu_platform_data *pdata = data->pdata;
402 const struct exynos_tmu_registers *reg = pdata->registers;
403 unsigned int val;
404 int ret = -EINVAL;
405
406 if (!TMU_SUPPORTS(pdata, EMULATION))
407 goto out;
408
409 if (temp && temp < MCELSIUS)
410 goto out;
411
412 mutex_lock(&data->lock);
413 clk_enable(data->clk);
414
415 val = readl(data->base + reg->emul_con);
416
417 if (temp) {
418 temp /= MCELSIUS;
419
420 if (TMU_SUPPORTS(pdata, EMUL_TIME)) {
421 val &= ~(EXYNOS_EMUL_TIME_MASK << reg->emul_time_shift);
422 val |= (EXYNOS_EMUL_TIME << reg->emul_time_shift);
423 }
424 val &= ~(EXYNOS_EMUL_DATA_MASK << reg->emul_temp_shift);
425 val |= (temp_to_code(data, temp) << reg->emul_temp_shift) |
426 EXYNOS_EMUL_ENABLE;
427 } else {
428 val &= ~EXYNOS_EMUL_ENABLE;
429 }
430
431 writel(val, data->base + reg->emul_con);
432
433 clk_disable(data->clk);
434 mutex_unlock(&data->lock);
435 return 0;
436out:
437 return ret;
438}
439#else
440static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
441 { return -EINVAL; }
442#endif/*CONFIG_THERMAL_EMULATION*/
443
444static void exynos_tmu_work(struct work_struct *work)
445{
446 struct exynos_tmu_data *data = container_of(work,
447 struct exynos_tmu_data, irq_work);
448 struct exynos_tmu_platform_data *pdata = data->pdata;
449 const struct exynos_tmu_registers *reg = pdata->registers;
450 unsigned int val_irq, val_type;
451
452 /* Find which sensor generated this interrupt */
453 if (reg->tmu_irqstatus) {
454 val_type = readl(data->base_common + reg->tmu_irqstatus);
455 if (!((val_type >> data->id) & 0x1))
456 goto out;
457 }
458
459 exynos_report_trigger(data->reg_conf);
460 mutex_lock(&data->lock);
461 clk_enable(data->clk);
462
463 /* TODO: take action based on particular interrupt */
464 val_irq = readl(data->base + reg->tmu_intstat);
465 /* clear the interrupts */
466 writel(val_irq, data->base + reg->tmu_intclear);
467
468 clk_disable(data->clk);
469 mutex_unlock(&data->lock);
470out:
471 enable_irq(data->irq);
472}
473
474static irqreturn_t exynos_tmu_irq(int irq, void *id)
475{
476 struct exynos_tmu_data *data = id;
477
478 disable_irq_nosync(irq);
479 schedule_work(&data->irq_work);
480
481 return IRQ_HANDLED;
482}
483
484static const struct of_device_id exynos_tmu_match[] = {
485 {
486 .compatible = "samsung,exynos4210-tmu",
487 .data = (void *)EXYNOS4210_TMU_DRV_DATA,
488 },
489 {
490 .compatible = "samsung,exynos4412-tmu",
491 .data = (void *)EXYNOS5250_TMU_DRV_DATA,
492 },
493 {
494 .compatible = "samsung,exynos5250-tmu",
495 .data = (void *)EXYNOS5250_TMU_DRV_DATA,
496 },
497 {
498 .compatible = "samsung,exynos5440-tmu",
499 .data = (void *)EXYNOS5440_TMU_DRV_DATA,
500 },
501 {},
502};
503MODULE_DEVICE_TABLE(of, exynos_tmu_match);
504
505static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
506 struct platform_device *pdev, int id)
507{
508 struct exynos_tmu_init_data *data_table;
509 struct exynos_tmu_platform_data *tmu_data;
510 const struct of_device_id *match;
511
512 match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
513 if (!match)
514 return NULL;
515 data_table = (struct exynos_tmu_init_data *) match->data;
516 if (!data_table || id >= data_table->tmu_count)
517 return NULL;
518 tmu_data = data_table->tmu_data;
519 return (struct exynos_tmu_platform_data *) (tmu_data + id);
520}
521
522static int exynos_map_dt_data(struct platform_device *pdev)
523{
524 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
525 struct exynos_tmu_platform_data *pdata;
526 struct resource res;
527 int ret;
528
529 if (!data || !pdev->dev.of_node)
530 return -ENODEV;
531
532 /*
533 * Try enabling the regulator if found
534 * TODO: Add regulator as an SOC feature, so that regulator enable
535 * is a compulsory call.
536 */
537 data->regulator = devm_regulator_get(&pdev->dev, "vtmu");
538 if (!IS_ERR(data->regulator)) {
539 ret = regulator_enable(data->regulator);
540 if (ret) {
541 dev_err(&pdev->dev, "failed to enable vtmu\n");
542 return ret;
543 }
544 } else {
545 dev_info(&pdev->dev, "Regulator node (vtmu) not found\n");
546 }
547
548 data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl");
549 if (data->id < 0)
550 data->id = 0;
551
552 data->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
553 if (data->irq <= 0) {
554 dev_err(&pdev->dev, "failed to get IRQ\n");
555 return -ENODEV;
556 }
557
558 if (of_address_to_resource(pdev->dev.of_node, 0, &res)) {
559 dev_err(&pdev->dev, "failed to get Resource 0\n");
560 return -ENODEV;
561 }
562
563 data->base = devm_ioremap(&pdev->dev, res.start, resource_size(&res));
564 if (!data->base) {
565 dev_err(&pdev->dev, "Failed to ioremap memory\n");
566 return -EADDRNOTAVAIL;
567 }
568
569 pdata = exynos_get_driver_data(pdev, data->id);
570 if (!pdata) {
571 dev_err(&pdev->dev, "No platform init data supplied.\n");
572 return -ENODEV;
573 }
574 data->pdata = pdata;
575 /*
576 * Check if the TMU shares some registers and then try to map the
577 * memory of common registers.
578 */
579 if (!TMU_SUPPORTS(pdata, SHARED_MEMORY))
580 return 0;
581
582 if (of_address_to_resource(pdev->dev.of_node, 1, &res)) {
583 dev_err(&pdev->dev, "failed to get Resource 1\n");
584 return -ENODEV;
585 }
586
587 data->base_common = devm_ioremap(&pdev->dev, res.start,
588 resource_size(&res));
589 if (!data->base_common) {
590 dev_err(&pdev->dev, "Failed to ioremap memory\n");
591 return -ENOMEM;
592 }
593
594 return 0;
595}
596
597static int exynos_tmu_probe(struct platform_device *pdev)
598{
599 struct exynos_tmu_data *data;
600 struct exynos_tmu_platform_data *pdata;
601 struct thermal_sensor_conf *sensor_conf;
602 int ret, i;
603
604 data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data),
605 GFP_KERNEL);
606 if (!data) {
607 dev_err(&pdev->dev, "Failed to allocate driver structure\n");
608 return -ENOMEM;
609 }
610
611 platform_set_drvdata(pdev, data);
612 mutex_init(&data->lock);
613
614 ret = exynos_map_dt_data(pdev);
615 if (ret)
616 return ret;
617
618 pdata = data->pdata;
619
620 INIT_WORK(&data->irq_work, exynos_tmu_work);
621
622 data->clk = devm_clk_get(&pdev->dev, "tmu_apbif");
623 if (IS_ERR(data->clk)) {
624 dev_err(&pdev->dev, "Failed to get clock\n");
625 return PTR_ERR(data->clk);
626 }
627
628 ret = clk_prepare(data->clk);
629 if (ret)
630 return ret;
631
632 if (pdata->type == SOC_ARCH_EXYNOS ||
633 pdata->type == SOC_ARCH_EXYNOS4210 ||
634 pdata->type == SOC_ARCH_EXYNOS5440)
635 data->soc = pdata->type;
636 else {
637 ret = -EINVAL;
638 dev_err(&pdev->dev, "Platform not supported\n");
639 goto err_clk;
640 }
641
642 ret = exynos_tmu_initialize(pdev);
643 if (ret) {
644 dev_err(&pdev->dev, "Failed to initialize TMU\n");
645 goto err_clk;
646 }
647
648 exynos_tmu_control(pdev, true);
649
650 /* Allocate a structure to register with the exynos core thermal */
651 sensor_conf = devm_kzalloc(&pdev->dev,
652 sizeof(struct thermal_sensor_conf), GFP_KERNEL);
653 if (!sensor_conf) {
654 dev_err(&pdev->dev, "Failed to allocate registration struct\n");
655 ret = -ENOMEM;
656 goto err_clk;
657 }
658 sprintf(sensor_conf->name, "therm_zone%d", data->id);
659 sensor_conf->read_temperature = (int (*)(void *))exynos_tmu_read;
660 sensor_conf->write_emul_temp =
661 (int (*)(void *, unsigned long))exynos_tmu_set_emulation;
662 sensor_conf->driver_data = data;
663 sensor_conf->trip_data.trip_count = pdata->trigger_enable[0] +
664 pdata->trigger_enable[1] + pdata->trigger_enable[2]+
665 pdata->trigger_enable[3];
666
667 for (i = 0; i < sensor_conf->trip_data.trip_count; i++) {
668 sensor_conf->trip_data.trip_val[i] =
669 pdata->threshold + pdata->trigger_levels[i];
670 sensor_conf->trip_data.trip_type[i] =
671 pdata->trigger_type[i];
672 }
673
674 sensor_conf->trip_data.trigger_falling = pdata->threshold_falling;
675
676 sensor_conf->cooling_data.freq_clip_count = pdata->freq_tab_count;
677 for (i = 0; i < pdata->freq_tab_count; i++) {
678 sensor_conf->cooling_data.freq_data[i].freq_clip_max =
679 pdata->freq_tab[i].freq_clip_max;
680 sensor_conf->cooling_data.freq_data[i].temp_level =
681 pdata->freq_tab[i].temp_level;
682 }
683 sensor_conf->dev = &pdev->dev;
684 /* Register the sensor with thermal management interface */
685 ret = exynos_register_thermal(sensor_conf);
686 if (ret) {
687 dev_err(&pdev->dev, "Failed to register thermal interface\n");
688 goto err_clk;
689 }
690 data->reg_conf = sensor_conf;
691
692 ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
693 IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data);
694 if (ret) {
695 dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
696 goto err_clk;
697 }
698
699 return 0;
700err_clk:
701 clk_unprepare(data->clk);
702 return ret;
703}
704
705static int exynos_tmu_remove(struct platform_device *pdev)
706{
707 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
708
709 exynos_tmu_control(pdev, false);
710
711 exynos_unregister_thermal(data->reg_conf);
712
713 clk_unprepare(data->clk);
714
715 if (!IS_ERR(data->regulator))
716 regulator_disable(data->regulator);
717
718 return 0;
719}
720
721#ifdef CONFIG_PM_SLEEP
722static int exynos_tmu_suspend(struct device *dev)
723{
724 exynos_tmu_control(to_platform_device(dev), false);
725
726 return 0;
727}
728
729static int exynos_tmu_resume(struct device *dev)
730{
731 struct platform_device *pdev = to_platform_device(dev);
732
733 exynos_tmu_initialize(pdev);
734 exynos_tmu_control(pdev, true);
735
736 return 0;
737}
738
739static SIMPLE_DEV_PM_OPS(exynos_tmu_pm,
740 exynos_tmu_suspend, exynos_tmu_resume);
741#define EXYNOS_TMU_PM (&exynos_tmu_pm)
742#else
743#define EXYNOS_TMU_PM NULL
744#endif
745
746static struct platform_driver exynos_tmu_driver = {
747 .driver = {
748 .name = "exynos-tmu",
749 .owner = THIS_MODULE,
750 .pm = EXYNOS_TMU_PM,
751 .of_match_table = exynos_tmu_match,
752 },
753 .probe = exynos_tmu_probe,
754 .remove = exynos_tmu_remove,
755};
756
757module_platform_driver(exynos_tmu_driver);
758
759MODULE_DESCRIPTION("EXYNOS TMU Driver");
760MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
761MODULE_LICENSE("GPL");
762MODULE_ALIAS("platform:exynos-tmu");
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
new file mode 100644
index 000000000000..b364c9eee701
--- /dev/null
+++ b/drivers/thermal/samsung/exynos_tmu.h
@@ -0,0 +1,311 @@
1/*
2 * exynos_tmu.h - Samsung EXYNOS TMU (Thermal Management Unit)
3 *
4 * Copyright (C) 2011 Samsung Electronics
5 * Donggeun Kim <dg77.kim@samsung.com>
6 * Amit Daniel Kachhap <amit.daniel@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#ifndef _EXYNOS_TMU_H
24#define _EXYNOS_TMU_H
25#include <linux/cpu_cooling.h>
26
27#include "exynos_thermal_common.h"
28
29enum calibration_type {
30 TYPE_ONE_POINT_TRIMMING,
31 TYPE_ONE_POINT_TRIMMING_25,
32 TYPE_ONE_POINT_TRIMMING_85,
33 TYPE_TWO_POINT_TRIMMING,
34 TYPE_NONE,
35};
36
37enum calibration_mode {
38 SW_MODE,
39 HW_MODE,
40};
41
42enum soc_type {
43 SOC_ARCH_EXYNOS4210 = 1,
44 SOC_ARCH_EXYNOS,
45 SOC_ARCH_EXYNOS5440,
46};
47
48/**
49 * EXYNOS TMU supported features.
50 * TMU_SUPPORT_EMULATION - This features is used to set user defined
51 * temperature to the TMU controller.
52 * TMU_SUPPORT_MULTI_INST - This features denotes that the soc
53 * has many instances of TMU.
54 * TMU_SUPPORT_TRIM_RELOAD - This features shows that trimming can
55 * be reloaded.
56 * TMU_SUPPORT_FALLING_TRIP - This features shows that interrupt can
57 * be registered for falling trips also.
58 * TMU_SUPPORT_READY_STATUS - This feature tells that the TMU current
59 * state(active/idle) can be checked.
60 * TMU_SUPPORT_EMUL_TIME - This features allows to set next temp emulation
61 * sample time.
62 * TMU_SUPPORT_SHARED_MEMORY - This feature tells that the different TMU
63 * sensors shares some common registers.
64 * TMU_SUPPORT - macro to compare the above features with the supplied.
65 */
66#define TMU_SUPPORT_EMULATION BIT(0)
67#define TMU_SUPPORT_MULTI_INST BIT(1)
68#define TMU_SUPPORT_TRIM_RELOAD BIT(2)
69#define TMU_SUPPORT_FALLING_TRIP BIT(3)
70#define TMU_SUPPORT_READY_STATUS BIT(4)
71#define TMU_SUPPORT_EMUL_TIME BIT(5)
72#define TMU_SUPPORT_SHARED_MEMORY BIT(6)
73
74#define TMU_SUPPORTS(a, b) (a->features & TMU_SUPPORT_ ## b)
75
76/**
77 * struct exynos_tmu_register - register descriptors to access registers and
78 * bitfields. The register validity, offsets and bitfield values may vary
79 * slightly across different exynos SOC's.
80 * @triminfo_data: register containing 2 pont trimming data
81 * @triminfo_25_shift: shift bit of the 25 C trim value in triminfo_data reg.
82 * @triminfo_85_shift: shift bit of the 85 C trim value in triminfo_data reg.
83 * @triminfo_ctrl: trim info controller register.
84 * @triminfo_reload_shift: shift of triminfo reload enable bit in triminfo_ctrl
85 reg.
86 * @tmu_ctrl: TMU main controller register.
87 * @buf_vref_sel_shift: shift bits of reference voltage in tmu_ctrl register.
88 * @buf_vref_sel_mask: mask bits of reference voltage in tmu_ctrl register.
89 * @therm_trip_mode_shift: shift bits of tripping mode in tmu_ctrl register.
90 * @therm_trip_mode_mask: mask bits of tripping mode in tmu_ctrl register.
91 * @therm_trip_en_shift: shift bits of tripping enable in tmu_ctrl register.
92 * @buf_slope_sel_shift: shift bits of amplifier gain value in tmu_ctrl
93 register.
94 * @buf_slope_sel_mask: mask bits of amplifier gain value in tmu_ctrl register.
95 * @calib_mode_shift: shift bits of calibration mode value in tmu_ctrl
96 register.
97 * @calib_mode_mask: mask bits of calibration mode value in tmu_ctrl
98 register.
99 * @therm_trip_tq_en_shift: shift bits of thermal trip enable by TQ pin in
100 tmu_ctrl register.
101 * @core_en_shift: shift bits of TMU core enable bit in tmu_ctrl register.
102 * @tmu_status: register drescribing the TMU status.
103 * @tmu_cur_temp: register containing the current temperature of the TMU.
104 * @tmu_cur_temp_shift: shift bits of current temp value in tmu_cur_temp
105 register.
106 * @threshold_temp: register containing the base threshold level.
107 * @threshold_th0: Register containing first set of rising levels.
108 * @threshold_th0_l0_shift: shift bits of level0 threshold temperature.
109 * @threshold_th0_l1_shift: shift bits of level1 threshold temperature.
110 * @threshold_th0_l2_shift: shift bits of level2 threshold temperature.
111 * @threshold_th0_l3_shift: shift bits of level3 threshold temperature.
112 * @threshold_th1: Register containing second set of rising levels.
113 * @threshold_th1_l0_shift: shift bits of level0 threshold temperature.
114 * @threshold_th1_l1_shift: shift bits of level1 threshold temperature.
115 * @threshold_th1_l2_shift: shift bits of level2 threshold temperature.
116 * @threshold_th1_l3_shift: shift bits of level3 threshold temperature.
117 * @threshold_th2: Register containing third set of rising levels.
118 * @threshold_th2_l0_shift: shift bits of level0 threshold temperature.
119 * @threshold_th3: Register containing fourth set of rising levels.
120 * @threshold_th3_l0_shift: shift bits of level0 threshold temperature.
121 * @tmu_inten: register containing the different threshold interrupt
122 enable bits.
123 * @inten_rise_shift: shift bits of all rising interrupt bits.
124 * @inten_rise_mask: mask bits of all rising interrupt bits.
125 * @inten_fall_shift: shift bits of all rising interrupt bits.
126 * @inten_fall_mask: mask bits of all rising interrupt bits.
127 * @inten_rise0_shift: shift bits of rising 0 interrupt bits.
128 * @inten_rise1_shift: shift bits of rising 1 interrupt bits.
129 * @inten_rise2_shift: shift bits of rising 2 interrupt bits.
130 * @inten_rise3_shift: shift bits of rising 3 interrupt bits.
131 * @inten_fall0_shift: shift bits of falling 0 interrupt bits.
132 * @inten_fall1_shift: shift bits of falling 1 interrupt bits.
133 * @inten_fall2_shift: shift bits of falling 2 interrupt bits.
134 * @inten_fall3_shift: shift bits of falling 3 interrupt bits.
135 * @tmu_intstat: Register containing the interrupt status values.
136 * @tmu_intclear: Register for clearing the raised interrupt status.
137 * @emul_con: TMU emulation controller register.
138 * @emul_temp_shift: shift bits of emulation temperature.
139 * @emul_time_shift: shift bits of emulation time.
140 * @emul_time_mask: mask bits of emulation time.
141 * @tmu_irqstatus: register to find which TMU generated interrupts.
142 * @tmu_pmin: register to get/set the Pmin value.
143 */
144struct exynos_tmu_registers {
145 u32 triminfo_data;
146 u32 triminfo_25_shift;
147 u32 triminfo_85_shift;
148
149 u32 triminfo_ctrl;
150 u32 triminfo_reload_shift;
151
152 u32 tmu_ctrl;
153 u32 buf_vref_sel_shift;
154 u32 buf_vref_sel_mask;
155 u32 therm_trip_mode_shift;
156 u32 therm_trip_mode_mask;
157 u32 therm_trip_en_shift;
158 u32 buf_slope_sel_shift;
159 u32 buf_slope_sel_mask;
160 u32 calib_mode_shift;
161 u32 calib_mode_mask;
162 u32 therm_trip_tq_en_shift;
163 u32 core_en_shift;
164
165 u32 tmu_status;
166
167 u32 tmu_cur_temp;
168 u32 tmu_cur_temp_shift;
169
170 u32 threshold_temp;
171
172 u32 threshold_th0;
173 u32 threshold_th0_l0_shift;
174 u32 threshold_th0_l1_shift;
175 u32 threshold_th0_l2_shift;
176 u32 threshold_th0_l3_shift;
177
178 u32 threshold_th1;
179 u32 threshold_th1_l0_shift;
180 u32 threshold_th1_l1_shift;
181 u32 threshold_th1_l2_shift;
182 u32 threshold_th1_l3_shift;
183
184 u32 threshold_th2;
185 u32 threshold_th2_l0_shift;
186
187 u32 threshold_th3;
188 u32 threshold_th3_l0_shift;
189
190 u32 tmu_inten;
191 u32 inten_rise_shift;
192 u32 inten_rise_mask;
193 u32 inten_fall_shift;
194 u32 inten_fall_mask;
195 u32 inten_rise0_shift;
196 u32 inten_rise1_shift;
197 u32 inten_rise2_shift;
198 u32 inten_rise3_shift;
199 u32 inten_fall0_shift;
200 u32 inten_fall1_shift;
201 u32 inten_fall2_shift;
202 u32 inten_fall3_shift;
203
204 u32 tmu_intstat;
205
206 u32 tmu_intclear;
207
208 u32 emul_con;
209 u32 emul_temp_shift;
210 u32 emul_time_shift;
211 u32 emul_time_mask;
212
213 u32 tmu_irqstatus;
214 u32 tmu_pmin;
215};
216
217/**
218 * struct exynos_tmu_platform_data
219 * @threshold: basic temperature for generating interrupt
220 * 25 <= threshold <= 125 [unit: degree Celsius]
221 * @threshold_falling: differntial value for setting threshold
222 * of temperature falling interrupt.
223 * @trigger_levels: array for each interrupt levels
224 * [unit: degree Celsius]
225 * 0: temperature for trigger_level0 interrupt
226 * condition for trigger_level0 interrupt:
227 * current temperature > threshold + trigger_levels[0]
228 * 1: temperature for trigger_level1 interrupt
229 * condition for trigger_level1 interrupt:
230 * current temperature > threshold + trigger_levels[1]
231 * 2: temperature for trigger_level2 interrupt
232 * condition for trigger_level2 interrupt:
233 * current temperature > threshold + trigger_levels[2]
234 * 3: temperature for trigger_level3 interrupt
235 * condition for trigger_level3 interrupt:
236 * current temperature > threshold + trigger_levels[3]
237 * @trigger_type: defines the type of trigger. Possible values are,
238 * THROTTLE_ACTIVE trigger type
239 * THROTTLE_PASSIVE trigger type
240 * SW_TRIP trigger type
241 * HW_TRIP
242 * @trigger_enable[]: array to denote which trigger levels are enabled.
243 * 1 = enable trigger_level[] interrupt,
244 * 0 = disable trigger_level[] interrupt
245 * @max_trigger_level: max trigger level supported by the TMU
246 * @gain: gain of amplifier in the positive-TC generator block
247 * 0 <= gain <= 15
248 * @reference_voltage: reference voltage of amplifier
249 * in the positive-TC generator block
250 * 0 <= reference_voltage <= 31
251 * @noise_cancel_mode: noise cancellation mode
252 * 000, 100, 101, 110 and 111 can be different modes
253 * @type: determines the type of SOC
254 * @efuse_value: platform defined fuse value
255 * @min_efuse_value: minimum valid trimming data
256 * @max_efuse_value: maximum valid trimming data
257 * @first_point_trim: temp value of the first point trimming
258 * @second_point_trim: temp value of the second point trimming
259 * @default_temp_offset: default temperature offset in case of no trimming
260 * @cal_type: calibration type for temperature
261 * @cal_mode: calibration mode for temperature
262 * @freq_clip_table: Table representing frequency reduction percentage.
263 * @freq_tab_count: Count of the above table as frequency reduction may
264 * applicable to only some of the trigger levels.
265 * @registers: Pointer to structure containing all the TMU controller registers
266 * and bitfields shifts and masks.
267 * @features: a bitfield value indicating the features supported in SOC like
268 * emulation, multi instance etc
269 *
270 * This structure is required for configuration of exynos_tmu driver.
271 */
272struct exynos_tmu_platform_data {
273 u8 threshold;
274 u8 threshold_falling;
275 u8 trigger_levels[MAX_TRIP_COUNT];
276 enum trigger_type trigger_type[MAX_TRIP_COUNT];
277 bool trigger_enable[MAX_TRIP_COUNT];
278 u8 max_trigger_level;
279 u8 gain;
280 u8 reference_voltage;
281 u8 noise_cancel_mode;
282
283 u32 efuse_value;
284 u32 min_efuse_value;
285 u32 max_efuse_value;
286 u8 first_point_trim;
287 u8 second_point_trim;
288 u8 default_temp_offset;
289
290 enum calibration_type cal_type;
291 enum calibration_mode cal_mode;
292 enum soc_type type;
293 struct freq_clip_table freq_tab[4];
294 unsigned int freq_tab_count;
295 const struct exynos_tmu_registers *registers;
296 unsigned int features;
297};
298
299/**
300 * struct exynos_tmu_init_data
301 * @tmu_count: number of TMU instances.
302 * @tmu_data: platform data of all TMU instances.
303 * This structure is required to store data for multi-instance exynos tmu
304 * driver.
305 */
306struct exynos_tmu_init_data {
307 int tmu_count;
308 struct exynos_tmu_platform_data tmu_data[];
309};
310
311#endif /* _EXYNOS_TMU_H */
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
new file mode 100644
index 000000000000..9002499c1f69
--- /dev/null
+++ b/drivers/thermal/samsung/exynos_tmu_data.c
@@ -0,0 +1,250 @@
1/*
2 * exynos_tmu_data.c - Samsung EXYNOS tmu data file
3 *
4 * Copyright (C) 2013 Samsung Electronics
5 * Amit Daniel Kachhap <amit.daniel@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include "exynos_thermal_common.h"
24#include "exynos_tmu.h"
25#include "exynos_tmu_data.h"
26
27#if defined(CONFIG_CPU_EXYNOS4210)
28static const struct exynos_tmu_registers exynos4210_tmu_registers = {
29 .triminfo_data = EXYNOS_TMU_REG_TRIMINFO,
30 .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
31 .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
32 .tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
33 .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
34 .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
35 .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
36 .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
37 .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
38 .tmu_status = EXYNOS_TMU_REG_STATUS,
39 .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
40 .threshold_temp = EXYNOS4210_TMU_REG_THRESHOLD_TEMP,
41 .threshold_th0 = EXYNOS4210_TMU_REG_TRIG_LEVEL0,
42 .tmu_inten = EXYNOS_TMU_REG_INTEN,
43 .inten_rise_mask = EXYNOS4210_TMU_TRIG_LEVEL_MASK,
44 .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
45 .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
46 .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT,
47 .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT,
48 .tmu_intstat = EXYNOS_TMU_REG_INTSTAT,
49 .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
50};
51
52struct exynos_tmu_init_data const exynos4210_default_tmu_data = {
53 .tmu_data = {
54 {
55 .threshold = 80,
56 .trigger_levels[0] = 5,
57 .trigger_levels[1] = 20,
58 .trigger_levels[2] = 30,
59 .trigger_enable[0] = true,
60 .trigger_enable[1] = true,
61 .trigger_enable[2] = true,
62 .trigger_enable[3] = false,
63 .trigger_type[0] = THROTTLE_ACTIVE,
64 .trigger_type[1] = THROTTLE_ACTIVE,
65 .trigger_type[2] = SW_TRIP,
66 .max_trigger_level = 4,
67 .gain = 15,
68 .reference_voltage = 7,
69 .cal_type = TYPE_ONE_POINT_TRIMMING,
70 .min_efuse_value = 40,
71 .max_efuse_value = 100,
72 .first_point_trim = 25,
73 .second_point_trim = 85,
74 .default_temp_offset = 50,
75 .freq_tab[0] = {
76 .freq_clip_max = 800 * 1000,
77 .temp_level = 85,
78 },
79 .freq_tab[1] = {
80 .freq_clip_max = 200 * 1000,
81 .temp_level = 100,
82 },
83 .freq_tab_count = 2,
84 .type = SOC_ARCH_EXYNOS4210,
85 .registers = &exynos4210_tmu_registers,
86 .features = TMU_SUPPORT_READY_STATUS,
87 },
88 },
89 .tmu_count = 1,
90};
91#endif
92
93#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
94static const struct exynos_tmu_registers exynos5250_tmu_registers = {
95 .triminfo_data = EXYNOS_TMU_REG_TRIMINFO,
96 .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
97 .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
98 .triminfo_ctrl = EXYNOS_TMU_TRIMINFO_CON,
99 .triminfo_reload_shift = EXYNOS_TRIMINFO_RELOAD_SHIFT,
100 .tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
101 .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
102 .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
103 .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT,
104 .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK,
105 .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT,
106 .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
107 .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
108 .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
109 .tmu_status = EXYNOS_TMU_REG_STATUS,
110 .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
111 .threshold_th0 = EXYNOS_THD_TEMP_RISE,
112 .threshold_th1 = EXYNOS_THD_TEMP_FALL,
113 .tmu_inten = EXYNOS_TMU_REG_INTEN,
114 .inten_rise_mask = EXYNOS_TMU_RISE_INT_MASK,
115 .inten_rise_shift = EXYNOS_TMU_RISE_INT_SHIFT,
116 .inten_fall_mask = EXYNOS_TMU_FALL_INT_MASK,
117 .inten_fall_shift = EXYNOS_TMU_FALL_INT_SHIFT,
118 .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
119 .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
120 .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT,
121 .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT,
122 .inten_fall0_shift = EXYNOS_TMU_INTEN_FALL0_SHIFT,
123 .tmu_intstat = EXYNOS_TMU_REG_INTSTAT,
124 .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
125 .emul_con = EXYNOS_EMUL_CON,
126 .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT,
127 .emul_time_shift = EXYNOS_EMUL_TIME_SHIFT,
128 .emul_time_mask = EXYNOS_EMUL_TIME_MASK,
129};
130
131#define EXYNOS5250_TMU_DATA \
132 .threshold_falling = 10, \
133 .trigger_levels[0] = 85, \
134 .trigger_levels[1] = 103, \
135 .trigger_levels[2] = 110, \
136 .trigger_levels[3] = 120, \
137 .trigger_enable[0] = true, \
138 .trigger_enable[1] = true, \
139 .trigger_enable[2] = true, \
140 .trigger_enable[3] = false, \
141 .trigger_type[0] = THROTTLE_ACTIVE, \
142 .trigger_type[1] = THROTTLE_ACTIVE, \
143 .trigger_type[2] = SW_TRIP, \
144 .trigger_type[3] = HW_TRIP, \
145 .max_trigger_level = 4, \
146 .gain = 8, \
147 .reference_voltage = 16, \
148 .noise_cancel_mode = 4, \
149 .cal_type = TYPE_ONE_POINT_TRIMMING, \
150 .efuse_value = 55, \
151 .min_efuse_value = 40, \
152 .max_efuse_value = 100, \
153 .first_point_trim = 25, \
154 .second_point_trim = 85, \
155 .default_temp_offset = 50, \
156 .freq_tab[0] = { \
157 .freq_clip_max = 800 * 1000, \
158 .temp_level = 85, \
159 }, \
160 .freq_tab[1] = { \
161 .freq_clip_max = 200 * 1000, \
162 .temp_level = 103, \
163 }, \
164 .freq_tab_count = 2, \
165 .type = SOC_ARCH_EXYNOS, \
166 .registers = &exynos5250_tmu_registers, \
167 .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_TRIM_RELOAD | \
168 TMU_SUPPORT_FALLING_TRIP | TMU_SUPPORT_READY_STATUS | \
169 TMU_SUPPORT_EMUL_TIME)
170
171struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
172 .tmu_data = {
173 { EXYNOS5250_TMU_DATA },
174 },
175 .tmu_count = 1,
176};
177#endif
178
179#if defined(CONFIG_SOC_EXYNOS5440)
180static const struct exynos_tmu_registers exynos5440_tmu_registers = {
181 .triminfo_data = EXYNOS5440_TMU_S0_7_TRIM,
182 .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
183 .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
184 .tmu_ctrl = EXYNOS5440_TMU_S0_7_CTRL,
185 .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
186 .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
187 .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT,
188 .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK,
189 .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT,
190 .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
191 .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
192 .calib_mode_shift = EXYNOS_TMU_CALIB_MODE_SHIFT,
193 .calib_mode_mask = EXYNOS_TMU_CALIB_MODE_MASK,
194 .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
195 .tmu_status = EXYNOS5440_TMU_S0_7_STATUS,
196 .tmu_cur_temp = EXYNOS5440_TMU_S0_7_TEMP,
197 .threshold_th0 = EXYNOS5440_TMU_S0_7_TH0,
198 .threshold_th1 = EXYNOS5440_TMU_S0_7_TH1,
199 .threshold_th2 = EXYNOS5440_TMU_S0_7_TH2,
200 .threshold_th3_l0_shift = EXYNOS5440_TMU_TH_RISE4_SHIFT,
201 .tmu_inten = EXYNOS5440_TMU_S0_7_IRQEN,
202 .inten_rise_mask = EXYNOS5440_TMU_RISE_INT_MASK,
203 .inten_rise_shift = EXYNOS5440_TMU_RISE_INT_SHIFT,
204 .inten_fall_mask = EXYNOS5440_TMU_FALL_INT_MASK,
205 .inten_fall_shift = EXYNOS5440_TMU_FALL_INT_SHIFT,
206 .inten_rise0_shift = EXYNOS5440_TMU_INTEN_RISE0_SHIFT,
207 .inten_rise1_shift = EXYNOS5440_TMU_INTEN_RISE1_SHIFT,
208 .inten_rise2_shift = EXYNOS5440_TMU_INTEN_RISE2_SHIFT,
209 .inten_rise3_shift = EXYNOS5440_TMU_INTEN_RISE3_SHIFT,
210 .inten_fall0_shift = EXYNOS5440_TMU_INTEN_FALL0_SHIFT,
211 .tmu_intstat = EXYNOS5440_TMU_S0_7_IRQ,
212 .tmu_intclear = EXYNOS5440_TMU_S0_7_IRQ,
213 .tmu_irqstatus = EXYNOS5440_TMU_IRQ_STATUS,
214 .emul_con = EXYNOS5440_TMU_S0_7_DEBUG,
215 .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT,
216 .tmu_pmin = EXYNOS5440_TMU_PMIN,
217};
218
219#define EXYNOS5440_TMU_DATA \
220 .trigger_levels[0] = 100, \
221 .trigger_levels[4] = 105, \
222 .trigger_enable[0] = 1, \
223 .trigger_type[0] = SW_TRIP, \
224 .trigger_type[4] = HW_TRIP, \
225 .max_trigger_level = 5, \
226 .gain = 5, \
227 .reference_voltage = 16, \
228 .noise_cancel_mode = 4, \
229 .cal_type = TYPE_ONE_POINT_TRIMMING, \
230 .cal_mode = 0, \
231 .efuse_value = 0x5b2d, \
232 .min_efuse_value = 16, \
233 .max_efuse_value = 76, \
234 .first_point_trim = 25, \
235 .second_point_trim = 70, \
236 .default_temp_offset = 25, \
237 .type = SOC_ARCH_EXYNOS5440, \
238 .registers = &exynos5440_tmu_registers, \
239 .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_FALLING_TRIP | \
240 TMU_SUPPORT_MULTI_INST | TMU_SUPPORT_SHARED_MEMORY),
241
242struct exynos_tmu_init_data const exynos5440_default_tmu_data = {
243 .tmu_data = {
244 { EXYNOS5440_TMU_DATA } ,
245 { EXYNOS5440_TMU_DATA } ,
246 { EXYNOS5440_TMU_DATA } ,
247 },
248 .tmu_count = 3,
249};
250#endif
diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
new file mode 100644
index 000000000000..dc7feb51099b
--- /dev/null
+++ b/drivers/thermal/samsung/exynos_tmu_data.h
@@ -0,0 +1,155 @@
1/*
2 * exynos_tmu_data.h - Samsung EXYNOS tmu data header file
3 *
4 * Copyright (C) 2013 Samsung Electronics
5 * Amit Daniel Kachhap <amit.daniel@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#ifndef _EXYNOS_TMU_DATA_H
24#define _EXYNOS_TMU_DATA_H
25
26/* Exynos generic registers */
27#define EXYNOS_TMU_REG_TRIMINFO 0x0
28#define EXYNOS_TMU_REG_CONTROL 0x20
29#define EXYNOS_TMU_REG_STATUS 0x28
30#define EXYNOS_TMU_REG_CURRENT_TEMP 0x40
31#define EXYNOS_TMU_REG_INTEN 0x70
32#define EXYNOS_TMU_REG_INTSTAT 0x74
33#define EXYNOS_TMU_REG_INTCLEAR 0x78
34
35#define EXYNOS_TMU_TEMP_MASK 0xff
36#define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24
37#define EXYNOS_TMU_REF_VOLTAGE_MASK 0x1f
38#define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
39#define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
40#define EXYNOS_TMU_CORE_EN_SHIFT 0
41
42/* Exynos4210 specific registers */
43#define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44
44#define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50
45#define EXYNOS4210_TMU_REG_TRIG_LEVEL1 0x54
46#define EXYNOS4210_TMU_REG_TRIG_LEVEL2 0x58
47#define EXYNOS4210_TMU_REG_TRIG_LEVEL3 0x5C
48#define EXYNOS4210_TMU_REG_PAST_TEMP0 0x60
49#define EXYNOS4210_TMU_REG_PAST_TEMP1 0x64
50#define EXYNOS4210_TMU_REG_PAST_TEMP2 0x68
51#define EXYNOS4210_TMU_REG_PAST_TEMP3 0x6C
52
53#define EXYNOS4210_TMU_TRIG_LEVEL0_MASK 0x1
54#define EXYNOS4210_TMU_TRIG_LEVEL1_MASK 0x10
55#define EXYNOS4210_TMU_TRIG_LEVEL2_MASK 0x100
56#define EXYNOS4210_TMU_TRIG_LEVEL3_MASK 0x1000
57#define EXYNOS4210_TMU_TRIG_LEVEL_MASK 0x1111
58#define EXYNOS4210_TMU_INTCLEAR_VAL 0x1111
59
60/* Exynos5250 and Exynos4412 specific registers */
61#define EXYNOS_TMU_TRIMINFO_CON 0x14
62#define EXYNOS_THD_TEMP_RISE 0x50
63#define EXYNOS_THD_TEMP_FALL 0x54
64#define EXYNOS_EMUL_CON 0x80
65
66#define EXYNOS_TRIMINFO_RELOAD_SHIFT 1
67#define EXYNOS_TRIMINFO_25_SHIFT 0
68#define EXYNOS_TRIMINFO_85_SHIFT 8
69#define EXYNOS_TMU_RISE_INT_MASK 0x111
70#define EXYNOS_TMU_RISE_INT_SHIFT 0
71#define EXYNOS_TMU_FALL_INT_MASK 0x111
72#define EXYNOS_TMU_FALL_INT_SHIFT 12
73#define EXYNOS_TMU_CLEAR_RISE_INT 0x111
74#define EXYNOS_TMU_CLEAR_FALL_INT (0x111 << 12)
75#define EXYNOS_TMU_TRIP_MODE_SHIFT 13
76#define EXYNOS_TMU_TRIP_MODE_MASK 0x7
77#define EXYNOS_TMU_THERM_TRIP_EN_SHIFT 12
78#define EXYNOS_TMU_CALIB_MODE_SHIFT 4
79#define EXYNOS_TMU_CALIB_MODE_MASK 0x3
80
81#define EXYNOS_TMU_INTEN_RISE0_SHIFT 0
82#define EXYNOS_TMU_INTEN_RISE1_SHIFT 4
83#define EXYNOS_TMU_INTEN_RISE2_SHIFT 8
84#define EXYNOS_TMU_INTEN_RISE3_SHIFT 12
85#define EXYNOS_TMU_INTEN_FALL0_SHIFT 16
86#define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
87#define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
88
89#define EXYNOS_EMUL_TIME 0x57F0
90#define EXYNOS_EMUL_TIME_MASK 0xffff
91#define EXYNOS_EMUL_TIME_SHIFT 16
92#define EXYNOS_EMUL_DATA_SHIFT 8
93#define EXYNOS_EMUL_DATA_MASK 0xFF
94#define EXYNOS_EMUL_ENABLE 0x1
95
96#define EXYNOS_MAX_TRIGGER_PER_REG 4
97
98/*exynos5440 specific registers*/
99#define EXYNOS5440_TMU_S0_7_TRIM 0x000
100#define EXYNOS5440_TMU_S0_7_CTRL 0x020
101#define EXYNOS5440_TMU_S0_7_DEBUG 0x040
102#define EXYNOS5440_TMU_S0_7_STATUS 0x060
103#define EXYNOS5440_TMU_S0_7_TEMP 0x0f0
104#define EXYNOS5440_TMU_S0_7_TH0 0x110
105#define EXYNOS5440_TMU_S0_7_TH1 0x130
106#define EXYNOS5440_TMU_S0_7_TH2 0x150
107#define EXYNOS5440_TMU_S0_7_EVTEN 0x1F0
108#define EXYNOS5440_TMU_S0_7_IRQEN 0x210
109#define EXYNOS5440_TMU_S0_7_IRQ 0x230
110/* exynos5440 common registers */
111#define EXYNOS5440_TMU_IRQ_STATUS 0x000
112#define EXYNOS5440_TMU_PMIN 0x004
113#define EXYNOS5440_TMU_TEMP 0x008
114
115#define EXYNOS5440_TMU_RISE_INT_MASK 0xf
116#define EXYNOS5440_TMU_RISE_INT_SHIFT 0
117#define EXYNOS5440_TMU_FALL_INT_MASK 0xf
118#define EXYNOS5440_TMU_FALL_INT_SHIFT 4
119#define EXYNOS5440_TMU_INTEN_RISE0_SHIFT 0
120#define EXYNOS5440_TMU_INTEN_RISE1_SHIFT 1
121#define EXYNOS5440_TMU_INTEN_RISE2_SHIFT 2
122#define EXYNOS5440_TMU_INTEN_RISE3_SHIFT 3
123#define EXYNOS5440_TMU_INTEN_FALL0_SHIFT 4
124#define EXYNOS5440_TMU_INTEN_FALL1_SHIFT 5
125#define EXYNOS5440_TMU_INTEN_FALL2_SHIFT 6
126#define EXYNOS5440_TMU_INTEN_FALL3_SHIFT 7
127#define EXYNOS5440_TMU_TH_RISE0_SHIFT 0
128#define EXYNOS5440_TMU_TH_RISE1_SHIFT 8
129#define EXYNOS5440_TMU_TH_RISE2_SHIFT 16
130#define EXYNOS5440_TMU_TH_RISE3_SHIFT 24
131#define EXYNOS5440_TMU_TH_RISE4_SHIFT 24
132#define EXYNOS5440_EFUSE_SWAP_OFFSET 8
133
134#if defined(CONFIG_CPU_EXYNOS4210)
135extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
136#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
137#else
138#define EXYNOS4210_TMU_DRV_DATA (NULL)
139#endif
140
141#if (defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412))
142extern struct exynos_tmu_init_data const exynos5250_default_tmu_data;
143#define EXYNOS5250_TMU_DRV_DATA (&exynos5250_default_tmu_data)
144#else
145#define EXYNOS5250_TMU_DRV_DATA (NULL)
146#endif
147
148#if defined(CONFIG_SOC_EXYNOS5440)
149extern struct exynos_tmu_init_data const exynos5440_default_tmu_data;
150#define EXYNOS5440_TMU_DRV_DATA (&exynos5440_default_tmu_data)
151#else
152#define EXYNOS5440_TMU_DRV_DATA (NULL)
153#endif
154
155#endif /*_EXYNOS_TMU_DATA_H*/
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
index 4d4ddae1a991..d89e781b0a18 100644
--- a/drivers/thermal/step_wise.c
+++ b/drivers/thermal/step_wise.c
@@ -51,44 +51,51 @@ static unsigned long get_target_state(struct thermal_instance *instance,
51{ 51{
52 struct thermal_cooling_device *cdev = instance->cdev; 52 struct thermal_cooling_device *cdev = instance->cdev;
53 unsigned long cur_state; 53 unsigned long cur_state;
54 unsigned long next_target;
54 55
56 /*
57 * We keep this instance the way it is by default.
58 * Otherwise, we use the current state of the
59 * cdev in use to determine the next_target.
60 */
55 cdev->ops->get_cur_state(cdev, &cur_state); 61 cdev->ops->get_cur_state(cdev, &cur_state);
62 next_target = instance->target;
56 63
57 switch (trend) { 64 switch (trend) {
58 case THERMAL_TREND_RAISING: 65 case THERMAL_TREND_RAISING:
59 if (throttle) { 66 if (throttle) {
60 cur_state = cur_state < instance->upper ? 67 next_target = cur_state < instance->upper ?
61 (cur_state + 1) : instance->upper; 68 (cur_state + 1) : instance->upper;
62 if (cur_state < instance->lower) 69 if (next_target < instance->lower)
63 cur_state = instance->lower; 70 next_target = instance->lower;
64 } 71 }
65 break; 72 break;
66 case THERMAL_TREND_RAISE_FULL: 73 case THERMAL_TREND_RAISE_FULL:
67 if (throttle) 74 if (throttle)
68 cur_state = instance->upper; 75 next_target = instance->upper;
69 break; 76 break;
70 case THERMAL_TREND_DROPPING: 77 case THERMAL_TREND_DROPPING:
71 if (cur_state == instance->lower) { 78 if (cur_state == instance->lower) {
72 if (!throttle) 79 if (!throttle)
73 cur_state = -1; 80 next_target = THERMAL_NO_TARGET;
74 } else { 81 } else {
75 cur_state -= 1; 82 next_target = cur_state - 1;
76 if (cur_state > instance->upper) 83 if (next_target > instance->upper)
77 cur_state = instance->upper; 84 next_target = instance->upper;
78 } 85 }
79 break; 86 break;
80 case THERMAL_TREND_DROP_FULL: 87 case THERMAL_TREND_DROP_FULL:
81 if (cur_state == instance->lower) { 88 if (cur_state == instance->lower) {
82 if (!throttle) 89 if (!throttle)
83 cur_state = -1; 90 next_target = THERMAL_NO_TARGET;
84 } else 91 } else
85 cur_state = instance->lower; 92 next_target = instance->lower;
86 break; 93 break;
87 default: 94 default:
88 break; 95 break;
89 } 96 }
90 97
91 return cur_state; 98 return next_target;
92} 99}
93 100
94static void update_passive_instance(struct thermal_zone_device *tz, 101static void update_passive_instance(struct thermal_zone_device *tz,
@@ -133,6 +140,9 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
133 old_target = instance->target; 140 old_target = instance->target;
134 instance->target = get_target_state(instance, trend, throttle); 141 instance->target = get_target_state(instance, trend, throttle);
135 142
143 if (old_target == instance->target)
144 continue;
145
136 /* Activate a passive thermal instance */ 146 /* Activate a passive thermal instance */
137 if (old_target == THERMAL_NO_TARGET && 147 if (old_target == THERMAL_NO_TARGET &&
138 instance->target != THERMAL_NO_TARGET) 148 instance->target != THERMAL_NO_TARGET)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 1f02e8edb45c..4962a6aaf295 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -38,6 +38,7 @@
38#include <net/genetlink.h> 38#include <net/genetlink.h>
39 39
40#include "thermal_core.h" 40#include "thermal_core.h"
41#include "thermal_hwmon.h"
41 42
42MODULE_AUTHOR("Zhang Rui"); 43MODULE_AUTHOR("Zhang Rui");
43MODULE_DESCRIPTION("Generic thermal management sysfs support"); 44MODULE_DESCRIPTION("Generic thermal management sysfs support");
@@ -201,14 +202,23 @@ static void print_bind_err_msg(struct thermal_zone_device *tz,
201} 202}
202 203
203static void __bind(struct thermal_zone_device *tz, int mask, 204static void __bind(struct thermal_zone_device *tz, int mask,
204 struct thermal_cooling_device *cdev) 205 struct thermal_cooling_device *cdev,
206 unsigned long *limits)
205{ 207{
206 int i, ret; 208 int i, ret;
207 209
208 for (i = 0; i < tz->trips; i++) { 210 for (i = 0; i < tz->trips; i++) {
209 if (mask & (1 << i)) { 211 if (mask & (1 << i)) {
212 unsigned long upper, lower;
213
214 upper = THERMAL_NO_LIMIT;
215 lower = THERMAL_NO_LIMIT;
216 if (limits) {
217 lower = limits[i * 2];
218 upper = limits[i * 2 + 1];
219 }
210 ret = thermal_zone_bind_cooling_device(tz, i, cdev, 220 ret = thermal_zone_bind_cooling_device(tz, i, cdev,
211 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT); 221 upper, lower);
212 if (ret) 222 if (ret)
213 print_bind_err_msg(tz, cdev, ret); 223 print_bind_err_msg(tz, cdev, ret);
214 } 224 }
@@ -253,7 +263,8 @@ static void bind_cdev(struct thermal_cooling_device *cdev)
253 if (tzp->tbp[i].match(pos, cdev)) 263 if (tzp->tbp[i].match(pos, cdev))
254 continue; 264 continue;
255 tzp->tbp[i].cdev = cdev; 265 tzp->tbp[i].cdev = cdev;
256 __bind(pos, tzp->tbp[i].trip_mask, cdev); 266 __bind(pos, tzp->tbp[i].trip_mask, cdev,
267 tzp->tbp[i].binding_limits);
257 } 268 }
258 } 269 }
259 270
@@ -291,7 +302,8 @@ static void bind_tz(struct thermal_zone_device *tz)
291 if (tzp->tbp[i].match(tz, pos)) 302 if (tzp->tbp[i].match(tz, pos))
292 continue; 303 continue;
293 tzp->tbp[i].cdev = pos; 304 tzp->tbp[i].cdev = pos;
294 __bind(tz, tzp->tbp[i].trip_mask, pos); 305 __bind(tz, tzp->tbp[i].trip_mask, pos,
306 tzp->tbp[i].binding_limits);
295 } 307 }
296 } 308 }
297exit: 309exit:
@@ -859,260 +871,6 @@ thermal_cooling_device_trip_point_show(struct device *dev,
859 871
860/* Device management */ 872/* Device management */
861 873
862#if defined(CONFIG_THERMAL_HWMON)
863
864/* hwmon sys I/F */
865#include <linux/hwmon.h>
866
867/* thermal zone devices with the same type share one hwmon device */
868struct thermal_hwmon_device {
869 char type[THERMAL_NAME_LENGTH];
870 struct device *device;
871 int count;
872 struct list_head tz_list;
873 struct list_head node;
874};
875
876struct thermal_hwmon_attr {
877 struct device_attribute attr;
878 char name[16];
879};
880
881/* one temperature input for each thermal zone */
882struct thermal_hwmon_temp {
883 struct list_head hwmon_node;
884 struct thermal_zone_device *tz;
885 struct thermal_hwmon_attr temp_input; /* hwmon sys attr */
886 struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */
887};
888
889static LIST_HEAD(thermal_hwmon_list);
890
891static ssize_t
892name_show(struct device *dev, struct device_attribute *attr, char *buf)
893{
894 struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
895 return sprintf(buf, "%s\n", hwmon->type);
896}
897static DEVICE_ATTR(name, 0444, name_show, NULL);
898
899static ssize_t
900temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
901{
902 long temperature;
903 int ret;
904 struct thermal_hwmon_attr *hwmon_attr
905 = container_of(attr, struct thermal_hwmon_attr, attr);
906 struct thermal_hwmon_temp *temp
907 = container_of(hwmon_attr, struct thermal_hwmon_temp,
908 temp_input);
909 struct thermal_zone_device *tz = temp->tz;
910
911 ret = thermal_zone_get_temp(tz, &temperature);
912
913 if (ret)
914 return ret;
915
916 return sprintf(buf, "%ld\n", temperature);
917}
918
919static ssize_t
920temp_crit_show(struct device *dev, struct device_attribute *attr,
921 char *buf)
922{
923 struct thermal_hwmon_attr *hwmon_attr
924 = container_of(attr, struct thermal_hwmon_attr, attr);
925 struct thermal_hwmon_temp *temp
926 = container_of(hwmon_attr, struct thermal_hwmon_temp,
927 temp_crit);
928 struct thermal_zone_device *tz = temp->tz;
929 long temperature;
930 int ret;
931
932 ret = tz->ops->get_trip_temp(tz, 0, &temperature);
933 if (ret)
934 return ret;
935
936 return sprintf(buf, "%ld\n", temperature);
937}
938
939
940static struct thermal_hwmon_device *
941thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
942{
943 struct thermal_hwmon_device *hwmon;
944
945 mutex_lock(&thermal_list_lock);
946 list_for_each_entry(hwmon, &thermal_hwmon_list, node)
947 if (!strcmp(hwmon->type, tz->type)) {
948 mutex_unlock(&thermal_list_lock);
949 return hwmon;
950 }
951 mutex_unlock(&thermal_list_lock);
952
953 return NULL;
954}
955
956/* Find the temperature input matching a given thermal zone */
957static struct thermal_hwmon_temp *
958thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
959 const struct thermal_zone_device *tz)
960{
961 struct thermal_hwmon_temp *temp;
962
963 mutex_lock(&thermal_list_lock);
964 list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
965 if (temp->tz == tz) {
966 mutex_unlock(&thermal_list_lock);
967 return temp;
968 }
969 mutex_unlock(&thermal_list_lock);
970
971 return NULL;
972}
973
974static int
975thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
976{
977 struct thermal_hwmon_device *hwmon;
978 struct thermal_hwmon_temp *temp;
979 int new_hwmon_device = 1;
980 int result;
981
982 hwmon = thermal_hwmon_lookup_by_type(tz);
983 if (hwmon) {
984 new_hwmon_device = 0;
985 goto register_sys_interface;
986 }
987
988 hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
989 if (!hwmon)
990 return -ENOMEM;
991
992 INIT_LIST_HEAD(&hwmon->tz_list);
993 strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
994 hwmon->device = hwmon_device_register(NULL);
995 if (IS_ERR(hwmon->device)) {
996 result = PTR_ERR(hwmon->device);
997 goto free_mem;
998 }
999 dev_set_drvdata(hwmon->device, hwmon);
1000 result = device_create_file(hwmon->device, &dev_attr_name);
1001 if (result)
1002 goto free_mem;
1003
1004 register_sys_interface:
1005 temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
1006 if (!temp) {
1007 result = -ENOMEM;
1008 goto unregister_name;
1009 }
1010
1011 temp->tz = tz;
1012 hwmon->count++;
1013
1014 snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
1015 "temp%d_input", hwmon->count);
1016 temp->temp_input.attr.attr.name = temp->temp_input.name;
1017 temp->temp_input.attr.attr.mode = 0444;
1018 temp->temp_input.attr.show = temp_input_show;
1019 sysfs_attr_init(&temp->temp_input.attr.attr);
1020 result = device_create_file(hwmon->device, &temp->temp_input.attr);
1021 if (result)
1022 goto free_temp_mem;
1023
1024 if (tz->ops->get_crit_temp) {
1025 unsigned long temperature;
1026 if (!tz->ops->get_crit_temp(tz, &temperature)) {
1027 snprintf(temp->temp_crit.name,
1028 sizeof(temp->temp_crit.name),
1029 "temp%d_crit", hwmon->count);
1030 temp->temp_crit.attr.attr.name = temp->temp_crit.name;
1031 temp->temp_crit.attr.attr.mode = 0444;
1032 temp->temp_crit.attr.show = temp_crit_show;
1033 sysfs_attr_init(&temp->temp_crit.attr.attr);
1034 result = device_create_file(hwmon->device,
1035 &temp->temp_crit.attr);
1036 if (result)
1037 goto unregister_input;
1038 }
1039 }
1040
1041 mutex_lock(&thermal_list_lock);
1042 if (new_hwmon_device)
1043 list_add_tail(&hwmon->node, &thermal_hwmon_list);
1044 list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
1045 mutex_unlock(&thermal_list_lock);
1046
1047 return 0;
1048
1049 unregister_input:
1050 device_remove_file(hwmon->device, &temp->temp_input.attr);
1051 free_temp_mem:
1052 kfree(temp);
1053 unregister_name:
1054 if (new_hwmon_device) {
1055 device_remove_file(hwmon->device, &dev_attr_name);
1056 hwmon_device_unregister(hwmon->device);
1057 }
1058 free_mem:
1059 if (new_hwmon_device)
1060 kfree(hwmon);
1061
1062 return result;
1063}
1064
1065static void
1066thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
1067{
1068 struct thermal_hwmon_device *hwmon;
1069 struct thermal_hwmon_temp *temp;
1070
1071 hwmon = thermal_hwmon_lookup_by_type(tz);
1072 if (unlikely(!hwmon)) {
1073 /* Should never happen... */
1074 dev_dbg(&tz->device, "hwmon device lookup failed!\n");
1075 return;
1076 }
1077
1078 temp = thermal_hwmon_lookup_temp(hwmon, tz);
1079 if (unlikely(!temp)) {
1080 /* Should never happen... */
1081 dev_dbg(&tz->device, "temperature input lookup failed!\n");
1082 return;
1083 }
1084
1085 device_remove_file(hwmon->device, &temp->temp_input.attr);
1086 if (tz->ops->get_crit_temp)
1087 device_remove_file(hwmon->device, &temp->temp_crit.attr);
1088
1089 mutex_lock(&thermal_list_lock);
1090 list_del(&temp->hwmon_node);
1091 kfree(temp);
1092 if (!list_empty(&hwmon->tz_list)) {
1093 mutex_unlock(&thermal_list_lock);
1094 return;
1095 }
1096 list_del(&hwmon->node);
1097 mutex_unlock(&thermal_list_lock);
1098
1099 device_remove_file(hwmon->device, &dev_attr_name);
1100 hwmon_device_unregister(hwmon->device);
1101 kfree(hwmon);
1102}
1103#else
1104static int
1105thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
1106{
1107 return 0;
1108}
1109
1110static void
1111thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
1112{
1113}
1114#endif
1115
1116/** 874/**
1117 * thermal_zone_bind_cooling_device() - bind a cooling device to a thermal zone 875 * thermal_zone_bind_cooling_device() - bind a cooling device to a thermal zone
1118 * @tz: pointer to struct thermal_zone_device 876 * @tz: pointer to struct thermal_zone_device
@@ -1715,9 +1473,11 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
1715 1473
1716 mutex_unlock(&thermal_governor_lock); 1474 mutex_unlock(&thermal_governor_lock);
1717 1475
1718 result = thermal_add_hwmon_sysfs(tz); 1476 if (!tz->tzp || !tz->tzp->no_hwmon) {
1719 if (result) 1477 result = thermal_add_hwmon_sysfs(tz);
1720 goto unregister; 1478 if (result)
1479 goto unregister;
1480 }
1721 1481
1722 mutex_lock(&thermal_list_lock); 1482 mutex_lock(&thermal_list_lock);
1723 list_add_tail(&tz->node, &thermal_tz_list); 1483 list_add_tail(&tz->node, &thermal_tz_list);
diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c
new file mode 100644
index 000000000000..eeef0e2498ca
--- /dev/null
+++ b/drivers/thermal/thermal_hwmon.c
@@ -0,0 +1,269 @@
1/*
2 * thermal_hwmon.c - Generic Thermal Management hwmon support.
3 *
4 * Code based on Intel thermal_core.c. Copyrights of the original code:
5 * Copyright (C) 2008 Intel Corp
6 * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
7 * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
8 *
9 * Copyright (C) 2013 Texas Instruments
10 * Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com>
11 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; version 2 of the License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 *
26 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27 */
28#include <linux/hwmon.h>
29#include <linux/thermal.h>
30#include <linux/slab.h>
31#include <linux/err.h>
32#include "thermal_hwmon.h"
33
34/* hwmon sys I/F */
35/* thermal zone devices with the same type share one hwmon device */
36struct thermal_hwmon_device {
37 char type[THERMAL_NAME_LENGTH];
38 struct device *device;
39 int count;
40 struct list_head tz_list;
41 struct list_head node;
42};
43
44struct thermal_hwmon_attr {
45 struct device_attribute attr;
46 char name[16];
47};
48
49/* one temperature input for each thermal zone */
50struct thermal_hwmon_temp {
51 struct list_head hwmon_node;
52 struct thermal_zone_device *tz;
53 struct thermal_hwmon_attr temp_input; /* hwmon sys attr */
54 struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */
55};
56
57static LIST_HEAD(thermal_hwmon_list);
58
59static DEFINE_MUTEX(thermal_hwmon_list_lock);
60
61static ssize_t
62name_show(struct device *dev, struct device_attribute *attr, char *buf)
63{
64 struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
65 return sprintf(buf, "%s\n", hwmon->type);
66}
67static DEVICE_ATTR(name, 0444, name_show, NULL);
68
69static ssize_t
70temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
71{
72 long temperature;
73 int ret;
74 struct thermal_hwmon_attr *hwmon_attr
75 = container_of(attr, struct thermal_hwmon_attr, attr);
76 struct thermal_hwmon_temp *temp
77 = container_of(hwmon_attr, struct thermal_hwmon_temp,
78 temp_input);
79 struct thermal_zone_device *tz = temp->tz;
80
81 ret = thermal_zone_get_temp(tz, &temperature);
82
83 if (ret)
84 return ret;
85
86 return sprintf(buf, "%ld\n", temperature);
87}
88
89static ssize_t
90temp_crit_show(struct device *dev, struct device_attribute *attr, char *buf)
91{
92 struct thermal_hwmon_attr *hwmon_attr
93 = container_of(attr, struct thermal_hwmon_attr, attr);
94 struct thermal_hwmon_temp *temp
95 = container_of(hwmon_attr, struct thermal_hwmon_temp,
96 temp_crit);
97 struct thermal_zone_device *tz = temp->tz;
98 long temperature;
99 int ret;
100
101 ret = tz->ops->get_trip_temp(tz, 0, &temperature);
102 if (ret)
103 return ret;
104
105 return sprintf(buf, "%ld\n", temperature);
106}
107
108
109static struct thermal_hwmon_device *
110thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
111{
112 struct thermal_hwmon_device *hwmon;
113
114 mutex_lock(&thermal_hwmon_list_lock);
115 list_for_each_entry(hwmon, &thermal_hwmon_list, node)
116 if (!strcmp(hwmon->type, tz->type)) {
117 mutex_unlock(&thermal_hwmon_list_lock);
118 return hwmon;
119 }
120 mutex_unlock(&thermal_hwmon_list_lock);
121
122 return NULL;
123}
124
125/* Find the temperature input matching a given thermal zone */
126static struct thermal_hwmon_temp *
127thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
128 const struct thermal_zone_device *tz)
129{
130 struct thermal_hwmon_temp *temp;
131
132 mutex_lock(&thermal_hwmon_list_lock);
133 list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
134 if (temp->tz == tz) {
135 mutex_unlock(&thermal_hwmon_list_lock);
136 return temp;
137 }
138 mutex_unlock(&thermal_hwmon_list_lock);
139
140 return NULL;
141}
142
143int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
144{
145 struct thermal_hwmon_device *hwmon;
146 struct thermal_hwmon_temp *temp;
147 int new_hwmon_device = 1;
148 int result;
149
150 hwmon = thermal_hwmon_lookup_by_type(tz);
151 if (hwmon) {
152 new_hwmon_device = 0;
153 goto register_sys_interface;
154 }
155
156 hwmon = kzalloc(sizeof(*hwmon), GFP_KERNEL);
157 if (!hwmon)
158 return -ENOMEM;
159
160 INIT_LIST_HEAD(&hwmon->tz_list);
161 strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
162 hwmon->device = hwmon_device_register(&tz->device);
163 if (IS_ERR(hwmon->device)) {
164 result = PTR_ERR(hwmon->device);
165 goto free_mem;
166 }
167 dev_set_drvdata(hwmon->device, hwmon);
168 result = device_create_file(hwmon->device, &dev_attr_name);
169 if (result)
170 goto free_mem;
171
172 register_sys_interface:
173 temp = kzalloc(sizeof(*temp), GFP_KERNEL);
174 if (!temp) {
175 result = -ENOMEM;
176 goto unregister_name;
177 }
178
179 temp->tz = tz;
180 hwmon->count++;
181
182 snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
183 "temp%d_input", hwmon->count);
184 temp->temp_input.attr.attr.name = temp->temp_input.name;
185 temp->temp_input.attr.attr.mode = 0444;
186 temp->temp_input.attr.show = temp_input_show;
187 sysfs_attr_init(&temp->temp_input.attr.attr);
188 result = device_create_file(hwmon->device, &temp->temp_input.attr);
189 if (result)
190 goto free_temp_mem;
191
192 if (tz->ops->get_crit_temp) {
193 unsigned long temperature;
194 if (!tz->ops->get_crit_temp(tz, &temperature)) {
195 snprintf(temp->temp_crit.name,
196 sizeof(temp->temp_crit.name),
197 "temp%d_crit", hwmon->count);
198 temp->temp_crit.attr.attr.name = temp->temp_crit.name;
199 temp->temp_crit.attr.attr.mode = 0444;
200 temp->temp_crit.attr.show = temp_crit_show;
201 sysfs_attr_init(&temp->temp_crit.attr.attr);
202 result = device_create_file(hwmon->device,
203 &temp->temp_crit.attr);
204 if (result)
205 goto unregister_input;
206 }
207 }
208
209 mutex_lock(&thermal_hwmon_list_lock);
210 if (new_hwmon_device)
211 list_add_tail(&hwmon->node, &thermal_hwmon_list);
212 list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
213 mutex_unlock(&thermal_hwmon_list_lock);
214
215 return 0;
216
217 unregister_input:
218 device_remove_file(hwmon->device, &temp->temp_input.attr);
219 free_temp_mem:
220 kfree(temp);
221 unregister_name:
222 if (new_hwmon_device) {
223 device_remove_file(hwmon->device, &dev_attr_name);
224 hwmon_device_unregister(hwmon->device);
225 }
226 free_mem:
227 if (new_hwmon_device)
228 kfree(hwmon);
229
230 return result;
231}
232
233void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
234{
235 struct thermal_hwmon_device *hwmon;
236 struct thermal_hwmon_temp *temp;
237
238 hwmon = thermal_hwmon_lookup_by_type(tz);
239 if (unlikely(!hwmon)) {
240 /* Should never happen... */
241 dev_dbg(&tz->device, "hwmon device lookup failed!\n");
242 return;
243 }
244
245 temp = thermal_hwmon_lookup_temp(hwmon, tz);
246 if (unlikely(!temp)) {
247 /* Should never happen... */
248 dev_dbg(&tz->device, "temperature input lookup failed!\n");
249 return;
250 }
251
252 device_remove_file(hwmon->device, &temp->temp_input.attr);
253 if (tz->ops->get_crit_temp)
254 device_remove_file(hwmon->device, &temp->temp_crit.attr);
255
256 mutex_lock(&thermal_hwmon_list_lock);
257 list_del(&temp->hwmon_node);
258 kfree(temp);
259 if (!list_empty(&hwmon->tz_list)) {
260 mutex_unlock(&thermal_hwmon_list_lock);
261 return;
262 }
263 list_del(&hwmon->node);
264 mutex_unlock(&thermal_hwmon_list_lock);
265
266 device_remove_file(hwmon->device, &dev_attr_name);
267 hwmon_device_unregister(hwmon->device);
268 kfree(hwmon);
269}
diff --git a/drivers/thermal/thermal_hwmon.h b/drivers/thermal/thermal_hwmon.h
new file mode 100644
index 000000000000..c798fdb2ae43
--- /dev/null
+++ b/drivers/thermal/thermal_hwmon.h
@@ -0,0 +1,49 @@
1/*
2 * thermal_hwmon.h - Generic Thermal Management hwmon support.
3 *
4 * Code based on Intel thermal_core.c. Copyrights of the original code:
5 * Copyright (C) 2008 Intel Corp
6 * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
7 * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
8 *
9 * Copyright (C) 2013 Texas Instruments
10 * Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com>
11 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; version 2 of the License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 *
26 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27 */
28#ifndef __THERMAL_HWMON_H__
29#define __THERMAL_HWMON_H__
30
31#include <linux/thermal.h>
32
33#ifdef CONFIG_THERMAL_HWMON
34int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz);
35void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz);
36#else
37static int
38thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
39{
40 return 0;
41}
42
43static void
44thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
45{
46}
47#endif
48
49#endif /* __THERMAL_HWMON_H__ */
diff --git a/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c b/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
index e5d8326a54d6..a4929272074f 100644
--- a/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
+++ b/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
@@ -42,6 +42,7 @@ dra752_core_temp_sensor_registers = {
42 .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_CORE_MASK, 42 .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_CORE_MASK,
43 .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_CORE_MASK, 43 .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_CORE_MASK,
44 .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK, 44 .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
45 .mask_counter_delay_mask = DRA752_BANDGAP_CTRL_1_COUNTER_DELAY_MASK,
45 .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_CORE_MASK, 46 .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_CORE_MASK,
46 .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_CORE_MASK, 47 .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_CORE_MASK,
47 .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_CORE_MASK, 48 .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_CORE_MASK,
@@ -77,6 +78,7 @@ dra752_iva_temp_sensor_registers = {
77 .mask_hot_mask = DRA752_BANDGAP_CTRL_2_MASK_HOT_IVA_MASK, 78 .mask_hot_mask = DRA752_BANDGAP_CTRL_2_MASK_HOT_IVA_MASK,
78 .mask_cold_mask = DRA752_BANDGAP_CTRL_2_MASK_COLD_IVA_MASK, 79 .mask_cold_mask = DRA752_BANDGAP_CTRL_2_MASK_COLD_IVA_MASK,
79 .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK, 80 .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
81 .mask_counter_delay_mask = DRA752_BANDGAP_CTRL_1_COUNTER_DELAY_MASK,
80 .mask_freeze_mask = DRA752_BANDGAP_CTRL_2_FREEZE_IVA_MASK, 82 .mask_freeze_mask = DRA752_BANDGAP_CTRL_2_FREEZE_IVA_MASK,
81 .mask_clear_mask = DRA752_BANDGAP_CTRL_2_CLEAR_IVA_MASK, 83 .mask_clear_mask = DRA752_BANDGAP_CTRL_2_CLEAR_IVA_MASK,
82 .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_IVA_MASK, 84 .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_IVA_MASK,
@@ -112,6 +114,7 @@ dra752_mpu_temp_sensor_registers = {
112 .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_MPU_MASK, 114 .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_MPU_MASK,
113 .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_MPU_MASK, 115 .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_MPU_MASK,
114 .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK, 116 .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
117 .mask_counter_delay_mask = DRA752_BANDGAP_CTRL_1_COUNTER_DELAY_MASK,
115 .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_MPU_MASK, 118 .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_MPU_MASK,
116 .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_MPU_MASK, 119 .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_MPU_MASK,
117 .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_MPU_MASK, 120 .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_MPU_MASK,
@@ -147,6 +150,7 @@ dra752_dspeve_temp_sensor_registers = {
147 .mask_hot_mask = DRA752_BANDGAP_CTRL_2_MASK_HOT_DSPEVE_MASK, 150 .mask_hot_mask = DRA752_BANDGAP_CTRL_2_MASK_HOT_DSPEVE_MASK,
148 .mask_cold_mask = DRA752_BANDGAP_CTRL_2_MASK_COLD_DSPEVE_MASK, 151 .mask_cold_mask = DRA752_BANDGAP_CTRL_2_MASK_COLD_DSPEVE_MASK,
149 .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK, 152 .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
153 .mask_counter_delay_mask = DRA752_BANDGAP_CTRL_1_COUNTER_DELAY_MASK,
150 .mask_freeze_mask = DRA752_BANDGAP_CTRL_2_FREEZE_DSPEVE_MASK, 154 .mask_freeze_mask = DRA752_BANDGAP_CTRL_2_FREEZE_DSPEVE_MASK,
151 .mask_clear_mask = DRA752_BANDGAP_CTRL_2_CLEAR_DSPEVE_MASK, 155 .mask_clear_mask = DRA752_BANDGAP_CTRL_2_CLEAR_DSPEVE_MASK,
152 .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_DSPEVE_MASK, 156 .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_DSPEVE_MASK,
@@ -182,6 +186,7 @@ dra752_gpu_temp_sensor_registers = {
182 .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_GPU_MASK, 186 .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_GPU_MASK,
183 .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_GPU_MASK, 187 .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_GPU_MASK,
184 .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK, 188 .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
189 .mask_counter_delay_mask = DRA752_BANDGAP_CTRL_1_COUNTER_DELAY_MASK,
185 .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_GPU_MASK, 190 .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_GPU_MASK,
186 .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_GPU_MASK, 191 .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_GPU_MASK,
187 .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_GPU_MASK, 192 .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_GPU_MASK,
diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.c b/drivers/thermal/ti-soc-thermal/ti-bandgap.c
index 9dfd47196e63..74c0e3474d6e 100644
--- a/drivers/thermal/ti-soc-thermal/ti-bandgap.c
+++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.c
@@ -1020,9 +1020,13 @@ int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
1020 1020
1021 /* Fetch the update interval */ 1021 /* Fetch the update interval */
1022 ret = ti_bandgap_read_update_interval(bgp, id, &interval); 1022 ret = ti_bandgap_read_update_interval(bgp, id, &interval);
1023 if (ret || !interval) 1023 if (ret)
1024 goto unfreeze; 1024 goto unfreeze;
1025 1025
1026 /* Set the interval to 1 ms if bandgap counter delay is not set */
1027 if (interval == 0)
1028 interval = 1;
1029
1026 *trend = (t1 - t2) / interval; 1030 *trend = (t1 - t2) / interval;
1027 1031
1028 dev_dbg(bgp->dev, "The temperatures are t1 = %d and t2 = %d and trend =%d\n", 1032 dev_dbg(bgp->dev, "The temperatures are t1 = %d and t2 = %d and trend =%d\n",
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
index 4c5f55c37349..4f8b9af54a5a 100644
--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
@@ -174,6 +174,9 @@ static int ti_thermal_set_mode(struct thermal_zone_device *thermal,
174 enum thermal_device_mode mode) 174 enum thermal_device_mode mode)
175{ 175{
176 struct ti_thermal_data *data = thermal->devdata; 176 struct ti_thermal_data *data = thermal->devdata;
177 struct ti_bandgap *bgp;
178
179 bgp = data->bgp;
177 180
178 if (!data->ti_thermal) { 181 if (!data->ti_thermal) {
179 dev_notice(&thermal->device, "thermal zone not registered\n"); 182 dev_notice(&thermal->device, "thermal zone not registered\n");
@@ -190,6 +193,8 @@ static int ti_thermal_set_mode(struct thermal_zone_device *thermal,
190 mutex_unlock(&data->ti_thermal->lock); 193 mutex_unlock(&data->ti_thermal->lock);
191 194
192 data->mode = mode; 195 data->mode = mode;
196 ti_bandgap_write_update_interval(bgp, data->sensor_id,
197 data->ti_thermal->polling_delay);
193 thermal_zone_device_update(data->ti_thermal); 198 thermal_zone_device_update(data->ti_thermal);
194 dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n", 199 dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n",
195 data->ti_thermal->polling_delay); 200 data->ti_thermal->polling_delay);
@@ -313,6 +318,8 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
313 } 318 }
314 data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE; 319 data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
315 ti_bandgap_set_sensor_data(bgp, id, data); 320 ti_bandgap_set_sensor_data(bgp, id, data);
321 ti_bandgap_write_update_interval(bgp, data->sensor_id,
322 data->ti_thermal->polling_delay);
316 323
317 return 0; 324 return 0;
318} 325}
diff --git a/include/linux/platform_data/exynos_thermal.h b/include/linux/platform_data/exynos_thermal.h
deleted file mode 100644
index da7e6274b175..000000000000
--- a/include/linux/platform_data/exynos_thermal.h
+++ /dev/null
@@ -1,119 +0,0 @@
1/*
2 * exynos_thermal.h - Samsung EXYNOS TMU (Thermal Management Unit)
3 *
4 * Copyright (C) 2011 Samsung Electronics
5 * Donggeun Kim <dg77.kim@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#ifndef _LINUX_EXYNOS_THERMAL_H
23#define _LINUX_EXYNOS_THERMAL_H
24#include <linux/cpu_cooling.h>
25
26enum calibration_type {
27 TYPE_ONE_POINT_TRIMMING,
28 TYPE_TWO_POINT_TRIMMING,
29 TYPE_NONE,
30};
31
32enum soc_type {
33 SOC_ARCH_EXYNOS4210 = 1,
34 SOC_ARCH_EXYNOS,
35};
36/**
37 * struct freq_clip_table
38 * @freq_clip_max: maximum frequency allowed for this cooling state.
39 * @temp_level: Temperature level at which the temperature clipping will
40 * happen.
41 * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
42 *
43 * This structure is required to be filled and passed to the
44 * cpufreq_cooling_unregister function.
45 */
46struct freq_clip_table {
47 unsigned int freq_clip_max;
48 unsigned int temp_level;
49 const struct cpumask *mask_val;
50};
51
52/**
53 * struct exynos_tmu_platform_data
54 * @threshold: basic temperature for generating interrupt
55 * 25 <= threshold <= 125 [unit: degree Celsius]
56 * @threshold_falling: differntial value for setting threshold
57 * of temperature falling interrupt.
58 * @trigger_levels: array for each interrupt levels
59 * [unit: degree Celsius]
60 * 0: temperature for trigger_level0 interrupt
61 * condition for trigger_level0 interrupt:
62 * current temperature > threshold + trigger_levels[0]
63 * 1: temperature for trigger_level1 interrupt
64 * condition for trigger_level1 interrupt:
65 * current temperature > threshold + trigger_levels[1]
66 * 2: temperature for trigger_level2 interrupt
67 * condition for trigger_level2 interrupt:
68 * current temperature > threshold + trigger_levels[2]
69 * 3: temperature for trigger_level3 interrupt
70 * condition for trigger_level3 interrupt:
71 * current temperature > threshold + trigger_levels[3]
72 * @trigger_level0_en:
73 * 1 = enable trigger_level0 interrupt,
74 * 0 = disable trigger_level0 interrupt
75 * @trigger_level1_en:
76 * 1 = enable trigger_level1 interrupt,
77 * 0 = disable trigger_level1 interrupt
78 * @trigger_level2_en:
79 * 1 = enable trigger_level2 interrupt,
80 * 0 = disable trigger_level2 interrupt
81 * @trigger_level3_en:
82 * 1 = enable trigger_level3 interrupt,
83 * 0 = disable trigger_level3 interrupt
84 * @gain: gain of amplifier in the positive-TC generator block
85 * 0 <= gain <= 15
86 * @reference_voltage: reference voltage of amplifier
87 * in the positive-TC generator block
88 * 0 <= reference_voltage <= 31
89 * @noise_cancel_mode: noise cancellation mode
90 * 000, 100, 101, 110 and 111 can be different modes
91 * @type: determines the type of SOC
92 * @efuse_value: platform defined fuse value
93 * @cal_type: calibration type for temperature
94 * @freq_clip_table: Table representing frequency reduction percentage.
95 * @freq_tab_count: Count of the above table as frequency reduction may
96 * applicable to only some of the trigger levels.
97 *
98 * This structure is required for configuration of exynos_tmu driver.
99 */
100struct exynos_tmu_platform_data {
101 u8 threshold;
102 u8 threshold_falling;
103 u8 trigger_levels[4];
104 bool trigger_level0_en;
105 bool trigger_level1_en;
106 bool trigger_level2_en;
107 bool trigger_level3_en;
108
109 u8 gain;
110 u8 reference_voltage;
111 u8 noise_cancel_mode;
112 u32 efuse_value;
113
114 enum calibration_type cal_type;
115 enum soc_type type;
116 struct freq_clip_table freq_tab[4];
117 unsigned int freq_tab_count;
118};
119#endif /* _LINUX_EXYNOS_THERMAL_H */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index a386a1cbb6e1..b268d3cf7ae3 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -207,6 +207,16 @@ struct thermal_bind_params {
207 * See Documentation/thermal/sysfs-api.txt for more information. 207 * See Documentation/thermal/sysfs-api.txt for more information.
208 */ 208 */
209 int trip_mask; 209 int trip_mask;
210
211 /*
212 * This is an array of cooling state limits. Must have exactly
213 * 2 * thermal_zone.number_of_trip_points. It is an array consisting
214 * of tuples <lower-state upper-state> of state limits. Each trip
215 * will be associated with one state limit tuple when binding.
216 * A NULL pointer means <THERMAL_NO_LIMITS THERMAL_NO_LIMITS>
217 * on all trips.
218 */
219 unsigned long *binding_limits;
210 int (*match) (struct thermal_zone_device *tz, 220 int (*match) (struct thermal_zone_device *tz,
211 struct thermal_cooling_device *cdev); 221 struct thermal_cooling_device *cdev);
212}; 222};
@@ -214,6 +224,14 @@ struct thermal_bind_params {
214/* Structure to define Thermal Zone parameters */ 224/* Structure to define Thermal Zone parameters */
215struct thermal_zone_params { 225struct thermal_zone_params {
216 char governor_name[THERMAL_NAME_LENGTH]; 226 char governor_name[THERMAL_NAME_LENGTH];
227
228 /*
229 * a boolean to indicate if the thermal to hwmon sysfs interface
230 * is required. when no_hwmon == false, a hwmon sysfs interface
231 * will be created. when no_hwmon == true, nothing will be done
232 */
233 bool no_hwmon;
234
217 int num_tbps; /* Number of tbp entries */ 235 int num_tbps; /* Number of tbp entries */
218 struct thermal_bind_params *tbp; 236 struct thermal_bind_params *tbp;
219}; 237};