Blame view

drivers/thermal/rcar_thermal.c 15.3 KB
c95457908   Kuninori Morimoto   thermal: rcar_the...
1
  // SPDX-License-Identifier: GPL-2.0
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
2
3
4
5
6
  /*
   *  R-Car THS/TSC thermal sensor driver
   *
   * Copyright (C) 2012 Renesas Solutions Corp.
   * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
7
8
9
   */
  #include <linux/delay.h>
  #include <linux/err.h>
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
10
11
  #include <linux/irq.h>
  #include <linux/interrupt.h>
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
12
13
  #include <linux/io.h>
  #include <linux/module.h>
8b477ea56   Kuninori Morimoto   thermal: rcar: en...
14
  #include <linux/of_device.h>
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
15
  #include <linux/platform_device.h>
51d45d259   Kuninori Morimoto   thermal: rcar: ad...
16
  #include <linux/pm_runtime.h>
d2a73e225   Kuninori Morimoto   thermal: rcar: ad...
17
  #include <linux/reboot.h>
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
18
19
20
  #include <linux/slab.h>
  #include <linux/spinlock.h>
  #include <linux/thermal.h>
64a411e80   Kuninori Morimoto   thermal: rcar-the...
21
  #include "thermal_hwmon.h"
d2a73e225   Kuninori Morimoto   thermal: rcar: ad...
22
  #define IDLE_INTERVAL	5000
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
23
24
25
26
27
28
  #define COMMON_STR	0x00
  #define COMMON_ENR	0x04
  #define COMMON_INTMSK	0x0c
  
  #define REG_POSNEG	0x20
  #define REG_FILONOFF	0x28
e9137a582   Kuninori Morimoto   thermal: rcar: ad...
29
30
  #define REG_THSCR	0x2c
  #define REG_THSSR	0x30
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
31
  #define REG_INTCTRL	0x34
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
32
33
  
  /* THSCR */
f8f53e187   Kuninori Morimoto   thermal: rcar: en...
34
  #define CPCTL	(1 << 12)
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
35
36
37
  
  /* THSSR */
  #define CTEMP	0x3f
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
38
39
40
41
  struct rcar_thermal_common {
  	void __iomem *base;
  	struct device *dev;
  	struct list_head head;
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
42
  	spinlock_t lock;
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
43
  };
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
44

1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
45
46
47
48
49
50
  struct rcar_thermal_chip {
  	unsigned int use_of_thermal : 1;
  	unsigned int has_filonoff : 1;
  	unsigned int irq_per_ch : 1;
  	unsigned int needs_suspend_resume : 1;
  	unsigned int nirqs;
20386f0d8   Yoshihiro Kaneko   thermal: rcar_the...
51
  	unsigned int ctemp_bands;
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
52
53
54
55
56
57
58
59
  };
  
  static const struct rcar_thermal_chip rcar_thermal = {
  	.use_of_thermal = 0,
  	.has_filonoff = 1,
  	.irq_per_ch = 0,
  	.needs_suspend_resume = 0,
  	.nirqs = 1,
20386f0d8   Yoshihiro Kaneko   thermal: rcar_the...
60
  	.ctemp_bands = 1,
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
61
62
63
64
65
66
67
68
  };
  
  static const struct rcar_thermal_chip rcar_gen2_thermal = {
  	.use_of_thermal = 1,
  	.has_filonoff = 1,
  	.irq_per_ch = 0,
  	.needs_suspend_resume = 0,
  	.nirqs = 1,
20386f0d8   Yoshihiro Kaneko   thermal: rcar_the...
69
  	.ctemp_bands = 1,
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
70
71
72
73
74
75
76
77
78
79
80
81
  };
  
  static const struct rcar_thermal_chip rcar_gen3_thermal = {
  	.use_of_thermal = 1,
  	.has_filonoff = 0,
  	.irq_per_ch = 1,
  	.needs_suspend_resume = 1,
  	/*
  	 * The Gen3 chip has 3 interrupts, but this driver uses only 2
  	 * interrupts to detect a temperature change, rise or fall.
  	 */
  	.nirqs = 2,
20386f0d8   Yoshihiro Kaneko   thermal: rcar_the...
82
  	.ctemp_bands = 2,
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
83
  };
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
84
85
  struct rcar_thermal_priv {
  	void __iomem *base;
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
86
87
  	struct rcar_thermal_common *common;
  	struct thermal_zone_device *zone;
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
88
  	const struct rcar_thermal_chip *chip;
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
89
  	struct delayed_work work;
b2bbc6a2a   Kuninori Morimoto   thermal: rcar: us...
90
  	struct mutex lock;
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
91
  	struct list_head list;
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
92
  	int id;
913015c6d   Yoshihiro Shimoda   thermal: rcar: ch...
93
  	u32 ctemp;
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
94
  };
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
95
96
  #define rcar_thermal_for_each_priv(pos, common)	\
  	list_for_each_entry(pos, &common->head, list)
c499703e6   Kuninori Morimoto   thermal: rcar: fi...
97
  #define MCELSIUS(temp)			((temp) * 1000)
9dde8f860   Kuninori Morimoto   thermal: rcar: us...
98
  #define rcar_zone_to_priv(zone)		((zone)->devdata)
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
99
100
  #define rcar_priv_to_dev(priv)		((priv)->common->dev)
  #define rcar_has_irq_support(priv)	((priv)->common->base)
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
101
  #define rcar_id_to_shift(priv)		((priv)->id * 8)
ca1e4558f   Kuninori Morimoto   thermal: rcar: mo...
102
  static const struct of_device_id rcar_thermal_dt_ids[] = {
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
103
104
105
106
107
108
109
110
111
  	{
  		.compatible = "renesas,rcar-thermal",
  		.data = &rcar_thermal,
  	},
  	{
  		.compatible = "renesas,rcar-gen2-thermal",
  		 .data = &rcar_gen2_thermal,
  	},
  	{
b8d3d1120   Fabrizio Castro   thermal: rcar_the...
112
113
114
115
  		.compatible = "renesas,thermal-r8a774c0",
  		.data = &rcar_gen3_thermal,
  	},
  	{
92ca366e9   Sergei Shtylyov   thermal: rcar_the...
116
117
118
119
  		.compatible = "renesas,thermal-r8a77970",
  		.data = &rcar_gen3_thermal,
  	},
  	{
e36e13003   Yoshihiro Kaneko   thermal: rcar_the...
120
121
122
123
  		.compatible = "renesas,thermal-r8a77990",
  		.data = &rcar_gen3_thermal,
  	},
  	{
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
124
125
126
  		.compatible = "renesas,thermal-r8a77995",
  		.data = &rcar_gen3_thermal,
  	},
ca1e4558f   Kuninori Morimoto   thermal: rcar: mo...
127
128
129
  	{},
  };
  MODULE_DEVICE_TABLE(of, rcar_thermal_dt_ids);
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
130
131
132
  /*
   *		basic functions
   */
e9137a582   Kuninori Morimoto   thermal: rcar: ad...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
  #define rcar_thermal_common_read(c, r) \
  	_rcar_thermal_common_read(c, COMMON_ ##r)
  static u32 _rcar_thermal_common_read(struct rcar_thermal_common *common,
  				     u32 reg)
  {
  	return ioread32(common->base + reg);
  }
  
  #define rcar_thermal_common_write(c, r, d) \
  	_rcar_thermal_common_write(c, COMMON_ ##r, d)
  static void _rcar_thermal_common_write(struct rcar_thermal_common *common,
  				       u32 reg, u32 data)
  {
  	iowrite32(data, common->base + reg);
  }
  
  #define rcar_thermal_common_bset(c, r, m, d) \
  	_rcar_thermal_common_bset(c, COMMON_ ##r, m, d)
  static void _rcar_thermal_common_bset(struct rcar_thermal_common *common,
  				      u32 reg, u32 mask, u32 data)
  {
  	u32 val;
  
  	val = ioread32(common->base + reg);
  	val &= ~mask;
  	val |= (data & mask);
  	iowrite32(val, common->base + reg);
  }
e9137a582   Kuninori Morimoto   thermal: rcar: ad...
161
162
163
  
  #define rcar_thermal_read(p, r) _rcar_thermal_read(p, REG_ ##r)
  static u32 _rcar_thermal_read(struct rcar_thermal_priv *priv, u32 reg)
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
164
  {
b2bbc6a2a   Kuninori Morimoto   thermal: rcar: us...
165
  	return ioread32(priv->base + reg);
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
166
  }
e9137a582   Kuninori Morimoto   thermal: rcar: ad...
167
168
169
  #define rcar_thermal_write(p, r, d) _rcar_thermal_write(p, REG_ ##r, d)
  static void _rcar_thermal_write(struct rcar_thermal_priv *priv,
  				u32 reg, u32 data)
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
170
  {
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
171
  	iowrite32(data, priv->base + reg);
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
172
  }
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
173

e9137a582   Kuninori Morimoto   thermal: rcar: ad...
174
175
176
  #define rcar_thermal_bset(p, r, m, d) _rcar_thermal_bset(p, REG_ ##r, m, d)
  static void _rcar_thermal_bset(struct rcar_thermal_priv *priv, u32 reg,
  			       u32 mask, u32 data)
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
177
  {
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
178
  	u32 val;
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
179
180
181
182
  	val = ioread32(priv->base + reg);
  	val &= ~mask;
  	val |= (data & mask);
  	iowrite32(val, priv->base + reg);
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
183
184
185
186
187
  }
  
  /*
   *		zone device functions
   */
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
188
  static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv)
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
189
  {
f8f53e187   Kuninori Morimoto   thermal: rcar: en...
190
191
  	struct device *dev = rcar_priv_to_dev(priv);
  	int i;
913015c6d   Yoshihiro Shimoda   thermal: rcar: ch...
192
  	u32 ctemp, old, new;
f0e68fc3c   Wei Yongjun   thermal: rcar: fi...
193
  	int ret = -EINVAL;
f8f53e187   Kuninori Morimoto   thermal: rcar: en...
194

b2bbc6a2a   Kuninori Morimoto   thermal: rcar: us...
195
  	mutex_lock(&priv->lock);
f8f53e187   Kuninori Morimoto   thermal: rcar: en...
196
197
198
199
200
201
202
203
204
  	/*
  	 * TSC decides a value of CPTAP automatically,
  	 * and this is the conditions which validate interrupt.
  	 */
  	rcar_thermal_bset(priv, THSCR, CPCTL, CPCTL);
  
  	ctemp = 0;
  	old = ~0;
  	for (i = 0; i < 128; i++) {
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
205
206
207
208
209
  		/*
  		 * we need to wait 300us after changing comparator offset
  		 * to get stable temperature.
  		 * see "Usage Notes" on datasheet
  		 */
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
210
  		udelay(300);
f8f53e187   Kuninori Morimoto   thermal: rcar: en...
211
212
213
  		new = rcar_thermal_read(priv, THSSR) & CTEMP;
  		if (new == old) {
  			ctemp = new;
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
214
215
  			break;
  		}
f8f53e187   Kuninori Morimoto   thermal: rcar: en...
216
  		old = new;
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
217
  	}
f8f53e187   Kuninori Morimoto   thermal: rcar: en...
218
219
220
  	if (!ctemp) {
  		dev_err(dev, "thermal sensor was broken
  ");
f0e68fc3c   Wei Yongjun   thermal: rcar: fi...
221
  		goto err_out_unlock;
f8f53e187   Kuninori Morimoto   thermal: rcar: en...
222
  	}
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
223
224
225
226
  	/*
  	 * enable IRQ
  	 */
  	if (rcar_has_irq_support(priv)) {
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
227
228
  		if (priv->chip->has_filonoff)
  			rcar_thermal_write(priv, FILONOFF, 0);
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
229
230
231
232
233
234
235
236
237
238
239
  
  		/* enable Rising/Falling edge interrupt */
  		rcar_thermal_write(priv, POSNEG,  0x1);
  		rcar_thermal_write(priv, INTCTRL, (((ctemp - 0) << 8) |
  						   ((ctemp - 1) << 0)));
  	}
  
  	dev_dbg(dev, "thermal%d  %d -> %d
  ", priv->id, priv->ctemp, ctemp);
  
  	priv->ctemp = ctemp;
f0e68fc3c   Wei Yongjun   thermal: rcar: fi...
240
241
  	ret = 0;
  err_out_unlock:
b2bbc6a2a   Kuninori Morimoto   thermal: rcar: us...
242
  	mutex_unlock(&priv->lock);
f0e68fc3c   Wei Yongjun   thermal: rcar: fi...
243
  	return ret;
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
244
  }
8b477ea56   Kuninori Morimoto   thermal: rcar: en...
245
246
  static int rcar_thermal_get_current_temp(struct rcar_thermal_priv *priv,
  					 int *temp)
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
247
  {
5440c40b9   Kuninori Morimoto   thermal: rcar: rc...
248
  	int tmp;
a1ade5653   Kuninori Morimoto   thermal: rcar: ch...
249
  	int ret;
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
250

a1ade5653   Kuninori Morimoto   thermal: rcar: ch...
251
252
253
  	ret = rcar_thermal_update_temp(priv);
  	if (ret < 0)
  		return ret;
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
254
255
  
  	mutex_lock(&priv->lock);
20386f0d8   Yoshihiro Kaneko   thermal: rcar_the...
256
257
258
259
260
261
  	if (priv->chip->ctemp_bands == 1)
  		tmp = MCELSIUS((priv->ctemp * 5) - 65);
  	else if (priv->ctemp < 24)
  		tmp = MCELSIUS(((priv->ctemp * 55) - 720) / 10);
  	else
  		tmp = MCELSIUS((priv->ctemp * 5) - 60);
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
262
  	mutex_unlock(&priv->lock);
5440c40b9   Kuninori Morimoto   thermal: rcar: rc...
263
264
265
266
267
268
269
270
271
  	if ((tmp < MCELSIUS(-45)) || (tmp > MCELSIUS(125))) {
  		struct device *dev = rcar_priv_to_dev(priv);
  
  		dev_err(dev, "it couldn't measure temperature correctly
  ");
  		return -EIO;
  	}
  
  	*temp = tmp;
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
272
273
  	return 0;
  }
8b477ea56   Kuninori Morimoto   thermal: rcar: en...
274
275
276
277
278
279
280
281
282
283
284
285
286
  static int rcar_thermal_of_get_temp(void *data, int *temp)
  {
  	struct rcar_thermal_priv *priv = data;
  
  	return rcar_thermal_get_current_temp(priv, temp);
  }
  
  static int rcar_thermal_get_temp(struct thermal_zone_device *zone, int *temp)
  {
  	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
  
  	return rcar_thermal_get_current_temp(priv, temp);
  }
d2a73e225   Kuninori Morimoto   thermal: rcar: ad...
287
288
289
290
  static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone,
  				      int trip, enum thermal_trip_type *type)
  {
  	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
291
  	struct device *dev = rcar_priv_to_dev(priv);
d2a73e225   Kuninori Morimoto   thermal: rcar: ad...
292
293
294
295
296
297
298
  
  	/* see rcar_thermal_get_temp() */
  	switch (trip) {
  	case 0: /* +90 <= temp */
  		*type = THERMAL_TRIP_CRITICAL;
  		break;
  	default:
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
299
300
  		dev_err(dev, "rcar driver trip error
  ");
d2a73e225   Kuninori Morimoto   thermal: rcar: ad...
301
302
303
304
305
306
307
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  static int rcar_thermal_get_trip_temp(struct thermal_zone_device *zone,
17e8351a7   Sascha Hauer   thermal: consiste...
308
  				      int trip, int *temp)
d2a73e225   Kuninori Morimoto   thermal: rcar: ad...
309
310
  {
  	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
311
  	struct device *dev = rcar_priv_to_dev(priv);
d2a73e225   Kuninori Morimoto   thermal: rcar: ad...
312
313
314
315
316
317
318
  
  	/* see rcar_thermal_get_temp() */
  	switch (trip) {
  	case 0: /* +90 <= temp */
  		*temp = MCELSIUS(90);
  		break;
  	default:
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
319
320
  		dev_err(dev, "rcar driver trip error
  ");
d2a73e225   Kuninori Morimoto   thermal: rcar: ad...
321
322
323
324
325
326
327
328
329
330
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  static int rcar_thermal_notify(struct thermal_zone_device *zone,
  			       int trip, enum thermal_trip_type type)
  {
  	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
331
  	struct device *dev = rcar_priv_to_dev(priv);
d2a73e225   Kuninori Morimoto   thermal: rcar: ad...
332
333
334
335
  
  	switch (type) {
  	case THERMAL_TRIP_CRITICAL:
  		/* FIXME */
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
336
337
  		dev_warn(dev, "Thermal reached to critical temperature
  ");
d2a73e225   Kuninori Morimoto   thermal: rcar: ad...
338
339
340
341
342
343
344
  		break;
  	default:
  		break;
  	}
  
  	return 0;
  }
8b477ea56   Kuninori Morimoto   thermal: rcar: en...
345
346
347
  static const struct thermal_zone_of_device_ops rcar_thermal_zone_of_ops = {
  	.get_temp	= rcar_thermal_of_get_temp,
  };
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
348
  static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
d2a73e225   Kuninori Morimoto   thermal: rcar: ad...
349
350
351
352
  	.get_temp	= rcar_thermal_get_temp,
  	.get_trip_type	= rcar_thermal_get_trip_type,
  	.get_trip_temp	= rcar_thermal_get_trip_temp,
  	.notify		= rcar_thermal_notify,
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
353
354
355
  };
  
  /*
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
356
357
358
359
360
361
362
363
364
   *		interrupt
   */
  #define rcar_thermal_irq_enable(p)	_rcar_thermal_irq_ctrl(p, 1)
  #define rcar_thermal_irq_disable(p)	_rcar_thermal_irq_ctrl(p, 0)
  static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable)
  {
  	struct rcar_thermal_common *common = priv->common;
  	unsigned long flags;
  	u32 mask = 0x3 << rcar_id_to_shift(priv); /* enable Rising/Falling */
ffbcdf8a7   Kuninori Morimoto   thermal: rcar: ch...
365
366
  	if (!rcar_has_irq_support(priv))
  		return;
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
367
368
369
370
371
372
373
374
375
376
  	spin_lock_irqsave(&common->lock, flags);
  
  	rcar_thermal_common_bset(common, INTMSK, mask, enable ? 0 : mask);
  
  	spin_unlock_irqrestore(&common->lock, flags);
  }
  
  static void rcar_thermal_work(struct work_struct *work)
  {
  	struct rcar_thermal_priv *priv;
17e8351a7   Sascha Hauer   thermal: consiste...
377
  	int cctemp, nctemp;
a1ade5653   Kuninori Morimoto   thermal: rcar: ch...
378
  	int ret;
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
379
380
  
  	priv = container_of(work, struct rcar_thermal_priv, work.work);
8b477ea56   Kuninori Morimoto   thermal: rcar: en...
381
382
383
  	ret = rcar_thermal_get_current_temp(priv, &cctemp);
  	if (ret < 0)
  		return;
a1ade5653   Kuninori Morimoto   thermal: rcar: ch...
384
385
386
  	ret = rcar_thermal_update_temp(priv);
  	if (ret < 0)
  		return;
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
387
  	rcar_thermal_irq_enable(priv);
9477165ec   Patrick Titiano   thermal: rcar-the...
388

8b477ea56   Kuninori Morimoto   thermal: rcar: en...
389
390
391
  	ret = rcar_thermal_get_current_temp(priv, &nctemp);
  	if (ret < 0)
  		return;
9477165ec   Patrick Titiano   thermal: rcar-the...
392
  	if (nctemp != cctemp)
0e70f466f   Srinivas Pandruvada   thermal: Enhance ...
393
394
  		thermal_zone_device_update(priv->zone,
  					   THERMAL_EVENT_UNSPECIFIED);
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
395
396
397
398
399
400
401
  }
  
  static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status)
  {
  	struct device *dev = rcar_priv_to_dev(priv);
  
  	status = (status >> rcar_id_to_shift(priv)) & 0x3;
206c0cba0   Patrick Titiano   thermal: rcar-the...
402
  	if (status) {
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
  		dev_dbg(dev, "thermal%d %s%s
  ",
  			priv->id,
  			(status & 0x2) ? "Rising " : "",
  			(status & 0x1) ? "Falling" : "");
  	}
  
  	return status;
  }
  
  static irqreturn_t rcar_thermal_irq(int irq, void *data)
  {
  	struct rcar_thermal_common *common = data;
  	struct rcar_thermal_priv *priv;
  	unsigned long flags;
  	u32 status, mask;
  
  	spin_lock_irqsave(&common->lock, flags);
  
  	mask	= rcar_thermal_common_read(common, INTMSK);
  	status	= rcar_thermal_common_read(common, STR);
  	rcar_thermal_common_write(common, STR, 0x000F0F0F & mask);
  
  	spin_unlock_irqrestore(&common->lock, flags);
  
  	status = status & ~mask;
  
  	/*
  	 * check the status
  	 */
  	rcar_thermal_for_each_priv(priv, common) {
  		if (rcar_thermal_had_changed(priv, status)) {
  			rcar_thermal_irq_disable(priv);
3a3138621   Geert Uytterhoeven   thermal: rcar_the...
436
437
  			queue_delayed_work(system_freezable_wq, &priv->work,
  					   msecs_to_jiffies(300));
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
438
439
440
441
442
443
444
  		}
  	}
  
  	return IRQ_HANDLED;
  }
  
  /*
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
445
446
   *		platform functions
   */
84f0e490b   Kuninori Morimoto   thermal: rcar_the...
447
448
449
450
451
452
453
  static int rcar_thermal_remove(struct platform_device *pdev)
  {
  	struct rcar_thermal_common *common = platform_get_drvdata(pdev);
  	struct device *dev = &pdev->dev;
  	struct rcar_thermal_priv *priv;
  
  	rcar_thermal_for_each_priv(priv, common) {
ffbcdf8a7   Kuninori Morimoto   thermal: rcar: ch...
454
  		rcar_thermal_irq_disable(priv);
697ee786f   Geert Uytterhoeven   thermal: rcar_the...
455
  		cancel_delayed_work_sync(&priv->work);
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
456
  		if (priv->chip->use_of_thermal)
64a411e80   Kuninori Morimoto   thermal: rcar-the...
457
  			thermal_remove_hwmon_sysfs(priv->zone);
d4b23c5c4   Bui Duc Phuc   thermal: rcar_the...
458
459
  		else
  			thermal_zone_device_unregister(priv->zone);
84f0e490b   Kuninori Morimoto   thermal: rcar_the...
460
461
462
463
464
465
466
  	}
  
  	pm_runtime_put(dev);
  	pm_runtime_disable(dev);
  
  	return 0;
  }
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
467
468
  static int rcar_thermal_probe(struct platform_device *pdev)
  {
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
469
  	struct rcar_thermal_common *common;
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
470
  	struct rcar_thermal_priv *priv;
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
471
472
  	struct device *dev = &pdev->dev;
  	struct resource *res, *irq;
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
473
  	const struct rcar_thermal_chip *chip = of_device_get_match_data(dev);
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
474
475
  	int mres = 0;
  	int i;
fb84d9907   Devendra Naga   thermal: rcar_the...
476
  	int ret = -ENODEV;
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
477
  	int idle = IDLE_INTERVAL;
113137465   Yoshihiro Shimoda   thermal: rcar: fi...
478
  	u32 enr_bits = 0;
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
479

3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
480
  	common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
b0a60d88d   Jingoo Han   thermal: rcar: re...
481
  	if (!common)
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
482
  		return -ENOMEM;
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
483

84f0e490b   Kuninori Morimoto   thermal: rcar_the...
484
  	platform_set_drvdata(pdev, common);
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
485
  	INIT_LIST_HEAD(&common->head);
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
486
  	spin_lock_init(&common->lock);
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
487
  	common->dev = dev;
51d45d259   Kuninori Morimoto   thermal: rcar: ad...
488
489
  	pm_runtime_enable(dev);
  	pm_runtime_get_sync(dev);
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
490
  	for (i = 0; i < chip->nirqs; i++) {
df016bbba   Sergei Shtylyov   thermal: rcar_the...
491
  		irq = platform_get_resource(pdev, IORESOURCE_IRQ, i);
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
492
493
494
495
496
497
498
499
500
501
502
  		if (!irq)
  			continue;
  		if (!common->base) {
  			/*
  			 * platform has IRQ support.
  			 * Then, driver uses common registers
  			 * rcar_has_irq_support() will be enabled
  			 */
  			res = platform_get_resource(pdev, IORESOURCE_MEM,
  						    mres++);
  			common->base = devm_ioremap_resource(dev, res);
157ff8866   Niklas Söderlund   thermal: rcar_the...
503
504
505
506
  			if (IS_ERR(common->base)) {
  				ret = PTR_ERR(common->base);
  				goto error_unregister;
  			}
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
507
508
509
  
  			idle = 0; /* polling delay is not needed */
  		}
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
510

1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
511
512
513
514
515
516
517
518
519
520
521
  		ret = devm_request_irq(dev, irq->start, rcar_thermal_irq,
  				       IRQF_SHARED, dev_name(dev), common);
  		if (ret) {
  			dev_err(dev, "irq request failed
   ");
  			goto error_unregister;
  		}
  
  		/* update ENR bits */
  		if (chip->irq_per_ch)
  			enr_bits |= 1 << i;
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
522
  	}
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
523
524
525
526
527
528
529
  	for (i = 0;; i++) {
  		res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
  		if (!res)
  			break;
  
  		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  		if (!priv) {
1dc20828e   Kuninori Morimoto   thermal: rcar: ti...
530
531
  			ret = -ENOMEM;
  			goto error_unregister;
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
532
  		}
5095526fa   Sachin Kamat   Thermal: rcar: Co...
533
  		priv->base = devm_ioremap_resource(dev, res);
1dc20828e   Kuninori Morimoto   thermal: rcar: ti...
534
535
536
537
  		if (IS_ERR(priv->base)) {
  			ret = PTR_ERR(priv->base);
  			goto error_unregister;
  		}
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
538
539
  
  		priv->common = common;
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
540
  		priv->id = i;
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
541
  		priv->chip = chip;
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
542
543
  		mutex_init(&priv->lock);
  		INIT_LIST_HEAD(&priv->list);
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
544
  		INIT_DELAYED_WORK(&priv->work, rcar_thermal_work);
a1ade5653   Kuninori Morimoto   thermal: rcar: ch...
545
546
547
  		ret = rcar_thermal_update_temp(priv);
  		if (ret < 0)
  			goto error_unregister;
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
548

1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
549
  		if (chip->use_of_thermal)
5e325868a   Eduardo Valentin   thermal: convert ...
550
  			priv->zone = devm_thermal_zone_of_sensor_register(
8b477ea56   Kuninori Morimoto   thermal: rcar: en...
551
552
553
554
555
  						dev, i, priv,
  						&rcar_thermal_zone_of_ops);
  		else
  			priv->zone = thermal_zone_device_register(
  						"rcar_thermal",
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
556
557
  						1, 0, priv,
  						&rcar_thermal_zone_ops, NULL, 0,
e0a5172e9   Kuninori Morimoto   thermal: rcar: ad...
558
  						idle);
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
559
560
561
  		if (IS_ERR(priv->zone)) {
  			dev_err(dev, "can't register thermal zone
  ");
fb84d9907   Devendra Naga   thermal: rcar_the...
562
  			ret = PTR_ERR(priv->zone);
87260d3f7   Dirk Behme   thermal: rcar_the...
563
  			priv->zone = NULL;
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
564
565
  			goto error_unregister;
  		}
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
566
  		if (chip->use_of_thermal) {
64a411e80   Kuninori Morimoto   thermal: rcar-the...
567
568
569
570
571
572
573
574
575
  			/*
  			 * thermal_zone doesn't enable hwmon as default,
  			 * but, enable it here to keep compatible
  			 */
  			priv->zone->tzp->no_hwmon = false;
  			ret = thermal_add_hwmon_sysfs(priv->zone);
  			if (ret)
  				goto error_unregister;
  		}
ffbcdf8a7   Kuninori Morimoto   thermal: rcar: ch...
576
  		rcar_thermal_irq_enable(priv);
1dc20828e   Kuninori Morimoto   thermal: rcar: ti...
577
578
  
  		list_move_tail(&priv->list, &common->head);
113137465   Yoshihiro Shimoda   thermal: rcar: fi...
579
580
  
  		/* update ENR bits */
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
581
582
  		if (!chip->irq_per_ch)
  			enr_bits |= 3 << (i * 8);
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
583
  	}
542cdf406   Simon Horman   thermal: rcar_the...
584
  	if (common->base && enr_bits)
113137465   Yoshihiro Shimoda   thermal: rcar: fi...
585
  		rcar_thermal_common_write(common, ENR, enr_bits);
3db46c939   Laurent Pinchart   thermal: rcar: Fi...
586
587
  	dev_info(dev, "%d sensor probed
  ", i);
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
588
589
  
  	return 0;
3676d1dd3   Kuninori Morimoto   thermal: rcar: mu...
590
591
  
  error_unregister:
84f0e490b   Kuninori Morimoto   thermal: rcar_the...
592
  	rcar_thermal_remove(pdev);
51d45d259   Kuninori Morimoto   thermal: rcar: ad...
593

fb84d9907   Devendra Naga   thermal: rcar_the...
594
  	return ret;
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
595
  }
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
  #ifdef CONFIG_PM_SLEEP
  static int rcar_thermal_suspend(struct device *dev)
  {
  	struct rcar_thermal_common *common = dev_get_drvdata(dev);
  	struct rcar_thermal_priv *priv = list_first_entry(&common->head,
  							  typeof(*priv), list);
  
  	if (priv->chip->needs_suspend_resume) {
  		rcar_thermal_common_write(common, ENR, 0);
  		rcar_thermal_irq_disable(priv);
  		rcar_thermal_bset(priv, THSCR, CPCTL, 0);
  	}
  
  	return 0;
  }
  
  static int rcar_thermal_resume(struct device *dev)
  {
  	struct rcar_thermal_common *common = dev_get_drvdata(dev);
  	struct rcar_thermal_priv *priv = list_first_entry(&common->head,
  							  typeof(*priv), list);
  	int ret;
  
  	if (priv->chip->needs_suspend_resume) {
  		ret = rcar_thermal_update_temp(priv);
  		if (ret < 0)
  			return ret;
  		rcar_thermal_irq_enable(priv);
  		rcar_thermal_common_write(common, ENR, 0x03);
  	}
  
  	return 0;
  }
  #endif
  
  static SIMPLE_DEV_PM_OPS(rcar_thermal_pm_ops, rcar_thermal_suspend,
  			 rcar_thermal_resume);
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
633
634
635
  static struct platform_driver rcar_thermal_driver = {
  	.driver	= {
  		.name	= "rcar_thermal",
1969d9dc2   Yoshihiro Kaneko   thermal: rcar_the...
636
  		.pm = &rcar_thermal_pm_ops,
76cc18874   Kuninori Morimoto   thermal: rcar: ad...
637
  		.of_match_table = rcar_thermal_dt_ids,
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
638
639
640
641
642
  	},
  	.probe		= rcar_thermal_probe,
  	.remove		= rcar_thermal_remove,
  };
  module_platform_driver(rcar_thermal_driver);
c95457908   Kuninori Morimoto   thermal: rcar_the...
643
  MODULE_LICENSE("GPL v2");
1e426ffdd   Kuninori Morimoto   thermal: add Rene...
644
645
  MODULE_DESCRIPTION("R-Car THS/TSC thermal sensor driver");
  MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");