aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-08-11 10:04:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-11 10:04:17 -0400
commit5fd41f2a10b38ab84b4c2436140ce490d34291fa (patch)
tree0c5e39f8c0ca03004db863cf05e5b20873c0cb48
parent2213d7c29a434626a15ffb285182cd19ed0b722d (diff)
parent47d104ba5879790c7c91c3390b0b08399e168efe (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
Pull thermal updates from Zhang Rui: "Specifics: - adds full support for 2 types of Thermal Controllers produced by STMicroelectronics. One is a more traditional memory mapped variant, the other is controlled solely by system configuration registers. From Lee Jones. - add TMU (Thermal Management Unit) support for Exynos3250 Soc. From Chanwoo Choi. - add critical and passive trip point support for int3403 thermal driver. From Srinivas Pandruvada. - a couple of small fixes/cleanups from Javi Merino, and Geert Uytterhoeven" * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: thermal: document struct thermal_zone_device and thermal_governor thermal: cpu_cooling: fix typo highjack -> hijack thermal: rcar: Document SoC-specific bindings thermal: samsung: Add TMU support for Exynos3250 SoC thermal: exynos: fix ordering in exynos_tmu_remove() thermal: allow building dove_thermal with mvebu thermal: sti: Add support for ST's Memory Mapped based Thermal controller thermal: sti: Add support for ST's System Config Register based Thermal controller thermal: sti: Introduce ST Thermal core code thermal: sti: Supply Device Tree documentation Thermal: int3403: Add CRT and PSV trip
-rw-r--r--Documentation/devicetree/bindings/thermal/exynos-thermal.txt1
-rw-r--r--Documentation/devicetree/bindings/thermal/rcar-thermal.txt18
-rw-r--r--Documentation/devicetree/bindings/thermal/st-thermal.txt42
-rw-r--r--drivers/thermal/Kconfig7
-rw-r--r--drivers/thermal/Makefile1
-rw-r--r--drivers/thermal/cpu_cooling.c2
-rw-r--r--drivers/thermal/int3403_thermal.c67
-rw-r--r--drivers/thermal/samsung/exynos_tmu.c11
-rw-r--r--drivers/thermal/samsung/exynos_tmu.h3
-rw-r--r--drivers/thermal/samsung/exynos_tmu_data.c89
-rw-r--r--drivers/thermal/samsung/exynos_tmu_data.h7
-rw-r--r--drivers/thermal/st/Kconfig12
-rw-r--r--drivers/thermal/st/Makefile3
-rw-r--r--drivers/thermal/st/st_thermal.c313
-rw-r--r--drivers/thermal/st/st_thermal.h104
-rw-r--r--drivers/thermal/st/st_thermal_memmap.c209
-rw-r--r--drivers/thermal/st/st_thermal_syscfg.c179
-rw-r--r--include/linux/thermal.h46
18 files changed, 1093 insertions, 21 deletions
diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
index c94909215c07..ae738f562acc 100644
--- a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
@@ -3,6 +3,7 @@
3** Required properties: 3** Required properties:
4 4
5- compatible : One of the following: 5- compatible : One of the following:
6 "samsung,exynos3250-tmu"
6 "samsung,exynos4412-tmu" 7 "samsung,exynos4412-tmu"
7 "samsung,exynos4210-tmu" 8 "samsung,exynos4210-tmu"
8 "samsung,exynos5250-tmu" 9 "samsung,exynos5250-tmu"
diff --git a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt
index 28ef498a66e5..0ef00be44b01 100644
--- a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt
@@ -1,7 +1,13 @@
1* Renesas R-Car Thermal 1* Renesas R-Car Thermal
2 2
3Required properties: 3Required properties:
4- compatible : "renesas,rcar-thermal" 4- compatible : "renesas,thermal-<soctype>", "renesas,rcar-thermal"
5 as fallback.
6 Examples with soctypes are:
7 - "renesas,thermal-r8a73a4" (R-Mobile AP6)
8 - "renesas,thermal-r8a7779" (R-Car H1)
9 - "renesas,thermal-r8a7790" (R-Car H2)
10 - "renesas,thermal-r8a7791" (R-Car M2)
5- reg : Address range of the thermal registers. 11- reg : Address range of the thermal registers.
6 The 1st reg will be recognized as common register 12 The 1st reg will be recognized as common register
7 if it has "interrupts". 13 if it has "interrupts".
@@ -12,18 +18,18 @@ Option properties:
12 18
13Example (non interrupt support): 19Example (non interrupt support):
14 20
15thermal@e61f0100 { 21thermal@ffc48000 {
16 compatible = "renesas,rcar-thermal"; 22 compatible = "renesas,thermal-r8a7779", "renesas,rcar-thermal";
17 reg = <0xe61f0100 0x38>; 23 reg = <0xffc48000 0x38>;
18}; 24};
19 25
20Example (interrupt support): 26Example (interrupt support):
21 27
22thermal@e61f0000 { 28thermal@e61f0000 {
23 compatible = "renesas,rcar-thermal"; 29 compatible = "renesas,thermal-r8a73a4", "renesas,rcar-thermal";
24 reg = <0xe61f0000 0x14 30 reg = <0xe61f0000 0x14
25 0xe61f0100 0x38 31 0xe61f0100 0x38
26 0xe61f0200 0x38 32 0xe61f0200 0x38
27 0xe61f0300 0x38>; 33 0xe61f0300 0x38>;
28 interrupts = <0 69 4>; 34 interrupts = <0 69 IRQ_TYPE_LEVEL_HIGH>;
29}; 35};
diff --git a/Documentation/devicetree/bindings/thermal/st-thermal.txt b/Documentation/devicetree/bindings/thermal/st-thermal.txt
new file mode 100644
index 000000000000..3b9251b4a145
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/st-thermal.txt
@@ -0,0 +1,42 @@
1Binding for Thermal Sensor driver for STMicroelectronics STi series of SoCs.
2
3Required parameters:
4-------------------
5
6compatible : st,<SoC>-<module>-thermal; should be one of:
7 "st,stih415-sas-thermal",
8 "st,stih415-mpe-thermal",
9 "st,stih416-sas-thermal"
10 "st,stih416-mpe-thermal"
11 "st,stid127-thermal" or
12 "st,stih407-thermal"
13 according to the SoC type (stih415, stih416, stid127, stih407)
14 and module type (sas or mpe). On stid127 & stih407 there is only
15 one die/module, so there is no module type in the compatible
16 string.
17clock-names : Should be "thermal".
18 See: Documentation/devicetree/bindings/resource-names.txt
19clocks : Phandle of the clock used by the thermal sensor.
20 See: Documentation/devicetree/bindings/clock/clock-bindings.txt
21
22Optional parameters:
23-------------------
24
25reg : For non-sysconf based sensors, this should be the physical base
26 address and length of the sensor's registers.
27interrupts : Standard way to define interrupt number.
28 Interrupt is mandatory to be defined when compatible is
29 "stih416-mpe-thermal".
30 NB: For thermal sensor's for which no interrupt has been
31 defined, a polling delay of 1000ms will be used to read the
32 temperature from device.
33
34Example:
35
36 temp1@fdfe8000 {
37 compatible = "st,stih416-mpe-thermal";
38 reg = <0xfdfe8000 0x10>;
39 clock-names = "thermal";
40 clocks = <&clk_m_mpethsens>;
41 interrupts = <GIC_SPI 23 IRQ_TYPE_NONE>;
42 };
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index f9a13867cb70..693208eb9047 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -151,7 +151,7 @@ config KIRKWOOD_THERMAL
151 151
152config DOVE_THERMAL 152config DOVE_THERMAL
153 tristate "Temperature sensor on Marvell Dove SoCs" 153 tristate "Temperature sensor on Marvell Dove SoCs"
154 depends on ARCH_DOVE 154 depends on ARCH_DOVE || MACH_DOVE
155 depends on OF 155 depends on OF
156 help 156 help
157 Support for the Dove thermal sensor driver in the Linux thermal 157 Support for the Dove thermal sensor driver in the Linux thermal
@@ -243,4 +243,9 @@ depends on ARCH_EXYNOS
243source "drivers/thermal/samsung/Kconfig" 243source "drivers/thermal/samsung/Kconfig"
244endmenu 244endmenu
245 245
246menu "STMicroelectronics thermal drivers"
247depends on ARCH_STI && OF
248source "drivers/thermal/st/Kconfig"
249endmenu
250
246endif 251endif
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index de0636a57a64..31e232f84b6b 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -32,3 +32,4 @@ obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
32obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o 32obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o
33obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ 33obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
34obj-$(CONFIG_ACPI_INT3403_THERMAL) += int3403_thermal.o 34obj-$(CONFIG_ACPI_INT3403_THERMAL) += int3403_thermal.o
35obj-$(CONFIG_ST_THERMAL) += st/
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 84a75f89bf74..1ab0018271c5 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -305,7 +305,7 @@ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
305 * @event: value showing cpufreq event for which this function invoked. 305 * @event: value showing cpufreq event for which this function invoked.
306 * @data: callback-specific data 306 * @data: callback-specific data
307 * 307 *
308 * Callback to highjack the notification on cpufreq policy transition. 308 * Callback to hijack the notification on cpufreq policy transition.
309 * Every time there is a change in policy, we will intercept and 309 * Every time there is a change in policy, we will intercept and
310 * update the cpufreq policy with thermal constraints. 310 * update the cpufreq policy with thermal constraints.
311 * 311 *
diff --git a/drivers/thermal/int3403_thermal.c b/drivers/thermal/int3403_thermal.c
index e93f0253f6ed..17554eeb3953 100644
--- a/drivers/thermal/int3403_thermal.c
+++ b/drivers/thermal/int3403_thermal.c
@@ -33,6 +33,10 @@
33struct int3403_sensor { 33struct int3403_sensor {
34 struct thermal_zone_device *tzone; 34 struct thermal_zone_device *tzone;
35 unsigned long *thresholds; 35 unsigned long *thresholds;
36 unsigned long crit_temp;
37 int crit_trip_id;
38 unsigned long psv_temp;
39 int psv_trip_id;
36}; 40};
37 41
38static int sys_get_curr_temp(struct thermal_zone_device *tzone, 42static int sys_get_curr_temp(struct thermal_zone_device *tzone,
@@ -79,12 +83,18 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzone,
79 struct acpi_device *device = tzone->devdata; 83 struct acpi_device *device = tzone->devdata;
80 struct int3403_sensor *obj = acpi_driver_data(device); 84 struct int3403_sensor *obj = acpi_driver_data(device);
81 85
82 /* 86 if (trip == obj->crit_trip_id)
83 * get_trip_temp is a mandatory callback but 87 *temp = obj->crit_temp;
84 * PATx method doesn't return any value, so return 88 else if (trip == obj->psv_trip_id)
85 * cached value, which was last set from user space. 89 *temp = obj->psv_temp;
86 */ 90 else {
87 *temp = obj->thresholds[trip]; 91 /*
92 * get_trip_temp is a mandatory callback but
93 * PATx method doesn't return any value, so return
94 * cached value, which was last set from user space.
95 */
96 *temp = obj->thresholds[trip];
97 }
88 98
89 return 0; 99 return 0;
90} 100}
@@ -92,8 +102,14 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzone,
92static int sys_get_trip_type(struct thermal_zone_device *thermal, 102static int sys_get_trip_type(struct thermal_zone_device *thermal,
93 int trip, enum thermal_trip_type *type) 103 int trip, enum thermal_trip_type *type)
94{ 104{
105 struct acpi_device *device = thermal->devdata;
106 struct int3403_sensor *obj = acpi_driver_data(device);
107
95 /* Mandatory callback, may not mean much here */ 108 /* Mandatory callback, may not mean much here */
96 *type = THERMAL_TRIP_PASSIVE; 109 if (trip == obj->crit_trip_id)
110 *type = THERMAL_TRIP_CRITICAL;
111 else
112 *type = THERMAL_TRIP_PASSIVE;
97 113
98 return 0; 114 return 0;
99} 115}
@@ -155,6 +171,34 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event)
155 } 171 }
156} 172}
157 173
174static int sys_get_trip_crt(struct acpi_device *device, unsigned long *temp)
175{
176 unsigned long long crt;
177 acpi_status status;
178
179 status = acpi_evaluate_integer(device->handle, "_CRT", NULL, &crt);
180 if (ACPI_FAILURE(status))
181 return -EIO;
182
183 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(crt, KELVIN_OFFSET);
184
185 return 0;
186}
187
188static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp)
189{
190 unsigned long long psv;
191 acpi_status status;
192
193 status = acpi_evaluate_integer(device->handle, "_PSV", NULL, &psv);
194 if (ACPI_FAILURE(status))
195 return -EIO;
196
197 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(psv, KELVIN_OFFSET);
198
199 return 0;
200}
201
158static int acpi_int3403_add(struct acpi_device *device) 202static int acpi_int3403_add(struct acpi_device *device)
159{ 203{
160 int result = 0; 204 int result = 0;
@@ -194,6 +238,15 @@ static int acpi_int3403_add(struct acpi_device *device)
194 return -ENOMEM; 238 return -ENOMEM;
195 trip_mask = BIT(trip_cnt) - 1; 239 trip_mask = BIT(trip_cnt) - 1;
196 } 240 }
241
242 obj->psv_trip_id = -1;
243 if (!sys_get_trip_psv(device, &obj->psv_temp))
244 obj->psv_trip_id = trip_cnt++;
245
246 obj->crit_trip_id = -1;
247 if (!sys_get_trip_crt(device, &obj->crit_temp))
248 obj->crit_trip_id = trip_cnt++;
249
197 obj->tzone = thermal_zone_device_register(acpi_device_bid(device), 250 obj->tzone = thermal_zone_device_register(acpi_device_bid(device),
198 trip_cnt, trip_mask, device, &tzone_ops, 251 trip_cnt, trip_mask, device, &tzone_ops,
199 NULL, 0, 0); 252 NULL, 0, 0);
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index d7ca9f49c9cb..acbff14da3a4 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -505,6 +505,10 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id)
505 505
506static const struct of_device_id exynos_tmu_match[] = { 506static const struct of_device_id exynos_tmu_match[] = {
507 { 507 {
508 .compatible = "samsung,exynos3250-tmu",
509 .data = (void *)EXYNOS3250_TMU_DRV_DATA,
510 },
511 {
508 .compatible = "samsung,exynos4210-tmu", 512 .compatible = "samsung,exynos4210-tmu",
509 .data = (void *)EXYNOS4210_TMU_DRV_DATA, 513 .data = (void *)EXYNOS4210_TMU_DRV_DATA,
510 }, 514 },
@@ -677,7 +681,8 @@ static int exynos_tmu_probe(struct platform_device *pdev)
677 goto err_clk_sec; 681 goto err_clk_sec;
678 } 682 }
679 683
680 if (pdata->type == SOC_ARCH_EXYNOS4210 || 684 if (pdata->type == SOC_ARCH_EXYNOS3250 ||
685 pdata->type == SOC_ARCH_EXYNOS4210 ||
681 pdata->type == SOC_ARCH_EXYNOS4412 || 686 pdata->type == SOC_ARCH_EXYNOS4412 ||
682 pdata->type == SOC_ARCH_EXYNOS5250 || 687 pdata->type == SOC_ARCH_EXYNOS5250 ||
683 pdata->type == SOC_ARCH_EXYNOS5260 || 688 pdata->type == SOC_ARCH_EXYNOS5260 ||
@@ -759,10 +764,10 @@ static int exynos_tmu_remove(struct platform_device *pdev)
759{ 764{
760 struct exynos_tmu_data *data = platform_get_drvdata(pdev); 765 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
761 766
762 exynos_tmu_control(pdev, false);
763
764 exynos_unregister_thermal(data->reg_conf); 767 exynos_unregister_thermal(data->reg_conf);
765 768
769 exynos_tmu_control(pdev, false);
770
766 clk_unprepare(data->clk); 771 clk_unprepare(data->clk);
767 if (!IS_ERR(data->clk_sec)) 772 if (!IS_ERR(data->clk_sec))
768 clk_unprepare(data->clk_sec); 773 clk_unprepare(data->clk_sec);
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
index edd08cf76729..1b4a6444ea61 100644
--- a/drivers/thermal/samsung/exynos_tmu.h
+++ b/drivers/thermal/samsung/exynos_tmu.h
@@ -40,7 +40,8 @@ enum calibration_mode {
40}; 40};
41 41
42enum soc_type { 42enum soc_type {
43 SOC_ARCH_EXYNOS4210 = 1, 43 SOC_ARCH_EXYNOS3250 = 1,
44 SOC_ARCH_EXYNOS4210,
44 SOC_ARCH_EXYNOS4412, 45 SOC_ARCH_EXYNOS4412,
45 SOC_ARCH_EXYNOS5250, 46 SOC_ARCH_EXYNOS5250,
46 SOC_ARCH_EXYNOS5260, 47 SOC_ARCH_EXYNOS5260,
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
index c1d81dcd7819..aa8e0dee2055 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.c
+++ b/drivers/thermal/samsung/exynos_tmu_data.c
@@ -90,6 +90,95 @@ struct exynos_tmu_init_data const exynos4210_default_tmu_data = {
90}; 90};
91#endif 91#endif
92 92
93#if defined(CONFIG_SOC_EXYNOS3250)
94static const struct exynos_tmu_registers exynos3250_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 .tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
99 .test_mux_addr_shift = EXYNOS4412_MUX_ADDR_SHIFT,
100 .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
101 .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
102 .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT,
103 .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK,
104 .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT,
105 .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
106 .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
107 .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
108 .tmu_status = EXYNOS_TMU_REG_STATUS,
109 .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
110 .threshold_th0 = EXYNOS_THD_TEMP_RISE,
111 .threshold_th1 = EXYNOS_THD_TEMP_FALL,
112 .tmu_inten = EXYNOS_TMU_REG_INTEN,
113 .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
114 .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
115 .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT,
116 .inten_fall0_shift = EXYNOS_TMU_INTEN_FALL0_SHIFT,
117 .tmu_intstat = EXYNOS_TMU_REG_INTSTAT,
118 .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
119 .intclr_fall_shift = EXYNOS_TMU_CLEAR_FALL_INT_SHIFT,
120 .intclr_rise_shift = EXYNOS_TMU_RISE_INT_SHIFT,
121 .intclr_rise_mask = EXYNOS_TMU_RISE_INT_MASK,
122 .intclr_fall_mask = EXYNOS_TMU_FALL_INT_MASK,
123 .emul_con = EXYNOS_EMUL_CON,
124 .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT,
125 .emul_time_shift = EXYNOS_EMUL_TIME_SHIFT,
126 .emul_time_mask = EXYNOS_EMUL_TIME_MASK,
127};
128
129#define EXYNOS3250_TMU_DATA \
130 .threshold_falling = 10, \
131 .trigger_levels[0] = 70, \
132 .trigger_levels[1] = 95, \
133 .trigger_levels[2] = 110, \
134 .trigger_levels[3] = 120, \
135 .trigger_enable[0] = true, \
136 .trigger_enable[1] = true, \
137 .trigger_enable[2] = true, \
138 .trigger_enable[3] = false, \
139 .trigger_type[0] = THROTTLE_ACTIVE, \
140 .trigger_type[1] = THROTTLE_ACTIVE, \
141 .trigger_type[2] = SW_TRIP, \
142 .trigger_type[3] = HW_TRIP, \
143 .max_trigger_level = 4, \
144 .gain = 8, \
145 .reference_voltage = 16, \
146 .noise_cancel_mode = 4, \
147 .cal_type = TYPE_TWO_POINT_TRIMMING, \
148 .efuse_value = 55, \
149 .min_efuse_value = 40, \
150 .max_efuse_value = 100, \
151 .first_point_trim = 25, \
152 .second_point_trim = 85, \
153 .default_temp_offset = 50, \
154 .freq_tab[0] = { \
155 .freq_clip_max = 800 * 1000, \
156 .temp_level = 70, \
157 }, \
158 .freq_tab[1] = { \
159 .freq_clip_max = 400 * 1000, \
160 .temp_level = 95, \
161 }, \
162 .freq_tab_count = 2, \
163 .registers = &exynos3250_tmu_registers, \
164 .features = (TMU_SUPPORT_EMULATION | \
165 TMU_SUPPORT_FALLING_TRIP | TMU_SUPPORT_READY_STATUS | \
166 TMU_SUPPORT_EMUL_TIME)
167#endif
168
169#if defined(CONFIG_SOC_EXYNOS3250)
170struct exynos_tmu_init_data const exynos3250_default_tmu_data = {
171 .tmu_data = {
172 {
173 EXYNOS3250_TMU_DATA,
174 .type = SOC_ARCH_EXYNOS3250,
175 .test_mux = EXYNOS4412_MUX_ADDR_VALUE,
176 },
177 },
178 .tmu_count = 1,
179};
180#endif
181
93#if defined(CONFIG_SOC_EXYNOS4412) || defined(CONFIG_SOC_EXYNOS5250) 182#if defined(CONFIG_SOC_EXYNOS4412) || defined(CONFIG_SOC_EXYNOS5250)
94static const struct exynos_tmu_registers exynos4412_tmu_registers = { 183static const struct exynos_tmu_registers exynos4412_tmu_registers = {
95 .triminfo_data = EXYNOS_TMU_REG_TRIMINFO, 184 .triminfo_data = EXYNOS_TMU_REG_TRIMINFO,
diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
index d268981b65e5..f0979e598491 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.h
+++ b/drivers/thermal/samsung/exynos_tmu_data.h
@@ -148,6 +148,13 @@
148#define EXYNOS5440_TMU_TH_RISE4_SHIFT 24 148#define EXYNOS5440_TMU_TH_RISE4_SHIFT 24
149#define EXYNOS5440_EFUSE_SWAP_OFFSET 8 149#define EXYNOS5440_EFUSE_SWAP_OFFSET 8
150 150
151#if defined(CONFIG_SOC_EXYNOS3250)
152extern struct exynos_tmu_init_data const exynos3250_default_tmu_data;
153#define EXYNOS3250_TMU_DRV_DATA (&exynos3250_default_tmu_data)
154#else
155#define EXYNOS3250_TMU_DRV_DATA (NULL)
156#endif
157
151#if defined(CONFIG_CPU_EXYNOS4210) 158#if defined(CONFIG_CPU_EXYNOS4210)
152extern struct exynos_tmu_init_data const exynos4210_default_tmu_data; 159extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
153#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data) 160#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
diff --git a/drivers/thermal/st/Kconfig b/drivers/thermal/st/Kconfig
new file mode 100644
index 000000000000..490fdbe22eea
--- /dev/null
+++ b/drivers/thermal/st/Kconfig
@@ -0,0 +1,12 @@
1config ST_THERMAL
2 tristate "Thermal sensors on STMicroelectronics STi series of SoCs"
3 help
4 Support for thermal sensors on STMicroelectronics STi series of SoCs.
5
6config ST_THERMAL_SYSCFG
7 select ST_THERMAL
8 tristate "STi series syscfg register access based thermal sensors"
9
10config ST_THERMAL_MEMMAP
11 select ST_THERMAL
12 tristate "STi series memory mapped access based thermal sensors"
diff --git a/drivers/thermal/st/Makefile b/drivers/thermal/st/Makefile
new file mode 100644
index 000000000000..b38878977bd8
--- /dev/null
+++ b/drivers/thermal/st/Makefile
@@ -0,0 +1,3 @@
1obj-$(CONFIG_ST_THERMAL) := st_thermal.o
2obj-$(CONFIG_ST_THERMAL_SYSCFG) += st_thermal_syscfg.o
3obj-$(CONFIG_ST_THERMAL_MEMMAP) += st_thermal_memmap.o
diff --git a/drivers/thermal/st/st_thermal.c b/drivers/thermal/st/st_thermal.c
new file mode 100644
index 000000000000..90163b384660
--- /dev/null
+++ b/drivers/thermal/st/st_thermal.c
@@ -0,0 +1,313 @@
1/*
2 * ST Thermal Sensor Driver core routines
3 * Author: Ajit Pal Singh <ajitpal.singh@st.com>
4 *
5 * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 */
13
14#include <linux/clk.h>
15#include <linux/module.h>
16#include <linux/of.h>
17#include <linux/of_device.h>
18
19#include "st_thermal.h"
20
21/* The Thermal Framework expects millidegrees */
22#define mcelsius(temp) ((temp) * 1000)
23
24/*
25 * Function to allocate regfields which are common
26 * between syscfg and memory mapped based sensors
27 */
28int st_thermal_alloc_regfields(struct st_thermal_sensor *sensor)
29{
30 struct device *dev = sensor->dev;
31 struct regmap *regmap = sensor->regmap;
32 const struct reg_field *reg_fields = sensor->cdata->reg_fields;
33
34 sensor->dcorrect = devm_regmap_field_alloc(dev, regmap,
35 reg_fields[DCORRECT]);
36
37 sensor->overflow = devm_regmap_field_alloc(dev, regmap,
38 reg_fields[OVERFLOW]);
39
40 sensor->temp_data = devm_regmap_field_alloc(dev, regmap,
41 reg_fields[DATA]);
42
43 if (IS_ERR(sensor->dcorrect) ||
44 IS_ERR(sensor->overflow) ||
45 IS_ERR(sensor->temp_data)) {
46 dev_err(dev, "failed to allocate common regfields\n");
47 return -EINVAL;
48 }
49
50 return sensor->ops->alloc_regfields(sensor);
51}
52
53static int st_thermal_sensor_on(struct st_thermal_sensor *sensor)
54{
55 int ret;
56 struct device *dev = sensor->dev;
57
58 ret = clk_prepare_enable(sensor->clk);
59 if (ret) {
60 dev_err(dev, "failed to enable clk\n");
61 return ret;
62 }
63
64 ret = sensor->ops->power_ctrl(sensor, POWER_ON);
65 if (ret) {
66 dev_err(dev, "failed to power on sensor\n");
67 clk_disable_unprepare(sensor->clk);
68 }
69
70 return ret;
71}
72
73static int st_thermal_sensor_off(struct st_thermal_sensor *sensor)
74{
75 int ret;
76
77 ret = sensor->ops->power_ctrl(sensor, POWER_OFF);
78 if (ret)
79 return ret;
80
81 clk_disable_unprepare(sensor->clk);
82
83 return 0;
84}
85
86static int st_thermal_calibration(struct st_thermal_sensor *sensor)
87{
88 int ret;
89 unsigned int val;
90 struct device *dev = sensor->dev;
91
92 /* Check if sensor calibration data is already written */
93 ret = regmap_field_read(sensor->dcorrect, &val);
94 if (ret) {
95 dev_err(dev, "failed to read calibration data\n");
96 return ret;
97 }
98
99 if (!val) {
100 /*
101 * Sensor calibration value not set by bootloader,
102 * default calibration data to be used
103 */
104 ret = regmap_field_write(sensor->dcorrect,
105 sensor->cdata->calibration_val);
106 if (ret)
107 dev_err(dev, "failed to set calibration data\n");
108 }
109
110 return ret;
111}
112
113/* Callback to get temperature from HW*/
114static int st_thermal_get_temp(struct thermal_zone_device *th,
115 unsigned long *temperature)
116{
117 struct st_thermal_sensor *sensor = th->devdata;
118 struct device *dev = sensor->dev;
119 unsigned int temp;
120 unsigned int overflow;
121 int ret;
122
123 ret = regmap_field_read(sensor->overflow, &overflow);
124 if (ret)
125 return ret;
126 if (overflow)
127 return -EIO;
128
129 ret = regmap_field_read(sensor->temp_data, &temp);
130 if (ret)
131 return ret;
132
133 temp += sensor->cdata->temp_adjust_val;
134 temp = mcelsius(temp);
135
136 dev_dbg(dev, "temperature: %d\n", temp);
137
138 *temperature = temp;
139
140 return 0;
141}
142
143static int st_thermal_get_trip_type(struct thermal_zone_device *th,
144 int trip, enum thermal_trip_type *type)
145{
146 struct st_thermal_sensor *sensor = th->devdata;
147 struct device *dev = sensor->dev;
148
149 switch (trip) {
150 case 0:
151 *type = THERMAL_TRIP_CRITICAL;
152 break;
153 default:
154 dev_err(dev, "invalid trip point\n");
155 return -EINVAL;
156 }
157
158 return 0;
159}
160
161static int st_thermal_get_trip_temp(struct thermal_zone_device *th,
162 int trip, unsigned long *temp)
163{
164 struct st_thermal_sensor *sensor = th->devdata;
165 struct device *dev = sensor->dev;
166
167 switch (trip) {
168 case 0:
169 *temp = mcelsius(sensor->cdata->crit_temp);
170 break;
171 default:
172 dev_err(dev, "Invalid trip point\n");
173 return -EINVAL;
174 }
175
176 return 0;
177}
178
179static struct thermal_zone_device_ops st_tz_ops = {
180 .get_temp = st_thermal_get_temp,
181 .get_trip_type = st_thermal_get_trip_type,
182 .get_trip_temp = st_thermal_get_trip_temp,
183};
184
185int st_thermal_register(struct platform_device *pdev,
186 const struct of_device_id *st_thermal_of_match)
187{
188 struct st_thermal_sensor *sensor;
189 struct device *dev = &pdev->dev;
190 struct device_node *np = dev->of_node;
191 const struct of_device_id *match;
192
193 int polling_delay;
194 int ret;
195
196 if (!np) {
197 dev_err(dev, "device tree node not found\n");
198 return -EINVAL;
199 }
200
201 sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
202 if (!sensor)
203 return -ENOMEM;
204
205 sensor->dev = dev;
206
207 match = of_match_device(st_thermal_of_match, dev);
208 if (!(match && match->data))
209 return -EINVAL;
210
211 sensor->cdata = match->data;
212 if (!sensor->cdata->ops)
213 return -EINVAL;
214
215 sensor->ops = sensor->cdata->ops;
216
217 ret = sensor->ops->regmap_init(sensor);
218 if (ret)
219 return ret;
220
221 ret = st_thermal_alloc_regfields(sensor);
222 if (ret)
223 return ret;
224
225 sensor->clk = devm_clk_get(dev, "thermal");
226 if (IS_ERR(sensor->clk)) {
227 dev_err(dev, "failed to fetch clock\n");
228 return PTR_ERR(sensor->clk);
229 }
230
231 if (sensor->ops->register_enable_irq) {
232 ret = sensor->ops->register_enable_irq(sensor);
233 if (ret)
234 return ret;
235 }
236
237 ret = st_thermal_sensor_on(sensor);
238 if (ret)
239 return ret;
240
241 ret = st_thermal_calibration(sensor);
242 if (ret)
243 goto sensor_off;
244
245 polling_delay = sensor->ops->register_enable_irq ? 0 : 1000;
246
247 sensor->thermal_dev =
248 thermal_zone_device_register(dev_name(dev), 1, 0, sensor,
249 &st_tz_ops, NULL, 0, polling_delay);
250 if (IS_ERR(sensor->thermal_dev)) {
251 dev_err(dev, "failed to register thermal zone device\n");
252 ret = PTR_ERR(sensor->thermal_dev);
253 goto sensor_off;
254 }
255
256 platform_set_drvdata(pdev, sensor);
257
258 return 0;
259
260sensor_off:
261 st_thermal_sensor_off(sensor);
262
263 return ret;
264}
265EXPORT_SYMBOL_GPL(st_thermal_register);
266
267int st_thermal_unregister(struct platform_device *pdev)
268{
269 struct st_thermal_sensor *sensor = platform_get_drvdata(pdev);
270
271 st_thermal_sensor_off(sensor);
272 thermal_zone_device_unregister(sensor->thermal_dev);
273
274 return 0;
275}
276EXPORT_SYMBOL_GPL(st_thermal_unregister);
277
278static int st_thermal_suspend(struct device *dev)
279{
280 struct platform_device *pdev = to_platform_device(dev);
281 struct st_thermal_sensor *sensor = platform_get_drvdata(pdev);
282
283 return st_thermal_sensor_off(sensor);
284}
285
286static int st_thermal_resume(struct device *dev)
287{
288 int ret;
289 struct platform_device *pdev = to_platform_device(dev);
290 struct st_thermal_sensor *sensor = platform_get_drvdata(pdev);
291
292 ret = st_thermal_sensor_on(sensor);
293 if (ret)
294 return ret;
295
296 ret = st_thermal_calibration(sensor);
297 if (ret)
298 return ret;
299
300 if (sensor->ops->enable_irq) {
301 ret = sensor->ops->enable_irq(sensor);
302 if (ret)
303 return ret;
304 }
305
306 return 0;
307}
308SIMPLE_DEV_PM_OPS(st_thermal_pm_ops, st_thermal_suspend, st_thermal_resume);
309EXPORT_SYMBOL_GPL(st_thermal_pm_ops);
310
311MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>");
312MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver");
313MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/st/st_thermal.h b/drivers/thermal/st/st_thermal.h
new file mode 100644
index 000000000000..fecafbe10fa7
--- /dev/null
+++ b/drivers/thermal/st/st_thermal.h
@@ -0,0 +1,104 @@
1/*
2 * ST Thermal Sensor Driver for STi series of SoCs
3 * Author: Ajit Pal Singh <ajitpal.singh@st.com>
4 *
5 * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#ifndef __STI_THERMAL_SYSCFG_H
14#define __STI_THERMAL_SYSCFG_H
15
16#include <linux/interrupt.h>
17#include <linux/platform_device.h>
18#include <linux/regmap.h>
19#include <linux/thermal.h>
20
21enum st_thermal_regfield_ids {
22 INT_THRESH_HI = 0, /* Top two regfield IDs are mutually exclusive */
23 TEMP_PWR = 0,
24 DCORRECT,
25 OVERFLOW,
26 DATA,
27 INT_ENABLE,
28
29 MAX_REGFIELDS
30};
31
32/* Thermal sensor power states */
33enum st_thermal_power_state {
34 POWER_OFF = 0,
35 POWER_ON
36};
37
38struct st_thermal_sensor;
39
40/**
41 * Description of private thermal sensor ops.
42 *
43 * @power_ctrl: Function for powering on/off a sensor. Clock to the
44 * sensor is also controlled from this function.
45 * @alloc_regfields: Allocate regmap register fields, specific to a sensor.
46 * @do_memmap_regmap: Memory map the thermal register space and init regmap
47 * instance or find regmap instance.
48 * @register_irq: Register an interrupt handler for a sensor.
49 */
50struct st_thermal_sensor_ops {
51 int (*power_ctrl)(struct st_thermal_sensor *, enum st_thermal_power_state);
52 int (*alloc_regfields)(struct st_thermal_sensor *);
53 int (*regmap_init)(struct st_thermal_sensor *);
54 int (*register_enable_irq)(struct st_thermal_sensor *);
55 int (*enable_irq)(struct st_thermal_sensor *);
56};
57
58/**
59 * Description of thermal driver compatible data.
60 *
61 * @reg_fields: Pointer to the regfields array for a sensor.
62 * @sys_compat: Pointer to the syscon node compatible string.
63 * @ops: Pointer to private thermal ops for a sensor.
64 * @calibration_val: Default calibration value to be written to the DCORRECT
65 * register field for a sensor.
66 * @temp_adjust_val: Value to be added/subtracted from the data read from
67 * the sensor. If value needs to be added please provide a
68 * positive value and if it is to be subtracted please
69 * provide a negative value.
70 * @crit_temp: The temperature beyond which the SoC should be shutdown
71 * to prevent damage.
72 */
73struct st_thermal_compat_data {
74 char *sys_compat;
75 const struct reg_field *reg_fields;
76 const struct st_thermal_sensor_ops *ops;
77 unsigned int calibration_val;
78 int temp_adjust_val;
79 int crit_temp;
80};
81
82struct st_thermal_sensor {
83 struct device *dev;
84 struct thermal_zone_device *thermal_dev;
85 const struct st_thermal_sensor_ops *ops;
86 const struct st_thermal_compat_data *cdata;
87 struct clk *clk;
88 struct regmap *regmap;
89 struct regmap_field *pwr;
90 struct regmap_field *dcorrect;
91 struct regmap_field *overflow;
92 struct regmap_field *temp_data;
93 struct regmap_field *int_thresh_hi;
94 struct regmap_field *int_enable;
95 int irq;
96 void __iomem *mmio_base;
97};
98
99extern int st_thermal_register(struct platform_device *pdev,
100 const struct of_device_id *st_thermal_of_match);
101extern int st_thermal_unregister(struct platform_device *pdev);
102extern const struct dev_pm_ops st_thermal_pm_ops;
103
104#endif /* __STI_RESET_SYSCFG_H */
diff --git a/drivers/thermal/st/st_thermal_memmap.c b/drivers/thermal/st/st_thermal_memmap.c
new file mode 100644
index 000000000000..39896ce2ee00
--- /dev/null
+++ b/drivers/thermal/st/st_thermal_memmap.c
@@ -0,0 +1,209 @@
1/*
2 * ST Thermal Sensor Driver for memory mapped sensors.
3 * Author: Ajit Pal Singh <ajitpal.singh@st.com>
4 *
5 * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <linux/of.h>
14#include <linux/module.h>
15
16#include "st_thermal.h"
17
18#define STIH416_MPE_CONF 0x0
19#define STIH416_MPE_STATUS 0x4
20#define STIH416_MPE_INT_THRESH 0x8
21#define STIH416_MPE_INT_EN 0xC
22
23/* Power control bits for the memory mapped thermal sensor */
24#define THERMAL_PDN BIT(4)
25#define THERMAL_SRSTN BIT(10)
26
27static const struct reg_field st_mmap_thermal_regfields[MAX_REGFIELDS] = {
28 /*
29 * According to the STIH416 MPE temp sensor data sheet -
30 * the PDN (Power Down Bit) and SRSTN (Soft Reset Bit) need to be
31 * written simultaneously for powering on and off the temperature
32 * sensor. regmap_update_bits() will be used to update the register.
33 */
34 [INT_THRESH_HI] = REG_FIELD(STIH416_MPE_INT_THRESH, 0, 7),
35 [DCORRECT] = REG_FIELD(STIH416_MPE_CONF, 5, 9),
36 [OVERFLOW] = REG_FIELD(STIH416_MPE_STATUS, 9, 9),
37 [DATA] = REG_FIELD(STIH416_MPE_STATUS, 11, 18),
38 [INT_ENABLE] = REG_FIELD(STIH416_MPE_INT_EN, 0, 0),
39};
40
41static irqreturn_t st_mmap_thermal_trip_handler(int irq, void *sdata)
42{
43 struct st_thermal_sensor *sensor = sdata;
44
45 thermal_zone_device_update(sensor->thermal_dev);
46
47 return IRQ_HANDLED;
48}
49
50/* Private ops for the Memory Mapped based thermal sensors */
51static int st_mmap_power_ctrl(struct st_thermal_sensor *sensor,
52 enum st_thermal_power_state power_state)
53{
54 const unsigned int mask = (THERMAL_PDN | THERMAL_SRSTN);
55 const unsigned int val = power_state ? mask : 0;
56
57 return regmap_update_bits(sensor->regmap, STIH416_MPE_CONF, mask, val);
58}
59
60static int st_mmap_alloc_regfields(struct st_thermal_sensor *sensor)
61{
62 struct device *dev = sensor->dev;
63 struct regmap *regmap = sensor->regmap;
64 const struct reg_field *reg_fields = sensor->cdata->reg_fields;
65
66 sensor->int_thresh_hi = devm_regmap_field_alloc(dev, regmap,
67 reg_fields[INT_THRESH_HI]);
68 sensor->int_enable = devm_regmap_field_alloc(dev, regmap,
69 reg_fields[INT_ENABLE]);
70
71 if (IS_ERR(sensor->int_thresh_hi) || IS_ERR(sensor->int_enable)) {
72 dev_err(dev, "failed to alloc mmap regfields\n");
73 return -EINVAL;
74 }
75
76 return 0;
77}
78
79static int st_mmap_enable_irq(struct st_thermal_sensor *sensor)
80{
81 int ret;
82
83 /* Set upper critical threshold */
84 ret = regmap_field_write(sensor->int_thresh_hi,
85 sensor->cdata->crit_temp -
86 sensor->cdata->temp_adjust_val);
87 if (ret)
88 return ret;
89
90 return regmap_field_write(sensor->int_enable, 1);
91}
92
93static int st_mmap_register_enable_irq(struct st_thermal_sensor *sensor)
94{
95 struct device *dev = sensor->dev;
96 struct platform_device *pdev = to_platform_device(dev);
97 int ret;
98
99 sensor->irq = platform_get_irq(pdev, 0);
100 if (sensor->irq < 0) {
101 dev_err(dev, "failed to register IRQ\n");
102 return sensor->irq;
103 }
104
105 ret = devm_request_threaded_irq(dev, sensor->irq,
106 NULL, st_mmap_thermal_trip_handler,
107 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
108 dev->driver->name, sensor);
109 if (ret) {
110 dev_err(dev, "failed to register IRQ %d\n", sensor->irq);
111 return ret;
112 }
113
114 return st_mmap_enable_irq(sensor);
115}
116
117static const struct regmap_config st_416mpe_regmap_config = {
118 .reg_bits = 32,
119 .val_bits = 32,
120 .reg_stride = 4,
121};
122
123static int st_mmap_regmap_init(struct st_thermal_sensor *sensor)
124{
125 struct device *dev = sensor->dev;
126 struct platform_device *pdev = to_platform_device(dev);
127 struct resource *res;
128
129 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
130 if (!res) {
131 dev_err(dev, "no memory resources defined\n");
132 return -ENODEV;
133 }
134
135 sensor->mmio_base = devm_ioremap_resource(dev, res);
136 if (IS_ERR(sensor->mmio_base)) {
137 dev_err(dev, "failed to remap IO\n");
138 return PTR_ERR(sensor->mmio_base);
139 }
140
141 sensor->regmap = devm_regmap_init_mmio(dev, sensor->mmio_base,
142 &st_416mpe_regmap_config);
143 if (IS_ERR(sensor->regmap)) {
144 dev_err(dev, "failed to initialise regmap\n");
145 return PTR_ERR(sensor->regmap);
146 }
147
148 return 0;
149}
150
151static const struct st_thermal_sensor_ops st_mmap_sensor_ops = {
152 .power_ctrl = st_mmap_power_ctrl,
153 .alloc_regfields = st_mmap_alloc_regfields,
154 .regmap_init = st_mmap_regmap_init,
155 .register_enable_irq = st_mmap_register_enable_irq,
156 .enable_irq = st_mmap_enable_irq,
157};
158
159/* Compatible device data stih416 mpe thermal sensor */
160const struct st_thermal_compat_data st_416mpe_cdata = {
161 .reg_fields = st_mmap_thermal_regfields,
162 .ops = &st_mmap_sensor_ops,
163 .calibration_val = 14,
164 .temp_adjust_val = -95,
165 .crit_temp = 120,
166};
167
168/* Compatible device data stih407 thermal sensor */
169const struct st_thermal_compat_data st_407_cdata = {
170 .reg_fields = st_mmap_thermal_regfields,
171 .ops = &st_mmap_sensor_ops,
172 .calibration_val = 16,
173 .temp_adjust_val = -95,
174 .crit_temp = 120,
175};
176
177static struct of_device_id st_mmap_thermal_of_match[] = {
178 { .compatible = "st,stih416-mpe-thermal", .data = &st_416mpe_cdata },
179 { .compatible = "st,stih407-thermal", .data = &st_407_cdata },
180 { /* sentinel */ }
181};
182MODULE_DEVICE_TABLE(of, st_mmap_thermal_of_match);
183
184int st_mmap_probe(struct platform_device *pdev)
185{
186 return st_thermal_register(pdev, st_mmap_thermal_of_match);
187}
188
189int st_mmap_remove(struct platform_device *pdev)
190{
191 return st_thermal_unregister(pdev);
192}
193
194static struct platform_driver st_mmap_thermal_driver = {
195 .driver = {
196 .name = "st_thermal_mmap",
197 .owner = THIS_MODULE,
198 .pm = &st_thermal_pm_ops,
199 .of_match_table = st_mmap_thermal_of_match,
200 },
201 .probe = st_mmap_probe,
202 .remove = st_mmap_remove,
203};
204
205module_platform_driver(st_mmap_thermal_driver);
206
207MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>");
208MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver");
209MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/st/st_thermal_syscfg.c b/drivers/thermal/st/st_thermal_syscfg.c
new file mode 100644
index 000000000000..888b58e64090
--- /dev/null
+++ b/drivers/thermal/st/st_thermal_syscfg.c
@@ -0,0 +1,179 @@
1/*
2 * ST Thermal Sensor Driver for syscfg based sensors.
3 * Author: Ajit Pal Singh <ajitpal.singh@st.com>
4 *
5 * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <linux/of.h>
14#include <linux/module.h>
15#include <linux/mfd/syscon.h>
16
17#include "st_thermal.h"
18
19/* STiH415 */
20#define STIH415_SYSCFG_FRONT(num) ((num - 100) * 4)
21#define STIH415_SAS_THSENS_CONF STIH415_SYSCFG_FRONT(178)
22#define STIH415_SAS_THSENS_STATUS STIH415_SYSCFG_FRONT(198)
23#define STIH415_SYSCFG_MPE(num) ((num - 600) * 4)
24#define STIH415_MPE_THSENS_CONF STIH415_SYSCFG_MPE(607)
25#define STIH415_MPE_THSENS_STATUS STIH415_SYSCFG_MPE(667)
26
27/* STiH416 */
28#define STIH416_SYSCFG_FRONT(num) ((num - 1000) * 4)
29#define STIH416_SAS_THSENS_CONF STIH416_SYSCFG_FRONT(1552)
30#define STIH416_SAS_THSENS_STATUS1 STIH416_SYSCFG_FRONT(1554)
31#define STIH416_SAS_THSENS_STATUS2 STIH416_SYSCFG_FRONT(1594)
32
33/* STiD127 */
34#define STID127_SYSCFG_CPU(num) ((num - 700) * 4)
35#define STID127_THSENS_CONF STID127_SYSCFG_CPU(743)
36#define STID127_THSENS_STATUS STID127_SYSCFG_CPU(767)
37
38static const struct reg_field st_415sas_regfields[MAX_REGFIELDS] = {
39 [TEMP_PWR] = REG_FIELD(STIH415_SAS_THSENS_CONF, 9, 9),
40 [DCORRECT] = REG_FIELD(STIH415_SAS_THSENS_CONF, 4, 8),
41 [OVERFLOW] = REG_FIELD(STIH415_SAS_THSENS_STATUS, 8, 8),
42 [DATA] = REG_FIELD(STIH415_SAS_THSENS_STATUS, 10, 16),
43};
44
45static const struct reg_field st_415mpe_regfields[MAX_REGFIELDS] = {
46 [TEMP_PWR] = REG_FIELD(STIH415_MPE_THSENS_CONF, 8, 8),
47 [DCORRECT] = REG_FIELD(STIH415_MPE_THSENS_CONF, 3, 7),
48 [OVERFLOW] = REG_FIELD(STIH415_MPE_THSENS_STATUS, 9, 9),
49 [DATA] = REG_FIELD(STIH415_MPE_THSENS_STATUS, 11, 18),
50};
51
52static const struct reg_field st_416sas_regfields[MAX_REGFIELDS] = {
53 [TEMP_PWR] = REG_FIELD(STIH416_SAS_THSENS_CONF, 9, 9),
54 [DCORRECT] = REG_FIELD(STIH416_SAS_THSENS_CONF, 4, 8),
55 [OVERFLOW] = REG_FIELD(STIH416_SAS_THSENS_STATUS1, 8, 8),
56 [DATA] = REG_FIELD(STIH416_SAS_THSENS_STATUS2, 10, 16),
57};
58
59static const struct reg_field st_127_regfields[MAX_REGFIELDS] = {
60 [TEMP_PWR] = REG_FIELD(STID127_THSENS_CONF, 7, 7),
61 [DCORRECT] = REG_FIELD(STID127_THSENS_CONF, 2, 6),
62 [OVERFLOW] = REG_FIELD(STID127_THSENS_STATUS, 9, 9),
63 [DATA] = REG_FIELD(STID127_THSENS_STATUS, 11, 18),
64};
65
66/* Private OPs for System Configuration Register based thermal sensors */
67static int st_syscfg_power_ctrl(struct st_thermal_sensor *sensor,
68 enum st_thermal_power_state power_state)
69{
70 return regmap_field_write(sensor->pwr, power_state);
71}
72
73static int st_syscfg_alloc_regfields(struct st_thermal_sensor *sensor)
74{
75 struct device *dev = sensor->dev;
76
77 sensor->pwr = devm_regmap_field_alloc(dev, sensor->regmap,
78 sensor->cdata->reg_fields[TEMP_PWR]);
79
80 if (IS_ERR(sensor->pwr)) {
81 dev_err(dev, "failed to alloc syscfg regfields\n");
82 return PTR_ERR(sensor->pwr);
83 }
84
85 return 0;
86}
87
88static int st_syscfg_regmap_init(struct st_thermal_sensor *sensor)
89{
90 sensor->regmap =
91 syscon_regmap_lookup_by_compatible(sensor->cdata->sys_compat);
92 if (IS_ERR(sensor->regmap)) {
93 dev_err(sensor->dev, "failed to find syscfg regmap\n");
94 return PTR_ERR(sensor->regmap);
95 }
96
97 return 0;
98}
99
100static const struct st_thermal_sensor_ops st_syscfg_sensor_ops = {
101 .power_ctrl = st_syscfg_power_ctrl,
102 .alloc_regfields = st_syscfg_alloc_regfields,
103 .regmap_init = st_syscfg_regmap_init,
104};
105
106/* Compatible device data for stih415 sas thermal sensor */
107const struct st_thermal_compat_data st_415sas_cdata = {
108 .sys_compat = "st,stih415-front-syscfg",
109 .reg_fields = st_415sas_regfields,
110 .ops = &st_syscfg_sensor_ops,
111 .calibration_val = 16,
112 .temp_adjust_val = 20,
113 .crit_temp = 120,
114};
115
116/* Compatible device data for stih415 mpe thermal sensor */
117const struct st_thermal_compat_data st_415mpe_cdata = {
118 .sys_compat = "st,stih415-system-syscfg",
119 .reg_fields = st_415mpe_regfields,
120 .ops = &st_syscfg_sensor_ops,
121 .calibration_val = 16,
122 .temp_adjust_val = -103,
123 .crit_temp = 120,
124};
125
126/* Compatible device data for stih416 sas thermal sensor */
127const struct st_thermal_compat_data st_416sas_cdata = {
128 .sys_compat = "st,stih416-front-syscfg",
129 .reg_fields = st_416sas_regfields,
130 .ops = &st_syscfg_sensor_ops,
131 .calibration_val = 16,
132 .temp_adjust_val = 20,
133 .crit_temp = 120,
134};
135
136/* Compatible device data for stid127 thermal sensor */
137const struct st_thermal_compat_data st_127_cdata = {
138 .sys_compat = "st,stid127-cpu-syscfg",
139 .reg_fields = st_127_regfields,
140 .ops = &st_syscfg_sensor_ops,
141 .calibration_val = 8,
142 .temp_adjust_val = -103,
143 .crit_temp = 120,
144};
145
146static struct of_device_id st_syscfg_thermal_of_match[] = {
147 { .compatible = "st,stih415-sas-thermal", .data = &st_415sas_cdata },
148 { .compatible = "st,stih415-mpe-thermal", .data = &st_415mpe_cdata },
149 { .compatible = "st,stih416-sas-thermal", .data = &st_416sas_cdata },
150 { .compatible = "st,stid127-thermal", .data = &st_127_cdata },
151 { /* sentinel */ }
152};
153MODULE_DEVICE_TABLE(of, st_syscfg_thermal_of_match);
154
155int st_syscfg_probe(struct platform_device *pdev)
156{
157 return st_thermal_register(pdev, st_syscfg_thermal_of_match);
158}
159
160int st_syscfg_remove(struct platform_device *pdev)
161{
162 return st_thermal_unregister(pdev);
163}
164
165static struct platform_driver st_syscfg_thermal_driver = {
166 .driver = {
167 .name = "st_syscfg_thermal",
168 .owner = THIS_MODULE,
169 .pm = &st_thermal_pm_ops,
170 .of_match_table = st_syscfg_thermal_of_match,
171 },
172 .probe = st_syscfg_probe,
173 .remove = st_syscfg_remove,
174};
175module_platform_driver(st_syscfg_thermal_driver);
176
177MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>");
178MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver");
179MODULE_LICENSE("GPL v2");
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index f7e11c7ea7d9..0305cde21a74 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -158,6 +158,42 @@ struct thermal_attr {
158 char name[THERMAL_NAME_LENGTH]; 158 char name[THERMAL_NAME_LENGTH];
159}; 159};
160 160
161/**
162 * struct thermal_zone_device - structure for a thermal zone
163 * @id: unique id number for each thermal zone
164 * @type: the thermal zone device type
165 * @device: &struct device for this thermal zone
166 * @trip_temp_attrs: attributes for trip points for sysfs: trip temperature
167 * @trip_type_attrs: attributes for trip points for sysfs: trip type
168 * @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis
169 * @devdata: private pointer for device private data
170 * @trips: number of trip points the thermal zone supports
171 * @passive_delay: number of milliseconds to wait between polls when
172 * performing passive cooling. Currenty only used by the
173 * step-wise governor
174 * @polling_delay: number of milliseconds to wait between polls when
175 * checking whether trip points have been crossed (0 for
176 * interrupt driven systems)
177 * @temperature: current temperature. This is only for core code,
178 * drivers should use thermal_zone_get_temp() to get the
179 * current temperature
180 * @last_temperature: previous temperature read
181 * @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION
182 * @passive: 1 if you've crossed a passive trip point, 0 otherwise.
183 * Currenty only used by the step-wise governor.
184 * @forced_passive: If > 0, temperature at which to switch on all ACPI
185 * processor cooling devices. Currently only used by the
186 * step-wise governor.
187 * @ops: operations this &thermal_zone_device supports
188 * @tzp: thermal zone parameters
189 * @governor: pointer to the governor for this thermal zone
190 * @thermal_instances: list of &struct thermal_instance of this thermal zone
191 * @idr: &struct idr to generate unique id for this zone's cooling
192 * devices
193 * @lock: lock to protect thermal_instances list
194 * @node: node in thermal_tz_list (in thermal_core.c)
195 * @poll_queue: delayed work for polling
196 */
161struct thermal_zone_device { 197struct thermal_zone_device {
162 int id; 198 int id;
163 char type[THERMAL_NAME_LENGTH]; 199 char type[THERMAL_NAME_LENGTH];
@@ -179,12 +215,18 @@ struct thermal_zone_device {
179 struct thermal_governor *governor; 215 struct thermal_governor *governor;
180 struct list_head thermal_instances; 216 struct list_head thermal_instances;
181 struct idr idr; 217 struct idr idr;
182 struct mutex lock; /* protect thermal_instances list */ 218 struct mutex lock;
183 struct list_head node; 219 struct list_head node;
184 struct delayed_work poll_queue; 220 struct delayed_work poll_queue;
185}; 221};
186 222
187/* Structure that holds thermal governor information */ 223/**
224 * struct thermal_governor - structure that holds thermal governor information
225 * @name: name of the governor
226 * @throttle: callback called for every trip point even if temperature is
227 * below the trip point temperature
228 * @governor_list: node in thermal_governor_list (in thermal_core.c)
229 */
188struct thermal_governor { 230struct thermal_governor {
189 char name[THERMAL_NAME_LENGTH]; 231 char name[THERMAL_NAME_LENGTH];
190 int (*throttle)(struct thermal_zone_device *tz, int trip); 232 int (*throttle)(struct thermal_zone_device *tz, int trip);