diff options
author | Eduardo Valentin <eduardo.valentin@ti.com> | 2013-05-15 11:46:00 -0400 |
---|---|---|
committer | Zhang Rui <rui.zhang@intel.com> | 2013-05-27 22:40:37 -0400 |
commit | eb982001dbd8546f273f444868a1031cc78b4250 (patch) | |
tree | 08547bb02ed69dec61a69511b66e1ee6ac8e49d1 /drivers/thermal/ti-soc-thermal | |
parent | c240a539df4e2d50f86e2f31813ff6b7334cd493 (diff) |
thermal: introduce TI SoC thermal driver
This patch moves the ti-soc-thermal driver out of
the staging tree to the thermal tree.
Cc: Grant Likely <grant.likely@linaro.org>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Rob Landley <rob@landley.net>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Zhang Rui <rui.zhang@intel.com>
Cc: Eduardo Valentin <eduardo.valentin@ti.com>
Cc: J Keerthy <j-keerthy@ti.com>
Cc: Radhesh Fadnis <radhesh.fadnis@ti.com>
Cc: Cyril Roelandt <tipecaml@gmail.com>
Cc: devicetree-discuss@lists.ozlabs.org
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: devel@driverdev.osuosl.org
Cc: linux-pm@vger.kernel.org
Signed-off-by: Eduardo Valentin <eduardo.valentin@ti.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Diffstat (limited to 'drivers/thermal/ti-soc-thermal')
-rw-r--r-- | drivers/thermal/ti-soc-thermal/Kconfig | 48 | ||||
-rw-r--r-- | drivers/thermal/ti-soc-thermal/Makefile | 5 | ||||
-rw-r--r-- | drivers/thermal/ti-soc-thermal/TODO | 12 | ||||
-rw-r--r-- | drivers/thermal/ti-soc-thermal/omap4-thermal-data.c | 267 | ||||
-rw-r--r-- | drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h | 175 | ||||
-rw-r--r-- | drivers/thermal/ti-soc-thermal/omap5-thermal-data.c | 359 | ||||
-rw-r--r-- | drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h | 200 | ||||
-rw-r--r-- | drivers/thermal/ti-soc-thermal/ti-bandgap.c | 1546 | ||||
-rw-r--r-- | drivers/thermal/ti-soc-thermal/ti-bandgap.h | 403 | ||||
-rw-r--r-- | drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 367 | ||||
-rw-r--r-- | drivers/thermal/ti-soc-thermal/ti-thermal.h | 117 |
11 files changed, 3499 insertions, 0 deletions
diff --git a/drivers/thermal/ti-soc-thermal/Kconfig b/drivers/thermal/ti-soc-thermal/Kconfig new file mode 100644 index 000000000000..e81375fb2155 --- /dev/null +++ b/drivers/thermal/ti-soc-thermal/Kconfig | |||
@@ -0,0 +1,48 @@ | |||
1 | config TI_SOC_THERMAL | ||
2 | tristate "Texas Instruments SoCs temperature sensor driver" | ||
3 | depends on THERMAL | ||
4 | depends on ARCH_HAS_BANDGAP | ||
5 | help | ||
6 | If you say yes here you get support for the Texas Instruments | ||
7 | OMAP4460+ on die bandgap temperature sensor support. The register | ||
8 | set is part of system control module. | ||
9 | |||
10 | This includes alert interrupts generation and also the TSHUT | ||
11 | support. | ||
12 | |||
13 | config TI_THERMAL | ||
14 | bool "Texas Instruments SoCs thermal framework support" | ||
15 | depends on TI_SOC_THERMAL | ||
16 | depends on CPU_THERMAL | ||
17 | help | ||
18 | If you say yes here you want to get support for generic thermal | ||
19 | framework for the Texas Instruments on die bandgap temperature sensor. | ||
20 | |||
21 | This includes trip points definitions, extrapolation rules and | ||
22 | CPU cooling device bindings. | ||
23 | |||
24 | config OMAP4_THERMAL | ||
25 | bool "Texas Instruments OMAP4 thermal support" | ||
26 | depends on TI_SOC_THERMAL | ||
27 | depends on ARCH_OMAP4 | ||
28 | help | ||
29 | If you say yes here you get thermal support for the Texas Instruments | ||
30 | OMAP4 SoC family. The current chip supported are: | ||
31 | - OMAP4430 | ||
32 | - OMAP4460 | ||
33 | - OMAP4470 | ||
34 | |||
35 | This includes alert interrupts generation and also the TSHUT | ||
36 | support. | ||
37 | |||
38 | config OMAP5_THERMAL | ||
39 | bool "Texas Instruments OMAP5 thermal support" | ||
40 | depends on TI_SOC_THERMAL | ||
41 | depends on SOC_OMAP5 | ||
42 | help | ||
43 | If you say yes here you get thermal support for the Texas Instruments | ||
44 | OMAP5 SoC family. The current chip supported are: | ||
45 | - OMAP5430 | ||
46 | |||
47 | This includes alert interrupts generation and also the TSHUT | ||
48 | support. | ||
diff --git a/drivers/thermal/ti-soc-thermal/Makefile b/drivers/thermal/ti-soc-thermal/Makefile new file mode 100644 index 000000000000..0ca034fb419d --- /dev/null +++ b/drivers/thermal/ti-soc-thermal/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal.o | ||
2 | ti-soc-thermal-y := ti-bandgap.o | ||
3 | ti-soc-thermal-$(CONFIG_TI_THERMAL) += ti-thermal-common.o | ||
4 | ti-soc-thermal-$(CONFIG_OMAP4_THERMAL) += omap4-thermal-data.o | ||
5 | ti-soc-thermal-$(CONFIG_OMAP5_THERMAL) += omap5-thermal-data.o | ||
diff --git a/drivers/thermal/ti-soc-thermal/TODO b/drivers/thermal/ti-soc-thermal/TODO new file mode 100644 index 000000000000..7da787d19241 --- /dev/null +++ b/drivers/thermal/ti-soc-thermal/TODO | |||
@@ -0,0 +1,12 @@ | |||
1 | List of TODOs (by Eduardo Valentin) | ||
2 | |||
3 | on ti-bandgap.c: | ||
4 | - Revisit PM support | ||
5 | |||
6 | on ti-thermal-common.c/ti-thermal.h: | ||
7 | - Revisit need for locking | ||
8 | |||
9 | generally: | ||
10 | - make sure this code works on OMAP4430, OMAP4460 and OMAP5430 | ||
11 | |||
12 | Copy patches to Eduardo Valentin <eduardo.valentin@ti.com> | ||
diff --git a/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c new file mode 100644 index 000000000000..d255d33da9eb --- /dev/null +++ b/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * OMAP4 thermal driver. | ||
3 | * | ||
4 | * Copyright (C) 2011-2012 Texas Instruments Inc. | ||
5 | * Contact: | ||
6 | * Eduardo Valentin <eduardo.valentin@ti.com> | ||
7 | * | ||
8 | * This software is licensed under the terms of the GNU General Public | ||
9 | * License version 2, as published by the Free Software Foundation, and | ||
10 | * may be copied, distributed, and modified under those terms. | ||
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 | */ | ||
18 | |||
19 | #include "ti-thermal.h" | ||
20 | #include "ti-bandgap.h" | ||
21 | #include "omap4xxx-bandgap.h" | ||
22 | |||
23 | /* | ||
24 | * OMAP4430 has one instance of thermal sensor for MPU | ||
25 | * need to describe the individual bit fields | ||
26 | */ | ||
27 | static struct temp_sensor_registers | ||
28 | omap4430_mpu_temp_sensor_registers = { | ||
29 | .temp_sensor_ctrl = OMAP4430_TEMP_SENSOR_CTRL_OFFSET, | ||
30 | .bgap_tempsoff_mask = OMAP4430_BGAP_TEMPSOFF_MASK, | ||
31 | .bgap_soc_mask = OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK, | ||
32 | .bgap_eocz_mask = OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK, | ||
33 | .bgap_dtemp_mask = OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK, | ||
34 | |||
35 | .bgap_mode_ctrl = OMAP4430_TEMP_SENSOR_CTRL_OFFSET, | ||
36 | .mode_ctrl_mask = OMAP4430_SINGLE_MODE_MASK, | ||
37 | |||
38 | .bgap_efuse = OMAP4430_FUSE_OPP_BGAP, | ||
39 | }; | ||
40 | |||
41 | /* Thresholds and limits for OMAP4430 MPU temperature sensor */ | ||
42 | static struct temp_sensor_data omap4430_mpu_temp_sensor_data = { | ||
43 | .min_freq = OMAP4430_MIN_FREQ, | ||
44 | .max_freq = OMAP4430_MAX_FREQ, | ||
45 | .max_temp = OMAP4430_MAX_TEMP, | ||
46 | .min_temp = OMAP4430_MIN_TEMP, | ||
47 | .hyst_val = OMAP4430_HYST_VAL, | ||
48 | }; | ||
49 | |||
50 | /* | ||
51 | * Temperature values in milli degree celsius | ||
52 | * ADC code values from 530 to 923 | ||
53 | */ | ||
54 | static const int | ||
55 | omap4430_adc_to_temp[OMAP4430_ADC_END_VALUE - OMAP4430_ADC_START_VALUE + 1] = { | ||
56 | -38000, -35000, -34000, -32000, -30000, -28000, -26000, -24000, -22000, | ||
57 | -20000, -18000, -17000, -15000, -13000, -12000, -10000, -8000, -6000, | ||
58 | -5000, -3000, -1000, 0, 2000, 3000, 5000, 6000, 8000, 10000, 12000, | ||
59 | 13000, 15000, 17000, 19000, 21000, 23000, 25000, 27000, 28000, 30000, | ||
60 | 32000, 33000, 35000, 37000, 38000, 40000, 42000, 43000, 45000, 47000, | ||
61 | 48000, 50000, 52000, 53000, 55000, 57000, 58000, 60000, 62000, 64000, | ||
62 | 66000, 68000, 70000, 71000, 73000, 75000, 77000, 78000, 80000, 82000, | ||
63 | 83000, 85000, 87000, 88000, 90000, 92000, 93000, 95000, 97000, 98000, | ||
64 | 100000, 102000, 103000, 105000, 107000, 109000, 111000, 113000, 115000, | ||
65 | 117000, 118000, 120000, 122000, 123000, | ||
66 | }; | ||
67 | |||
68 | /* OMAP4430 data */ | ||
69 | const struct ti_bandgap_data omap4430_data = { | ||
70 | .features = TI_BANDGAP_FEATURE_MODE_CONFIG | | ||
71 | TI_BANDGAP_FEATURE_CLK_CTRL | | ||
72 | TI_BANDGAP_FEATURE_POWER_SWITCH, | ||
73 | .fclock_name = "bandgap_fclk", | ||
74 | .div_ck_name = "bandgap_fclk", | ||
75 | .conv_table = omap4430_adc_to_temp, | ||
76 | .adc_start_val = OMAP4430_ADC_START_VALUE, | ||
77 | .adc_end_val = OMAP4430_ADC_END_VALUE, | ||
78 | .expose_sensor = ti_thermal_expose_sensor, | ||
79 | .remove_sensor = ti_thermal_remove_sensor, | ||
80 | .sensors = { | ||
81 | { | ||
82 | .registers = &omap4430_mpu_temp_sensor_registers, | ||
83 | .ts_data = &omap4430_mpu_temp_sensor_data, | ||
84 | .domain = "cpu", | ||
85 | .slope = OMAP_GRADIENT_SLOPE_4430, | ||
86 | .constant = OMAP_GRADIENT_CONST_4430, | ||
87 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4430, | ||
88 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4430, | ||
89 | .register_cooling = ti_thermal_register_cpu_cooling, | ||
90 | .unregister_cooling = ti_thermal_unregister_cpu_cooling, | ||
91 | }, | ||
92 | }, | ||
93 | .sensor_count = 1, | ||
94 | }; | ||
95 | /* | ||
96 | * OMAP4460 has one instance of thermal sensor for MPU | ||
97 | * need to describe the individual bit fields | ||
98 | */ | ||
99 | static struct temp_sensor_registers | ||
100 | omap4460_mpu_temp_sensor_registers = { | ||
101 | .temp_sensor_ctrl = OMAP4460_TEMP_SENSOR_CTRL_OFFSET, | ||
102 | .bgap_tempsoff_mask = OMAP4460_BGAP_TEMPSOFF_MASK, | ||
103 | .bgap_soc_mask = OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK, | ||
104 | .bgap_eocz_mask = OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK, | ||
105 | .bgap_dtemp_mask = OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK, | ||
106 | |||
107 | .bgap_mask_ctrl = OMAP4460_BGAP_CTRL_OFFSET, | ||
108 | .mask_hot_mask = OMAP4460_MASK_HOT_MASK, | ||
109 | .mask_cold_mask = OMAP4460_MASK_COLD_MASK, | ||
110 | |||
111 | .bgap_mode_ctrl = OMAP4460_BGAP_CTRL_OFFSET, | ||
112 | .mode_ctrl_mask = OMAP4460_SINGLE_MODE_MASK, | ||
113 | |||
114 | .bgap_counter = OMAP4460_BGAP_COUNTER_OFFSET, | ||
115 | .counter_mask = OMAP4460_COUNTER_MASK, | ||
116 | |||
117 | .bgap_threshold = OMAP4460_BGAP_THRESHOLD_OFFSET, | ||
118 | .threshold_thot_mask = OMAP4460_T_HOT_MASK, | ||
119 | .threshold_tcold_mask = OMAP4460_T_COLD_MASK, | ||
120 | |||
121 | .tshut_threshold = OMAP4460_BGAP_TSHUT_OFFSET, | ||
122 | .tshut_hot_mask = OMAP4460_TSHUT_HOT_MASK, | ||
123 | .tshut_cold_mask = OMAP4460_TSHUT_COLD_MASK, | ||
124 | |||
125 | .bgap_status = OMAP4460_BGAP_STATUS_OFFSET, | ||
126 | .status_clean_stop_mask = OMAP4460_CLEAN_STOP_MASK, | ||
127 | .status_bgap_alert_mask = OMAP4460_BGAP_ALERT_MASK, | ||
128 | .status_hot_mask = OMAP4460_HOT_FLAG_MASK, | ||
129 | .status_cold_mask = OMAP4460_COLD_FLAG_MASK, | ||
130 | |||
131 | .bgap_efuse = OMAP4460_FUSE_OPP_BGAP, | ||
132 | }; | ||
133 | |||
134 | /* Thresholds and limits for OMAP4460 MPU temperature sensor */ | ||
135 | static struct temp_sensor_data omap4460_mpu_temp_sensor_data = { | ||
136 | .tshut_hot = OMAP4460_TSHUT_HOT, | ||
137 | .tshut_cold = OMAP4460_TSHUT_COLD, | ||
138 | .t_hot = OMAP4460_T_HOT, | ||
139 | .t_cold = OMAP4460_T_COLD, | ||
140 | .min_freq = OMAP4460_MIN_FREQ, | ||
141 | .max_freq = OMAP4460_MAX_FREQ, | ||
142 | .max_temp = OMAP4460_MAX_TEMP, | ||
143 | .min_temp = OMAP4460_MIN_TEMP, | ||
144 | .hyst_val = OMAP4460_HYST_VAL, | ||
145 | .update_int1 = 1000, | ||
146 | .update_int2 = 2000, | ||
147 | }; | ||
148 | |||
149 | /* | ||
150 | * Temperature values in milli degree celsius | ||
151 | * ADC code values from 530 to 923 | ||
152 | */ | ||
153 | static const int | ||
154 | omap4460_adc_to_temp[OMAP4460_ADC_END_VALUE - OMAP4460_ADC_START_VALUE + 1] = { | ||
155 | -40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600, -38200, | ||
156 | -37800, -37300, -36800, -36400, -36000, -35600, -35200, -34800, | ||
157 | -34300, -33800, -33400, -33000, -32600, -32200, -31800, -31300, | ||
158 | -30800, -30400, -30000, -29600, -29200, -28700, -28200, -27800, | ||
159 | -27400, -27000, -26600, -26200, -25700, -25200, -24800, -24400, | ||
160 | -24000, -23600, -23200, -22700, -22200, -21800, -21400, -21000, | ||
161 | -20600, -20200, -19700, -19200, -18800, -18400, -18000, -17600, | ||
162 | -17200, -16700, -16200, -15800, -15400, -15000, -14600, -14200, | ||
163 | -13700, -13200, -12800, -12400, -12000, -11600, -11200, -10700, | ||
164 | -10200, -9800, -9400, -9000, -8600, -8200, -7700, -7200, -6800, | ||
165 | -6400, -6000, -5600, -5200, -4800, -4300, -3800, -3400, -3000, | ||
166 | -2600, -2200, -1800, -1300, -800, -400, 0, 400, 800, 1200, 1600, | ||
167 | 2100, 2600, 3000, 3400, 3800, 4200, 4600, 5100, 5600, 6000, 6400, | ||
168 | 6800, 7200, 7600, 8000, 8500, 9000, 9400, 9800, 10200, 10600, 11000, | ||
169 | 11400, 11900, 12400, 12800, 13200, 13600, 14000, 14400, 14800, | ||
170 | 15300, 15800, 16200, 16600, 17000, 17400, 17800, 18200, 18700, | ||
171 | 19200, 19600, 20000, 20400, 20800, 21200, 21600, 22100, 22600, | ||
172 | 23000, 23400, 23800, 24200, 24600, 25000, 25400, 25900, 26400, | ||
173 | 26800, 27200, 27600, 28000, 28400, 28800, 29300, 29800, 30200, | ||
174 | 30600, 31000, 31400, 31800, 32200, 32600, 33100, 33600, 34000, | ||
175 | 34400, 34800, 35200, 35600, 36000, 36400, 36800, 37300, 37800, | ||
176 | 38200, 38600, 39000, 39400, 39800, 40200, 40600, 41100, 41600, | ||
177 | 42000, 42400, 42800, 43200, 43600, 44000, 44400, 44800, 45300, | ||
178 | 45800, 46200, 46600, 47000, 47400, 47800, 48200, 48600, 49000, | ||
179 | 49500, 50000, 50400, 50800, 51200, 51600, 52000, 52400, 52800, | ||
180 | 53200, 53700, 54200, 54600, 55000, 55400, 55800, 56200, 56600, | ||
181 | 57000, 57400, 57800, 58200, 58700, 59200, 59600, 60000, 60400, | ||
182 | 60800, 61200, 61600, 62000, 62400, 62800, 63300, 63800, 64200, | ||
183 | 64600, 65000, 65400, 65800, 66200, 66600, 67000, 67400, 67800, | ||
184 | 68200, 68700, 69200, 69600, 70000, 70400, 70800, 71200, 71600, | ||
185 | 72000, 72400, 72800, 73200, 73600, 74100, 74600, 75000, 75400, | ||
186 | 75800, 76200, 76600, 77000, 77400, 77800, 78200, 78600, 79000, | ||
187 | 79400, 79800, 80300, 80800, 81200, 81600, 82000, 82400, 82800, | ||
188 | 83200, 83600, 84000, 84400, 84800, 85200, 85600, 86000, 86400, | ||
189 | 86800, 87300, 87800, 88200, 88600, 89000, 89400, 89800, 90200, | ||
190 | 90600, 91000, 91400, 91800, 92200, 92600, 93000, 93400, 93800, | ||
191 | 94200, 94600, 95000, 95500, 96000, 96400, 96800, 97200, 97600, | ||
192 | 98000, 98400, 98800, 99200, 99600, 100000, 100400, 100800, 101200, | ||
193 | 101600, 102000, 102400, 102800, 103200, 103600, 104000, 104400, | ||
194 | 104800, 105200, 105600, 106100, 106600, 107000, 107400, 107800, | ||
195 | 108200, 108600, 109000, 109400, 109800, 110200, 110600, 111000, | ||
196 | 111400, 111800, 112200, 112600, 113000, 113400, 113800, 114200, | ||
197 | 114600, 115000, 115400, 115800, 116200, 116600, 117000, 117400, | ||
198 | 117800, 118200, 118600, 119000, 119400, 119800, 120200, 120600, | ||
199 | 121000, 121400, 121800, 122200, 122600, 123000, 123400, 123800, 124200, | ||
200 | 124600, 124900, 125000, 125000, 125000, 125000 | ||
201 | }; | ||
202 | |||
203 | /* OMAP4460 data */ | ||
204 | const struct ti_bandgap_data omap4460_data = { | ||
205 | .features = TI_BANDGAP_FEATURE_TSHUT | | ||
206 | TI_BANDGAP_FEATURE_TSHUT_CONFIG | | ||
207 | TI_BANDGAP_FEATURE_TALERT | | ||
208 | TI_BANDGAP_FEATURE_MODE_CONFIG | | ||
209 | TI_BANDGAP_FEATURE_POWER_SWITCH | | ||
210 | TI_BANDGAP_FEATURE_CLK_CTRL | | ||
211 | TI_BANDGAP_FEATURE_COUNTER, | ||
212 | .fclock_name = "bandgap_ts_fclk", | ||
213 | .div_ck_name = "div_ts_ck", | ||
214 | .conv_table = omap4460_adc_to_temp, | ||
215 | .adc_start_val = OMAP4460_ADC_START_VALUE, | ||
216 | .adc_end_val = OMAP4460_ADC_END_VALUE, | ||
217 | .expose_sensor = ti_thermal_expose_sensor, | ||
218 | .remove_sensor = ti_thermal_remove_sensor, | ||
219 | .report_temperature = ti_thermal_report_sensor_temperature, | ||
220 | .sensors = { | ||
221 | { | ||
222 | .registers = &omap4460_mpu_temp_sensor_registers, | ||
223 | .ts_data = &omap4460_mpu_temp_sensor_data, | ||
224 | .domain = "cpu", | ||
225 | .slope = OMAP_GRADIENT_SLOPE_4460, | ||
226 | .constant = OMAP_GRADIENT_CONST_4460, | ||
227 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4460, | ||
228 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4460, | ||
229 | .register_cooling = ti_thermal_register_cpu_cooling, | ||
230 | .unregister_cooling = ti_thermal_unregister_cpu_cooling, | ||
231 | }, | ||
232 | }, | ||
233 | .sensor_count = 1, | ||
234 | }; | ||
235 | |||
236 | /* OMAP4470 data */ | ||
237 | const struct ti_bandgap_data omap4470_data = { | ||
238 | .features = TI_BANDGAP_FEATURE_TSHUT | | ||
239 | TI_BANDGAP_FEATURE_TSHUT_CONFIG | | ||
240 | TI_BANDGAP_FEATURE_TALERT | | ||
241 | TI_BANDGAP_FEATURE_MODE_CONFIG | | ||
242 | TI_BANDGAP_FEATURE_POWER_SWITCH | | ||
243 | TI_BANDGAP_FEATURE_CLK_CTRL | | ||
244 | TI_BANDGAP_FEATURE_COUNTER, | ||
245 | .fclock_name = "bandgap_ts_fclk", | ||
246 | .div_ck_name = "div_ts_ck", | ||
247 | .conv_table = omap4460_adc_to_temp, | ||
248 | .adc_start_val = OMAP4460_ADC_START_VALUE, | ||
249 | .adc_end_val = OMAP4460_ADC_END_VALUE, | ||
250 | .expose_sensor = ti_thermal_expose_sensor, | ||
251 | .remove_sensor = ti_thermal_remove_sensor, | ||
252 | .report_temperature = ti_thermal_report_sensor_temperature, | ||
253 | .sensors = { | ||
254 | { | ||
255 | .registers = &omap4460_mpu_temp_sensor_registers, | ||
256 | .ts_data = &omap4460_mpu_temp_sensor_data, | ||
257 | .domain = "cpu", | ||
258 | .slope = OMAP_GRADIENT_SLOPE_4470, | ||
259 | .constant = OMAP_GRADIENT_CONST_4470, | ||
260 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4470, | ||
261 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4470, | ||
262 | .register_cooling = ti_thermal_register_cpu_cooling, | ||
263 | .unregister_cooling = ti_thermal_unregister_cpu_cooling, | ||
264 | }, | ||
265 | }, | ||
266 | .sensor_count = 1, | ||
267 | }; | ||
diff --git a/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h b/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h new file mode 100644 index 000000000000..6f2de3a3356d --- /dev/null +++ b/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h | |||
@@ -0,0 +1,175 @@ | |||
1 | /* | ||
2 | * OMAP4xxx bandgap registers, bitfields and temperature definitions | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * Contact: | ||
6 | * Eduardo Valentin <eduardo.valentin@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | #ifndef __OMAP4XXX_BANDGAP_H | ||
24 | #define __OMAP4XXX_BANDGAP_H | ||
25 | |||
26 | /** | ||
27 | * *** OMAP4430 *** | ||
28 | * | ||
29 | * Below, in sequence, are the Register definitions, | ||
30 | * the bitfields and the temperature definitions for OMAP4430. | ||
31 | */ | ||
32 | |||
33 | /** | ||
34 | * OMAP4430 register definitions | ||
35 | * | ||
36 | * Registers are defined as offsets. The offsets are | ||
37 | * relative to FUSE_OPP_BGAP on 4430. | ||
38 | */ | ||
39 | |||
40 | /* OMAP4430.FUSE_OPP_BGAP */ | ||
41 | #define OMAP4430_FUSE_OPP_BGAP 0x0 | ||
42 | |||
43 | /* OMAP4430.TEMP_SENSOR */ | ||
44 | #define OMAP4430_TEMP_SENSOR_CTRL_OFFSET 0xCC | ||
45 | |||
46 | /** | ||
47 | * Register and bit definitions for OMAP4430 | ||
48 | * | ||
49 | * All the macros bellow define the required bits for | ||
50 | * controlling temperature on OMAP4430. Bit defines are | ||
51 | * grouped by register. | ||
52 | */ | ||
53 | |||
54 | /* OMAP4430.TEMP_SENSOR bits */ | ||
55 | #define OMAP4430_BGAP_TEMPSOFF_MASK BIT(12) | ||
56 | #define OMAP4430_BGAP_TSHUT_MASK BIT(11) | ||
57 | #define OMAP4430_SINGLE_MODE_MASK BIT(10) | ||
58 | #define OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK BIT(9) | ||
59 | #define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK BIT(8) | ||
60 | #define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK (0xff << 0) | ||
61 | |||
62 | /** | ||
63 | * Temperature limits and thresholds for OMAP4430 | ||
64 | * | ||
65 | * All the macros bellow are definitions for handling the | ||
66 | * ADC conversions and representation of temperature limits | ||
67 | * and thresholds for OMAP4430. | ||
68 | */ | ||
69 | |||
70 | /* ADC conversion table limits */ | ||
71 | #define OMAP4430_ADC_START_VALUE 0 | ||
72 | #define OMAP4430_ADC_END_VALUE 127 | ||
73 | /* bandgap clock limits (no control on 4430) */ | ||
74 | #define OMAP4430_MAX_FREQ 32768 | ||
75 | #define OMAP4430_MIN_FREQ 32768 | ||
76 | /* sensor limits */ | ||
77 | #define OMAP4430_MIN_TEMP -40000 | ||
78 | #define OMAP4430_MAX_TEMP 125000 | ||
79 | #define OMAP4430_HYST_VAL 5000 | ||
80 | |||
81 | /** | ||
82 | * *** OMAP4460 *** Applicable for OMAP4470 | ||
83 | * | ||
84 | * Below, in sequence, are the Register definitions, | ||
85 | * the bitfields and the temperature definitions for OMAP4460. | ||
86 | */ | ||
87 | |||
88 | /** | ||
89 | * OMAP4460 register definitions | ||
90 | * | ||
91 | * Registers are defined as offsets. The offsets are | ||
92 | * relative to FUSE_OPP_BGAP on 4460. | ||
93 | */ | ||
94 | |||
95 | /* OMAP4460.FUSE_OPP_BGAP */ | ||
96 | #define OMAP4460_FUSE_OPP_BGAP 0x0 | ||
97 | |||
98 | /* OMAP4460.TEMP_SENSOR */ | ||
99 | #define OMAP4460_TEMP_SENSOR_CTRL_OFFSET 0xCC | ||
100 | |||
101 | /* OMAP4460.BANDGAP_CTRL */ | ||
102 | #define OMAP4460_BGAP_CTRL_OFFSET 0x118 | ||
103 | |||
104 | /* OMAP4460.BANDGAP_COUNTER */ | ||
105 | #define OMAP4460_BGAP_COUNTER_OFFSET 0x11C | ||
106 | |||
107 | /* OMAP4460.BANDGAP_THRESHOLD */ | ||
108 | #define OMAP4460_BGAP_THRESHOLD_OFFSET 0x120 | ||
109 | |||
110 | /* OMAP4460.TSHUT_THRESHOLD */ | ||
111 | #define OMAP4460_BGAP_TSHUT_OFFSET 0x124 | ||
112 | |||
113 | /* OMAP4460.BANDGAP_STATUS */ | ||
114 | #define OMAP4460_BGAP_STATUS_OFFSET 0x128 | ||
115 | |||
116 | /** | ||
117 | * Register bitfields for OMAP4460 | ||
118 | * | ||
119 | * All the macros bellow define the required bits for | ||
120 | * controlling temperature on OMAP4460. Bit defines are | ||
121 | * grouped by register. | ||
122 | */ | ||
123 | /* OMAP4460.TEMP_SENSOR bits */ | ||
124 | #define OMAP4460_BGAP_TEMPSOFF_MASK BIT(13) | ||
125 | #define OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK BIT(11) | ||
126 | #define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK BIT(10) | ||
127 | #define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0) | ||
128 | |||
129 | /* OMAP4460.BANDGAP_CTRL bits */ | ||
130 | #define OMAP4460_SINGLE_MODE_MASK BIT(31) | ||
131 | #define OMAP4460_MASK_HOT_MASK BIT(1) | ||
132 | #define OMAP4460_MASK_COLD_MASK BIT(0) | ||
133 | |||
134 | /* OMAP4460.BANDGAP_COUNTER bits */ | ||
135 | #define OMAP4460_COUNTER_MASK (0xffffff << 0) | ||
136 | |||
137 | /* OMAP4460.BANDGAP_THRESHOLD bits */ | ||
138 | #define OMAP4460_T_HOT_MASK (0x3ff << 16) | ||
139 | #define OMAP4460_T_COLD_MASK (0x3ff << 0) | ||
140 | |||
141 | /* OMAP4460.TSHUT_THRESHOLD bits */ | ||
142 | #define OMAP4460_TSHUT_HOT_MASK (0x3ff << 16) | ||
143 | #define OMAP4460_TSHUT_COLD_MASK (0x3ff << 0) | ||
144 | |||
145 | /* OMAP4460.BANDGAP_STATUS bits */ | ||
146 | #define OMAP4460_CLEAN_STOP_MASK BIT(3) | ||
147 | #define OMAP4460_BGAP_ALERT_MASK BIT(2) | ||
148 | #define OMAP4460_HOT_FLAG_MASK BIT(1) | ||
149 | #define OMAP4460_COLD_FLAG_MASK BIT(0) | ||
150 | |||
151 | /** | ||
152 | * Temperature limits and thresholds for OMAP4460 | ||
153 | * | ||
154 | * All the macros bellow are definitions for handling the | ||
155 | * ADC conversions and representation of temperature limits | ||
156 | * and thresholds for OMAP4460. | ||
157 | */ | ||
158 | |||
159 | /* ADC conversion table limits */ | ||
160 | #define OMAP4460_ADC_START_VALUE 530 | ||
161 | #define OMAP4460_ADC_END_VALUE 932 | ||
162 | /* bandgap clock limits */ | ||
163 | #define OMAP4460_MAX_FREQ 1500000 | ||
164 | #define OMAP4460_MIN_FREQ 1000000 | ||
165 | /* sensor limits */ | ||
166 | #define OMAP4460_MIN_TEMP -40000 | ||
167 | #define OMAP4460_MAX_TEMP 123000 | ||
168 | #define OMAP4460_HYST_VAL 5000 | ||
169 | /* interrupts thresholds */ | ||
170 | #define OMAP4460_TSHUT_HOT 900 /* 122 deg C */ | ||
171 | #define OMAP4460_TSHUT_COLD 895 /* 100 deg C */ | ||
172 | #define OMAP4460_T_HOT 800 /* 73 deg C */ | ||
173 | #define OMAP4460_T_COLD 795 /* 71 deg C */ | ||
174 | |||
175 | #endif /* __OMAP4XXX_BANDGAP_H */ | ||
diff --git a/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c new file mode 100644 index 000000000000..eff0c80fd4af --- /dev/null +++ b/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c | |||
@@ -0,0 +1,359 @@ | |||
1 | /* | ||
2 | * OMAP5 thermal driver. | ||
3 | * | ||
4 | * Copyright (C) 2011-2012 Texas Instruments Inc. | ||
5 | * Contact: | ||
6 | * Eduardo Valentin <eduardo.valentin@ti.com> | ||
7 | * | ||
8 | * This software is licensed under the terms of the GNU General Public | ||
9 | * License version 2, as published by the Free Software Foundation, and | ||
10 | * may be copied, distributed, and modified under those terms. | ||
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 | */ | ||
18 | |||
19 | #include "ti-thermal.h" | ||
20 | #include "ti-bandgap.h" | ||
21 | #include "omap5xxx-bandgap.h" | ||
22 | |||
23 | /* | ||
24 | * OMAP5430 has three instances of thermal sensor for MPU, GPU & CORE, | ||
25 | * need to describe the individual registers and bit fields. | ||
26 | */ | ||
27 | |||
28 | /* | ||
29 | * OMAP5430 MPU thermal sensor register offset and bit-fields | ||
30 | */ | ||
31 | static struct temp_sensor_registers | ||
32 | omap5430_mpu_temp_sensor_registers = { | ||
33 | .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_MPU_OFFSET, | ||
34 | .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK, | ||
35 | .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK, | ||
36 | .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK, | ||
37 | |||
38 | .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET, | ||
39 | .mask_hot_mask = OMAP5430_MASK_HOT_MPU_MASK, | ||
40 | .mask_cold_mask = OMAP5430_MASK_COLD_MPU_MASK, | ||
41 | .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK, | ||
42 | .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK, | ||
43 | .mask_freeze_mask = OMAP5430_MASK_FREEZE_MPU_MASK, | ||
44 | .mask_clear_mask = OMAP5430_MASK_CLEAR_MPU_MASK, | ||
45 | .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_MPU_MASK, | ||
46 | |||
47 | |||
48 | .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET, | ||
49 | .counter_mask = OMAP5430_COUNTER_MASK, | ||
50 | |||
51 | .bgap_threshold = OMAP5430_BGAP_THRESHOLD_MPU_OFFSET, | ||
52 | .threshold_thot_mask = OMAP5430_T_HOT_MASK, | ||
53 | .threshold_tcold_mask = OMAP5430_T_COLD_MASK, | ||
54 | |||
55 | .tshut_threshold = OMAP5430_BGAP_TSHUT_MPU_OFFSET, | ||
56 | .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK, | ||
57 | .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK, | ||
58 | |||
59 | .bgap_status = OMAP5430_BGAP_STATUS_OFFSET, | ||
60 | .status_clean_stop_mask = 0x0, | ||
61 | .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK, | ||
62 | .status_hot_mask = OMAP5430_HOT_MPU_FLAG_MASK, | ||
63 | .status_cold_mask = OMAP5430_COLD_MPU_FLAG_MASK, | ||
64 | |||
65 | .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_MPU_OFFSET, | ||
66 | .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_MPU_0_OFFSET, | ||
67 | .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_MPU_1_OFFSET, | ||
68 | .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_MPU_2_OFFSET, | ||
69 | .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_MPU_3_OFFSET, | ||
70 | .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_MPU_4_OFFSET, | ||
71 | .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_MPU, | ||
72 | }; | ||
73 | |||
74 | /* | ||
75 | * OMAP5430 GPU thermal sensor register offset and bit-fields | ||
76 | */ | ||
77 | static struct temp_sensor_registers | ||
78 | omap5430_gpu_temp_sensor_registers = { | ||
79 | .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_GPU_OFFSET, | ||
80 | .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK, | ||
81 | .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK, | ||
82 | .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK, | ||
83 | |||
84 | .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET, | ||
85 | .mask_hot_mask = OMAP5430_MASK_HOT_GPU_MASK, | ||
86 | .mask_cold_mask = OMAP5430_MASK_COLD_GPU_MASK, | ||
87 | .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK, | ||
88 | .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK, | ||
89 | .mask_freeze_mask = OMAP5430_MASK_FREEZE_GPU_MASK, | ||
90 | .mask_clear_mask = OMAP5430_MASK_CLEAR_GPU_MASK, | ||
91 | .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_GPU_MASK, | ||
92 | |||
93 | .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET, | ||
94 | .counter_mask = OMAP5430_COUNTER_MASK, | ||
95 | |||
96 | .bgap_threshold = OMAP5430_BGAP_THRESHOLD_GPU_OFFSET, | ||
97 | .threshold_thot_mask = OMAP5430_T_HOT_MASK, | ||
98 | .threshold_tcold_mask = OMAP5430_T_COLD_MASK, | ||
99 | |||
100 | .tshut_threshold = OMAP5430_BGAP_TSHUT_GPU_OFFSET, | ||
101 | .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK, | ||
102 | .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK, | ||
103 | |||
104 | .bgap_status = OMAP5430_BGAP_STATUS_OFFSET, | ||
105 | .status_clean_stop_mask = 0x0, | ||
106 | .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK, | ||
107 | .status_hot_mask = OMAP5430_HOT_GPU_FLAG_MASK, | ||
108 | .status_cold_mask = OMAP5430_COLD_GPU_FLAG_MASK, | ||
109 | |||
110 | .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_GPU_OFFSET, | ||
111 | .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_GPU_0_OFFSET, | ||
112 | .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_GPU_1_OFFSET, | ||
113 | .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_GPU_2_OFFSET, | ||
114 | .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_GPU_3_OFFSET, | ||
115 | .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_GPU_4_OFFSET, | ||
116 | |||
117 | .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_GPU, | ||
118 | }; | ||
119 | |||
120 | /* | ||
121 | * OMAP5430 CORE thermal sensor register offset and bit-fields | ||
122 | */ | ||
123 | static struct temp_sensor_registers | ||
124 | omap5430_core_temp_sensor_registers = { | ||
125 | .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_CORE_OFFSET, | ||
126 | .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK, | ||
127 | .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK, | ||
128 | .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK, | ||
129 | |||
130 | .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET, | ||
131 | .mask_hot_mask = OMAP5430_MASK_HOT_CORE_MASK, | ||
132 | .mask_cold_mask = OMAP5430_MASK_COLD_CORE_MASK, | ||
133 | .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK, | ||
134 | .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK, | ||
135 | .mask_freeze_mask = OMAP5430_MASK_FREEZE_CORE_MASK, | ||
136 | .mask_clear_mask = OMAP5430_MASK_CLEAR_CORE_MASK, | ||
137 | .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_CORE_MASK, | ||
138 | |||
139 | .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET, | ||
140 | .counter_mask = OMAP5430_COUNTER_MASK, | ||
141 | |||
142 | .bgap_threshold = OMAP5430_BGAP_THRESHOLD_CORE_OFFSET, | ||
143 | .threshold_thot_mask = OMAP5430_T_HOT_MASK, | ||
144 | .threshold_tcold_mask = OMAP5430_T_COLD_MASK, | ||
145 | |||
146 | .tshut_threshold = OMAP5430_BGAP_TSHUT_CORE_OFFSET, | ||
147 | .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK, | ||
148 | .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK, | ||
149 | |||
150 | .bgap_status = OMAP5430_BGAP_STATUS_OFFSET, | ||
151 | .status_clean_stop_mask = 0x0, | ||
152 | .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK, | ||
153 | .status_hot_mask = OMAP5430_HOT_CORE_FLAG_MASK, | ||
154 | .status_cold_mask = OMAP5430_COLD_CORE_FLAG_MASK, | ||
155 | |||
156 | .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_CORE_OFFSET, | ||
157 | .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_CORE_0_OFFSET, | ||
158 | .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_CORE_1_OFFSET, | ||
159 | .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_CORE_2_OFFSET, | ||
160 | .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_CORE_3_OFFSET, | ||
161 | .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_CORE_4_OFFSET, | ||
162 | |||
163 | .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_CORE, | ||
164 | }; | ||
165 | |||
166 | /* Thresholds and limits for OMAP5430 MPU temperature sensor */ | ||
167 | static struct temp_sensor_data omap5430_mpu_temp_sensor_data = { | ||
168 | .tshut_hot = OMAP5430_MPU_TSHUT_HOT, | ||
169 | .tshut_cold = OMAP5430_MPU_TSHUT_COLD, | ||
170 | .t_hot = OMAP5430_MPU_T_HOT, | ||
171 | .t_cold = OMAP5430_MPU_T_COLD, | ||
172 | .min_freq = OMAP5430_MPU_MIN_FREQ, | ||
173 | .max_freq = OMAP5430_MPU_MAX_FREQ, | ||
174 | .max_temp = OMAP5430_MPU_MAX_TEMP, | ||
175 | .min_temp = OMAP5430_MPU_MIN_TEMP, | ||
176 | .hyst_val = OMAP5430_MPU_HYST_VAL, | ||
177 | .update_int1 = 1000, | ||
178 | .update_int2 = 2000, | ||
179 | }; | ||
180 | |||
181 | /* Thresholds and limits for OMAP5430 GPU temperature sensor */ | ||
182 | static struct temp_sensor_data omap5430_gpu_temp_sensor_data = { | ||
183 | .tshut_hot = OMAP5430_GPU_TSHUT_HOT, | ||
184 | .tshut_cold = OMAP5430_GPU_TSHUT_COLD, | ||
185 | .t_hot = OMAP5430_GPU_T_HOT, | ||
186 | .t_cold = OMAP5430_GPU_T_COLD, | ||
187 | .min_freq = OMAP5430_GPU_MIN_FREQ, | ||
188 | .max_freq = OMAP5430_GPU_MAX_FREQ, | ||
189 | .max_temp = OMAP5430_GPU_MAX_TEMP, | ||
190 | .min_temp = OMAP5430_GPU_MIN_TEMP, | ||
191 | .hyst_val = OMAP5430_GPU_HYST_VAL, | ||
192 | .update_int1 = 1000, | ||
193 | .update_int2 = 2000, | ||
194 | }; | ||
195 | |||
196 | /* Thresholds and limits for OMAP5430 CORE temperature sensor */ | ||
197 | static struct temp_sensor_data omap5430_core_temp_sensor_data = { | ||
198 | .tshut_hot = OMAP5430_CORE_TSHUT_HOT, | ||
199 | .tshut_cold = OMAP5430_CORE_TSHUT_COLD, | ||
200 | .t_hot = OMAP5430_CORE_T_HOT, | ||
201 | .t_cold = OMAP5430_CORE_T_COLD, | ||
202 | .min_freq = OMAP5430_CORE_MIN_FREQ, | ||
203 | .max_freq = OMAP5430_CORE_MAX_FREQ, | ||
204 | .max_temp = OMAP5430_CORE_MAX_TEMP, | ||
205 | .min_temp = OMAP5430_CORE_MIN_TEMP, | ||
206 | .hyst_val = OMAP5430_CORE_HYST_VAL, | ||
207 | .update_int1 = 1000, | ||
208 | .update_int2 = 2000, | ||
209 | }; | ||
210 | |||
211 | /* | ||
212 | * OMAP54xx ES2.0 : Temperature values in milli degree celsius | ||
213 | * ADC code values from 540 to 945 | ||
214 | */ | ||
215 | static int | ||
216 | omap5430_adc_to_temp[ | ||
217 | OMAP5430_ADC_END_VALUE - OMAP5430_ADC_START_VALUE + 1] = { | ||
218 | /* Index 540 - 549 */ | ||
219 | -40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600, -38200, | ||
220 | -37800, | ||
221 | /* Index 550 - 559 */ | ||
222 | -37400, -37000, -36600, -36200, -35800, -35300, -34700, -34200, -33800, | ||
223 | -33400, | ||
224 | /* Index 560 - 569 */ | ||
225 | -33000, -32600, -32200, -31800, -31400, -31000, -30600, -30200, -29800, | ||
226 | -29400, | ||
227 | /* Index 570 - 579 */ | ||
228 | -29000, -28600, -28200, -27700, -27100, -26600, -26200, -25800, -25400, | ||
229 | -25000, | ||
230 | /* Index 580 - 589 */ | ||
231 | -24600, -24200, -23800, -23400, -23000, -22600, -22200, -21600, -21400, | ||
232 | -21000, | ||
233 | /* Index 590 - 599 */ | ||
234 | -20500, -19900, -19400, -19000, -18600, -18200, -17800, -17400, -17000, | ||
235 | -16600, | ||
236 | /* Index 600 - 609 */ | ||
237 | -16200, -15800, -15400, -15000, -14600, -14200, -13800, -13400, -13000, | ||
238 | -12500, | ||
239 | /* Index 610 - 619 */ | ||
240 | -11900, -11400, -11000, -10600, -10200, -9800, -9400, -9000, -8600, | ||
241 | -8200, | ||
242 | /* Index 620 - 629 */ | ||
243 | -7800, -7400, -7000, -6600, -6200, -5800, -5400, -5000, -4500, -3900, | ||
244 | /* Index 630 - 639 */ | ||
245 | -3400, -3000, -2600, -2200, -1800, -1400, -1000, -600, -200, 200, | ||
246 | /* Index 640 - 649 */ | ||
247 | 600, 1000, 1400, 1800, 2200, 2600, 3000, 3400, 3900, 4500, | ||
248 | /* Index 650 - 659 */ | ||
249 | 5000, 5400, 5800, 6200, 6600, 7000, 7400, 7800, 8200, 8600, | ||
250 | /* Index 660 - 669 */ | ||
251 | 9000, 9400, 9800, 10200, 10600, 11000, 11400, 11800, 12200, 12700, | ||
252 | /* Index 670 - 679 */ | ||
253 | 13300, 13800, 14200, 14600, 15000, 15400, 15800, 16200, 16600, 17000, | ||
254 | /* Index 680 - 689 */ | ||
255 | 17400, 17800, 18200, 18600, 19000, 19400, 19800, 20200, 20600, 21100, | ||
256 | /* Index 690 - 699 */ | ||
257 | 21400, 21900, 22500, 23000, 23400, 23800, 24200, 24600, 25000, 25400, | ||
258 | /* Index 700 - 709 */ | ||
259 | 25800, 26200, 26600, 27000, 27400, 27800, 28200, 28600, 29000, 29400, | ||
260 | /* Index 710 - 719 */ | ||
261 | 29800, 30200, 30600, 31000, 31400, 31900, 32500, 33000, 33400, 33800, | ||
262 | /* Index 720 - 729 */ | ||
263 | 34200, 34600, 35000, 35400, 35800, 36200, 36600, 37000, 37400, 37800, | ||
264 | /* Index 730 - 739 */ | ||
265 | 38200, 38600, 39000, 39400, 39800, 40200, 40600, 41000, 41400, 41800, | ||
266 | /* Index 740 - 749 */ | ||
267 | 42200, 42600, 43100, 43700, 44200, 44600, 45000, 45400, 45800, 46200, | ||
268 | /* Index 750 - 759 */ | ||
269 | 46600, 47000, 47400, 47800, 48200, 48600, 49000, 49400, 49800, 50200, | ||
270 | /* Index 760 - 769 */ | ||
271 | 50600, 51000, 51400, 51800, 52200, 52600, 53000, 53400, 53800, 54200, | ||
272 | /* Index 770 - 779 */ | ||
273 | 54600, 55000, 55400, 55900, 56500, 57000, 57400, 57800, 58200, 58600, | ||
274 | /* Index 780 - 789 */ | ||
275 | 59000, 59400, 59800, 60200, 60600, 61000, 61400, 61800, 62200, 62600, | ||
276 | /* Index 790 - 799 */ | ||
277 | 63000, 63400, 63800, 64200, 64600, 65000, 65400, 65800, 66200, 66600, | ||
278 | /* Index 800 - 809 */ | ||
279 | 67000, 67400, 67800, 68200, 68600, 69000, 69400, 69800, 70200, 70600, | ||
280 | /* Index 810 - 819 */ | ||
281 | 71000, 71500, 72100, 72600, 73000, 73400, 73800, 74200, 74600, 75000, | ||
282 | /* Index 820 - 829 */ | ||
283 | 75400, 75800, 76200, 76600, 77000, 77400, 77800, 78200, 78600, 79000, | ||
284 | /* Index 830 - 839 */ | ||
285 | 79400, 79800, 80200, 80600, 81000, 81400, 81800, 82200, 82600, 83000, | ||
286 | /* Index 840 - 849 */ | ||
287 | 83400, 83800, 84200, 84600, 85000, 85400, 85800, 86200, 86600, 87000, | ||
288 | /* Index 850 - 859 */ | ||
289 | 87400, 87800, 88200, 88600, 89000, 89400, 89800, 90200, 90600, 91000, | ||
290 | /* Index 860 - 869 */ | ||
291 | 91400, 91800, 92200, 92600, 93000, 93400, 93800, 94200, 94600, 95000, | ||
292 | /* Index 870 - 879 */ | ||
293 | 95400, 95800, 96200, 96600, 97000, 97500, 98100, 98600, 99000, 99400, | ||
294 | /* Index 880 - 889 */ | ||
295 | 99800, 100200, 100600, 101000, 101400, 101800, 102200, 102600, 103000, | ||
296 | 103400, | ||
297 | /* Index 890 - 899 */ | ||
298 | 103800, 104200, 104600, 105000, 105400, 105800, 106200, 106600, 107000, | ||
299 | 107400, | ||
300 | /* Index 900 - 909 */ | ||
301 | 107800, 108200, 108600, 109000, 109400, 109800, 110200, 110600, 111000, | ||
302 | 111400, | ||
303 | /* Index 910 - 919 */ | ||
304 | 111800, 112200, 112600, 113000, 113400, 113800, 114200, 114600, 115000, | ||
305 | 115400, | ||
306 | /* Index 920 - 929 */ | ||
307 | 115800, 116200, 116600, 117000, 117400, 117800, 118200, 118600, 119000, | ||
308 | 119400, | ||
309 | /* Index 930 - 939 */ | ||
310 | 119800, 120200, 120600, 121000, 121400, 121800, 122400, 122600, 123000, | ||
311 | 123400, | ||
312 | /* Index 940 - 945 */ | ||
313 | 123800, 1242000, 124600, 124900, 125000, 125000, | ||
314 | }; | ||
315 | |||
316 | /* OMAP54xx ES2.0 data */ | ||
317 | const struct ti_bandgap_data omap5430_data = { | ||
318 | .features = TI_BANDGAP_FEATURE_TSHUT_CONFIG | | ||
319 | TI_BANDGAP_FEATURE_FREEZE_BIT | | ||
320 | TI_BANDGAP_FEATURE_TALERT | | ||
321 | TI_BANDGAP_FEATURE_COUNTER_DELAY | | ||
322 | TI_BANDGAP_FEATURE_HISTORY_BUFFER, | ||
323 | .fclock_name = "l3instr_ts_gclk_div", | ||
324 | .div_ck_name = "l3instr_ts_gclk_div", | ||
325 | .conv_table = omap5430_adc_to_temp, | ||
326 | .adc_start_val = OMAP5430_ADC_START_VALUE, | ||
327 | .adc_end_val = OMAP5430_ADC_END_VALUE, | ||
328 | .expose_sensor = ti_thermal_expose_sensor, | ||
329 | .remove_sensor = ti_thermal_remove_sensor, | ||
330 | .report_temperature = ti_thermal_report_sensor_temperature, | ||
331 | .sensors = { | ||
332 | { | ||
333 | .registers = &omap5430_mpu_temp_sensor_registers, | ||
334 | .ts_data = &omap5430_mpu_temp_sensor_data, | ||
335 | .domain = "cpu", | ||
336 | .register_cooling = ti_thermal_register_cpu_cooling, | ||
337 | .unregister_cooling = ti_thermal_unregister_cpu_cooling, | ||
338 | .slope = OMAP_GRADIENT_SLOPE_5430_CPU, | ||
339 | .constant = OMAP_GRADIENT_CONST_5430_CPU, | ||
340 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU, | ||
341 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_CPU, | ||
342 | }, | ||
343 | { | ||
344 | .registers = &omap5430_gpu_temp_sensor_registers, | ||
345 | .ts_data = &omap5430_gpu_temp_sensor_data, | ||
346 | .domain = "gpu", | ||
347 | .slope = OMAP_GRADIENT_SLOPE_5430_GPU, | ||
348 | .constant = OMAP_GRADIENT_CONST_5430_GPU, | ||
349 | .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU, | ||
350 | .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_GPU, | ||
351 | }, | ||
352 | { | ||
353 | .registers = &omap5430_core_temp_sensor_registers, | ||
354 | .ts_data = &omap5430_core_temp_sensor_data, | ||
355 | .domain = "core", | ||
356 | }, | ||
357 | }, | ||
358 | .sensor_count = 3, | ||
359 | }; | ||
diff --git a/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h b/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h new file mode 100644 index 000000000000..400b55dffadd --- /dev/null +++ b/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * OMAP5xxx bandgap registers, bitfields and temperature definitions | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * Contact: | ||
6 | * Eduardo Valentin <eduardo.valentin@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | #ifndef __OMAP5XXX_BANDGAP_H | ||
24 | #define __OMAP5XXX_BANDGAP_H | ||
25 | |||
26 | /** | ||
27 | * *** OMAP5430 *** | ||
28 | * | ||
29 | * Below, in sequence, are the Register definitions, | ||
30 | * the bitfields and the temperature definitions for OMAP5430. | ||
31 | */ | ||
32 | |||
33 | /** | ||
34 | * OMAP5430 register definitions | ||
35 | * | ||
36 | * Registers are defined as offsets. The offsets are | ||
37 | * relative to FUSE_OPP_BGAP_GPU on 5430. | ||
38 | * | ||
39 | * Register below are grouped by domain (not necessarily in offset order) | ||
40 | */ | ||
41 | |||
42 | /* OMAP5430.GPU register offsets */ | ||
43 | #define OMAP5430_FUSE_OPP_BGAP_GPU 0x0 | ||
44 | #define OMAP5430_TEMP_SENSOR_GPU_OFFSET 0x150 | ||
45 | #define OMAP5430_BGAP_THRESHOLD_GPU_OFFSET 0x1A8 | ||
46 | #define OMAP5430_BGAP_TSHUT_GPU_OFFSET 0x1B4 | ||
47 | #define OMAP5430_BGAP_CUMUL_DTEMP_GPU_OFFSET 0x1C0 | ||
48 | #define OMAP5430_BGAP_DTEMP_GPU_0_OFFSET 0x1F4 | ||
49 | #define OMAP5430_BGAP_DTEMP_GPU_1_OFFSET 0x1F8 | ||
50 | #define OMAP5430_BGAP_DTEMP_GPU_2_OFFSET 0x1FC | ||
51 | #define OMAP5430_BGAP_DTEMP_GPU_3_OFFSET 0x200 | ||
52 | #define OMAP5430_BGAP_DTEMP_GPU_4_OFFSET 0x204 | ||
53 | |||
54 | /* OMAP5430.MPU register offsets */ | ||
55 | #define OMAP5430_FUSE_OPP_BGAP_MPU 0x4 | ||
56 | #define OMAP5430_TEMP_SENSOR_MPU_OFFSET 0x14C | ||
57 | #define OMAP5430_BGAP_THRESHOLD_MPU_OFFSET 0x1A4 | ||
58 | #define OMAP5430_BGAP_TSHUT_MPU_OFFSET 0x1B0 | ||
59 | #define OMAP5430_BGAP_CUMUL_DTEMP_MPU_OFFSET 0x1BC | ||
60 | #define OMAP5430_BGAP_DTEMP_MPU_0_OFFSET 0x1E0 | ||
61 | #define OMAP5430_BGAP_DTEMP_MPU_1_OFFSET 0x1E4 | ||
62 | #define OMAP5430_BGAP_DTEMP_MPU_2_OFFSET 0x1E8 | ||
63 | #define OMAP5430_BGAP_DTEMP_MPU_3_OFFSET 0x1EC | ||
64 | #define OMAP5430_BGAP_DTEMP_MPU_4_OFFSET 0x1F0 | ||
65 | |||
66 | /* OMAP5430.MPU register offsets */ | ||
67 | #define OMAP5430_FUSE_OPP_BGAP_CORE 0x8 | ||
68 | #define OMAP5430_TEMP_SENSOR_CORE_OFFSET 0x154 | ||
69 | #define OMAP5430_BGAP_THRESHOLD_CORE_OFFSET 0x1AC | ||
70 | #define OMAP5430_BGAP_TSHUT_CORE_OFFSET 0x1B8 | ||
71 | #define OMAP5430_BGAP_CUMUL_DTEMP_CORE_OFFSET 0x1C4 | ||
72 | #define OMAP5430_BGAP_DTEMP_CORE_0_OFFSET 0x208 | ||
73 | #define OMAP5430_BGAP_DTEMP_CORE_1_OFFSET 0x20C | ||
74 | #define OMAP5430_BGAP_DTEMP_CORE_2_OFFSET 0x210 | ||
75 | #define OMAP5430_BGAP_DTEMP_CORE_3_OFFSET 0x214 | ||
76 | #define OMAP5430_BGAP_DTEMP_CORE_4_OFFSET 0x218 | ||
77 | |||
78 | /* OMAP5430.common register offsets */ | ||
79 | #define OMAP5430_BGAP_CTRL_OFFSET 0x1A0 | ||
80 | #define OMAP5430_BGAP_STATUS_OFFSET 0x1C8 | ||
81 | |||
82 | /** | ||
83 | * Register bitfields for OMAP5430 | ||
84 | * | ||
85 | * All the macros bellow define the required bits for | ||
86 | * controlling temperature on OMAP5430. Bit defines are | ||
87 | * grouped by register. | ||
88 | */ | ||
89 | |||
90 | /* OMAP5430.TEMP_SENSOR */ | ||
91 | #define OMAP5430_BGAP_TEMP_SENSOR_SOC_MASK BIT(12) | ||
92 | #define OMAP5430_BGAP_TEMPSOFF_MASK BIT(11) | ||
93 | #define OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK BIT(10) | ||
94 | #define OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0) | ||
95 | |||
96 | /* OMAP5430.BANDGAP_CTRL */ | ||
97 | #define OMAP5430_MASK_SIDLEMODE_MASK (0x3 << 30) | ||
98 | #define OMAP5430_MASK_COUNTER_DELAY_MASK (0x7 << 27) | ||
99 | #define OMAP5430_MASK_FREEZE_CORE_MASK BIT(23) | ||
100 | #define OMAP5430_MASK_FREEZE_GPU_MASK BIT(22) | ||
101 | #define OMAP5430_MASK_FREEZE_MPU_MASK BIT(21) | ||
102 | #define OMAP5430_MASK_CLEAR_CORE_MASK BIT(20) | ||
103 | #define OMAP5430_MASK_CLEAR_GPU_MASK BIT(19) | ||
104 | #define OMAP5430_MASK_CLEAR_MPU_MASK BIT(18) | ||
105 | #define OMAP5430_MASK_CLEAR_ACCUM_CORE_MASK BIT(17) | ||
106 | #define OMAP5430_MASK_CLEAR_ACCUM_GPU_MASK BIT(16) | ||
107 | #define OMAP5430_MASK_CLEAR_ACCUM_MPU_MASK BIT(15) | ||
108 | #define OMAP5430_MASK_HOT_CORE_MASK BIT(5) | ||
109 | #define OMAP5430_MASK_COLD_CORE_MASK BIT(4) | ||
110 | #define OMAP5430_MASK_HOT_GPU_MASK BIT(3) | ||
111 | #define OMAP5430_MASK_COLD_GPU_MASK BIT(2) | ||
112 | #define OMAP5430_MASK_HOT_MPU_MASK BIT(1) | ||
113 | #define OMAP5430_MASK_COLD_MPU_MASK BIT(0) | ||
114 | |||
115 | /* OMAP5430.BANDGAP_COUNTER */ | ||
116 | #define OMAP5430_COUNTER_MASK (0xffffff << 0) | ||
117 | |||
118 | /* OMAP5430.BANDGAP_THRESHOLD */ | ||
119 | #define OMAP5430_T_HOT_MASK (0x3ff << 16) | ||
120 | #define OMAP5430_T_COLD_MASK (0x3ff << 0) | ||
121 | |||
122 | /* OMAP5430.TSHUT_THRESHOLD */ | ||
123 | #define OMAP5430_TSHUT_HOT_MASK (0x3ff << 16) | ||
124 | #define OMAP5430_TSHUT_COLD_MASK (0x3ff << 0) | ||
125 | |||
126 | /* OMAP5430.BANDGAP_CUMUL_DTEMP_MPU */ | ||
127 | #define OMAP5430_CUMUL_DTEMP_MPU_MASK (0xffffffff << 0) | ||
128 | |||
129 | /* OMAP5430.BANDGAP_CUMUL_DTEMP_GPU */ | ||
130 | #define OMAP5430_CUMUL_DTEMP_GPU_MASK (0xffffffff << 0) | ||
131 | |||
132 | /* OMAP5430.BANDGAP_CUMUL_DTEMP_CORE */ | ||
133 | #define OMAP5430_CUMUL_DTEMP_CORE_MASK (0xffffffff << 0) | ||
134 | |||
135 | /* OMAP5430.BANDGAP_STATUS */ | ||
136 | #define OMAP5430_BGAP_ALERT_MASK BIT(31) | ||
137 | #define OMAP5430_HOT_CORE_FLAG_MASK BIT(5) | ||
138 | #define OMAP5430_COLD_CORE_FLAG_MASK BIT(4) | ||
139 | #define OMAP5430_HOT_GPU_FLAG_MASK BIT(3) | ||
140 | #define OMAP5430_COLD_GPU_FLAG_MASK BIT(2) | ||
141 | #define OMAP5430_HOT_MPU_FLAG_MASK BIT(1) | ||
142 | #define OMAP5430_COLD_MPU_FLAG_MASK BIT(0) | ||
143 | |||
144 | /** | ||
145 | * Temperature limits and thresholds for OMAP5430 | ||
146 | * | ||
147 | * All the macros bellow are definitions for handling the | ||
148 | * ADC conversions and representation of temperature limits | ||
149 | * and thresholds for OMAP5430. Definitions are grouped | ||
150 | * by temperature domain. | ||
151 | */ | ||
152 | |||
153 | /* OMAP5430.common temperature definitions */ | ||
154 | /* ADC conversion table limits */ | ||
155 | #define OMAP5430_ADC_START_VALUE 540 | ||
156 | #define OMAP5430_ADC_END_VALUE 945 | ||
157 | |||
158 | /* OMAP5430.GPU temperature definitions */ | ||
159 | /* bandgap clock limits */ | ||
160 | #define OMAP5430_GPU_MAX_FREQ 1500000 | ||
161 | #define OMAP5430_GPU_MIN_FREQ 1000000 | ||
162 | /* sensor limits */ | ||
163 | #define OMAP5430_GPU_MIN_TEMP -40000 | ||
164 | #define OMAP5430_GPU_MAX_TEMP 125000 | ||
165 | #define OMAP5430_GPU_HYST_VAL 5000 | ||
166 | /* interrupts thresholds */ | ||
167 | #define OMAP5430_GPU_TSHUT_HOT 915 | ||
168 | #define OMAP5430_GPU_TSHUT_COLD 900 | ||
169 | #define OMAP5430_GPU_T_HOT 800 | ||
170 | #define OMAP5430_GPU_T_COLD 795 | ||
171 | |||
172 | /* OMAP5430.MPU temperature definitions */ | ||
173 | /* bandgap clock limits */ | ||
174 | #define OMAP5430_MPU_MAX_FREQ 1500000 | ||
175 | #define OMAP5430_MPU_MIN_FREQ 1000000 | ||
176 | /* sensor limits */ | ||
177 | #define OMAP5430_MPU_MIN_TEMP -40000 | ||
178 | #define OMAP5430_MPU_MAX_TEMP 125000 | ||
179 | #define OMAP5430_MPU_HYST_VAL 5000 | ||
180 | /* interrupts thresholds */ | ||
181 | #define OMAP5430_MPU_TSHUT_HOT 915 | ||
182 | #define OMAP5430_MPU_TSHUT_COLD 900 | ||
183 | #define OMAP5430_MPU_T_HOT 800 | ||
184 | #define OMAP5430_MPU_T_COLD 795 | ||
185 | |||
186 | /* OMAP5430.CORE temperature definitions */ | ||
187 | /* bandgap clock limits */ | ||
188 | #define OMAP5430_CORE_MAX_FREQ 1500000 | ||
189 | #define OMAP5430_CORE_MIN_FREQ 1000000 | ||
190 | /* sensor limits */ | ||
191 | #define OMAP5430_CORE_MIN_TEMP -40000 | ||
192 | #define OMAP5430_CORE_MAX_TEMP 125000 | ||
193 | #define OMAP5430_CORE_HYST_VAL 5000 | ||
194 | /* interrupts thresholds */ | ||
195 | #define OMAP5430_CORE_TSHUT_HOT 915 | ||
196 | #define OMAP5430_CORE_TSHUT_COLD 900 | ||
197 | #define OMAP5430_CORE_T_HOT 800 | ||
198 | #define OMAP5430_CORE_T_COLD 795 | ||
199 | |||
200 | #endif /* __OMAP5XXX_BANDGAP_H */ | ||
diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.c b/drivers/thermal/ti-soc-thermal/ti-bandgap.c new file mode 100644 index 000000000000..f20c1cfe9800 --- /dev/null +++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.c | |||
@@ -0,0 +1,1546 @@ | |||
1 | /* | ||
2 | * TI Bandgap temperature sensor driver | ||
3 | * | ||
4 | * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * Author: J Keerthy <j-keerthy@ti.com> | ||
6 | * Author: Moiz Sonasath <m-sonasath@ti.com> | ||
7 | * Couple of fixes, DT and MFD adaptation: | ||
8 | * Eduardo Valentin <eduardo.valentin@ti.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * version 2 as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
22 | * 02110-1301 USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/export.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/clk.h> | ||
32 | #include <linux/gpio.h> | ||
33 | #include <linux/platform_device.h> | ||
34 | #include <linux/err.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/spinlock.h> | ||
37 | #include <linux/reboot.h> | ||
38 | #include <linux/of_device.h> | ||
39 | #include <linux/of_platform.h> | ||
40 | #include <linux/of_irq.h> | ||
41 | #include <linux/io.h> | ||
42 | |||
43 | #include "ti-bandgap.h" | ||
44 | |||
45 | /*** Helper functions to access registers and their bitfields ***/ | ||
46 | |||
47 | /** | ||
48 | * ti_bandgap_readl() - simple read helper function | ||
49 | * @bgp: pointer to ti_bandgap structure | ||
50 | * @reg: desired register (offset) to be read | ||
51 | * | ||
52 | * Helper function to read bandgap registers. It uses the io remapped area. | ||
53 | * Return: the register value. | ||
54 | */ | ||
55 | static u32 ti_bandgap_readl(struct ti_bandgap *bgp, u32 reg) | ||
56 | { | ||
57 | return readl(bgp->base + reg); | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * ti_bandgap_writel() - simple write helper function | ||
62 | * @bgp: pointer to ti_bandgap structure | ||
63 | * @val: desired register value to be written | ||
64 | * @reg: desired register (offset) to be written | ||
65 | * | ||
66 | * Helper function to write bandgap registers. It uses the io remapped area. | ||
67 | */ | ||
68 | static void ti_bandgap_writel(struct ti_bandgap *bgp, u32 val, u32 reg) | ||
69 | { | ||
70 | writel(val, bgp->base + reg); | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * DOC: macro to update bits. | ||
75 | * | ||
76 | * RMW_BITS() - used to read, modify and update bandgap bitfields. | ||
77 | * The value passed will be shifted. | ||
78 | */ | ||
79 | #define RMW_BITS(bgp, id, reg, mask, val) \ | ||
80 | do { \ | ||
81 | struct temp_sensor_registers *t; \ | ||
82 | u32 r; \ | ||
83 | \ | ||
84 | t = bgp->conf->sensors[(id)].registers; \ | ||
85 | r = ti_bandgap_readl(bgp, t->reg); \ | ||
86 | r &= ~t->mask; \ | ||
87 | r |= (val) << __ffs(t->mask); \ | ||
88 | ti_bandgap_writel(bgp, r, t->reg); \ | ||
89 | } while (0) | ||
90 | |||
91 | /*** Basic helper functions ***/ | ||
92 | |||
93 | /** | ||
94 | * ti_bandgap_power() - controls the power state of a bandgap device | ||
95 | * @bgp: pointer to ti_bandgap structure | ||
96 | * @on: desired power state (1 - on, 0 - off) | ||
97 | * | ||
98 | * Used to power on/off a bandgap device instance. Only used on those | ||
99 | * that features tempsoff bit. | ||
100 | * | ||
101 | * Return: 0 on success, -ENOTSUPP if tempsoff is not supported. | ||
102 | */ | ||
103 | static int ti_bandgap_power(struct ti_bandgap *bgp, bool on) | ||
104 | { | ||
105 | int i, ret = 0; | ||
106 | |||
107 | if (!TI_BANDGAP_HAS(bgp, POWER_SWITCH)) { | ||
108 | ret = -ENOTSUPP; | ||
109 | goto exit; | ||
110 | } | ||
111 | |||
112 | for (i = 0; i < bgp->conf->sensor_count; i++) | ||
113 | /* active on 0 */ | ||
114 | RMW_BITS(bgp, i, temp_sensor_ctrl, bgap_tempsoff_mask, !on); | ||
115 | |||
116 | exit: | ||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * ti_bandgap_read_temp() - helper function to read sensor temperature | ||
122 | * @bgp: pointer to ti_bandgap structure | ||
123 | * @id: bandgap sensor id | ||
124 | * | ||
125 | * Function to concentrate the steps to read sensor temperature register. | ||
126 | * This function is desired because, depending on bandgap device version, | ||
127 | * it might be needed to freeze the bandgap state machine, before fetching | ||
128 | * the register value. | ||
129 | * | ||
130 | * Return: temperature in ADC values. | ||
131 | */ | ||
132 | static u32 ti_bandgap_read_temp(struct ti_bandgap *bgp, int id) | ||
133 | { | ||
134 | struct temp_sensor_registers *tsr; | ||
135 | u32 temp, reg; | ||
136 | |||
137 | tsr = bgp->conf->sensors[id].registers; | ||
138 | reg = tsr->temp_sensor_ctrl; | ||
139 | |||
140 | if (TI_BANDGAP_HAS(bgp, FREEZE_BIT)) { | ||
141 | RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1); | ||
142 | /* | ||
143 | * In case we cannot read from cur_dtemp / dtemp_0, | ||
144 | * then we read from the last valid temp read | ||
145 | */ | ||
146 | reg = tsr->ctrl_dtemp_1; | ||
147 | } | ||
148 | |||
149 | /* read temperature */ | ||
150 | temp = ti_bandgap_readl(bgp, reg); | ||
151 | temp &= tsr->bgap_dtemp_mask; | ||
152 | |||
153 | if (TI_BANDGAP_HAS(bgp, FREEZE_BIT)) | ||
154 | RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0); | ||
155 | |||
156 | return temp; | ||
157 | } | ||
158 | |||
159 | /*** IRQ handlers ***/ | ||
160 | |||
161 | /** | ||
162 | * ti_bandgap_talert_irq_handler() - handles Temperature alert IRQs | ||
163 | * @irq: IRQ number | ||
164 | * @data: private data (struct ti_bandgap *) | ||
165 | * | ||
166 | * This is the Talert handler. Use it only if bandgap device features | ||
167 | * HAS(TALERT). This handler goes over all sensors and checks their | ||
168 | * conditions and acts accordingly. In case there are events pending, | ||
169 | * it will reset the event mask to wait for the opposite event (next event). | ||
170 | * Every time there is a new event, it will be reported to thermal layer. | ||
171 | * | ||
172 | * Return: IRQ_HANDLED | ||
173 | */ | ||
174 | static irqreturn_t ti_bandgap_talert_irq_handler(int irq, void *data) | ||
175 | { | ||
176 | struct ti_bandgap *bgp = data; | ||
177 | struct temp_sensor_registers *tsr; | ||
178 | u32 t_hot = 0, t_cold = 0, ctrl; | ||
179 | int i; | ||
180 | |||
181 | spin_lock(&bgp->lock); | ||
182 | for (i = 0; i < bgp->conf->sensor_count; i++) { | ||
183 | tsr = bgp->conf->sensors[i].registers; | ||
184 | ctrl = ti_bandgap_readl(bgp, tsr->bgap_status); | ||
185 | |||
186 | /* Read the status of t_hot */ | ||
187 | t_hot = ctrl & tsr->status_hot_mask; | ||
188 | |||
189 | /* Read the status of t_cold */ | ||
190 | t_cold = ctrl & tsr->status_cold_mask; | ||
191 | |||
192 | if (!t_cold && !t_hot) | ||
193 | continue; | ||
194 | |||
195 | ctrl = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl); | ||
196 | /* | ||
197 | * One TALERT interrupt: Two sources | ||
198 | * If the interrupt is due to t_hot then mask t_hot and | ||
199 | * and unmask t_cold else mask t_cold and unmask t_hot | ||
200 | */ | ||
201 | if (t_hot) { | ||
202 | ctrl &= ~tsr->mask_hot_mask; | ||
203 | ctrl |= tsr->mask_cold_mask; | ||
204 | } else if (t_cold) { | ||
205 | ctrl &= ~tsr->mask_cold_mask; | ||
206 | ctrl |= tsr->mask_hot_mask; | ||
207 | } | ||
208 | |||
209 | ti_bandgap_writel(bgp, ctrl, tsr->bgap_mask_ctrl); | ||
210 | |||
211 | dev_dbg(bgp->dev, | ||
212 | "%s: IRQ from %s sensor: hotevent %d coldevent %d\n", | ||
213 | __func__, bgp->conf->sensors[i].domain, | ||
214 | t_hot, t_cold); | ||
215 | |||
216 | /* report temperature to whom may concern */ | ||
217 | if (bgp->conf->report_temperature) | ||
218 | bgp->conf->report_temperature(bgp, i); | ||
219 | } | ||
220 | spin_unlock(&bgp->lock); | ||
221 | |||
222 | return IRQ_HANDLED; | ||
223 | } | ||
224 | |||
225 | /** | ||
226 | * ti_bandgap_tshut_irq_handler() - handles Temperature shutdown signal | ||
227 | * @irq: IRQ number | ||
228 | * @data: private data (unused) | ||
229 | * | ||
230 | * This is the Tshut handler. Use it only if bandgap device features | ||
231 | * HAS(TSHUT). If any sensor fires the Tshut signal, we simply shutdown | ||
232 | * the system. | ||
233 | * | ||
234 | * Return: IRQ_HANDLED | ||
235 | */ | ||
236 | static irqreturn_t ti_bandgap_tshut_irq_handler(int irq, void *data) | ||
237 | { | ||
238 | pr_emerg("%s: TSHUT temperature reached. Needs shut down...\n", | ||
239 | __func__); | ||
240 | |||
241 | orderly_poweroff(true); | ||
242 | |||
243 | return IRQ_HANDLED; | ||
244 | } | ||
245 | |||
246 | /*** Helper functions which manipulate conversion ADC <-> mi Celsius ***/ | ||
247 | |||
248 | /** | ||
249 | * ti_bandgap_adc_to_mcelsius() - converts an ADC value to mCelsius scale | ||
250 | * @bgp: struct ti_bandgap pointer | ||
251 | * @adc_val: value in ADC representation | ||
252 | * @t: address where to write the resulting temperature in mCelsius | ||
253 | * | ||
254 | * Simple conversion from ADC representation to mCelsius. In case the ADC value | ||
255 | * is out of the ADC conv table range, it returns -ERANGE, 0 on success. | ||
256 | * The conversion table is indexed by the ADC values. | ||
257 | * | ||
258 | * Return: 0 if conversion was successful, else -ERANGE in case the @adc_val | ||
259 | * argument is out of the ADC conv table range. | ||
260 | */ | ||
261 | static | ||
262 | int ti_bandgap_adc_to_mcelsius(struct ti_bandgap *bgp, int adc_val, int *t) | ||
263 | { | ||
264 | const struct ti_bandgap_data *conf = bgp->conf; | ||
265 | int ret = 0; | ||
266 | |||
267 | /* look up for temperature in the table and return the temperature */ | ||
268 | if (adc_val < conf->adc_start_val || adc_val > conf->adc_end_val) { | ||
269 | ret = -ERANGE; | ||
270 | goto exit; | ||
271 | } | ||
272 | |||
273 | *t = bgp->conf->conv_table[adc_val - conf->adc_start_val]; | ||
274 | |||
275 | exit: | ||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | /** | ||
280 | * ti_bandgap_mcelsius_to_adc() - converts a mCelsius value to ADC scale | ||
281 | * @bgp: struct ti_bandgap pointer | ||
282 | * @temp: value in mCelsius | ||
283 | * @adc: address where to write the resulting temperature in ADC representation | ||
284 | * | ||
285 | * Simple conversion from mCelsius to ADC values. In case the temp value | ||
286 | * is out of the ADC conv table range, it returns -ERANGE, 0 on success. | ||
287 | * The conversion table is indexed by the ADC values. | ||
288 | * | ||
289 | * Return: 0 if conversion was successful, else -ERANGE in case the @temp | ||
290 | * argument is out of the ADC conv table range. | ||
291 | */ | ||
292 | static | ||
293 | int ti_bandgap_mcelsius_to_adc(struct ti_bandgap *bgp, long temp, int *adc) | ||
294 | { | ||
295 | const struct ti_bandgap_data *conf = bgp->conf; | ||
296 | const int *conv_table = bgp->conf->conv_table; | ||
297 | int high, low, mid, ret = 0; | ||
298 | |||
299 | low = 0; | ||
300 | high = conf->adc_end_val - conf->adc_start_val; | ||
301 | mid = (high + low) / 2; | ||
302 | |||
303 | if (temp < conv_table[low] || temp > conv_table[high]) { | ||
304 | ret = -ERANGE; | ||
305 | goto exit; | ||
306 | } | ||
307 | |||
308 | while (low < high) { | ||
309 | if (temp < conv_table[mid]) | ||
310 | high = mid - 1; | ||
311 | else | ||
312 | low = mid + 1; | ||
313 | mid = (low + high) / 2; | ||
314 | } | ||
315 | |||
316 | *adc = conf->adc_start_val + low; | ||
317 | |||
318 | exit: | ||
319 | return ret; | ||
320 | } | ||
321 | |||
322 | /** | ||
323 | * ti_bandgap_add_hyst() - add hysteresis (in mCelsius) to an ADC value | ||
324 | * @bgp: struct ti_bandgap pointer | ||
325 | * @adc_val: temperature value in ADC representation | ||
326 | * @hyst_val: hysteresis value in mCelsius | ||
327 | * @sum: address where to write the resulting temperature (in ADC scale) | ||
328 | * | ||
329 | * Adds an hysteresis value (in mCelsius) to a ADC temperature value. | ||
330 | * | ||
331 | * Return: 0 on success, -ERANGE otherwise. | ||
332 | */ | ||
333 | static | ||
334 | int ti_bandgap_add_hyst(struct ti_bandgap *bgp, int adc_val, int hyst_val, | ||
335 | u32 *sum) | ||
336 | { | ||
337 | int temp, ret; | ||
338 | |||
339 | /* | ||
340 | * Need to add in the mcelsius domain, so we have a temperature | ||
341 | * the conv_table range | ||
342 | */ | ||
343 | ret = ti_bandgap_adc_to_mcelsius(bgp, adc_val, &temp); | ||
344 | if (ret < 0) | ||
345 | goto exit; | ||
346 | |||
347 | temp += hyst_val; | ||
348 | |||
349 | ret = ti_bandgap_mcelsius_to_adc(bgp, temp, sum); | ||
350 | |||
351 | exit: | ||
352 | return ret; | ||
353 | } | ||
354 | |||
355 | /*** Helper functions handling device Alert/Shutdown signals ***/ | ||
356 | |||
357 | /** | ||
358 | * ti_bandgap_unmask_interrupts() - unmasks the events of thot & tcold | ||
359 | * @bgp: struct ti_bandgap pointer | ||
360 | * @id: bandgap sensor id | ||
361 | * @t_hot: hot temperature value to trigger alert signal | ||
362 | * @t_cold: cold temperature value to trigger alert signal | ||
363 | * | ||
364 | * Checks the requested t_hot and t_cold values and configures the IRQ event | ||
365 | * masks accordingly. Call this function only if bandgap features HAS(TALERT). | ||
366 | */ | ||
367 | static void ti_bandgap_unmask_interrupts(struct ti_bandgap *bgp, int id, | ||
368 | u32 t_hot, u32 t_cold) | ||
369 | { | ||
370 | struct temp_sensor_registers *tsr; | ||
371 | u32 temp, reg_val; | ||
372 | |||
373 | /* Read the current on die temperature */ | ||
374 | temp = ti_bandgap_read_temp(bgp, id); | ||
375 | |||
376 | tsr = bgp->conf->sensors[id].registers; | ||
377 | reg_val = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl); | ||
378 | |||
379 | if (temp < t_hot) | ||
380 | reg_val |= tsr->mask_hot_mask; | ||
381 | else | ||
382 | reg_val &= ~tsr->mask_hot_mask; | ||
383 | |||
384 | if (t_cold < temp) | ||
385 | reg_val |= tsr->mask_cold_mask; | ||
386 | else | ||
387 | reg_val &= ~tsr->mask_cold_mask; | ||
388 | ti_bandgap_writel(bgp, reg_val, tsr->bgap_mask_ctrl); | ||
389 | } | ||
390 | |||
391 | /** | ||
392 | * ti_bandgap_update_alert_threshold() - sequence to update thresholds | ||
393 | * @bgp: struct ti_bandgap pointer | ||
394 | * @id: bandgap sensor id | ||
395 | * @val: value (ADC) of a new threshold | ||
396 | * @hot: desired threshold to be updated. true if threshold hot, false if | ||
397 | * threshold cold | ||
398 | * | ||
399 | * It will program the required thresholds (hot and cold) for TALERT signal. | ||
400 | * This function can be used to update t_hot or t_cold, depending on @hot value. | ||
401 | * It checks the resulting t_hot and t_cold values, based on the new passed @val | ||
402 | * and configures the thresholds so that t_hot is always greater than t_cold. | ||
403 | * Call this function only if bandgap features HAS(TALERT). | ||
404 | * | ||
405 | * Return: 0 if no error, else corresponding error | ||
406 | */ | ||
407 | static int ti_bandgap_update_alert_threshold(struct ti_bandgap *bgp, int id, | ||
408 | int val, bool hot) | ||
409 | { | ||
410 | struct temp_sensor_data *ts_data = bgp->conf->sensors[id].ts_data; | ||
411 | struct temp_sensor_registers *tsr; | ||
412 | u32 thresh_val, reg_val, t_hot, t_cold; | ||
413 | int err = 0; | ||
414 | |||
415 | tsr = bgp->conf->sensors[id].registers; | ||
416 | |||
417 | /* obtain the current value */ | ||
418 | thresh_val = ti_bandgap_readl(bgp, tsr->bgap_threshold); | ||
419 | t_cold = (thresh_val & tsr->threshold_tcold_mask) >> | ||
420 | __ffs(tsr->threshold_tcold_mask); | ||
421 | t_hot = (thresh_val & tsr->threshold_thot_mask) >> | ||
422 | __ffs(tsr->threshold_thot_mask); | ||
423 | if (hot) | ||
424 | t_hot = val; | ||
425 | else | ||
426 | t_cold = val; | ||
427 | |||
428 | if (t_cold > t_hot) { | ||
429 | if (hot) | ||
430 | err = ti_bandgap_add_hyst(bgp, t_hot, | ||
431 | -ts_data->hyst_val, | ||
432 | &t_cold); | ||
433 | else | ||
434 | err = ti_bandgap_add_hyst(bgp, t_cold, | ||
435 | ts_data->hyst_val, | ||
436 | &t_hot); | ||
437 | } | ||
438 | |||
439 | /* write the new threshold values */ | ||
440 | reg_val = thresh_val & | ||
441 | ~(tsr->threshold_thot_mask | tsr->threshold_tcold_mask); | ||
442 | reg_val |= (t_hot << __ffs(tsr->threshold_thot_mask)) | | ||
443 | (t_cold << __ffs(tsr->threshold_tcold_mask)); | ||
444 | ti_bandgap_writel(bgp, reg_val, tsr->bgap_threshold); | ||
445 | |||
446 | if (err) { | ||
447 | dev_err(bgp->dev, "failed to reprogram thot threshold\n"); | ||
448 | err = -EIO; | ||
449 | goto exit; | ||
450 | } | ||
451 | |||
452 | ti_bandgap_unmask_interrupts(bgp, id, t_hot, t_cold); | ||
453 | exit: | ||
454 | return err; | ||
455 | } | ||
456 | |||
457 | /** | ||
458 | * ti_bandgap_validate() - helper to check the sanity of a struct ti_bandgap | ||
459 | * @bgp: struct ti_bandgap pointer | ||
460 | * @id: bandgap sensor id | ||
461 | * | ||
462 | * Checks if the bandgap pointer is valid and if the sensor id is also | ||
463 | * applicable. | ||
464 | * | ||
465 | * Return: 0 if no errors, -EINVAL for invalid @bgp pointer or -ERANGE if | ||
466 | * @id cannot index @bgp sensors. | ||
467 | */ | ||
468 | static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id) | ||
469 | { | ||
470 | int ret = 0; | ||
471 | |||
472 | if (IS_ERR_OR_NULL(bgp)) { | ||
473 | pr_err("%s: invalid bandgap pointer\n", __func__); | ||
474 | ret = -EINVAL; | ||
475 | goto exit; | ||
476 | } | ||
477 | |||
478 | if ((id < 0) || (id >= bgp->conf->sensor_count)) { | ||
479 | dev_err(bgp->dev, "%s: sensor id out of range (%d)\n", | ||
480 | __func__, id); | ||
481 | ret = -ERANGE; | ||
482 | } | ||
483 | |||
484 | exit: | ||
485 | return ret; | ||
486 | } | ||
487 | |||
488 | /** | ||
489 | * _ti_bandgap_write_threshold() - helper to update TALERT t_cold or t_hot | ||
490 | * @bgp: struct ti_bandgap pointer | ||
491 | * @id: bandgap sensor id | ||
492 | * @val: value (mCelsius) of a new threshold | ||
493 | * @hot: desired threshold to be updated. true if threshold hot, false if | ||
494 | * threshold cold | ||
495 | * | ||
496 | * It will update the required thresholds (hot and cold) for TALERT signal. | ||
497 | * This function can be used to update t_hot or t_cold, depending on @hot value. | ||
498 | * Validates the mCelsius range and update the requested threshold. | ||
499 | * Call this function only if bandgap features HAS(TALERT). | ||
500 | * | ||
501 | * Return: 0 if no error, else corresponding error value. | ||
502 | */ | ||
503 | static int _ti_bandgap_write_threshold(struct ti_bandgap *bgp, int id, int val, | ||
504 | bool hot) | ||
505 | { | ||
506 | struct temp_sensor_data *ts_data; | ||
507 | struct temp_sensor_registers *tsr; | ||
508 | u32 adc_val; | ||
509 | int ret; | ||
510 | |||
511 | ret = ti_bandgap_validate(bgp, id); | ||
512 | if (ret) | ||
513 | goto exit; | ||
514 | |||
515 | if (!TI_BANDGAP_HAS(bgp, TALERT)) { | ||
516 | ret = -ENOTSUPP; | ||
517 | goto exit; | ||
518 | } | ||
519 | |||
520 | ts_data = bgp->conf->sensors[id].ts_data; | ||
521 | tsr = bgp->conf->sensors[id].registers; | ||
522 | if (hot) { | ||
523 | if (val < ts_data->min_temp + ts_data->hyst_val) | ||
524 | ret = -EINVAL; | ||
525 | } else { | ||
526 | if (val > ts_data->max_temp + ts_data->hyst_val) | ||
527 | ret = -EINVAL; | ||
528 | } | ||
529 | |||
530 | if (ret) | ||
531 | goto exit; | ||
532 | |||
533 | ret = ti_bandgap_mcelsius_to_adc(bgp, val, &adc_val); | ||
534 | if (ret < 0) | ||
535 | goto exit; | ||
536 | |||
537 | spin_lock(&bgp->lock); | ||
538 | ret = ti_bandgap_update_alert_threshold(bgp, id, adc_val, hot); | ||
539 | spin_unlock(&bgp->lock); | ||
540 | |||
541 | exit: | ||
542 | return ret; | ||
543 | } | ||
544 | |||
545 | /** | ||
546 | * _ti_bandgap_read_threshold() - helper to read TALERT t_cold or t_hot | ||
547 | * @bgp: struct ti_bandgap pointer | ||
548 | * @id: bandgap sensor id | ||
549 | * @val: value (mCelsius) of a threshold | ||
550 | * @hot: desired threshold to be read. true if threshold hot, false if | ||
551 | * threshold cold | ||
552 | * | ||
553 | * It will fetch the required thresholds (hot and cold) for TALERT signal. | ||
554 | * This function can be used to read t_hot or t_cold, depending on @hot value. | ||
555 | * Call this function only if bandgap features HAS(TALERT). | ||
556 | * | ||
557 | * Return: 0 if no error, -ENOTSUPP if it has no TALERT support, or the | ||
558 | * corresponding error value if some operation fails. | ||
559 | */ | ||
560 | static int _ti_bandgap_read_threshold(struct ti_bandgap *bgp, int id, | ||
561 | int *val, bool hot) | ||
562 | { | ||
563 | struct temp_sensor_registers *tsr; | ||
564 | u32 temp, mask; | ||
565 | int ret = 0; | ||
566 | |||
567 | ret = ti_bandgap_validate(bgp, id); | ||
568 | if (ret) | ||
569 | goto exit; | ||
570 | |||
571 | if (!TI_BANDGAP_HAS(bgp, TALERT)) { | ||
572 | ret = -ENOTSUPP; | ||
573 | goto exit; | ||
574 | } | ||
575 | |||
576 | tsr = bgp->conf->sensors[id].registers; | ||
577 | if (hot) | ||
578 | mask = tsr->threshold_thot_mask; | ||
579 | else | ||
580 | mask = tsr->threshold_tcold_mask; | ||
581 | |||
582 | temp = ti_bandgap_readl(bgp, tsr->bgap_threshold); | ||
583 | temp = (temp & mask) >> __ffs(mask); | ||
584 | ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp); | ||
585 | if (ret) { | ||
586 | dev_err(bgp->dev, "failed to read thot\n"); | ||
587 | ret = -EIO; | ||
588 | goto exit; | ||
589 | } | ||
590 | |||
591 | *val = temp; | ||
592 | |||
593 | exit: | ||
594 | return ret; | ||
595 | } | ||
596 | |||
597 | /*** Exposed APIs ***/ | ||
598 | |||
599 | /** | ||
600 | * ti_bandgap_read_thot() - reads sensor current thot | ||
601 | * @bgp: pointer to bandgap instance | ||
602 | * @id: sensor id | ||
603 | * @thot: resulting current thot value | ||
604 | * | ||
605 | * Return: 0 on success or the proper error code | ||
606 | */ | ||
607 | int ti_bandgap_read_thot(struct ti_bandgap *bgp, int id, int *thot) | ||
608 | { | ||
609 | return _ti_bandgap_read_threshold(bgp, id, thot, true); | ||
610 | } | ||
611 | |||
612 | /** | ||
613 | * ti_bandgap_write_thot() - sets sensor current thot | ||
614 | * @bgp: pointer to bandgap instance | ||
615 | * @id: sensor id | ||
616 | * @val: desired thot value | ||
617 | * | ||
618 | * Return: 0 on success or the proper error code | ||
619 | */ | ||
620 | int ti_bandgap_write_thot(struct ti_bandgap *bgp, int id, int val) | ||
621 | { | ||
622 | return _ti_bandgap_write_threshold(bgp, id, val, true); | ||
623 | } | ||
624 | |||
625 | /** | ||
626 | * ti_bandgap_read_tcold() - reads sensor current tcold | ||
627 | * @bgp: pointer to bandgap instance | ||
628 | * @id: sensor id | ||
629 | * @tcold: resulting current tcold value | ||
630 | * | ||
631 | * Return: 0 on success or the proper error code | ||
632 | */ | ||
633 | int ti_bandgap_read_tcold(struct ti_bandgap *bgp, int id, int *tcold) | ||
634 | { | ||
635 | return _ti_bandgap_read_threshold(bgp, id, tcold, false); | ||
636 | } | ||
637 | |||
638 | /** | ||
639 | * ti_bandgap_write_tcold() - sets the sensor tcold | ||
640 | * @bgp: pointer to bandgap instance | ||
641 | * @id: sensor id | ||
642 | * @val: desired tcold value | ||
643 | * | ||
644 | * Return: 0 on success or the proper error code | ||
645 | */ | ||
646 | int ti_bandgap_write_tcold(struct ti_bandgap *bgp, int id, int val) | ||
647 | { | ||
648 | return _ti_bandgap_write_threshold(bgp, id, val, false); | ||
649 | } | ||
650 | |||
651 | /** | ||
652 | * ti_bandgap_read_counter() - read the sensor counter | ||
653 | * @bgp: pointer to bandgap instance | ||
654 | * @id: sensor id | ||
655 | * @interval: resulting update interval in miliseconds | ||
656 | */ | ||
657 | static void ti_bandgap_read_counter(struct ti_bandgap *bgp, int id, | ||
658 | int *interval) | ||
659 | { | ||
660 | struct temp_sensor_registers *tsr; | ||
661 | int time; | ||
662 | |||
663 | tsr = bgp->conf->sensors[id].registers; | ||
664 | time = ti_bandgap_readl(bgp, tsr->bgap_counter); | ||
665 | time = (time & tsr->counter_mask) >> | ||
666 | __ffs(tsr->counter_mask); | ||
667 | time = time * 1000 / bgp->clk_rate; | ||
668 | *interval = time; | ||
669 | } | ||
670 | |||
671 | /** | ||
672 | * ti_bandgap_read_counter_delay() - read the sensor counter delay | ||
673 | * @bgp: pointer to bandgap instance | ||
674 | * @id: sensor id | ||
675 | * @interval: resulting update interval in miliseconds | ||
676 | */ | ||
677 | static void ti_bandgap_read_counter_delay(struct ti_bandgap *bgp, int id, | ||
678 | int *interval) | ||
679 | { | ||
680 | struct temp_sensor_registers *tsr; | ||
681 | int reg_val; | ||
682 | |||
683 | tsr = bgp->conf->sensors[id].registers; | ||
684 | |||
685 | reg_val = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl); | ||
686 | reg_val = (reg_val & tsr->mask_counter_delay_mask) >> | ||
687 | __ffs(tsr->mask_counter_delay_mask); | ||
688 | switch (reg_val) { | ||
689 | case 0: | ||
690 | *interval = 0; | ||
691 | break; | ||
692 | case 1: | ||
693 | *interval = 1; | ||
694 | break; | ||
695 | case 2: | ||
696 | *interval = 10; | ||
697 | break; | ||
698 | case 3: | ||
699 | *interval = 100; | ||
700 | break; | ||
701 | case 4: | ||
702 | *interval = 250; | ||
703 | break; | ||
704 | case 5: | ||
705 | *interval = 500; | ||
706 | break; | ||
707 | default: | ||
708 | dev_warn(bgp->dev, "Wrong counter delay value read from register %X", | ||
709 | reg_val); | ||
710 | } | ||
711 | } | ||
712 | |||
713 | /** | ||
714 | * ti_bandgap_read_update_interval() - read the sensor update interval | ||
715 | * @bgp: pointer to bandgap instance | ||
716 | * @id: sensor id | ||
717 | * @interval: resulting update interval in miliseconds | ||
718 | * | ||
719 | * Return: 0 on success or the proper error code | ||
720 | */ | ||
721 | int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id, | ||
722 | int *interval) | ||
723 | { | ||
724 | int ret = 0; | ||
725 | |||
726 | ret = ti_bandgap_validate(bgp, id); | ||
727 | if (ret) | ||
728 | goto exit; | ||
729 | |||
730 | if (!TI_BANDGAP_HAS(bgp, COUNTER) && | ||
731 | !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) { | ||
732 | ret = -ENOTSUPP; | ||
733 | goto exit; | ||
734 | } | ||
735 | |||
736 | if (TI_BANDGAP_HAS(bgp, COUNTER)) { | ||
737 | ti_bandgap_read_counter(bgp, id, interval); | ||
738 | goto exit; | ||
739 | } | ||
740 | |||
741 | ti_bandgap_read_counter_delay(bgp, id, interval); | ||
742 | exit: | ||
743 | return ret; | ||
744 | } | ||
745 | |||
746 | /** | ||
747 | * ti_bandgap_write_counter_delay() - set the counter_delay | ||
748 | * @bgp: pointer to bandgap instance | ||
749 | * @id: sensor id | ||
750 | * @interval: desired update interval in miliseconds | ||
751 | * | ||
752 | * Return: 0 on success or the proper error code | ||
753 | */ | ||
754 | static int ti_bandgap_write_counter_delay(struct ti_bandgap *bgp, int id, | ||
755 | u32 interval) | ||
756 | { | ||
757 | int rval; | ||
758 | |||
759 | switch (interval) { | ||
760 | case 0: /* Immediate conversion */ | ||
761 | rval = 0x0; | ||
762 | break; | ||
763 | case 1: /* Conversion after ever 1ms */ | ||
764 | rval = 0x1; | ||
765 | break; | ||
766 | case 10: /* Conversion after ever 10ms */ | ||
767 | rval = 0x2; | ||
768 | break; | ||
769 | case 100: /* Conversion after ever 100ms */ | ||
770 | rval = 0x3; | ||
771 | break; | ||
772 | case 250: /* Conversion after ever 250ms */ | ||
773 | rval = 0x4; | ||
774 | break; | ||
775 | case 500: /* Conversion after ever 500ms */ | ||
776 | rval = 0x5; | ||
777 | break; | ||
778 | default: | ||
779 | dev_warn(bgp->dev, "Delay %d ms is not supported\n", interval); | ||
780 | return -EINVAL; | ||
781 | } | ||
782 | |||
783 | spin_lock(&bgp->lock); | ||
784 | RMW_BITS(bgp, id, bgap_mask_ctrl, mask_counter_delay_mask, rval); | ||
785 | spin_unlock(&bgp->lock); | ||
786 | |||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | /** | ||
791 | * ti_bandgap_write_counter() - set the bandgap sensor counter | ||
792 | * @bgp: pointer to bandgap instance | ||
793 | * @id: sensor id | ||
794 | * @interval: desired update interval in miliseconds | ||
795 | */ | ||
796 | static void ti_bandgap_write_counter(struct ti_bandgap *bgp, int id, | ||
797 | u32 interval) | ||
798 | { | ||
799 | interval = interval * bgp->clk_rate / 1000; | ||
800 | spin_lock(&bgp->lock); | ||
801 | RMW_BITS(bgp, id, bgap_counter, counter_mask, interval); | ||
802 | spin_unlock(&bgp->lock); | ||
803 | } | ||
804 | |||
805 | /** | ||
806 | * ti_bandgap_write_update_interval() - set the update interval | ||
807 | * @bgp: pointer to bandgap instance | ||
808 | * @id: sensor id | ||
809 | * @interval: desired update interval in miliseconds | ||
810 | * | ||
811 | * Return: 0 on success or the proper error code | ||
812 | */ | ||
813 | int ti_bandgap_write_update_interval(struct ti_bandgap *bgp, | ||
814 | int id, u32 interval) | ||
815 | { | ||
816 | int ret = ti_bandgap_validate(bgp, id); | ||
817 | if (ret) | ||
818 | goto exit; | ||
819 | |||
820 | if (!TI_BANDGAP_HAS(bgp, COUNTER) && | ||
821 | !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) { | ||
822 | ret = -ENOTSUPP; | ||
823 | goto exit; | ||
824 | } | ||
825 | |||
826 | if (TI_BANDGAP_HAS(bgp, COUNTER)) { | ||
827 | ti_bandgap_write_counter(bgp, id, interval); | ||
828 | goto exit; | ||
829 | } | ||
830 | |||
831 | ret = ti_bandgap_write_counter_delay(bgp, id, interval); | ||
832 | exit: | ||
833 | return ret; | ||
834 | } | ||
835 | |||
836 | /** | ||
837 | * ti_bandgap_read_temperature() - report current temperature | ||
838 | * @bgp: pointer to bandgap instance | ||
839 | * @id: sensor id | ||
840 | * @temperature: resulting temperature | ||
841 | * | ||
842 | * Return: 0 on success or the proper error code | ||
843 | */ | ||
844 | int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id, | ||
845 | int *temperature) | ||
846 | { | ||
847 | u32 temp; | ||
848 | int ret; | ||
849 | |||
850 | ret = ti_bandgap_validate(bgp, id); | ||
851 | if (ret) | ||
852 | return ret; | ||
853 | |||
854 | spin_lock(&bgp->lock); | ||
855 | temp = ti_bandgap_read_temp(bgp, id); | ||
856 | spin_unlock(&bgp->lock); | ||
857 | |||
858 | ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp); | ||
859 | if (ret) | ||
860 | return -EIO; | ||
861 | |||
862 | *temperature = temp; | ||
863 | |||
864 | return 0; | ||
865 | } | ||
866 | |||
867 | /** | ||
868 | * ti_bandgap_set_sensor_data() - helper function to store thermal | ||
869 | * framework related data. | ||
870 | * @bgp: pointer to bandgap instance | ||
871 | * @id: sensor id | ||
872 | * @data: thermal framework related data to be stored | ||
873 | * | ||
874 | * Return: 0 on success or the proper error code | ||
875 | */ | ||
876 | int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data) | ||
877 | { | ||
878 | int ret = ti_bandgap_validate(bgp, id); | ||
879 | if (ret) | ||
880 | return ret; | ||
881 | |||
882 | bgp->regval[id].data = data; | ||
883 | |||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | /** | ||
888 | * ti_bandgap_get_sensor_data() - helper function to get thermal | ||
889 | * framework related data. | ||
890 | * @bgp: pointer to bandgap instance | ||
891 | * @id: sensor id | ||
892 | * | ||
893 | * Return: data stored by set function with sensor id on success or NULL | ||
894 | */ | ||
895 | void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id) | ||
896 | { | ||
897 | int ret = ti_bandgap_validate(bgp, id); | ||
898 | if (ret) | ||
899 | return ERR_PTR(ret); | ||
900 | |||
901 | return bgp->regval[id].data; | ||
902 | } | ||
903 | |||
904 | /*** Helper functions used during device initialization ***/ | ||
905 | |||
906 | /** | ||
907 | * ti_bandgap_force_single_read() - executes 1 single ADC conversion | ||
908 | * @bgp: pointer to struct ti_bandgap | ||
909 | * @id: sensor id which it is desired to read 1 temperature | ||
910 | * | ||
911 | * Used to initialize the conversion state machine and set it to a valid | ||
912 | * state. Called during device initialization and context restore events. | ||
913 | * | ||
914 | * Return: 0 | ||
915 | */ | ||
916 | static int | ||
917 | ti_bandgap_force_single_read(struct ti_bandgap *bgp, int id) | ||
918 | { | ||
919 | u32 temp = 0, counter = 1000; | ||
920 | |||
921 | /* Select single conversion mode */ | ||
922 | if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) | ||
923 | RMW_BITS(bgp, id, bgap_mode_ctrl, mode_ctrl_mask, 0); | ||
924 | |||
925 | /* Start of Conversion = 1 */ | ||
926 | RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 1); | ||
927 | /* Wait until DTEMP is updated */ | ||
928 | temp = ti_bandgap_read_temp(bgp, id); | ||
929 | |||
930 | while ((temp == 0) && --counter) | ||
931 | temp = ti_bandgap_read_temp(bgp, id); | ||
932 | /* REVISIT: Check correct condition for end of conversion */ | ||
933 | |||
934 | /* Start of Conversion = 0 */ | ||
935 | RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 0); | ||
936 | |||
937 | return 0; | ||
938 | } | ||
939 | |||
940 | /** | ||
941 | * ti_bandgap_set_continous_mode() - One time enabling of continuous mode | ||
942 | * @bgp: pointer to struct ti_bandgap | ||
943 | * | ||
944 | * Call this function only if HAS(MODE_CONFIG) is set. As this driver may | ||
945 | * be used for junction temperature monitoring, it is desirable that the | ||
946 | * sensors are operational all the time, so that alerts are generated | ||
947 | * properly. | ||
948 | * | ||
949 | * Return: 0 | ||
950 | */ | ||
951 | static int ti_bandgap_set_continuous_mode(struct ti_bandgap *bgp) | ||
952 | { | ||
953 | int i; | ||
954 | |||
955 | for (i = 0; i < bgp->conf->sensor_count; i++) { | ||
956 | /* Perform a single read just before enabling continuous */ | ||
957 | ti_bandgap_force_single_read(bgp, i); | ||
958 | RMW_BITS(bgp, i, bgap_mode_ctrl, mode_ctrl_mask, 1); | ||
959 | } | ||
960 | |||
961 | return 0; | ||
962 | } | ||
963 | |||
964 | /** | ||
965 | * ti_bandgap_get_trend() - To fetch the temperature trend of a sensor | ||
966 | * @bgp: pointer to struct ti_bandgap | ||
967 | * @id: id of the individual sensor | ||
968 | * @trend: Pointer to trend. | ||
969 | * | ||
970 | * This function needs to be called to fetch the temperature trend of a | ||
971 | * Particular sensor. The function computes the difference in temperature | ||
972 | * w.r.t time. For the bandgaps with built in history buffer the temperatures | ||
973 | * are read from the buffer and for those without the Buffer -ENOTSUPP is | ||
974 | * returned. | ||
975 | * | ||
976 | * Return: 0 if no error, else return corresponding error. If no | ||
977 | * error then the trend value is passed on to trend parameter | ||
978 | */ | ||
979 | int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend) | ||
980 | { | ||
981 | struct temp_sensor_registers *tsr; | ||
982 | u32 temp1, temp2, reg1, reg2; | ||
983 | int t1, t2, interval, ret = 0; | ||
984 | |||
985 | ret = ti_bandgap_validate(bgp, id); | ||
986 | if (ret) | ||
987 | goto exit; | ||
988 | |||
989 | if (!TI_BANDGAP_HAS(bgp, HISTORY_BUFFER) || | ||
990 | !TI_BANDGAP_HAS(bgp, FREEZE_BIT)) { | ||
991 | ret = -ENOTSUPP; | ||
992 | goto exit; | ||
993 | } | ||
994 | |||
995 | tsr = bgp->conf->sensors[id].registers; | ||
996 | |||
997 | /* Freeze and read the last 2 valid readings */ | ||
998 | reg1 = tsr->ctrl_dtemp_1; | ||
999 | reg2 = tsr->ctrl_dtemp_2; | ||
1000 | |||
1001 | /* read temperature from history buffer */ | ||
1002 | temp1 = ti_bandgap_readl(bgp, reg1); | ||
1003 | temp1 &= tsr->bgap_dtemp_mask; | ||
1004 | |||
1005 | temp2 = ti_bandgap_readl(bgp, reg2); | ||
1006 | temp2 &= tsr->bgap_dtemp_mask; | ||
1007 | |||
1008 | /* Convert from adc values to mCelsius temperature */ | ||
1009 | ret = ti_bandgap_adc_to_mcelsius(bgp, temp1, &t1); | ||
1010 | if (ret) | ||
1011 | goto exit; | ||
1012 | |||
1013 | ret = ti_bandgap_adc_to_mcelsius(bgp, temp2, &t2); | ||
1014 | if (ret) | ||
1015 | goto exit; | ||
1016 | |||
1017 | /* Fetch the update interval */ | ||
1018 | ret = ti_bandgap_read_update_interval(bgp, id, &interval); | ||
1019 | if (ret || !interval) | ||
1020 | goto exit; | ||
1021 | |||
1022 | *trend = (t1 - t2) / interval; | ||
1023 | |||
1024 | dev_dbg(bgp->dev, "The temperatures are t1 = %d and t2 = %d and trend =%d\n", | ||
1025 | t1, t2, *trend); | ||
1026 | |||
1027 | exit: | ||
1028 | return ret; | ||
1029 | } | ||
1030 | |||
1031 | /** | ||
1032 | * ti_bandgap_tshut_init() - setup and initialize tshut handling | ||
1033 | * @bgp: pointer to struct ti_bandgap | ||
1034 | * @pdev: pointer to device struct platform_device | ||
1035 | * | ||
1036 | * Call this function only in case the bandgap features HAS(TSHUT). | ||
1037 | * In this case, the driver needs to handle the TSHUT signal as an IRQ. | ||
1038 | * The IRQ is wired as a GPIO, and for this purpose, it is required | ||
1039 | * to specify which GPIO line is used. TSHUT IRQ is fired anytime | ||
1040 | * one of the bandgap sensors violates the TSHUT high/hot threshold. | ||
1041 | * And in that case, the system must go off. | ||
1042 | * | ||
1043 | * Return: 0 if no error, else error status | ||
1044 | */ | ||
1045 | static int ti_bandgap_tshut_init(struct ti_bandgap *bgp, | ||
1046 | struct platform_device *pdev) | ||
1047 | { | ||
1048 | int gpio_nr = bgp->tshut_gpio; | ||
1049 | int status; | ||
1050 | |||
1051 | /* Request for gpio_86 line */ | ||
1052 | status = gpio_request(gpio_nr, "tshut"); | ||
1053 | if (status < 0) { | ||
1054 | dev_err(bgp->dev, "Could not request for TSHUT GPIO:%i\n", 86); | ||
1055 | return status; | ||
1056 | } | ||
1057 | status = gpio_direction_input(gpio_nr); | ||
1058 | if (status) { | ||
1059 | dev_err(bgp->dev, "Cannot set input TSHUT GPIO %d\n", gpio_nr); | ||
1060 | return status; | ||
1061 | } | ||
1062 | |||
1063 | status = request_irq(gpio_to_irq(gpio_nr), ti_bandgap_tshut_irq_handler, | ||
1064 | IRQF_TRIGGER_RISING, "tshut", NULL); | ||
1065 | if (status) { | ||
1066 | gpio_free(gpio_nr); | ||
1067 | dev_err(bgp->dev, "request irq failed for TSHUT"); | ||
1068 | } | ||
1069 | |||
1070 | return 0; | ||
1071 | } | ||
1072 | |||
1073 | /** | ||
1074 | * ti_bandgap_alert_init() - setup and initialize talert handling | ||
1075 | * @bgp: pointer to struct ti_bandgap | ||
1076 | * @pdev: pointer to device struct platform_device | ||
1077 | * | ||
1078 | * Call this function only in case the bandgap features HAS(TALERT). | ||
1079 | * In this case, the driver needs to handle the TALERT signals as an IRQs. | ||
1080 | * TALERT is a normal IRQ and it is fired any time thresholds (hot or cold) | ||
1081 | * are violated. In these situation, the driver must reprogram the thresholds, | ||
1082 | * accordingly to specified policy. | ||
1083 | * | ||
1084 | * Return: 0 if no error, else return corresponding error. | ||
1085 | */ | ||
1086 | static int ti_bandgap_talert_init(struct ti_bandgap *bgp, | ||
1087 | struct platform_device *pdev) | ||
1088 | { | ||
1089 | int ret; | ||
1090 | |||
1091 | bgp->irq = platform_get_irq(pdev, 0); | ||
1092 | if (bgp->irq < 0) { | ||
1093 | dev_err(&pdev->dev, "get_irq failed\n"); | ||
1094 | return bgp->irq; | ||
1095 | } | ||
1096 | ret = request_threaded_irq(bgp->irq, NULL, | ||
1097 | ti_bandgap_talert_irq_handler, | ||
1098 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, | ||
1099 | "talert", bgp); | ||
1100 | if (ret) { | ||
1101 | dev_err(&pdev->dev, "Request threaded irq failed.\n"); | ||
1102 | return ret; | ||
1103 | } | ||
1104 | |||
1105 | return 0; | ||
1106 | } | ||
1107 | |||
1108 | static const struct of_device_id of_ti_bandgap_match[]; | ||
1109 | /** | ||
1110 | * ti_bandgap_build() - parse DT and setup a struct ti_bandgap | ||
1111 | * @pdev: pointer to device struct platform_device | ||
1112 | * | ||
1113 | * Used to read the device tree properties accordingly to the bandgap | ||
1114 | * matching version. Based on bandgap version and its capabilities it | ||
1115 | * will build a struct ti_bandgap out of the required DT entries. | ||
1116 | * | ||
1117 | * Return: valid bandgap structure if successful, else returns ERR_PTR | ||
1118 | * return value must be verified with IS_ERR. | ||
1119 | */ | ||
1120 | static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev) | ||
1121 | { | ||
1122 | struct device_node *node = pdev->dev.of_node; | ||
1123 | const struct of_device_id *of_id; | ||
1124 | struct ti_bandgap *bgp; | ||
1125 | struct resource *res; | ||
1126 | u32 prop; | ||
1127 | int i; | ||
1128 | |||
1129 | /* just for the sake */ | ||
1130 | if (!node) { | ||
1131 | dev_err(&pdev->dev, "no platform information available\n"); | ||
1132 | return ERR_PTR(-EINVAL); | ||
1133 | } | ||
1134 | |||
1135 | bgp = devm_kzalloc(&pdev->dev, sizeof(*bgp), GFP_KERNEL); | ||
1136 | if (!bgp) { | ||
1137 | dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n"); | ||
1138 | return ERR_PTR(-ENOMEM); | ||
1139 | } | ||
1140 | |||
1141 | of_id = of_match_device(of_ti_bandgap_match, &pdev->dev); | ||
1142 | if (of_id) | ||
1143 | bgp->conf = of_id->data; | ||
1144 | |||
1145 | /* register shadow for context save and restore */ | ||
1146 | bgp->regval = devm_kzalloc(&pdev->dev, sizeof(*bgp->regval) * | ||
1147 | bgp->conf->sensor_count, GFP_KERNEL); | ||
1148 | if (!bgp) { | ||
1149 | dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n"); | ||
1150 | return ERR_PTR(-ENOMEM); | ||
1151 | } | ||
1152 | |||
1153 | i = 0; | ||
1154 | do { | ||
1155 | void __iomem *chunk; | ||
1156 | |||
1157 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
1158 | if (!res) | ||
1159 | break; | ||
1160 | chunk = devm_ioremap_resource(&pdev->dev, res); | ||
1161 | if (i == 0) | ||
1162 | bgp->base = chunk; | ||
1163 | if (IS_ERR(chunk)) | ||
1164 | return ERR_CAST(chunk); | ||
1165 | |||
1166 | i++; | ||
1167 | } while (res); | ||
1168 | |||
1169 | if (TI_BANDGAP_HAS(bgp, TSHUT)) { | ||
1170 | if (of_property_read_u32(node, "ti,tshut-gpio", &prop) < 0) { | ||
1171 | dev_err(&pdev->dev, "missing tshut gpio in device tree\n"); | ||
1172 | return ERR_PTR(-EINVAL); | ||
1173 | } | ||
1174 | bgp->tshut_gpio = prop; | ||
1175 | if (!gpio_is_valid(bgp->tshut_gpio)) { | ||
1176 | dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n", | ||
1177 | bgp->tshut_gpio); | ||
1178 | return ERR_PTR(-EINVAL); | ||
1179 | } | ||
1180 | } | ||
1181 | |||
1182 | return bgp; | ||
1183 | } | ||
1184 | |||
1185 | /*** Device driver call backs ***/ | ||
1186 | |||
1187 | static | ||
1188 | int ti_bandgap_probe(struct platform_device *pdev) | ||
1189 | { | ||
1190 | struct ti_bandgap *bgp; | ||
1191 | int clk_rate, ret = 0, i; | ||
1192 | |||
1193 | bgp = ti_bandgap_build(pdev); | ||
1194 | if (IS_ERR_OR_NULL(bgp)) { | ||
1195 | dev_err(&pdev->dev, "failed to fetch platform data\n"); | ||
1196 | return PTR_ERR(bgp); | ||
1197 | } | ||
1198 | bgp->dev = &pdev->dev; | ||
1199 | |||
1200 | if (TI_BANDGAP_HAS(bgp, TSHUT)) { | ||
1201 | ret = ti_bandgap_tshut_init(bgp, pdev); | ||
1202 | if (ret) { | ||
1203 | dev_err(&pdev->dev, | ||
1204 | "failed to initialize system tshut IRQ\n"); | ||
1205 | return ret; | ||
1206 | } | ||
1207 | } | ||
1208 | |||
1209 | bgp->fclock = clk_get(NULL, bgp->conf->fclock_name); | ||
1210 | ret = IS_ERR_OR_NULL(bgp->fclock); | ||
1211 | if (ret) { | ||
1212 | dev_err(&pdev->dev, "failed to request fclock reference\n"); | ||
1213 | goto free_irqs; | ||
1214 | } | ||
1215 | |||
1216 | bgp->div_clk = clk_get(NULL, bgp->conf->div_ck_name); | ||
1217 | ret = IS_ERR_OR_NULL(bgp->div_clk); | ||
1218 | if (ret) { | ||
1219 | dev_err(&pdev->dev, | ||
1220 | "failed to request div_ts_ck clock ref\n"); | ||
1221 | goto free_irqs; | ||
1222 | } | ||
1223 | |||
1224 | for (i = 0; i < bgp->conf->sensor_count; i++) { | ||
1225 | struct temp_sensor_registers *tsr; | ||
1226 | u32 val; | ||
1227 | |||
1228 | tsr = bgp->conf->sensors[i].registers; | ||
1229 | /* | ||
1230 | * check if the efuse has a non-zero value if not | ||
1231 | * it is an untrimmed sample and the temperatures | ||
1232 | * may not be accurate | ||
1233 | */ | ||
1234 | val = ti_bandgap_readl(bgp, tsr->bgap_efuse); | ||
1235 | if (ret || !val) | ||
1236 | dev_info(&pdev->dev, | ||
1237 | "Non-trimmed BGAP, Temp not accurate\n"); | ||
1238 | } | ||
1239 | |||
1240 | clk_rate = clk_round_rate(bgp->div_clk, | ||
1241 | bgp->conf->sensors[0].ts_data->max_freq); | ||
1242 | if (clk_rate < bgp->conf->sensors[0].ts_data->min_freq || | ||
1243 | clk_rate == 0xffffffff) { | ||
1244 | ret = -ENODEV; | ||
1245 | dev_err(&pdev->dev, "wrong clock rate (%d)\n", clk_rate); | ||
1246 | goto put_clks; | ||
1247 | } | ||
1248 | |||
1249 | ret = clk_set_rate(bgp->div_clk, clk_rate); | ||
1250 | if (ret) | ||
1251 | dev_err(&pdev->dev, "Cannot re-set clock rate. Continuing\n"); | ||
1252 | |||
1253 | bgp->clk_rate = clk_rate; | ||
1254 | if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) | ||
1255 | clk_prepare_enable(bgp->fclock); | ||
1256 | |||
1257 | |||
1258 | spin_lock_init(&bgp->lock); | ||
1259 | bgp->dev = &pdev->dev; | ||
1260 | platform_set_drvdata(pdev, bgp); | ||
1261 | |||
1262 | ti_bandgap_power(bgp, true); | ||
1263 | |||
1264 | /* Set default counter to 1 for now */ | ||
1265 | if (TI_BANDGAP_HAS(bgp, COUNTER)) | ||
1266 | for (i = 0; i < bgp->conf->sensor_count; i++) | ||
1267 | RMW_BITS(bgp, i, bgap_counter, counter_mask, 1); | ||
1268 | |||
1269 | /* Set default thresholds for alert and shutdown */ | ||
1270 | for (i = 0; i < bgp->conf->sensor_count; i++) { | ||
1271 | struct temp_sensor_data *ts_data; | ||
1272 | |||
1273 | ts_data = bgp->conf->sensors[i].ts_data; | ||
1274 | |||
1275 | if (TI_BANDGAP_HAS(bgp, TALERT)) { | ||
1276 | /* Set initial Talert thresholds */ | ||
1277 | RMW_BITS(bgp, i, bgap_threshold, | ||
1278 | threshold_tcold_mask, ts_data->t_cold); | ||
1279 | RMW_BITS(bgp, i, bgap_threshold, | ||
1280 | threshold_thot_mask, ts_data->t_hot); | ||
1281 | /* Enable the alert events */ | ||
1282 | RMW_BITS(bgp, i, bgap_mask_ctrl, mask_hot_mask, 1); | ||
1283 | RMW_BITS(bgp, i, bgap_mask_ctrl, mask_cold_mask, 1); | ||
1284 | } | ||
1285 | |||
1286 | if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) { | ||
1287 | /* Set initial Tshut thresholds */ | ||
1288 | RMW_BITS(bgp, i, tshut_threshold, | ||
1289 | tshut_hot_mask, ts_data->tshut_hot); | ||
1290 | RMW_BITS(bgp, i, tshut_threshold, | ||
1291 | tshut_cold_mask, ts_data->tshut_cold); | ||
1292 | } | ||
1293 | } | ||
1294 | |||
1295 | if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) | ||
1296 | ti_bandgap_set_continuous_mode(bgp); | ||
1297 | |||
1298 | /* Set .250 seconds time as default counter */ | ||
1299 | if (TI_BANDGAP_HAS(bgp, COUNTER)) | ||
1300 | for (i = 0; i < bgp->conf->sensor_count; i++) | ||
1301 | RMW_BITS(bgp, i, bgap_counter, counter_mask, | ||
1302 | bgp->clk_rate / 4); | ||
1303 | |||
1304 | /* Every thing is good? Then expose the sensors */ | ||
1305 | for (i = 0; i < bgp->conf->sensor_count; i++) { | ||
1306 | char *domain; | ||
1307 | |||
1308 | if (bgp->conf->sensors[i].register_cooling) { | ||
1309 | ret = bgp->conf->sensors[i].register_cooling(bgp, i); | ||
1310 | if (ret) | ||
1311 | goto remove_sensors; | ||
1312 | } | ||
1313 | |||
1314 | if (bgp->conf->expose_sensor) { | ||
1315 | domain = bgp->conf->sensors[i].domain; | ||
1316 | ret = bgp->conf->expose_sensor(bgp, i, domain); | ||
1317 | if (ret) | ||
1318 | goto remove_last_cooling; | ||
1319 | } | ||
1320 | } | ||
1321 | |||
1322 | /* | ||
1323 | * Enable the Interrupts once everything is set. Otherwise irq handler | ||
1324 | * might be called as soon as it is enabled where as rest of framework | ||
1325 | * is still getting initialised. | ||
1326 | */ | ||
1327 | if (TI_BANDGAP_HAS(bgp, TALERT)) { | ||
1328 | ret = ti_bandgap_talert_init(bgp, pdev); | ||
1329 | if (ret) { | ||
1330 | dev_err(&pdev->dev, "failed to initialize Talert IRQ\n"); | ||
1331 | i = bgp->conf->sensor_count; | ||
1332 | goto disable_clk; | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | return 0; | ||
1337 | |||
1338 | remove_last_cooling: | ||
1339 | if (bgp->conf->sensors[i].unregister_cooling) | ||
1340 | bgp->conf->sensors[i].unregister_cooling(bgp, i); | ||
1341 | remove_sensors: | ||
1342 | for (i--; i >= 0; i--) { | ||
1343 | if (bgp->conf->sensors[i].unregister_cooling) | ||
1344 | bgp->conf->sensors[i].unregister_cooling(bgp, i); | ||
1345 | if (bgp->conf->remove_sensor) | ||
1346 | bgp->conf->remove_sensor(bgp, i); | ||
1347 | } | ||
1348 | ti_bandgap_power(bgp, false); | ||
1349 | disable_clk: | ||
1350 | if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) | ||
1351 | clk_disable_unprepare(bgp->fclock); | ||
1352 | put_clks: | ||
1353 | clk_put(bgp->fclock); | ||
1354 | clk_put(bgp->div_clk); | ||
1355 | free_irqs: | ||
1356 | if (TI_BANDGAP_HAS(bgp, TSHUT)) { | ||
1357 | free_irq(gpio_to_irq(bgp->tshut_gpio), NULL); | ||
1358 | gpio_free(bgp->tshut_gpio); | ||
1359 | } | ||
1360 | |||
1361 | return ret; | ||
1362 | } | ||
1363 | |||
1364 | static | ||
1365 | int ti_bandgap_remove(struct platform_device *pdev) | ||
1366 | { | ||
1367 | struct ti_bandgap *bgp = platform_get_drvdata(pdev); | ||
1368 | int i; | ||
1369 | |||
1370 | /* First thing is to remove sensor interfaces */ | ||
1371 | for (i = 0; i < bgp->conf->sensor_count; i++) { | ||
1372 | if (bgp->conf->sensors[i].unregister_cooling) | ||
1373 | bgp->conf->sensors[i].unregister_cooling(bgp, i); | ||
1374 | |||
1375 | if (bgp->conf->remove_sensor) | ||
1376 | bgp->conf->remove_sensor(bgp, i); | ||
1377 | } | ||
1378 | |||
1379 | ti_bandgap_power(bgp, false); | ||
1380 | |||
1381 | if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) | ||
1382 | clk_disable_unprepare(bgp->fclock); | ||
1383 | clk_put(bgp->fclock); | ||
1384 | clk_put(bgp->div_clk); | ||
1385 | |||
1386 | if (TI_BANDGAP_HAS(bgp, TALERT)) | ||
1387 | free_irq(bgp->irq, bgp); | ||
1388 | |||
1389 | if (TI_BANDGAP_HAS(bgp, TSHUT)) { | ||
1390 | free_irq(gpio_to_irq(bgp->tshut_gpio), NULL); | ||
1391 | gpio_free(bgp->tshut_gpio); | ||
1392 | } | ||
1393 | |||
1394 | return 0; | ||
1395 | } | ||
1396 | |||
1397 | #ifdef CONFIG_PM | ||
1398 | static int ti_bandgap_save_ctxt(struct ti_bandgap *bgp) | ||
1399 | { | ||
1400 | int i; | ||
1401 | |||
1402 | for (i = 0; i < bgp->conf->sensor_count; i++) { | ||
1403 | struct temp_sensor_registers *tsr; | ||
1404 | struct temp_sensor_regval *rval; | ||
1405 | |||
1406 | rval = &bgp->regval[i]; | ||
1407 | tsr = bgp->conf->sensors[i].registers; | ||
1408 | |||
1409 | if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) | ||
1410 | rval->bg_mode_ctrl = ti_bandgap_readl(bgp, | ||
1411 | tsr->bgap_mode_ctrl); | ||
1412 | if (TI_BANDGAP_HAS(bgp, COUNTER)) | ||
1413 | rval->bg_counter = ti_bandgap_readl(bgp, | ||
1414 | tsr->bgap_counter); | ||
1415 | if (TI_BANDGAP_HAS(bgp, TALERT)) { | ||
1416 | rval->bg_threshold = ti_bandgap_readl(bgp, | ||
1417 | tsr->bgap_threshold); | ||
1418 | rval->bg_ctrl = ti_bandgap_readl(bgp, | ||
1419 | tsr->bgap_mask_ctrl); | ||
1420 | } | ||
1421 | |||
1422 | if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) | ||
1423 | rval->tshut_threshold = ti_bandgap_readl(bgp, | ||
1424 | tsr->tshut_threshold); | ||
1425 | } | ||
1426 | |||
1427 | return 0; | ||
1428 | } | ||
1429 | |||
1430 | static int ti_bandgap_restore_ctxt(struct ti_bandgap *bgp) | ||
1431 | { | ||
1432 | int i; | ||
1433 | |||
1434 | for (i = 0; i < bgp->conf->sensor_count; i++) { | ||
1435 | struct temp_sensor_registers *tsr; | ||
1436 | struct temp_sensor_regval *rval; | ||
1437 | u32 val = 0; | ||
1438 | |||
1439 | rval = &bgp->regval[i]; | ||
1440 | tsr = bgp->conf->sensors[i].registers; | ||
1441 | |||
1442 | if (TI_BANDGAP_HAS(bgp, COUNTER)) | ||
1443 | val = ti_bandgap_readl(bgp, tsr->bgap_counter); | ||
1444 | |||
1445 | if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) | ||
1446 | ti_bandgap_writel(bgp, rval->tshut_threshold, | ||
1447 | tsr->tshut_threshold); | ||
1448 | /* Force immediate temperature measurement and update | ||
1449 | * of the DTEMP field | ||
1450 | */ | ||
1451 | ti_bandgap_force_single_read(bgp, i); | ||
1452 | |||
1453 | if (TI_BANDGAP_HAS(bgp, COUNTER)) | ||
1454 | ti_bandgap_writel(bgp, rval->bg_counter, | ||
1455 | tsr->bgap_counter); | ||
1456 | if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) | ||
1457 | ti_bandgap_writel(bgp, rval->bg_mode_ctrl, | ||
1458 | tsr->bgap_mode_ctrl); | ||
1459 | if (TI_BANDGAP_HAS(bgp, TALERT)) { | ||
1460 | ti_bandgap_writel(bgp, rval->bg_threshold, | ||
1461 | tsr->bgap_threshold); | ||
1462 | ti_bandgap_writel(bgp, rval->bg_ctrl, | ||
1463 | tsr->bgap_mask_ctrl); | ||
1464 | } | ||
1465 | } | ||
1466 | |||
1467 | return 0; | ||
1468 | } | ||
1469 | |||
1470 | static int ti_bandgap_suspend(struct device *dev) | ||
1471 | { | ||
1472 | struct ti_bandgap *bgp = dev_get_drvdata(dev); | ||
1473 | int err; | ||
1474 | |||
1475 | err = ti_bandgap_save_ctxt(bgp); | ||
1476 | ti_bandgap_power(bgp, false); | ||
1477 | |||
1478 | if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) | ||
1479 | clk_disable_unprepare(bgp->fclock); | ||
1480 | |||
1481 | return err; | ||
1482 | } | ||
1483 | |||
1484 | static int ti_bandgap_resume(struct device *dev) | ||
1485 | { | ||
1486 | struct ti_bandgap *bgp = dev_get_drvdata(dev); | ||
1487 | |||
1488 | if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) | ||
1489 | clk_prepare_enable(bgp->fclock); | ||
1490 | |||
1491 | ti_bandgap_power(bgp, true); | ||
1492 | |||
1493 | return ti_bandgap_restore_ctxt(bgp); | ||
1494 | } | ||
1495 | static const struct dev_pm_ops ti_bandgap_dev_pm_ops = { | ||
1496 | SET_SYSTEM_SLEEP_PM_OPS(ti_bandgap_suspend, | ||
1497 | ti_bandgap_resume) | ||
1498 | }; | ||
1499 | |||
1500 | #define DEV_PM_OPS (&ti_bandgap_dev_pm_ops) | ||
1501 | #else | ||
1502 | #define DEV_PM_OPS NULL | ||
1503 | #endif | ||
1504 | |||
1505 | static const struct of_device_id of_ti_bandgap_match[] = { | ||
1506 | #ifdef CONFIG_OMAP4_THERMAL | ||
1507 | { | ||
1508 | .compatible = "ti,omap4430-bandgap", | ||
1509 | .data = (void *)&omap4430_data, | ||
1510 | }, | ||
1511 | { | ||
1512 | .compatible = "ti,omap4460-bandgap", | ||
1513 | .data = (void *)&omap4460_data, | ||
1514 | }, | ||
1515 | { | ||
1516 | .compatible = "ti,omap4470-bandgap", | ||
1517 | .data = (void *)&omap4470_data, | ||
1518 | }, | ||
1519 | #endif | ||
1520 | #ifdef CONFIG_OMAP5_THERMAL | ||
1521 | { | ||
1522 | .compatible = "ti,omap5430-bandgap", | ||
1523 | .data = (void *)&omap5430_data, | ||
1524 | }, | ||
1525 | #endif | ||
1526 | /* Sentinel */ | ||
1527 | { }, | ||
1528 | }; | ||
1529 | MODULE_DEVICE_TABLE(of, of_ti_bandgap_match); | ||
1530 | |||
1531 | static struct platform_driver ti_bandgap_sensor_driver = { | ||
1532 | .probe = ti_bandgap_probe, | ||
1533 | .remove = ti_bandgap_remove, | ||
1534 | .driver = { | ||
1535 | .name = "ti-soc-thermal", | ||
1536 | .pm = DEV_PM_OPS, | ||
1537 | .of_match_table = of_ti_bandgap_match, | ||
1538 | }, | ||
1539 | }; | ||
1540 | |||
1541 | module_platform_driver(ti_bandgap_sensor_driver); | ||
1542 | |||
1543 | MODULE_DESCRIPTION("OMAP4+ bandgap temperature sensor driver"); | ||
1544 | MODULE_LICENSE("GPL v2"); | ||
1545 | MODULE_ALIAS("platform:ti-soc-thermal"); | ||
1546 | MODULE_AUTHOR("Texas Instrument Inc."); | ||
diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.h b/drivers/thermal/ti-soc-thermal/ti-bandgap.h new file mode 100644 index 000000000000..5f4794abf583 --- /dev/null +++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.h | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | * OMAP4 Bandgap temperature sensor driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * Contact: | ||
6 | * Eduardo Valentin <eduardo.valentin@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | #ifndef __TI_BANDGAP_H | ||
24 | #define __TI_BANDGAP_H | ||
25 | |||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/err.h> | ||
29 | |||
30 | /** | ||
31 | * DOC: bandgap driver data structure | ||
32 | * ================================== | ||
33 | * | ||
34 | * +----------+----------------+ | ||
35 | * | struct temp_sensor_regval | | ||
36 | * +---------------------------+ | ||
37 | * * (Array of) | ||
38 | * | | ||
39 | * | | ||
40 | * +-------------------+ +-----------------+ | ||
41 | * | struct ti_bandgap |-->| struct device * | | ||
42 | * +----------+--------+ +-----------------+ | ||
43 | * | | ||
44 | * | | ||
45 | * V | ||
46 | * +------------------------+ | ||
47 | * | struct ti_bandgap_data | | ||
48 | * +------------------------+ | ||
49 | * | | ||
50 | * | | ||
51 | * * (Array of) | ||
52 | * +------------+------------------------------------------------------+ | ||
53 | * | +----------+------------+ +-------------------------+ | | ||
54 | * | | struct ti_temp_sensor |-->| struct temp_sensor_data | | | ||
55 | * | +-----------------------+ +------------+------------+ | | ||
56 | * | | | | ||
57 | * | + | | ||
58 | * | V | | ||
59 | * | +----------+-------------------+ | | ||
60 | * | | struct temp_sensor_registers | | | ||
61 | * | +------------------------------+ | | ||
62 | * | | | ||
63 | * +-------------------------------------------------------------------+ | ||
64 | * | ||
65 | * Above is a simple diagram describing how the data structure below | ||
66 | * are organized. For each bandgap device there should be a ti_bandgap_data | ||
67 | * containing the device instance configuration, as well as, an array of | ||
68 | * sensors, representing every sensor instance present in this bandgap. | ||
69 | */ | ||
70 | |||
71 | /** | ||
72 | * struct temp_sensor_registers - descriptor to access registers and bitfields | ||
73 | * @temp_sensor_ctrl: TEMP_SENSOR_CTRL register offset | ||
74 | * @bgap_tempsoff_mask: mask to temp_sensor_ctrl.tempsoff | ||
75 | * @bgap_soc_mask: mask to temp_sensor_ctrl.soc | ||
76 | * @bgap_eocz_mask: mask to temp_sensor_ctrl.eocz | ||
77 | * @bgap_dtemp_mask: mask to temp_sensor_ctrl.dtemp | ||
78 | * @bgap_mask_ctrl: BANDGAP_MASK_CTRL register offset | ||
79 | * @mask_hot_mask: mask to bandgap_mask_ctrl.mask_hot | ||
80 | * @mask_cold_mask: mask to bandgap_mask_ctrl.mask_cold | ||
81 | * @mask_sidlemode_mask: mask to bandgap_mask_ctrl.mask_sidlemode | ||
82 | * @mask_counter_delay_mask: mask to bandgap_mask_ctrl.mask_counter_delay | ||
83 | * @mask_freeze_mask: mask to bandgap_mask_ctrl.mask_free | ||
84 | * @mask_clear_mask: mask to bandgap_mask_ctrl.mask_clear | ||
85 | * @mask_clear_accum_mask: mask to bandgap_mask_ctrl.mask_clear_accum | ||
86 | * @bgap_mode_ctrl: BANDGAP_MODE_CTRL register offset | ||
87 | * @mode_ctrl_mask: mask to bandgap_mode_ctrl.mode_ctrl | ||
88 | * @bgap_counter: BANDGAP_COUNTER register offset | ||
89 | * @counter_mask: mask to bandgap_counter.counter | ||
90 | * @bgap_threshold: BANDGAP_THRESHOLD register offset (TALERT thresholds) | ||
91 | * @threshold_thot_mask: mask to bandgap_threhold.thot | ||
92 | * @threshold_tcold_mask: mask to bandgap_threhold.tcold | ||
93 | * @tshut_threshold: TSHUT_THRESHOLD register offset (TSHUT thresholds) | ||
94 | * @tshut_efuse_mask: mask to tshut_threshold.tshut_efuse | ||
95 | * @tshut_efuse_shift: shift to tshut_threshold.tshut_efuse | ||
96 | * @tshut_hot_mask: mask to tshut_threhold.thot | ||
97 | * @tshut_cold_mask: mask to tshut_threhold.thot | ||
98 | * @bgap_status: BANDGAP_STATUS register offset | ||
99 | * @status_clean_stop_mask: mask to bandgap_status.clean_stop | ||
100 | * @status_bgap_alert_mask: mask to bandgap_status.bandgap_alert | ||
101 | * @status_hot_mask: mask to bandgap_status.hot | ||
102 | * @status_cold_mask: mask to bandgap_status.cold | ||
103 | * @bgap_cumul_dtemp: BANDGAP_CUMUL_DTEMP register offset | ||
104 | * @ctrl_dtemp_0: CTRL_DTEMP0 register offset | ||
105 | * @ctrl_dtemp_1: CTRL_DTEMP1 register offset | ||
106 | * @ctrl_dtemp_2: CTRL_DTEMP2 register offset | ||
107 | * @ctrl_dtemp_3: CTRL_DTEMP3 register offset | ||
108 | * @ctrl_dtemp_4: CTRL_DTEMP4 register offset | ||
109 | * @bgap_efuse: BANDGAP_EFUSE register offset | ||
110 | * | ||
111 | * The register offsets and bitfields might change across | ||
112 | * OMAP and variants versions. Hence this struct serves as a | ||
113 | * descriptor map on how to access the registers and the bitfields. | ||
114 | * | ||
115 | * This descriptor contains registers of all versions of bandgap chips. | ||
116 | * Not all versions will use all registers, depending on the available | ||
117 | * features. Please read TRMs for descriptive explanation on each bitfield. | ||
118 | */ | ||
119 | |||
120 | struct temp_sensor_registers { | ||
121 | u32 temp_sensor_ctrl; | ||
122 | u32 bgap_tempsoff_mask; | ||
123 | u32 bgap_soc_mask; | ||
124 | u32 bgap_eocz_mask; /* not used: but needs revisit */ | ||
125 | u32 bgap_dtemp_mask; | ||
126 | |||
127 | u32 bgap_mask_ctrl; | ||
128 | u32 mask_hot_mask; | ||
129 | u32 mask_cold_mask; | ||
130 | u32 mask_sidlemode_mask; /* not used: but may be needed for pm */ | ||
131 | u32 mask_counter_delay_mask; | ||
132 | u32 mask_freeze_mask; | ||
133 | u32 mask_clear_mask; /* not used: but needed for trending */ | ||
134 | u32 mask_clear_accum_mask; /* not used: but needed for trending */ | ||
135 | |||
136 | u32 bgap_mode_ctrl; | ||
137 | u32 mode_ctrl_mask; | ||
138 | |||
139 | u32 bgap_counter; | ||
140 | u32 counter_mask; | ||
141 | |||
142 | u32 bgap_threshold; | ||
143 | u32 threshold_thot_mask; | ||
144 | u32 threshold_tcold_mask; | ||
145 | |||
146 | u32 tshut_threshold; | ||
147 | u32 tshut_efuse_mask; /* not used */ | ||
148 | u32 tshut_efuse_shift; /* not used */ | ||
149 | u32 tshut_hot_mask; | ||
150 | u32 tshut_cold_mask; | ||
151 | |||
152 | u32 bgap_status; | ||
153 | u32 status_clean_stop_mask; /* not used: but needed for trending */ | ||
154 | u32 status_bgap_alert_mask; /* not used */ | ||
155 | u32 status_hot_mask; | ||
156 | u32 status_cold_mask; | ||
157 | |||
158 | u32 bgap_cumul_dtemp; /* not used: but needed for trending */ | ||
159 | u32 ctrl_dtemp_0; /* not used: but needed for trending */ | ||
160 | u32 ctrl_dtemp_1; /* not used: but needed for trending */ | ||
161 | u32 ctrl_dtemp_2; /* not used: but needed for trending */ | ||
162 | u32 ctrl_dtemp_3; /* not used: but needed for trending */ | ||
163 | u32 ctrl_dtemp_4; /* not used: but needed for trending */ | ||
164 | u32 bgap_efuse; | ||
165 | }; | ||
166 | |||
167 | /** | ||
168 | * struct temp_sensor_data - The thresholds and limits for temperature sensors. | ||
169 | * @tshut_hot: temperature to trigger a thermal reset (initial value) | ||
170 | * @tshut_cold: temp to get the plat out of reset due to thermal (init val) | ||
171 | * @t_hot: temperature to trigger a thermal alert (high initial value) | ||
172 | * @t_cold: temperature to trigger a thermal alert (low initial value) | ||
173 | * @min_freq: sensor minimum clock rate | ||
174 | * @max_freq: sensor maximum clock rate | ||
175 | * @max_temp: sensor maximum temperature | ||
176 | * @min_temp: sensor minimum temperature | ||
177 | * @hyst_val: temperature hysteresis considered while converting ADC values | ||
178 | * @update_int1: update interval | ||
179 | * @update_int2: update interval | ||
180 | * | ||
181 | * This data structure will hold the required thresholds and temperature limits | ||
182 | * for a specific temperature sensor, like shutdown temperature, alert | ||
183 | * temperature, clock / rate used, ADC conversion limits and update intervals | ||
184 | */ | ||
185 | struct temp_sensor_data { | ||
186 | u32 tshut_hot; | ||
187 | u32 tshut_cold; | ||
188 | u32 t_hot; | ||
189 | u32 t_cold; | ||
190 | u32 min_freq; | ||
191 | u32 max_freq; | ||
192 | int max_temp; | ||
193 | int min_temp; | ||
194 | int hyst_val; | ||
195 | u32 update_int1; /* not used */ | ||
196 | u32 update_int2; /* not used */ | ||
197 | }; | ||
198 | |||
199 | struct ti_bandgap_data; | ||
200 | |||
201 | /** | ||
202 | * struct temp_sensor_regval - temperature sensor register values and priv data | ||
203 | * @bg_mode_ctrl: temp sensor control register value | ||
204 | * @bg_ctrl: bandgap ctrl register value | ||
205 | * @bg_counter: bandgap counter value | ||
206 | * @bg_threshold: bandgap threshold register value | ||
207 | * @tshut_threshold: bandgap tshut register value | ||
208 | * @data: private data | ||
209 | * | ||
210 | * Data structure to save and restore bandgap register set context. Only | ||
211 | * required registers are shadowed, when needed. | ||
212 | */ | ||
213 | struct temp_sensor_regval { | ||
214 | u32 bg_mode_ctrl; | ||
215 | u32 bg_ctrl; | ||
216 | u32 bg_counter; | ||
217 | u32 bg_threshold; | ||
218 | u32 tshut_threshold; | ||
219 | void *data; | ||
220 | }; | ||
221 | |||
222 | /** | ||
223 | * struct ti_bandgap - bandgap device structure | ||
224 | * @dev: struct device pointer | ||
225 | * @base: io memory base address | ||
226 | * @conf: struct with bandgap configuration set (# sensors, conv_table, etc) | ||
227 | * @regval: temperature sensor register values | ||
228 | * @fclock: pointer to functional clock of temperature sensor | ||
229 | * @div_clk: pointer to divider clock of temperature sensor fclk | ||
230 | * @lock: spinlock for ti_bandgap structure | ||
231 | * @irq: MPU IRQ number for thermal alert | ||
232 | * @tshut_gpio: GPIO where Tshut signal is routed | ||
233 | * @clk_rate: Holds current clock rate | ||
234 | * | ||
235 | * The bandgap device structure representing the bandgap device instance. | ||
236 | * It holds most of the dynamic stuff. Configurations and sensor specific | ||
237 | * entries are inside the @conf structure. | ||
238 | */ | ||
239 | struct ti_bandgap { | ||
240 | struct device *dev; | ||
241 | void __iomem *base; | ||
242 | const struct ti_bandgap_data *conf; | ||
243 | struct temp_sensor_regval *regval; | ||
244 | struct clk *fclock; | ||
245 | struct clk *div_clk; | ||
246 | spinlock_t lock; /* shields this struct */ | ||
247 | int irq; | ||
248 | int tshut_gpio; | ||
249 | u32 clk_rate; | ||
250 | }; | ||
251 | |||
252 | /** | ||
253 | * struct ti_temp_sensor - bandgap temperature sensor configuration data | ||
254 | * @ts_data: pointer to struct with thresholds, limits of temperature sensor | ||
255 | * @registers: pointer to the list of register offsets and bitfields | ||
256 | * @domain: the name of the domain where the sensor is located | ||
257 | * @slope: sensor gradient slope info for hotspot extrapolation equation | ||
258 | * @constant: sensor gradient const info for hotspot extrapolation equation | ||
259 | * @slope_pcb: sensor gradient slope info for hotspot extrapolation equation | ||
260 | * with no external influence | ||
261 | * @constant_pcb: sensor gradient const info for hotspot extrapolation equation | ||
262 | * with no external influence | ||
263 | * @register_cooling: function to describe how this sensor is going to be cooled | ||
264 | * @unregister_cooling: function to release cooling data | ||
265 | * | ||
266 | * Data structure to describe a temperature sensor handled by a bandgap device. | ||
267 | * It should provide configuration details on this sensor, such as how to | ||
268 | * access the registers affecting this sensor, shadow register buffer, how to | ||
269 | * assess the gradient from hotspot, how to cooldown the domain when sensor | ||
270 | * reports too hot temperature. | ||
271 | */ | ||
272 | struct ti_temp_sensor { | ||
273 | struct temp_sensor_data *ts_data; | ||
274 | struct temp_sensor_registers *registers; | ||
275 | char *domain; | ||
276 | /* for hotspot extrapolation */ | ||
277 | const int slope; | ||
278 | const int constant; | ||
279 | const int slope_pcb; | ||
280 | const int constant_pcb; | ||
281 | int (*register_cooling)(struct ti_bandgap *bgp, int id); | ||
282 | int (*unregister_cooling)(struct ti_bandgap *bgp, int id); | ||
283 | }; | ||
284 | |||
285 | /** | ||
286 | * DOC: ti bandgap feature types | ||
287 | * | ||
288 | * TI_BANDGAP_FEATURE_TSHUT - used when the thermal shutdown signal output | ||
289 | * of a bandgap device instance is routed to the processor. This means | ||
290 | * the system must react and perform the shutdown by itself (handle an | ||
291 | * IRQ, for instance). | ||
292 | * | ||
293 | * TI_BANDGAP_FEATURE_TSHUT_CONFIG - used when the bandgap device has control | ||
294 | * over the thermal shutdown configuration. This means that the thermal | ||
295 | * shutdown thresholds are programmable, for instance. | ||
296 | * | ||
297 | * TI_BANDGAP_FEATURE_TALERT - used when the bandgap device instance outputs | ||
298 | * a signal representing violation of programmable alert thresholds. | ||
299 | * | ||
300 | * TI_BANDGAP_FEATURE_MODE_CONFIG - used when it is possible to choose which | ||
301 | * mode, continuous or one shot, the bandgap device instance will operate. | ||
302 | * | ||
303 | * TI_BANDGAP_FEATURE_COUNTER - used when the bandgap device instance allows | ||
304 | * programming the update interval of its internal state machine. | ||
305 | * | ||
306 | * TI_BANDGAP_FEATURE_POWER_SWITCH - used when the bandgap device allows | ||
307 | * itself to be switched on/off. | ||
308 | * | ||
309 | * TI_BANDGAP_FEATURE_CLK_CTRL - used when the clocks feeding the bandgap | ||
310 | * device are gateable or not. | ||
311 | * | ||
312 | * TI_BANDGAP_FEATURE_FREEZE_BIT - used when the bandgap device features | ||
313 | * a history buffer that its update can be freezed/unfreezed. | ||
314 | * | ||
315 | * TI_BANDGAP_FEATURE_COUNTER_DELAY - used when the bandgap device features | ||
316 | * a delay programming based on distinct values. | ||
317 | * | ||
318 | * TI_BANDGAP_FEATURE_HISTORY_BUFFER - used when the bandgap device features | ||
319 | * a history buffer of temperatures. | ||
320 | * | ||
321 | * TI_BANDGAP_HAS(b, f) - macro to check if a bandgap device is capable of a | ||
322 | * specific feature (above) or not. Return non-zero, if yes. | ||
323 | */ | ||
324 | #define TI_BANDGAP_FEATURE_TSHUT BIT(0) | ||
325 | #define TI_BANDGAP_FEATURE_TSHUT_CONFIG BIT(1) | ||
326 | #define TI_BANDGAP_FEATURE_TALERT BIT(2) | ||
327 | #define TI_BANDGAP_FEATURE_MODE_CONFIG BIT(3) | ||
328 | #define TI_BANDGAP_FEATURE_COUNTER BIT(4) | ||
329 | #define TI_BANDGAP_FEATURE_POWER_SWITCH BIT(5) | ||
330 | #define TI_BANDGAP_FEATURE_CLK_CTRL BIT(6) | ||
331 | #define TI_BANDGAP_FEATURE_FREEZE_BIT BIT(7) | ||
332 | #define TI_BANDGAP_FEATURE_COUNTER_DELAY BIT(8) | ||
333 | #define TI_BANDGAP_FEATURE_HISTORY_BUFFER BIT(9) | ||
334 | #define TI_BANDGAP_HAS(b, f) \ | ||
335 | ((b)->conf->features & TI_BANDGAP_FEATURE_ ## f) | ||
336 | |||
337 | /** | ||
338 | * struct ti_bandgap_data - ti bandgap data configuration structure | ||
339 | * @features: a bitwise flag set to describe the device features | ||
340 | * @conv_table: Pointer to ADC to temperature conversion table | ||
341 | * @adc_start_val: ADC conversion table starting value | ||
342 | * @adc_end_val: ADC conversion table ending value | ||
343 | * @fclock_name: clock name of the functional clock | ||
344 | * @div_ck_name: clock name of the clock divisor | ||
345 | * @sensor_count: count of temperature sensor within this bandgap device | ||
346 | * @report_temperature: callback to report thermal alert to thermal API | ||
347 | * @expose_sensor: callback to export sensor to thermal API | ||
348 | * @remove_sensor: callback to destroy sensor from thermal API | ||
349 | * @sensors: array of sensors present in this bandgap instance | ||
350 | * | ||
351 | * This is a data structure which should hold most of the static configuration | ||
352 | * of a bandgap device instance. It should describe which features this instance | ||
353 | * is capable of, the clock names to feed this device, the amount of sensors and | ||
354 | * their configuration representation, and how to export and unexport them to | ||
355 | * a thermal API. | ||
356 | */ | ||
357 | struct ti_bandgap_data { | ||
358 | unsigned int features; | ||
359 | const int *conv_table; | ||
360 | u32 adc_start_val; | ||
361 | u32 adc_end_val; | ||
362 | char *fclock_name; | ||
363 | char *div_ck_name; | ||
364 | int sensor_count; | ||
365 | int (*report_temperature)(struct ti_bandgap *bgp, int id); | ||
366 | int (*expose_sensor)(struct ti_bandgap *bgp, int id, char *domain); | ||
367 | int (*remove_sensor)(struct ti_bandgap *bgp, int id); | ||
368 | |||
369 | /* this needs to be at the end */ | ||
370 | struct ti_temp_sensor sensors[]; | ||
371 | }; | ||
372 | |||
373 | int ti_bandgap_read_thot(struct ti_bandgap *bgp, int id, int *thot); | ||
374 | int ti_bandgap_write_thot(struct ti_bandgap *bgp, int id, int val); | ||
375 | int ti_bandgap_read_tcold(struct ti_bandgap *bgp, int id, int *tcold); | ||
376 | int ti_bandgap_write_tcold(struct ti_bandgap *bgp, int id, int val); | ||
377 | int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id, | ||
378 | int *interval); | ||
379 | int ti_bandgap_write_update_interval(struct ti_bandgap *bgp, int id, | ||
380 | u32 interval); | ||
381 | int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id, | ||
382 | int *temperature); | ||
383 | int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data); | ||
384 | void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id); | ||
385 | int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend); | ||
386 | |||
387 | #ifdef CONFIG_OMAP4_THERMAL | ||
388 | extern const struct ti_bandgap_data omap4430_data; | ||
389 | extern const struct ti_bandgap_data omap4460_data; | ||
390 | extern const struct ti_bandgap_data omap4470_data; | ||
391 | #else | ||
392 | #define omap4430_data NULL | ||
393 | #define omap4460_data NULL | ||
394 | #define omap4470_data NULL | ||
395 | #endif | ||
396 | |||
397 | #ifdef CONFIG_OMAP5_THERMAL | ||
398 | extern const struct ti_bandgap_data omap5430_data; | ||
399 | #else | ||
400 | #define omap5430_data NULL | ||
401 | #endif | ||
402 | |||
403 | #endif | ||
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c new file mode 100644 index 000000000000..e3c5e677eaa5 --- /dev/null +++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c | |||
@@ -0,0 +1,367 @@ | |||
1 | /* | ||
2 | * OMAP thermal driver interface | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * Contact: | ||
6 | * Eduardo Valentin <eduardo.valentin@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/device.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/mutex.h> | ||
27 | #include <linux/gfp.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/workqueue.h> | ||
30 | #include <linux/thermal.h> | ||
31 | #include <linux/cpufreq.h> | ||
32 | #include <linux/cpumask.h> | ||
33 | #include <linux/cpu_cooling.h> | ||
34 | |||
35 | #include "ti-thermal.h" | ||
36 | #include "ti-bandgap.h" | ||
37 | |||
38 | /* common data structures */ | ||
39 | struct ti_thermal_data { | ||
40 | struct thermal_zone_device *ti_thermal; | ||
41 | struct thermal_cooling_device *cool_dev; | ||
42 | struct ti_bandgap *bgp; | ||
43 | enum thermal_device_mode mode; | ||
44 | struct work_struct thermal_wq; | ||
45 | int sensor_id; | ||
46 | }; | ||
47 | |||
48 | static void ti_thermal_work(struct work_struct *work) | ||
49 | { | ||
50 | struct ti_thermal_data *data = container_of(work, | ||
51 | struct ti_thermal_data, thermal_wq); | ||
52 | |||
53 | thermal_zone_device_update(data->ti_thermal); | ||
54 | |||
55 | dev_dbg(&data->ti_thermal->device, "updated thermal zone %s\n", | ||
56 | data->ti_thermal->type); | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * ti_thermal_hotspot_temperature - returns sensor extrapolated temperature | ||
61 | * @t: omap sensor temperature | ||
62 | * @s: omap sensor slope value | ||
63 | * @c: omap sensor const value | ||
64 | */ | ||
65 | static inline int ti_thermal_hotspot_temperature(int t, int s, int c) | ||
66 | { | ||
67 | int delta = t * s / 1000 + c; | ||
68 | |||
69 | if (delta < 0) | ||
70 | delta = 0; | ||
71 | |||
72 | return t + delta; | ||
73 | } | ||
74 | |||
75 | /* thermal zone ops */ | ||
76 | /* Get temperature callback function for thermal zone*/ | ||
77 | static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal, | ||
78 | unsigned long *temp) | ||
79 | { | ||
80 | struct ti_thermal_data *data = thermal->devdata; | ||
81 | struct ti_bandgap *bgp; | ||
82 | const struct ti_temp_sensor *s; | ||
83 | int ret, tmp, pcb_temp, slope, constant; | ||
84 | |||
85 | if (!data) | ||
86 | return 0; | ||
87 | |||
88 | bgp = data->bgp; | ||
89 | s = &bgp->conf->sensors[data->sensor_id]; | ||
90 | |||
91 | ret = ti_bandgap_read_temperature(bgp, data->sensor_id, &tmp); | ||
92 | if (ret) | ||
93 | return ret; | ||
94 | |||
95 | pcb_temp = 0; | ||
96 | /* TODO: Introduce pcb temperature lookup */ | ||
97 | /* In case pcb zone is available, use the extrapolation rule with it */ | ||
98 | if (pcb_temp) { | ||
99 | tmp -= pcb_temp; | ||
100 | slope = s->slope_pcb; | ||
101 | constant = s->constant_pcb; | ||
102 | } else { | ||
103 | slope = s->slope; | ||
104 | constant = s->constant; | ||
105 | } | ||
106 | *temp = ti_thermal_hotspot_temperature(tmp, slope, constant); | ||
107 | |||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | /* Bind callback functions for thermal zone */ | ||
112 | static int ti_thermal_bind(struct thermal_zone_device *thermal, | ||
113 | struct thermal_cooling_device *cdev) | ||
114 | { | ||
115 | struct ti_thermal_data *data = thermal->devdata; | ||
116 | int id; | ||
117 | |||
118 | if (IS_ERR_OR_NULL(data)) | ||
119 | return -ENODEV; | ||
120 | |||
121 | /* check if this is the cooling device we registered */ | ||
122 | if (data->cool_dev != cdev) | ||
123 | return 0; | ||
124 | |||
125 | id = data->sensor_id; | ||
126 | |||
127 | /* Simple thing, two trips, one passive another critical */ | ||
128 | return thermal_zone_bind_cooling_device(thermal, 0, cdev, | ||
129 | /* bind with min and max states defined by cpu_cooling */ | ||
130 | THERMAL_NO_LIMIT, | ||
131 | THERMAL_NO_LIMIT); | ||
132 | } | ||
133 | |||
134 | /* Unbind callback functions for thermal zone */ | ||
135 | static int ti_thermal_unbind(struct thermal_zone_device *thermal, | ||
136 | struct thermal_cooling_device *cdev) | ||
137 | { | ||
138 | struct ti_thermal_data *data = thermal->devdata; | ||
139 | |||
140 | if (IS_ERR_OR_NULL(data)) | ||
141 | return -ENODEV; | ||
142 | |||
143 | /* check if this is the cooling device we registered */ | ||
144 | if (data->cool_dev != cdev) | ||
145 | return 0; | ||
146 | |||
147 | /* Simple thing, two trips, one passive another critical */ | ||
148 | return thermal_zone_unbind_cooling_device(thermal, 0, cdev); | ||
149 | } | ||
150 | |||
151 | /* Get mode callback functions for thermal zone */ | ||
152 | static int ti_thermal_get_mode(struct thermal_zone_device *thermal, | ||
153 | enum thermal_device_mode *mode) | ||
154 | { | ||
155 | struct ti_thermal_data *data = thermal->devdata; | ||
156 | |||
157 | if (data) | ||
158 | *mode = data->mode; | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /* Set mode callback functions for thermal zone */ | ||
164 | static int ti_thermal_set_mode(struct thermal_zone_device *thermal, | ||
165 | enum thermal_device_mode mode) | ||
166 | { | ||
167 | struct ti_thermal_data *data = thermal->devdata; | ||
168 | |||
169 | if (!data->ti_thermal) { | ||
170 | dev_notice(&thermal->device, "thermal zone not registered\n"); | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | mutex_lock(&data->ti_thermal->lock); | ||
175 | |||
176 | if (mode == THERMAL_DEVICE_ENABLED) | ||
177 | data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE; | ||
178 | else | ||
179 | data->ti_thermal->polling_delay = 0; | ||
180 | |||
181 | mutex_unlock(&data->ti_thermal->lock); | ||
182 | |||
183 | data->mode = mode; | ||
184 | thermal_zone_device_update(data->ti_thermal); | ||
185 | dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n", | ||
186 | data->ti_thermal->polling_delay); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | /* Get trip type callback functions for thermal zone */ | ||
192 | static int ti_thermal_get_trip_type(struct thermal_zone_device *thermal, | ||
193 | int trip, enum thermal_trip_type *type) | ||
194 | { | ||
195 | if (!ti_thermal_is_valid_trip(trip)) | ||
196 | return -EINVAL; | ||
197 | |||
198 | if (trip + 1 == OMAP_TRIP_NUMBER) | ||
199 | *type = THERMAL_TRIP_CRITICAL; | ||
200 | else | ||
201 | *type = THERMAL_TRIP_PASSIVE; | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | /* Get trip temperature callback functions for thermal zone */ | ||
207 | static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal, | ||
208 | int trip, unsigned long *temp) | ||
209 | { | ||
210 | if (!ti_thermal_is_valid_trip(trip)) | ||
211 | return -EINVAL; | ||
212 | |||
213 | *temp = ti_thermal_get_trip_value(trip); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | /* Get the temperature trend callback functions for thermal zone */ | ||
219 | static int ti_thermal_get_trend(struct thermal_zone_device *thermal, | ||
220 | int trip, enum thermal_trend *trend) | ||
221 | { | ||
222 | struct ti_thermal_data *data = thermal->devdata; | ||
223 | struct ti_bandgap *bgp; | ||
224 | int id, tr, ret = 0; | ||
225 | |||
226 | bgp = data->bgp; | ||
227 | id = data->sensor_id; | ||
228 | |||
229 | ret = ti_bandgap_get_trend(bgp, id, &tr); | ||
230 | if (ret) | ||
231 | return ret; | ||
232 | |||
233 | if (tr > 0) | ||
234 | *trend = THERMAL_TREND_RAISING; | ||
235 | else if (tr < 0) | ||
236 | *trend = THERMAL_TREND_DROPPING; | ||
237 | else | ||
238 | *trend = THERMAL_TREND_STABLE; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | /* Get critical temperature callback functions for thermal zone */ | ||
244 | static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal, | ||
245 | unsigned long *temp) | ||
246 | { | ||
247 | /* shutdown zone */ | ||
248 | return ti_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp); | ||
249 | } | ||
250 | |||
251 | static struct thermal_zone_device_ops ti_thermal_ops = { | ||
252 | .get_temp = ti_thermal_get_temp, | ||
253 | .get_trend = ti_thermal_get_trend, | ||
254 | .bind = ti_thermal_bind, | ||
255 | .unbind = ti_thermal_unbind, | ||
256 | .get_mode = ti_thermal_get_mode, | ||
257 | .set_mode = ti_thermal_set_mode, | ||
258 | .get_trip_type = ti_thermal_get_trip_type, | ||
259 | .get_trip_temp = ti_thermal_get_trip_temp, | ||
260 | .get_crit_temp = ti_thermal_get_crit_temp, | ||
261 | }; | ||
262 | |||
263 | static struct ti_thermal_data | ||
264 | *ti_thermal_build_data(struct ti_bandgap *bgp, int id) | ||
265 | { | ||
266 | struct ti_thermal_data *data; | ||
267 | |||
268 | data = devm_kzalloc(bgp->dev, sizeof(*data), GFP_KERNEL); | ||
269 | if (!data) { | ||
270 | dev_err(bgp->dev, "kzalloc fail\n"); | ||
271 | return NULL; | ||
272 | } | ||
273 | data->sensor_id = id; | ||
274 | data->bgp = bgp; | ||
275 | data->mode = THERMAL_DEVICE_ENABLED; | ||
276 | INIT_WORK(&data->thermal_wq, ti_thermal_work); | ||
277 | |||
278 | return data; | ||
279 | } | ||
280 | |||
281 | int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, | ||
282 | char *domain) | ||
283 | { | ||
284 | struct ti_thermal_data *data; | ||
285 | |||
286 | data = ti_bandgap_get_sensor_data(bgp, id); | ||
287 | |||
288 | if (IS_ERR_OR_NULL(data)) | ||
289 | data = ti_thermal_build_data(bgp, id); | ||
290 | |||
291 | if (!data) | ||
292 | return -EINVAL; | ||
293 | |||
294 | /* Create thermal zone */ | ||
295 | data->ti_thermal = thermal_zone_device_register(domain, | ||
296 | OMAP_TRIP_NUMBER, 0, data, &ti_thermal_ops, | ||
297 | NULL, FAST_TEMP_MONITORING_RATE, | ||
298 | FAST_TEMP_MONITORING_RATE); | ||
299 | if (IS_ERR_OR_NULL(data->ti_thermal)) { | ||
300 | dev_err(bgp->dev, "thermal zone device is NULL\n"); | ||
301 | return PTR_ERR(data->ti_thermal); | ||
302 | } | ||
303 | data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE; | ||
304 | ti_bandgap_set_sensor_data(bgp, id, data); | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id) | ||
310 | { | ||
311 | struct ti_thermal_data *data; | ||
312 | |||
313 | data = ti_bandgap_get_sensor_data(bgp, id); | ||
314 | |||
315 | thermal_zone_device_unregister(data->ti_thermal); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id) | ||
321 | { | ||
322 | struct ti_thermal_data *data; | ||
323 | |||
324 | data = ti_bandgap_get_sensor_data(bgp, id); | ||
325 | |||
326 | schedule_work(&data->thermal_wq); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id) | ||
332 | { | ||
333 | struct ti_thermal_data *data; | ||
334 | |||
335 | data = ti_bandgap_get_sensor_data(bgp, id); | ||
336 | if (IS_ERR_OR_NULL(data)) | ||
337 | data = ti_thermal_build_data(bgp, id); | ||
338 | |||
339 | if (!data) | ||
340 | return -EINVAL; | ||
341 | |||
342 | if (!cpufreq_get_current_driver()) { | ||
343 | dev_dbg(bgp->dev, "no cpufreq driver yet\n"); | ||
344 | return -EPROBE_DEFER; | ||
345 | } | ||
346 | |||
347 | /* Register cooling device */ | ||
348 | data->cool_dev = cpufreq_cooling_register(cpu_present_mask); | ||
349 | if (IS_ERR_OR_NULL(data->cool_dev)) { | ||
350 | dev_err(bgp->dev, | ||
351 | "Failed to register cpufreq cooling device\n"); | ||
352 | return PTR_ERR(data->cool_dev); | ||
353 | } | ||
354 | ti_bandgap_set_sensor_data(bgp, id, data); | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id) | ||
360 | { | ||
361 | struct ti_thermal_data *data; | ||
362 | |||
363 | data = ti_bandgap_get_sensor_data(bgp, id); | ||
364 | cpufreq_cooling_unregister(data->cool_dev); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal.h b/drivers/thermal/ti-soc-thermal/ti-thermal.h new file mode 100644 index 000000000000..5055777727cc --- /dev/null +++ b/drivers/thermal/ti-soc-thermal/ti-thermal.h | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * OMAP thermal definitions | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * Contact: | ||
6 | * Eduardo Valentin <eduardo.valentin@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | #ifndef __TI_THERMAL_H | ||
24 | #define __TI_THERMAL_H | ||
25 | |||
26 | #include "ti-bandgap.h" | ||
27 | |||
28 | /* sensors gradient and offsets */ | ||
29 | #define OMAP_GRADIENT_SLOPE_4430 0 | ||
30 | #define OMAP_GRADIENT_CONST_4430 20000 | ||
31 | #define OMAP_GRADIENT_SLOPE_4460 348 | ||
32 | #define OMAP_GRADIENT_CONST_4460 -9301 | ||
33 | #define OMAP_GRADIENT_SLOPE_4470 308 | ||
34 | #define OMAP_GRADIENT_CONST_4470 -7896 | ||
35 | |||
36 | #define OMAP_GRADIENT_SLOPE_5430_CPU 65 | ||
37 | #define OMAP_GRADIENT_CONST_5430_CPU -1791 | ||
38 | #define OMAP_GRADIENT_SLOPE_5430_GPU 117 | ||
39 | #define OMAP_GRADIENT_CONST_5430_GPU -2992 | ||
40 | |||
41 | /* PCB sensor calculation constants */ | ||
42 | #define OMAP_GRADIENT_SLOPE_W_PCB_4430 0 | ||
43 | #define OMAP_GRADIENT_CONST_W_PCB_4430 20000 | ||
44 | #define OMAP_GRADIENT_SLOPE_W_PCB_4460 1142 | ||
45 | #define OMAP_GRADIENT_CONST_W_PCB_4460 -393 | ||
46 | #define OMAP_GRADIENT_SLOPE_W_PCB_4470 1063 | ||
47 | #define OMAP_GRADIENT_CONST_W_PCB_4470 -477 | ||
48 | |||
49 | #define OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU 100 | ||
50 | #define OMAP_GRADIENT_CONST_W_PCB_5430_CPU 484 | ||
51 | #define OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU 464 | ||
52 | #define OMAP_GRADIENT_CONST_W_PCB_5430_GPU -5102 | ||
53 | |||
54 | /* trip points of interest in milicelsius (at hotspot level) */ | ||
55 | #define OMAP_TRIP_COLD 100000 | ||
56 | #define OMAP_TRIP_HOT 110000 | ||
57 | #define OMAP_TRIP_SHUTDOWN 125000 | ||
58 | #define OMAP_TRIP_NUMBER 2 | ||
59 | #define OMAP_TRIP_STEP \ | ||
60 | ((OMAP_TRIP_SHUTDOWN - OMAP_TRIP_HOT) / (OMAP_TRIP_NUMBER - 1)) | ||
61 | |||
62 | /* Update rates */ | ||
63 | #define FAST_TEMP_MONITORING_RATE 250 | ||
64 | |||
65 | /* helper macros */ | ||
66 | /** | ||
67 | * ti_thermal_get_trip_value - returns trip temperature based on index | ||
68 | * @i: trip index | ||
69 | */ | ||
70 | #define ti_thermal_get_trip_value(i) \ | ||
71 | (OMAP_TRIP_HOT + ((i) * OMAP_TRIP_STEP)) | ||
72 | |||
73 | /** | ||
74 | * ti_thermal_is_valid_trip - check for trip index | ||
75 | * @i: trip index | ||
76 | */ | ||
77 | #define ti_thermal_is_valid_trip(trip) \ | ||
78 | ((trip) >= 0 && (trip) < OMAP_TRIP_NUMBER) | ||
79 | |||
80 | #ifdef CONFIG_TI_THERMAL | ||
81 | int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, char *domain); | ||
82 | int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id); | ||
83 | int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id); | ||
84 | int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id); | ||
85 | int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id); | ||
86 | #else | ||
87 | static inline | ||
88 | int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, char *domain) | ||
89 | { | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static inline | ||
94 | int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id) | ||
95 | { | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static inline | ||
100 | int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id) | ||
101 | { | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static inline | ||
106 | int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id) | ||
107 | { | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static inline | ||
112 | int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id) | ||
113 | { | ||
114 | return 0; | ||
115 | } | ||
116 | #endif | ||
117 | #endif | ||