1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // Copyright 2013 Freescale Semiconductor, Inc.
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun #include <linux/clk.h>
6*4882a593Smuzhiyun #include <linux/cpufreq.h>
7*4882a593Smuzhiyun #include <linux/cpu_cooling.h>
8*4882a593Smuzhiyun #include <linux/delay.h>
9*4882a593Smuzhiyun #include <linux/interrupt.h>
10*4882a593Smuzhiyun #include <linux/io.h>
11*4882a593Smuzhiyun #include <linux/mfd/syscon.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/of.h>
14*4882a593Smuzhiyun #include <linux/of_device.h>
15*4882a593Smuzhiyun #include <linux/regmap.h>
16*4882a593Smuzhiyun #include <linux/thermal.h>
17*4882a593Smuzhiyun #include <linux/nvmem-consumer.h>
18*4882a593Smuzhiyun #include <linux/pm_runtime.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define REG_SET 0x4
21*4882a593Smuzhiyun #define REG_CLR 0x8
22*4882a593Smuzhiyun #define REG_TOG 0xc
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun /* i.MX6 specific */
25*4882a593Smuzhiyun #define IMX6_MISC0 0x0150
26*4882a593Smuzhiyun #define IMX6_MISC0_REFTOP_SELBIASOFF (1 << 3)
27*4882a593Smuzhiyun #define IMX6_MISC1 0x0160
28*4882a593Smuzhiyun #define IMX6_MISC1_IRQ_TEMPHIGH (1 << 29)
29*4882a593Smuzhiyun /* Below LOW and PANIC bits are only for TEMPMON_IMX6SX */
30*4882a593Smuzhiyun #define IMX6_MISC1_IRQ_TEMPLOW (1 << 28)
31*4882a593Smuzhiyun #define IMX6_MISC1_IRQ_TEMPPANIC (1 << 27)
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define IMX6_TEMPSENSE0 0x0180
34*4882a593Smuzhiyun #define IMX6_TEMPSENSE0_ALARM_VALUE_SHIFT 20
35*4882a593Smuzhiyun #define IMX6_TEMPSENSE0_ALARM_VALUE_MASK (0xfff << 20)
36*4882a593Smuzhiyun #define IMX6_TEMPSENSE0_TEMP_CNT_SHIFT 8
37*4882a593Smuzhiyun #define IMX6_TEMPSENSE0_TEMP_CNT_MASK (0xfff << 8)
38*4882a593Smuzhiyun #define IMX6_TEMPSENSE0_FINISHED (1 << 2)
39*4882a593Smuzhiyun #define IMX6_TEMPSENSE0_MEASURE_TEMP (1 << 1)
40*4882a593Smuzhiyun #define IMX6_TEMPSENSE0_POWER_DOWN (1 << 0)
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #define IMX6_TEMPSENSE1 0x0190
43*4882a593Smuzhiyun #define IMX6_TEMPSENSE1_MEASURE_FREQ 0xffff
44*4882a593Smuzhiyun #define IMX6_TEMPSENSE1_MEASURE_FREQ_SHIFT 0
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun #define OCOTP_MEM0 0x0480
47*4882a593Smuzhiyun #define OCOTP_ANA1 0x04e0
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun /* Below TEMPSENSE2 is only for TEMPMON_IMX6SX */
50*4882a593Smuzhiyun #define IMX6_TEMPSENSE2 0x0290
51*4882a593Smuzhiyun #define IMX6_TEMPSENSE2_LOW_VALUE_SHIFT 0
52*4882a593Smuzhiyun #define IMX6_TEMPSENSE2_LOW_VALUE_MASK 0xfff
53*4882a593Smuzhiyun #define IMX6_TEMPSENSE2_PANIC_VALUE_SHIFT 16
54*4882a593Smuzhiyun #define IMX6_TEMPSENSE2_PANIC_VALUE_MASK 0xfff0000
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /* i.MX7 specific */
57*4882a593Smuzhiyun #define IMX7_ANADIG_DIGPROG 0x800
58*4882a593Smuzhiyun #define IMX7_TEMPSENSE0 0x300
59*4882a593Smuzhiyun #define IMX7_TEMPSENSE0_PANIC_ALARM_SHIFT 18
60*4882a593Smuzhiyun #define IMX7_TEMPSENSE0_PANIC_ALARM_MASK (0x1ff << 18)
61*4882a593Smuzhiyun #define IMX7_TEMPSENSE0_HIGH_ALARM_SHIFT 9
62*4882a593Smuzhiyun #define IMX7_TEMPSENSE0_HIGH_ALARM_MASK (0x1ff << 9)
63*4882a593Smuzhiyun #define IMX7_TEMPSENSE0_LOW_ALARM_SHIFT 0
64*4882a593Smuzhiyun #define IMX7_TEMPSENSE0_LOW_ALARM_MASK 0x1ff
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun #define IMX7_TEMPSENSE1 0x310
67*4882a593Smuzhiyun #define IMX7_TEMPSENSE1_MEASURE_FREQ_SHIFT 16
68*4882a593Smuzhiyun #define IMX7_TEMPSENSE1_MEASURE_FREQ_MASK (0xffff << 16)
69*4882a593Smuzhiyun #define IMX7_TEMPSENSE1_FINISHED (1 << 11)
70*4882a593Smuzhiyun #define IMX7_TEMPSENSE1_MEASURE_TEMP (1 << 10)
71*4882a593Smuzhiyun #define IMX7_TEMPSENSE1_POWER_DOWN (1 << 9)
72*4882a593Smuzhiyun #define IMX7_TEMPSENSE1_TEMP_VALUE_SHIFT 0
73*4882a593Smuzhiyun #define IMX7_TEMPSENSE1_TEMP_VALUE_MASK 0x1ff
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* The driver supports 1 passive trip point and 1 critical trip point */
76*4882a593Smuzhiyun enum imx_thermal_trip {
77*4882a593Smuzhiyun IMX_TRIP_PASSIVE,
78*4882a593Smuzhiyun IMX_TRIP_CRITICAL,
79*4882a593Smuzhiyun IMX_TRIP_NUM,
80*4882a593Smuzhiyun };
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun #define IMX_POLLING_DELAY 2000 /* millisecond */
83*4882a593Smuzhiyun #define IMX_PASSIVE_DELAY 1000
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun #define TEMPMON_IMX6Q 1
86*4882a593Smuzhiyun #define TEMPMON_IMX6SX 2
87*4882a593Smuzhiyun #define TEMPMON_IMX7D 3
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun struct thermal_soc_data {
90*4882a593Smuzhiyun u32 version;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun u32 sensor_ctrl;
93*4882a593Smuzhiyun u32 power_down_mask;
94*4882a593Smuzhiyun u32 measure_temp_mask;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun u32 measure_freq_ctrl;
97*4882a593Smuzhiyun u32 measure_freq_mask;
98*4882a593Smuzhiyun u32 measure_freq_shift;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun u32 temp_data;
101*4882a593Smuzhiyun u32 temp_value_mask;
102*4882a593Smuzhiyun u32 temp_value_shift;
103*4882a593Smuzhiyun u32 temp_valid_mask;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun u32 panic_alarm_ctrl;
106*4882a593Smuzhiyun u32 panic_alarm_mask;
107*4882a593Smuzhiyun u32 panic_alarm_shift;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun u32 high_alarm_ctrl;
110*4882a593Smuzhiyun u32 high_alarm_mask;
111*4882a593Smuzhiyun u32 high_alarm_shift;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun u32 low_alarm_ctrl;
114*4882a593Smuzhiyun u32 low_alarm_mask;
115*4882a593Smuzhiyun u32 low_alarm_shift;
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun static struct thermal_soc_data thermal_imx6q_data = {
119*4882a593Smuzhiyun .version = TEMPMON_IMX6Q,
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun .sensor_ctrl = IMX6_TEMPSENSE0,
122*4882a593Smuzhiyun .power_down_mask = IMX6_TEMPSENSE0_POWER_DOWN,
123*4882a593Smuzhiyun .measure_temp_mask = IMX6_TEMPSENSE0_MEASURE_TEMP,
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun .measure_freq_ctrl = IMX6_TEMPSENSE1,
126*4882a593Smuzhiyun .measure_freq_shift = IMX6_TEMPSENSE1_MEASURE_FREQ_SHIFT,
127*4882a593Smuzhiyun .measure_freq_mask = IMX6_TEMPSENSE1_MEASURE_FREQ,
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun .temp_data = IMX6_TEMPSENSE0,
130*4882a593Smuzhiyun .temp_value_mask = IMX6_TEMPSENSE0_TEMP_CNT_MASK,
131*4882a593Smuzhiyun .temp_value_shift = IMX6_TEMPSENSE0_TEMP_CNT_SHIFT,
132*4882a593Smuzhiyun .temp_valid_mask = IMX6_TEMPSENSE0_FINISHED,
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun .high_alarm_ctrl = IMX6_TEMPSENSE0,
135*4882a593Smuzhiyun .high_alarm_mask = IMX6_TEMPSENSE0_ALARM_VALUE_MASK,
136*4882a593Smuzhiyun .high_alarm_shift = IMX6_TEMPSENSE0_ALARM_VALUE_SHIFT,
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun static struct thermal_soc_data thermal_imx6sx_data = {
140*4882a593Smuzhiyun .version = TEMPMON_IMX6SX,
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun .sensor_ctrl = IMX6_TEMPSENSE0,
143*4882a593Smuzhiyun .power_down_mask = IMX6_TEMPSENSE0_POWER_DOWN,
144*4882a593Smuzhiyun .measure_temp_mask = IMX6_TEMPSENSE0_MEASURE_TEMP,
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun .measure_freq_ctrl = IMX6_TEMPSENSE1,
147*4882a593Smuzhiyun .measure_freq_shift = IMX6_TEMPSENSE1_MEASURE_FREQ_SHIFT,
148*4882a593Smuzhiyun .measure_freq_mask = IMX6_TEMPSENSE1_MEASURE_FREQ,
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun .temp_data = IMX6_TEMPSENSE0,
151*4882a593Smuzhiyun .temp_value_mask = IMX6_TEMPSENSE0_TEMP_CNT_MASK,
152*4882a593Smuzhiyun .temp_value_shift = IMX6_TEMPSENSE0_TEMP_CNT_SHIFT,
153*4882a593Smuzhiyun .temp_valid_mask = IMX6_TEMPSENSE0_FINISHED,
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun .high_alarm_ctrl = IMX6_TEMPSENSE0,
156*4882a593Smuzhiyun .high_alarm_mask = IMX6_TEMPSENSE0_ALARM_VALUE_MASK,
157*4882a593Smuzhiyun .high_alarm_shift = IMX6_TEMPSENSE0_ALARM_VALUE_SHIFT,
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun .panic_alarm_ctrl = IMX6_TEMPSENSE2,
160*4882a593Smuzhiyun .panic_alarm_mask = IMX6_TEMPSENSE2_PANIC_VALUE_MASK,
161*4882a593Smuzhiyun .panic_alarm_shift = IMX6_TEMPSENSE2_PANIC_VALUE_SHIFT,
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun .low_alarm_ctrl = IMX6_TEMPSENSE2,
164*4882a593Smuzhiyun .low_alarm_mask = IMX6_TEMPSENSE2_LOW_VALUE_MASK,
165*4882a593Smuzhiyun .low_alarm_shift = IMX6_TEMPSENSE2_LOW_VALUE_SHIFT,
166*4882a593Smuzhiyun };
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun static struct thermal_soc_data thermal_imx7d_data = {
169*4882a593Smuzhiyun .version = TEMPMON_IMX7D,
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun .sensor_ctrl = IMX7_TEMPSENSE1,
172*4882a593Smuzhiyun .power_down_mask = IMX7_TEMPSENSE1_POWER_DOWN,
173*4882a593Smuzhiyun .measure_temp_mask = IMX7_TEMPSENSE1_MEASURE_TEMP,
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun .measure_freq_ctrl = IMX7_TEMPSENSE1,
176*4882a593Smuzhiyun .measure_freq_shift = IMX7_TEMPSENSE1_MEASURE_FREQ_SHIFT,
177*4882a593Smuzhiyun .measure_freq_mask = IMX7_TEMPSENSE1_MEASURE_FREQ_MASK,
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun .temp_data = IMX7_TEMPSENSE1,
180*4882a593Smuzhiyun .temp_value_mask = IMX7_TEMPSENSE1_TEMP_VALUE_MASK,
181*4882a593Smuzhiyun .temp_value_shift = IMX7_TEMPSENSE1_TEMP_VALUE_SHIFT,
182*4882a593Smuzhiyun .temp_valid_mask = IMX7_TEMPSENSE1_FINISHED,
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun .panic_alarm_ctrl = IMX7_TEMPSENSE1,
185*4882a593Smuzhiyun .panic_alarm_mask = IMX7_TEMPSENSE0_PANIC_ALARM_MASK,
186*4882a593Smuzhiyun .panic_alarm_shift = IMX7_TEMPSENSE0_PANIC_ALARM_SHIFT,
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun .high_alarm_ctrl = IMX7_TEMPSENSE0,
189*4882a593Smuzhiyun .high_alarm_mask = IMX7_TEMPSENSE0_HIGH_ALARM_MASK,
190*4882a593Smuzhiyun .high_alarm_shift = IMX7_TEMPSENSE0_HIGH_ALARM_SHIFT,
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun .low_alarm_ctrl = IMX7_TEMPSENSE0,
193*4882a593Smuzhiyun .low_alarm_mask = IMX7_TEMPSENSE0_LOW_ALARM_MASK,
194*4882a593Smuzhiyun .low_alarm_shift = IMX7_TEMPSENSE0_LOW_ALARM_SHIFT,
195*4882a593Smuzhiyun };
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun struct imx_thermal_data {
198*4882a593Smuzhiyun struct device *dev;
199*4882a593Smuzhiyun struct cpufreq_policy *policy;
200*4882a593Smuzhiyun struct thermal_zone_device *tz;
201*4882a593Smuzhiyun struct thermal_cooling_device *cdev;
202*4882a593Smuzhiyun struct regmap *tempmon;
203*4882a593Smuzhiyun u32 c1, c2; /* See formula in imx_init_calib() */
204*4882a593Smuzhiyun int temp_passive;
205*4882a593Smuzhiyun int temp_critical;
206*4882a593Smuzhiyun int temp_max;
207*4882a593Smuzhiyun int alarm_temp;
208*4882a593Smuzhiyun int last_temp;
209*4882a593Smuzhiyun bool irq_enabled;
210*4882a593Smuzhiyun int irq;
211*4882a593Smuzhiyun struct clk *thermal_clk;
212*4882a593Smuzhiyun const struct thermal_soc_data *socdata;
213*4882a593Smuzhiyun const char *temp_grade;
214*4882a593Smuzhiyun };
215*4882a593Smuzhiyun
imx_set_panic_temp(struct imx_thermal_data * data,int panic_temp)216*4882a593Smuzhiyun static void imx_set_panic_temp(struct imx_thermal_data *data,
217*4882a593Smuzhiyun int panic_temp)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun const struct thermal_soc_data *soc_data = data->socdata;
220*4882a593Smuzhiyun struct regmap *map = data->tempmon;
221*4882a593Smuzhiyun int critical_value;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun critical_value = (data->c2 - panic_temp) / data->c1;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun regmap_write(map, soc_data->panic_alarm_ctrl + REG_CLR,
226*4882a593Smuzhiyun soc_data->panic_alarm_mask);
227*4882a593Smuzhiyun regmap_write(map, soc_data->panic_alarm_ctrl + REG_SET,
228*4882a593Smuzhiyun critical_value << soc_data->panic_alarm_shift);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
imx_set_alarm_temp(struct imx_thermal_data * data,int alarm_temp)231*4882a593Smuzhiyun static void imx_set_alarm_temp(struct imx_thermal_data *data,
232*4882a593Smuzhiyun int alarm_temp)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun struct regmap *map = data->tempmon;
235*4882a593Smuzhiyun const struct thermal_soc_data *soc_data = data->socdata;
236*4882a593Smuzhiyun int alarm_value;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun data->alarm_temp = alarm_temp;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun if (data->socdata->version == TEMPMON_IMX7D)
241*4882a593Smuzhiyun alarm_value = alarm_temp / 1000 + data->c1 - 25;
242*4882a593Smuzhiyun else
243*4882a593Smuzhiyun alarm_value = (data->c2 - alarm_temp) / data->c1;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun regmap_write(map, soc_data->high_alarm_ctrl + REG_CLR,
246*4882a593Smuzhiyun soc_data->high_alarm_mask);
247*4882a593Smuzhiyun regmap_write(map, soc_data->high_alarm_ctrl + REG_SET,
248*4882a593Smuzhiyun alarm_value << soc_data->high_alarm_shift);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
imx_get_temp(struct thermal_zone_device * tz,int * temp)251*4882a593Smuzhiyun static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun struct imx_thermal_data *data = tz->devdata;
254*4882a593Smuzhiyun const struct thermal_soc_data *soc_data = data->socdata;
255*4882a593Smuzhiyun struct regmap *map = data->tempmon;
256*4882a593Smuzhiyun unsigned int n_meas;
257*4882a593Smuzhiyun u32 val;
258*4882a593Smuzhiyun int ret;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun ret = pm_runtime_resume_and_get(data->dev);
261*4882a593Smuzhiyun if (ret < 0)
262*4882a593Smuzhiyun return ret;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun regmap_read(map, soc_data->temp_data, &val);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun if ((val & soc_data->temp_valid_mask) == 0) {
267*4882a593Smuzhiyun dev_dbg(&tz->device, "temp measurement never finished\n");
268*4882a593Smuzhiyun return -EAGAIN;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun n_meas = (val & soc_data->temp_value_mask)
272*4882a593Smuzhiyun >> soc_data->temp_value_shift;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun /* See imx_init_calib() for formula derivation */
275*4882a593Smuzhiyun if (data->socdata->version == TEMPMON_IMX7D)
276*4882a593Smuzhiyun *temp = (n_meas - data->c1 + 25) * 1000;
277*4882a593Smuzhiyun else
278*4882a593Smuzhiyun *temp = data->c2 - n_meas * data->c1;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun /* Update alarm value to next higher trip point for TEMPMON_IMX6Q */
281*4882a593Smuzhiyun if (data->socdata->version == TEMPMON_IMX6Q) {
282*4882a593Smuzhiyun if (data->alarm_temp == data->temp_passive &&
283*4882a593Smuzhiyun *temp >= data->temp_passive)
284*4882a593Smuzhiyun imx_set_alarm_temp(data, data->temp_critical);
285*4882a593Smuzhiyun if (data->alarm_temp == data->temp_critical &&
286*4882a593Smuzhiyun *temp < data->temp_passive) {
287*4882a593Smuzhiyun imx_set_alarm_temp(data, data->temp_passive);
288*4882a593Smuzhiyun dev_dbg(&tz->device, "thermal alarm off: T < %d\n",
289*4882a593Smuzhiyun data->alarm_temp / 1000);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun if (*temp != data->last_temp) {
294*4882a593Smuzhiyun dev_dbg(&tz->device, "millicelsius: %d\n", *temp);
295*4882a593Smuzhiyun data->last_temp = *temp;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun /* Reenable alarm IRQ if temperature below alarm temperature */
299*4882a593Smuzhiyun if (!data->irq_enabled && *temp < data->alarm_temp) {
300*4882a593Smuzhiyun data->irq_enabled = true;
301*4882a593Smuzhiyun enable_irq(data->irq);
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun pm_runtime_put(data->dev);
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun return 0;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
imx_change_mode(struct thermal_zone_device * tz,enum thermal_device_mode mode)309*4882a593Smuzhiyun static int imx_change_mode(struct thermal_zone_device *tz,
310*4882a593Smuzhiyun enum thermal_device_mode mode)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun struct imx_thermal_data *data = tz->devdata;
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun if (mode == THERMAL_DEVICE_ENABLED) {
315*4882a593Smuzhiyun pm_runtime_get(data->dev);
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun if (!data->irq_enabled) {
318*4882a593Smuzhiyun data->irq_enabled = true;
319*4882a593Smuzhiyun enable_irq(data->irq);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun } else {
322*4882a593Smuzhiyun pm_runtime_put(data->dev);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun if (data->irq_enabled) {
325*4882a593Smuzhiyun disable_irq(data->irq);
326*4882a593Smuzhiyun data->irq_enabled = false;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun return 0;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
imx_get_trip_type(struct thermal_zone_device * tz,int trip,enum thermal_trip_type * type)333*4882a593Smuzhiyun static int imx_get_trip_type(struct thermal_zone_device *tz, int trip,
334*4882a593Smuzhiyun enum thermal_trip_type *type)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun *type = (trip == IMX_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
337*4882a593Smuzhiyun THERMAL_TRIP_CRITICAL;
338*4882a593Smuzhiyun return 0;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
imx_get_crit_temp(struct thermal_zone_device * tz,int * temp)341*4882a593Smuzhiyun static int imx_get_crit_temp(struct thermal_zone_device *tz, int *temp)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun struct imx_thermal_data *data = tz->devdata;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun *temp = data->temp_critical;
346*4882a593Smuzhiyun return 0;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
imx_get_trip_temp(struct thermal_zone_device * tz,int trip,int * temp)349*4882a593Smuzhiyun static int imx_get_trip_temp(struct thermal_zone_device *tz, int trip,
350*4882a593Smuzhiyun int *temp)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun struct imx_thermal_data *data = tz->devdata;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun *temp = (trip == IMX_TRIP_PASSIVE) ? data->temp_passive :
355*4882a593Smuzhiyun data->temp_critical;
356*4882a593Smuzhiyun return 0;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
imx_set_trip_temp(struct thermal_zone_device * tz,int trip,int temp)359*4882a593Smuzhiyun static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
360*4882a593Smuzhiyun int temp)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun struct imx_thermal_data *data = tz->devdata;
363*4882a593Smuzhiyun int ret;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun ret = pm_runtime_resume_and_get(data->dev);
366*4882a593Smuzhiyun if (ret < 0)
367*4882a593Smuzhiyun return ret;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun /* do not allow changing critical threshold */
370*4882a593Smuzhiyun if (trip == IMX_TRIP_CRITICAL)
371*4882a593Smuzhiyun return -EPERM;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun /* do not allow passive to be set higher than critical */
374*4882a593Smuzhiyun if (temp < 0 || temp > data->temp_critical)
375*4882a593Smuzhiyun return -EINVAL;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun data->temp_passive = temp;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun imx_set_alarm_temp(data, temp);
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun pm_runtime_put(data->dev);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun return 0;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
imx_bind(struct thermal_zone_device * tz,struct thermal_cooling_device * cdev)386*4882a593Smuzhiyun static int imx_bind(struct thermal_zone_device *tz,
387*4882a593Smuzhiyun struct thermal_cooling_device *cdev)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun int ret;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun ret = thermal_zone_bind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev,
392*4882a593Smuzhiyun THERMAL_NO_LIMIT,
393*4882a593Smuzhiyun THERMAL_NO_LIMIT,
394*4882a593Smuzhiyun THERMAL_WEIGHT_DEFAULT);
395*4882a593Smuzhiyun if (ret) {
396*4882a593Smuzhiyun dev_err(&tz->device,
397*4882a593Smuzhiyun "binding zone %s with cdev %s failed:%d\n",
398*4882a593Smuzhiyun tz->type, cdev->type, ret);
399*4882a593Smuzhiyun return ret;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun return 0;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
imx_unbind(struct thermal_zone_device * tz,struct thermal_cooling_device * cdev)405*4882a593Smuzhiyun static int imx_unbind(struct thermal_zone_device *tz,
406*4882a593Smuzhiyun struct thermal_cooling_device *cdev)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun int ret;
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun ret = thermal_zone_unbind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev);
411*4882a593Smuzhiyun if (ret) {
412*4882a593Smuzhiyun dev_err(&tz->device,
413*4882a593Smuzhiyun "unbinding zone %s with cdev %s failed:%d\n",
414*4882a593Smuzhiyun tz->type, cdev->type, ret);
415*4882a593Smuzhiyun return ret;
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun return 0;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun static struct thermal_zone_device_ops imx_tz_ops = {
422*4882a593Smuzhiyun .bind = imx_bind,
423*4882a593Smuzhiyun .unbind = imx_unbind,
424*4882a593Smuzhiyun .get_temp = imx_get_temp,
425*4882a593Smuzhiyun .change_mode = imx_change_mode,
426*4882a593Smuzhiyun .get_trip_type = imx_get_trip_type,
427*4882a593Smuzhiyun .get_trip_temp = imx_get_trip_temp,
428*4882a593Smuzhiyun .get_crit_temp = imx_get_crit_temp,
429*4882a593Smuzhiyun .set_trip_temp = imx_set_trip_temp,
430*4882a593Smuzhiyun };
431*4882a593Smuzhiyun
imx_init_calib(struct platform_device * pdev,u32 ocotp_ana1)432*4882a593Smuzhiyun static int imx_init_calib(struct platform_device *pdev, u32 ocotp_ana1)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun struct imx_thermal_data *data = platform_get_drvdata(pdev);
435*4882a593Smuzhiyun int n1;
436*4882a593Smuzhiyun u64 temp64;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun if (ocotp_ana1 == 0 || ocotp_ana1 == ~0) {
439*4882a593Smuzhiyun dev_err(&pdev->dev, "invalid sensor calibration data\n");
440*4882a593Smuzhiyun return -EINVAL;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun /*
444*4882a593Smuzhiyun * On i.MX7D, we only use the calibration data at 25C to get the temp,
445*4882a593Smuzhiyun * Tmeas = ( Nmeas - n1) + 25; n1 is the fuse value for 25C.
446*4882a593Smuzhiyun */
447*4882a593Smuzhiyun if (data->socdata->version == TEMPMON_IMX7D) {
448*4882a593Smuzhiyun data->c1 = (ocotp_ana1 >> 9) & 0x1ff;
449*4882a593Smuzhiyun return 0;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /*
453*4882a593Smuzhiyun * The sensor is calibrated at 25 °C (aka T1) and the value measured
454*4882a593Smuzhiyun * (aka N1) at this temperature is provided in bits [31:20] in the
455*4882a593Smuzhiyun * i.MX's OCOTP value ANA1.
456*4882a593Smuzhiyun * To find the actual temperature T, the following formula has to be used
457*4882a593Smuzhiyun * when reading value n from the sensor:
458*4882a593Smuzhiyun *
459*4882a593Smuzhiyun * T = T1 + (N - N1) / (0.4148468 - 0.0015423 * N1) °C + 3.580661 °C
460*4882a593Smuzhiyun * = [T1' - N1 / (0.4148468 - 0.0015423 * N1) °C] + N / (0.4148468 - 0.0015423 * N1) °C
461*4882a593Smuzhiyun * = [T1' + N1 / (0.0015423 * N1 - 0.4148468) °C] - N / (0.0015423 * N1 - 0.4148468) °C
462*4882a593Smuzhiyun * = c2 - c1 * N
463*4882a593Smuzhiyun *
464*4882a593Smuzhiyun * with
465*4882a593Smuzhiyun *
466*4882a593Smuzhiyun * T1' = 28.580661 °C
467*4882a593Smuzhiyun * c1 = 1 / (0.0015423 * N1 - 0.4297157) °C
468*4882a593Smuzhiyun * c2 = T1' + N1 / (0.0015423 * N1 - 0.4148468) °C
469*4882a593Smuzhiyun * = T1' + N1 * c1
470*4882a593Smuzhiyun */
471*4882a593Smuzhiyun n1 = ocotp_ana1 >> 20;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun temp64 = 10000000; /* use 10^7 as fixed point constant for values in formula */
474*4882a593Smuzhiyun temp64 *= 1000; /* to get result in °mC */
475*4882a593Smuzhiyun do_div(temp64, 15423 * n1 - 4148468);
476*4882a593Smuzhiyun data->c1 = temp64;
477*4882a593Smuzhiyun data->c2 = n1 * data->c1 + 28581;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun return 0;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
imx_init_temp_grade(struct platform_device * pdev,u32 ocotp_mem0)482*4882a593Smuzhiyun static void imx_init_temp_grade(struct platform_device *pdev, u32 ocotp_mem0)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun struct imx_thermal_data *data = platform_get_drvdata(pdev);
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun /* The maximum die temp is specified by the Temperature Grade */
487*4882a593Smuzhiyun switch ((ocotp_mem0 >> 6) & 0x3) {
488*4882a593Smuzhiyun case 0: /* Commercial (0 to 95 °C) */
489*4882a593Smuzhiyun data->temp_grade = "Commercial";
490*4882a593Smuzhiyun data->temp_max = 95000;
491*4882a593Smuzhiyun break;
492*4882a593Smuzhiyun case 1: /* Extended Commercial (-20 °C to 105 °C) */
493*4882a593Smuzhiyun data->temp_grade = "Extended Commercial";
494*4882a593Smuzhiyun data->temp_max = 105000;
495*4882a593Smuzhiyun break;
496*4882a593Smuzhiyun case 2: /* Industrial (-40 °C to 105 °C) */
497*4882a593Smuzhiyun data->temp_grade = "Industrial";
498*4882a593Smuzhiyun data->temp_max = 105000;
499*4882a593Smuzhiyun break;
500*4882a593Smuzhiyun case 3: /* Automotive (-40 °C to 125 °C) */
501*4882a593Smuzhiyun data->temp_grade = "Automotive";
502*4882a593Smuzhiyun data->temp_max = 125000;
503*4882a593Smuzhiyun break;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun /*
507*4882a593Smuzhiyun * Set the critical trip point at 5 °C under max
508*4882a593Smuzhiyun * Set the passive trip point at 10 °C under max (changeable via sysfs)
509*4882a593Smuzhiyun */
510*4882a593Smuzhiyun data->temp_critical = data->temp_max - (1000 * 5);
511*4882a593Smuzhiyun data->temp_passive = data->temp_max - (1000 * 10);
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun
imx_init_from_tempmon_data(struct platform_device * pdev)514*4882a593Smuzhiyun static int imx_init_from_tempmon_data(struct platform_device *pdev)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun struct regmap *map;
517*4882a593Smuzhiyun int ret;
518*4882a593Smuzhiyun u32 val;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
521*4882a593Smuzhiyun "fsl,tempmon-data");
522*4882a593Smuzhiyun if (IS_ERR(map)) {
523*4882a593Smuzhiyun ret = PTR_ERR(map);
524*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to get sensor regmap: %d\n", ret);
525*4882a593Smuzhiyun return ret;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun ret = regmap_read(map, OCOTP_ANA1, &val);
529*4882a593Smuzhiyun if (ret) {
530*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
531*4882a593Smuzhiyun return ret;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun ret = imx_init_calib(pdev, val);
534*4882a593Smuzhiyun if (ret)
535*4882a593Smuzhiyun return ret;
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun ret = regmap_read(map, OCOTP_MEM0, &val);
538*4882a593Smuzhiyun if (ret) {
539*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
540*4882a593Smuzhiyun return ret;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun imx_init_temp_grade(pdev, val);
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun return 0;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
imx_init_from_nvmem_cells(struct platform_device * pdev)547*4882a593Smuzhiyun static int imx_init_from_nvmem_cells(struct platform_device *pdev)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun int ret;
550*4882a593Smuzhiyun u32 val;
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun ret = nvmem_cell_read_u32(&pdev->dev, "calib", &val);
553*4882a593Smuzhiyun if (ret)
554*4882a593Smuzhiyun return ret;
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun ret = imx_init_calib(pdev, val);
557*4882a593Smuzhiyun if (ret)
558*4882a593Smuzhiyun return ret;
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun ret = nvmem_cell_read_u32(&pdev->dev, "temp_grade", &val);
561*4882a593Smuzhiyun if (ret)
562*4882a593Smuzhiyun return ret;
563*4882a593Smuzhiyun imx_init_temp_grade(pdev, val);
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun return 0;
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun
imx_thermal_alarm_irq(int irq,void * dev)568*4882a593Smuzhiyun static irqreturn_t imx_thermal_alarm_irq(int irq, void *dev)
569*4882a593Smuzhiyun {
570*4882a593Smuzhiyun struct imx_thermal_data *data = dev;
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun disable_irq_nosync(irq);
573*4882a593Smuzhiyun data->irq_enabled = false;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun return IRQ_WAKE_THREAD;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
imx_thermal_alarm_irq_thread(int irq,void * dev)578*4882a593Smuzhiyun static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun struct imx_thermal_data *data = dev;
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun dev_dbg(&data->tz->device, "THERMAL ALARM: T > %d\n",
583*4882a593Smuzhiyun data->alarm_temp / 1000);
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun thermal_zone_device_update(data->tz, THERMAL_EVENT_UNSPECIFIED);
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun return IRQ_HANDLED;
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun static const struct of_device_id of_imx_thermal_match[] = {
591*4882a593Smuzhiyun { .compatible = "fsl,imx6q-tempmon", .data = &thermal_imx6q_data, },
592*4882a593Smuzhiyun { .compatible = "fsl,imx6sx-tempmon", .data = &thermal_imx6sx_data, },
593*4882a593Smuzhiyun { .compatible = "fsl,imx7d-tempmon", .data = &thermal_imx7d_data, },
594*4882a593Smuzhiyun { /* end */ }
595*4882a593Smuzhiyun };
596*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, of_imx_thermal_match);
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun #ifdef CONFIG_CPU_FREQ
599*4882a593Smuzhiyun /*
600*4882a593Smuzhiyun * Create cooling device in case no #cooling-cells property is available in
601*4882a593Smuzhiyun * CPU node
602*4882a593Smuzhiyun */
imx_thermal_register_legacy_cooling(struct imx_thermal_data * data)603*4882a593Smuzhiyun static int imx_thermal_register_legacy_cooling(struct imx_thermal_data *data)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun struct device_node *np;
606*4882a593Smuzhiyun int ret = 0;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun data->policy = cpufreq_cpu_get(0);
609*4882a593Smuzhiyun if (!data->policy) {
610*4882a593Smuzhiyun pr_debug("%s: CPUFreq policy not found\n", __func__);
611*4882a593Smuzhiyun return -EPROBE_DEFER;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun np = of_get_cpu_node(data->policy->cpu, NULL);
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun if (!np || !of_find_property(np, "#cooling-cells", NULL)) {
617*4882a593Smuzhiyun data->cdev = cpufreq_cooling_register(data->policy);
618*4882a593Smuzhiyun if (IS_ERR(data->cdev)) {
619*4882a593Smuzhiyun ret = PTR_ERR(data->cdev);
620*4882a593Smuzhiyun cpufreq_cpu_put(data->policy);
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun of_node_put(np);
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun return ret;
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun
imx_thermal_unregister_legacy_cooling(struct imx_thermal_data * data)629*4882a593Smuzhiyun static void imx_thermal_unregister_legacy_cooling(struct imx_thermal_data *data)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun cpufreq_cooling_unregister(data->cdev);
632*4882a593Smuzhiyun cpufreq_cpu_put(data->policy);
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun #else
636*4882a593Smuzhiyun
imx_thermal_register_legacy_cooling(struct imx_thermal_data * data)637*4882a593Smuzhiyun static inline int imx_thermal_register_legacy_cooling(struct imx_thermal_data *data)
638*4882a593Smuzhiyun {
639*4882a593Smuzhiyun return 0;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun
imx_thermal_unregister_legacy_cooling(struct imx_thermal_data * data)642*4882a593Smuzhiyun static inline void imx_thermal_unregister_legacy_cooling(struct imx_thermal_data *data)
643*4882a593Smuzhiyun {
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun #endif
646*4882a593Smuzhiyun
imx_thermal_probe(struct platform_device * pdev)647*4882a593Smuzhiyun static int imx_thermal_probe(struct platform_device *pdev)
648*4882a593Smuzhiyun {
649*4882a593Smuzhiyun struct imx_thermal_data *data;
650*4882a593Smuzhiyun struct regmap *map;
651*4882a593Smuzhiyun int measure_freq;
652*4882a593Smuzhiyun int ret;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
655*4882a593Smuzhiyun if (!data)
656*4882a593Smuzhiyun return -ENOMEM;
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun data->dev = &pdev->dev;
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "fsl,tempmon");
661*4882a593Smuzhiyun if (IS_ERR(map)) {
662*4882a593Smuzhiyun ret = PTR_ERR(map);
663*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to get tempmon regmap: %d\n", ret);
664*4882a593Smuzhiyun return ret;
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun data->tempmon = map;
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun data->socdata = of_device_get_match_data(&pdev->dev);
669*4882a593Smuzhiyun if (!data->socdata) {
670*4882a593Smuzhiyun dev_err(&pdev->dev, "no device match found\n");
671*4882a593Smuzhiyun return -ENODEV;
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun /* make sure the IRQ flag is clear before enabling irq on i.MX6SX */
675*4882a593Smuzhiyun if (data->socdata->version == TEMPMON_IMX6SX) {
676*4882a593Smuzhiyun regmap_write(map, IMX6_MISC1 + REG_CLR,
677*4882a593Smuzhiyun IMX6_MISC1_IRQ_TEMPHIGH | IMX6_MISC1_IRQ_TEMPLOW
678*4882a593Smuzhiyun | IMX6_MISC1_IRQ_TEMPPANIC);
679*4882a593Smuzhiyun /*
680*4882a593Smuzhiyun * reset value of LOW ALARM is incorrect, set it to lowest
681*4882a593Smuzhiyun * value to avoid false trigger of low alarm.
682*4882a593Smuzhiyun */
683*4882a593Smuzhiyun regmap_write(map, data->socdata->low_alarm_ctrl + REG_SET,
684*4882a593Smuzhiyun data->socdata->low_alarm_mask);
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun data->irq = platform_get_irq(pdev, 0);
688*4882a593Smuzhiyun if (data->irq < 0)
689*4882a593Smuzhiyun return data->irq;
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun platform_set_drvdata(pdev, data);
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun if (of_find_property(pdev->dev.of_node, "nvmem-cells", NULL)) {
694*4882a593Smuzhiyun ret = imx_init_from_nvmem_cells(pdev);
695*4882a593Smuzhiyun if (ret)
696*4882a593Smuzhiyun return dev_err_probe(&pdev->dev, ret,
697*4882a593Smuzhiyun "failed to init from nvmem\n");
698*4882a593Smuzhiyun } else {
699*4882a593Smuzhiyun ret = imx_init_from_tempmon_data(pdev);
700*4882a593Smuzhiyun if (ret) {
701*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to init from fsl,tempmon-data\n");
702*4882a593Smuzhiyun return ret;
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun /* Make sure sensor is in known good state for measurements */
707*4882a593Smuzhiyun regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
708*4882a593Smuzhiyun data->socdata->power_down_mask);
709*4882a593Smuzhiyun regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
710*4882a593Smuzhiyun data->socdata->measure_temp_mask);
711*4882a593Smuzhiyun regmap_write(map, data->socdata->measure_freq_ctrl + REG_CLR,
712*4882a593Smuzhiyun data->socdata->measure_freq_mask);
713*4882a593Smuzhiyun if (data->socdata->version != TEMPMON_IMX7D)
714*4882a593Smuzhiyun regmap_write(map, IMX6_MISC0 + REG_SET,
715*4882a593Smuzhiyun IMX6_MISC0_REFTOP_SELBIASOFF);
716*4882a593Smuzhiyun regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
717*4882a593Smuzhiyun data->socdata->power_down_mask);
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun ret = imx_thermal_register_legacy_cooling(data);
720*4882a593Smuzhiyun if (ret)
721*4882a593Smuzhiyun return dev_err_probe(&pdev->dev, ret,
722*4882a593Smuzhiyun "failed to register cpufreq cooling device\n");
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun data->thermal_clk = devm_clk_get(&pdev->dev, NULL);
725*4882a593Smuzhiyun if (IS_ERR(data->thermal_clk)) {
726*4882a593Smuzhiyun ret = PTR_ERR(data->thermal_clk);
727*4882a593Smuzhiyun if (ret != -EPROBE_DEFER)
728*4882a593Smuzhiyun dev_err(&pdev->dev,
729*4882a593Smuzhiyun "failed to get thermal clk: %d\n", ret);
730*4882a593Smuzhiyun goto legacy_cleanup;
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun /*
734*4882a593Smuzhiyun * Thermal sensor needs clk on to get correct value, normally
735*4882a593Smuzhiyun * we should enable its clk before taking measurement and disable
736*4882a593Smuzhiyun * clk after measurement is done, but if alarm function is enabled,
737*4882a593Smuzhiyun * hardware will auto measure the temperature periodically, so we
738*4882a593Smuzhiyun * need to keep the clk always on for alarm function.
739*4882a593Smuzhiyun */
740*4882a593Smuzhiyun ret = clk_prepare_enable(data->thermal_clk);
741*4882a593Smuzhiyun if (ret) {
742*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
743*4882a593Smuzhiyun goto legacy_cleanup;
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun data->tz = thermal_zone_device_register("imx_thermal_zone",
747*4882a593Smuzhiyun IMX_TRIP_NUM,
748*4882a593Smuzhiyun BIT(IMX_TRIP_PASSIVE), data,
749*4882a593Smuzhiyun &imx_tz_ops, NULL,
750*4882a593Smuzhiyun IMX_PASSIVE_DELAY,
751*4882a593Smuzhiyun IMX_POLLING_DELAY);
752*4882a593Smuzhiyun if (IS_ERR(data->tz)) {
753*4882a593Smuzhiyun ret = PTR_ERR(data->tz);
754*4882a593Smuzhiyun dev_err(&pdev->dev,
755*4882a593Smuzhiyun "failed to register thermal zone device %d\n", ret);
756*4882a593Smuzhiyun goto clk_disable;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun dev_info(&pdev->dev, "%s CPU temperature grade - max:%dC"
760*4882a593Smuzhiyun " critical:%dC passive:%dC\n", data->temp_grade,
761*4882a593Smuzhiyun data->temp_max / 1000, data->temp_critical / 1000,
762*4882a593Smuzhiyun data->temp_passive / 1000);
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun /* Enable measurements at ~ 10 Hz */
765*4882a593Smuzhiyun regmap_write(map, data->socdata->measure_freq_ctrl + REG_CLR,
766*4882a593Smuzhiyun data->socdata->measure_freq_mask);
767*4882a593Smuzhiyun measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
768*4882a593Smuzhiyun regmap_write(map, data->socdata->measure_freq_ctrl + REG_SET,
769*4882a593Smuzhiyun measure_freq << data->socdata->measure_freq_shift);
770*4882a593Smuzhiyun imx_set_alarm_temp(data, data->temp_passive);
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun if (data->socdata->version == TEMPMON_IMX6SX)
773*4882a593Smuzhiyun imx_set_panic_temp(data, data->temp_critical);
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
776*4882a593Smuzhiyun data->socdata->power_down_mask);
777*4882a593Smuzhiyun regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
778*4882a593Smuzhiyun data->socdata->measure_temp_mask);
779*4882a593Smuzhiyun /* After power up, we need a delay before first access can be done. */
780*4882a593Smuzhiyun usleep_range(20, 50);
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun /* the core was configured and enabled just before */
783*4882a593Smuzhiyun pm_runtime_set_active(&pdev->dev);
784*4882a593Smuzhiyun pm_runtime_enable(data->dev);
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun ret = pm_runtime_resume_and_get(data->dev);
787*4882a593Smuzhiyun if (ret < 0)
788*4882a593Smuzhiyun goto disable_runtime_pm;
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun data->irq_enabled = true;
791*4882a593Smuzhiyun ret = thermal_zone_device_enable(data->tz);
792*4882a593Smuzhiyun if (ret)
793*4882a593Smuzhiyun goto thermal_zone_unregister;
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun ret = devm_request_threaded_irq(&pdev->dev, data->irq,
796*4882a593Smuzhiyun imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
797*4882a593Smuzhiyun 0, "imx_thermal", data);
798*4882a593Smuzhiyun if (ret < 0) {
799*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
800*4882a593Smuzhiyun goto thermal_zone_unregister;
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun pm_runtime_put(data->dev);
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun return 0;
806*4882a593Smuzhiyun
807*4882a593Smuzhiyun thermal_zone_unregister:
808*4882a593Smuzhiyun thermal_zone_device_unregister(data->tz);
809*4882a593Smuzhiyun disable_runtime_pm:
810*4882a593Smuzhiyun pm_runtime_put_noidle(data->dev);
811*4882a593Smuzhiyun pm_runtime_disable(data->dev);
812*4882a593Smuzhiyun clk_disable:
813*4882a593Smuzhiyun clk_disable_unprepare(data->thermal_clk);
814*4882a593Smuzhiyun legacy_cleanup:
815*4882a593Smuzhiyun imx_thermal_unregister_legacy_cooling(data);
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun return ret;
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun
imx_thermal_remove(struct platform_device * pdev)820*4882a593Smuzhiyun static int imx_thermal_remove(struct platform_device *pdev)
821*4882a593Smuzhiyun {
822*4882a593Smuzhiyun struct imx_thermal_data *data = platform_get_drvdata(pdev);
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun pm_runtime_put_noidle(data->dev);
825*4882a593Smuzhiyun pm_runtime_disable(data->dev);
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun thermal_zone_device_unregister(data->tz);
828*4882a593Smuzhiyun imx_thermal_unregister_legacy_cooling(data);
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun return 0;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun
imx_thermal_suspend(struct device * dev)833*4882a593Smuzhiyun static int __maybe_unused imx_thermal_suspend(struct device *dev)
834*4882a593Smuzhiyun {
835*4882a593Smuzhiyun struct imx_thermal_data *data = dev_get_drvdata(dev);
836*4882a593Smuzhiyun int ret;
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun /*
839*4882a593Smuzhiyun * Need to disable thermal sensor, otherwise, when thermal core
840*4882a593Smuzhiyun * try to get temperature before thermal sensor resume, a wrong
841*4882a593Smuzhiyun * temperature will be read as the thermal sensor is powered
842*4882a593Smuzhiyun * down. This is done in change_mode() operation called from
843*4882a593Smuzhiyun * thermal_zone_device_disable()
844*4882a593Smuzhiyun */
845*4882a593Smuzhiyun ret = thermal_zone_device_disable(data->tz);
846*4882a593Smuzhiyun if (ret)
847*4882a593Smuzhiyun return ret;
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun return pm_runtime_force_suspend(data->dev);
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun
imx_thermal_resume(struct device * dev)852*4882a593Smuzhiyun static int __maybe_unused imx_thermal_resume(struct device *dev)
853*4882a593Smuzhiyun {
854*4882a593Smuzhiyun struct imx_thermal_data *data = dev_get_drvdata(dev);
855*4882a593Smuzhiyun int ret;
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun ret = pm_runtime_force_resume(data->dev);
858*4882a593Smuzhiyun if (ret)
859*4882a593Smuzhiyun return ret;
860*4882a593Smuzhiyun /* Enabled thermal sensor after resume */
861*4882a593Smuzhiyun return thermal_zone_device_enable(data->tz);
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun
imx_thermal_runtime_suspend(struct device * dev)864*4882a593Smuzhiyun static int __maybe_unused imx_thermal_runtime_suspend(struct device *dev)
865*4882a593Smuzhiyun {
866*4882a593Smuzhiyun struct imx_thermal_data *data = dev_get_drvdata(dev);
867*4882a593Smuzhiyun const struct thermal_soc_data *socdata = data->socdata;
868*4882a593Smuzhiyun struct regmap *map = data->tempmon;
869*4882a593Smuzhiyun int ret;
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun ret = regmap_write(map, socdata->sensor_ctrl + REG_CLR,
872*4882a593Smuzhiyun socdata->measure_temp_mask);
873*4882a593Smuzhiyun if (ret)
874*4882a593Smuzhiyun return ret;
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun ret = regmap_write(map, socdata->sensor_ctrl + REG_SET,
877*4882a593Smuzhiyun socdata->power_down_mask);
878*4882a593Smuzhiyun if (ret)
879*4882a593Smuzhiyun return ret;
880*4882a593Smuzhiyun
881*4882a593Smuzhiyun clk_disable_unprepare(data->thermal_clk);
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun return 0;
884*4882a593Smuzhiyun }
885*4882a593Smuzhiyun
imx_thermal_runtime_resume(struct device * dev)886*4882a593Smuzhiyun static int __maybe_unused imx_thermal_runtime_resume(struct device *dev)
887*4882a593Smuzhiyun {
888*4882a593Smuzhiyun struct imx_thermal_data *data = dev_get_drvdata(dev);
889*4882a593Smuzhiyun const struct thermal_soc_data *socdata = data->socdata;
890*4882a593Smuzhiyun struct regmap *map = data->tempmon;
891*4882a593Smuzhiyun int ret;
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun ret = clk_prepare_enable(data->thermal_clk);
894*4882a593Smuzhiyun if (ret)
895*4882a593Smuzhiyun return ret;
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun ret = regmap_write(map, socdata->sensor_ctrl + REG_CLR,
898*4882a593Smuzhiyun socdata->power_down_mask);
899*4882a593Smuzhiyun if (ret)
900*4882a593Smuzhiyun return ret;
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun ret = regmap_write(map, socdata->sensor_ctrl + REG_SET,
903*4882a593Smuzhiyun socdata->measure_temp_mask);
904*4882a593Smuzhiyun if (ret)
905*4882a593Smuzhiyun return ret;
906*4882a593Smuzhiyun
907*4882a593Smuzhiyun /*
908*4882a593Smuzhiyun * According to the temp sensor designers, it may require up to ~17us
909*4882a593Smuzhiyun * to complete a measurement.
910*4882a593Smuzhiyun */
911*4882a593Smuzhiyun usleep_range(20, 50);
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun return 0;
914*4882a593Smuzhiyun }
915*4882a593Smuzhiyun
916*4882a593Smuzhiyun static const struct dev_pm_ops imx_thermal_pm_ops = {
917*4882a593Smuzhiyun SET_SYSTEM_SLEEP_PM_OPS(imx_thermal_suspend, imx_thermal_resume)
918*4882a593Smuzhiyun SET_RUNTIME_PM_OPS(imx_thermal_runtime_suspend,
919*4882a593Smuzhiyun imx_thermal_runtime_resume, NULL)
920*4882a593Smuzhiyun };
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun static struct platform_driver imx_thermal = {
923*4882a593Smuzhiyun .driver = {
924*4882a593Smuzhiyun .name = "imx_thermal",
925*4882a593Smuzhiyun .pm = &imx_thermal_pm_ops,
926*4882a593Smuzhiyun .of_match_table = of_imx_thermal_match,
927*4882a593Smuzhiyun },
928*4882a593Smuzhiyun .probe = imx_thermal_probe,
929*4882a593Smuzhiyun .remove = imx_thermal_remove,
930*4882a593Smuzhiyun };
931*4882a593Smuzhiyun module_platform_driver(imx_thermal);
932*4882a593Smuzhiyun
933*4882a593Smuzhiyun MODULE_AUTHOR("Freescale Semiconductor, Inc.");
934*4882a593Smuzhiyun MODULE_DESCRIPTION("Thermal driver for Freescale i.MX SoCs");
935*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
936*4882a593Smuzhiyun MODULE_ALIAS("platform:imx-thermal");
937