23
23
#include <linux/of_device.h>
24
24
#include <linux/platform_device.h>
25
25
#include <linux/pm_runtime.h>
26
+ #include <linux/spinlock.h>
26
27
#include <linux/thermal.h>
27
28
29
+ #include "thermal_core.h"
30
+
28
31
/* Register offsets */
29
32
#define REG_GEN3_IRQSTR 0x04
30
33
#define REG_GEN3_IRQMSK 0x08
40
43
#define REG_GEN3_THCODE2 0x54
41
44
#define REG_GEN3_THCODE3 0x58
42
45
46
+ /* IRQ{STR,MSK,EN} bits */
47
+ #define IRQ_TEMP1 BIT(0)
48
+ #define IRQ_TEMP2 BIT(1)
49
+ #define IRQ_TEMP3 BIT(2)
50
+ #define IRQ_TEMPD1 BIT(3)
51
+ #define IRQ_TEMPD2 BIT(4)
52
+ #define IRQ_TEMPD3 BIT(5)
53
+
43
54
/* CTSR bits */
44
55
#define CTSR_PONM BIT(8)
45
56
#define CTSR_AOUT BIT(7)
@@ -76,6 +87,7 @@ struct rcar_gen3_thermal_tsc {
76
87
struct rcar_gen3_thermal_priv {
77
88
struct rcar_gen3_thermal_tsc * tscs [TSC_MAX_NUM ];
78
89
unsigned int num_tscs ;
90
+ spinlock_t lock ; /* Protect interrupts on and off */
79
91
};
80
92
81
93
struct rcar_gen3_thermal_data {
@@ -113,6 +125,7 @@ static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
113
125
114
126
#define FIXPT_SHIFT 7
115
127
#define FIXPT_INT (_x ) ((_x) << FIXPT_SHIFT)
128
+ #define INT_FIXPT (_x ) ((_x) >> FIXPT_SHIFT)
116
129
#define FIXPT_DIV (_a , _b ) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b))
117
130
#define FIXPT_TO_MCELSIUS (_x ) ((_x) * 1000 >> FIXPT_SHIFT)
118
131
@@ -178,10 +191,87 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
178
191
return 0 ;
179
192
}
180
193
194
+ static int rcar_gen3_thermal_mcelsius_to_temp (struct rcar_gen3_thermal_tsc * tsc ,
195
+ int mcelsius )
196
+ {
197
+ int celsius , val1 , val2 ;
198
+
199
+ celsius = DIV_ROUND_CLOSEST (mcelsius , 1000 );
200
+ val1 = celsius * tsc -> coef .a1 + tsc -> coef .b1 ;
201
+ val2 = celsius * tsc -> coef .a2 + tsc -> coef .b2 ;
202
+
203
+ return INT_FIXPT ((val1 + val2 ) / 2 );
204
+ }
205
+
206
+ static int rcar_gen3_thermal_set_trips (void * devdata , int low , int high )
207
+ {
208
+ struct rcar_gen3_thermal_tsc * tsc = devdata ;
209
+
210
+ low = clamp_val (low , -40000 , 125000 );
211
+ high = clamp_val (high , -40000 , 125000 );
212
+
213
+ rcar_gen3_thermal_write (tsc , REG_GEN3_IRQTEMP1 ,
214
+ rcar_gen3_thermal_mcelsius_to_temp (tsc , low ));
215
+
216
+ rcar_gen3_thermal_write (tsc , REG_GEN3_IRQTEMP2 ,
217
+ rcar_gen3_thermal_mcelsius_to_temp (tsc , high ));
218
+
219
+ return 0 ;
220
+ }
221
+
181
222
static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
182
223
.get_temp = rcar_gen3_thermal_get_temp ,
224
+ .set_trips = rcar_gen3_thermal_set_trips ,
183
225
};
184
226
227
+ static void rcar_thermal_irq_set (struct rcar_gen3_thermal_priv * priv , bool on )
228
+ {
229
+ unsigned int i ;
230
+ u32 val = on ? IRQ_TEMPD1 | IRQ_TEMP2 : 0 ;
231
+
232
+ for (i = 0 ; i < priv -> num_tscs ; i ++ )
233
+ rcar_gen3_thermal_write (priv -> tscs [i ], REG_GEN3_IRQMSK , val );
234
+ }
235
+
236
+ static irqreturn_t rcar_gen3_thermal_irq (int irq , void * data )
237
+ {
238
+ struct rcar_gen3_thermal_priv * priv = data ;
239
+ u32 status ;
240
+ int i , ret = IRQ_HANDLED ;
241
+
242
+ spin_lock (& priv -> lock );
243
+ for (i = 0 ; i < priv -> num_tscs ; i ++ ) {
244
+ status = rcar_gen3_thermal_read (priv -> tscs [i ], REG_GEN3_IRQSTR );
245
+ rcar_gen3_thermal_write (priv -> tscs [i ], REG_GEN3_IRQSTR , 0 );
246
+ if (status )
247
+ ret = IRQ_WAKE_THREAD ;
248
+ }
249
+
250
+ if (ret == IRQ_WAKE_THREAD )
251
+ rcar_thermal_irq_set (priv , false);
252
+
253
+ spin_unlock (& priv -> lock );
254
+
255
+ return ret ;
256
+ }
257
+
258
+ static irqreturn_t rcar_gen3_thermal_irq_thread (int irq , void * data )
259
+ {
260
+ struct rcar_gen3_thermal_priv * priv = data ;
261
+ unsigned long flags ;
262
+ int i ;
263
+
264
+ for (i = 0 ; i < priv -> num_tscs ; i ++ )
265
+ thermal_zone_device_update (priv -> tscs [i ]-> zone ,
266
+ THERMAL_EVENT_UNSPECIFIED );
267
+
268
+ spin_lock_irqsave (& priv -> lock , flags );
269
+ rcar_thermal_irq_set (priv , true);
270
+ spin_unlock_irqrestore (& priv -> lock , flags );
271
+
272
+ return IRQ_HANDLED ;
273
+ }
274
+
185
275
static void r8a7795_thermal_init (struct rcar_gen3_thermal_tsc * tsc )
186
276
{
187
277
rcar_gen3_thermal_write (tsc , REG_GEN3_CTSR , CTSR_THBGR );
@@ -190,7 +280,11 @@ static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
190
280
usleep_range (1000 , 2000 );
191
281
192
282
rcar_gen3_thermal_write (tsc , REG_GEN3_CTSR , CTSR_PONM );
283
+
193
284
rcar_gen3_thermal_write (tsc , REG_GEN3_IRQCTL , 0x3F );
285
+ rcar_gen3_thermal_write (tsc , REG_GEN3_IRQMSK , 0 );
286
+ rcar_gen3_thermal_write (tsc , REG_GEN3_IRQEN , IRQ_TEMPD1 | IRQ_TEMP2 );
287
+
194
288
rcar_gen3_thermal_write (tsc , REG_GEN3_CTSR ,
195
289
CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN );
196
290
@@ -214,6 +308,9 @@ static void r8a7796_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
214
308
usleep_range (1000 , 2000 );
215
309
216
310
rcar_gen3_thermal_write (tsc , REG_GEN3_IRQCTL , 0x3F );
311
+ rcar_gen3_thermal_write (tsc , REG_GEN3_IRQMSK , 0 );
312
+ rcar_gen3_thermal_write (tsc , REG_GEN3_IRQEN , IRQ_TEMPD1 | IRQ_TEMP2 );
313
+
217
314
reg_val = rcar_gen3_thermal_read (tsc , REG_GEN3_THCTR );
218
315
reg_val |= THCTR_THSST ;
219
316
rcar_gen3_thermal_write (tsc , REG_GEN3_THCTR , reg_val );
@@ -252,7 +349,8 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
252
349
struct device * dev = & pdev -> dev ;
253
350
struct resource * res ;
254
351
struct thermal_zone_device * zone ;
255
- int ret , i ;
352
+ int ret , irq , i ;
353
+ char * irqname ;
256
354
const struct rcar_gen3_thermal_data * match_data =
257
355
of_device_get_match_data (dev );
258
356
@@ -269,8 +367,32 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
269
367
if (!priv )
270
368
return - ENOMEM ;
271
369
370
+ spin_lock_init (& priv -> lock );
371
+
272
372
platform_set_drvdata (pdev , priv );
273
373
374
+ /*
375
+ * Request 2 (of the 3 possible) IRQs, the driver only needs to
376
+ * to trigger on the low and high trip points of the current
377
+ * temp window at this point.
378
+ */
379
+ for (i = 0 ; i < 2 ; i ++ ) {
380
+ irq = platform_get_irq (pdev , i );
381
+ if (irq < 0 )
382
+ return irq ;
383
+
384
+ irqname = devm_kasprintf (dev , GFP_KERNEL , "%s:ch%d" ,
385
+ dev_name (dev ), i );
386
+ if (!irqname )
387
+ return - ENOMEM ;
388
+
389
+ ret = devm_request_threaded_irq (dev , irq , rcar_gen3_thermal_irq ,
390
+ rcar_gen3_thermal_irq_thread ,
391
+ IRQF_SHARED , irqname , priv );
392
+ if (ret )
393
+ return ret ;
394
+ }
395
+
274
396
pm_runtime_enable (dev );
275
397
pm_runtime_get_sync (dev );
276
398
@@ -306,6 +428,12 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
306
428
goto error_unregister ;
307
429
}
308
430
tsc -> zone = zone ;
431
+
432
+ ret = of_thermal_get_ntrips (tsc -> zone );
433
+ if (ret < 0 )
434
+ goto error_unregister ;
435
+
436
+ dev_info (dev , "TSC%d: Loaded %d trip points\n" , i , ret );
309
437
}
310
438
311
439
priv -> num_tscs = i ;
@@ -315,6 +443,8 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
315
443
goto error_unregister ;
316
444
}
317
445
446
+ rcar_thermal_irq_set (priv , true);
447
+
318
448
return 0 ;
319
449
320
450
error_unregister :
0 commit comments