Blame view

drivers/thermal/rcar_gen3_thermal.c 13 KB
d316522d0   Kuninori Morimoto   thermal: rcar_gen...
1
  // SPDX-License-Identifier: GPL-2.0
564e73d28   Wolfram Sang   thermal: rcar_gen...
2
3
4
5
6
7
  /*
   *  R-Car Gen3 THS thermal sensor driver
   *  Based on rcar_thermal.c and work from Hien Dang and Khiem Nguyen.
   *
   * Copyright (C) 2016 Renesas Electronics Corporation.
   * Copyright (C) 2016 Sang Engineering
564e73d28   Wolfram Sang   thermal: rcar_gen...
8
9
10
11
12
13
   */
  #include <linux/delay.h>
  #include <linux/err.h>
  #include <linux/interrupt.h>
  #include <linux/io.h>
  #include <linux/module.h>
564e73d28   Wolfram Sang   thermal: rcar_gen...
14
15
16
  #include <linux/of_device.h>
  #include <linux/platform_device.h>
  #include <linux/pm_runtime.h>
d668c807a   Niklas Söderlund   thermal: rcar_gen...
17
  #include <linux/sys_soc.h>
564e73d28   Wolfram Sang   thermal: rcar_gen...
18
  #include <linux/thermal.h>
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
19
  #include "thermal_core.h"
6269e9f79   Marek Vasut   thermal: rcar_gen...
20
  #include "thermal_hwmon.h"
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
21

564e73d28   Wolfram Sang   thermal: rcar_gen...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  /* Register offsets */
  #define REG_GEN3_IRQSTR		0x04
  #define REG_GEN3_IRQMSK		0x08
  #define REG_GEN3_IRQCTL		0x0C
  #define REG_GEN3_IRQEN		0x10
  #define REG_GEN3_IRQTEMP1	0x14
  #define REG_GEN3_IRQTEMP2	0x18
  #define REG_GEN3_IRQTEMP3	0x1C
  #define REG_GEN3_CTSR		0x20
  #define REG_GEN3_THCTR		0x20
  #define REG_GEN3_TEMP		0x28
  #define REG_GEN3_THCODE1	0x50
  #define REG_GEN3_THCODE2	0x54
  #define REG_GEN3_THCODE3	0x58
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
36
37
38
39
40
41
42
  /* IRQ{STR,MSK,EN} bits */
  #define IRQ_TEMP1		BIT(0)
  #define IRQ_TEMP2		BIT(1)
  #define IRQ_TEMP3		BIT(2)
  #define IRQ_TEMPD1		BIT(3)
  #define IRQ_TEMPD2		BIT(4)
  #define IRQ_TEMPD3		BIT(5)
564e73d28   Wolfram Sang   thermal: rcar_gen...
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  /* CTSR bits */
  #define CTSR_PONM	BIT(8)
  #define CTSR_AOUT	BIT(7)
  #define CTSR_THBGR	BIT(5)
  #define CTSR_VMEN	BIT(4)
  #define CTSR_VMST	BIT(1)
  #define CTSR_THSST	BIT(0)
  
  /* THCTR bits */
  #define THCTR_PONM	BIT(6)
  #define THCTR_THSST	BIT(0)
  
  #define CTEMP_MASK	0xFFF
  
  #define MCELSIUS(temp)	((temp) * 1000)
  #define GEN3_FUSE_MASK	0xFFF
  
  #define TSC_MAX_NUM	3
6a310f8f9   Yoshihiro Kaneko   thermal: rcar_gen...
61
  /* default THCODE values if FUSEs are missing */
679d10df7   Niklas Söderlund   thermal: rcar_gen...
62
  static const int thcodes[TSC_MAX_NUM][3] = {
6a310f8f9   Yoshihiro Kaneko   thermal: rcar_gen...
63
64
65
66
  	{ 3397, 2800, 2221 },
  	{ 3393, 2795, 2216 },
  	{ 3389, 2805, 2237 },
  };
564e73d28   Wolfram Sang   thermal: rcar_gen...
67
68
69
70
71
72
73
74
75
76
77
78
  /* Structure for thermal temperature calculation */
  struct equation_coefs {
  	int a1;
  	int b1;
  	int a2;
  	int b2;
  };
  
  struct rcar_gen3_thermal_tsc {
  	void __iomem *base;
  	struct thermal_zone_device *zone;
  	struct equation_coefs coef;
bdc4480a6   Yoshihiro Kaneko   thermal: rcar_gen...
79
  	int tj_t;
6a310f8f9   Yoshihiro Kaneko   thermal: rcar_gen...
80
  	int id; /* thermal channel id */
564e73d28   Wolfram Sang   thermal: rcar_gen...
81
82
83
84
  };
  
  struct rcar_gen3_thermal_priv {
  	struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
97dad1f1d   Niklas Söderlund   thermal: rcar_gen...
85
  	unsigned int num_tscs;
564e73d28   Wolfram Sang   thermal: rcar_gen...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  	void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc);
  };
  
  static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc,
  					 u32 reg)
  {
  	return ioread32(tsc->base + reg);
  }
  
  static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
  					   u32 reg, u32 data)
  {
  	iowrite32(data, tsc->base + reg);
  }
  
  /*
   * Linear approximation for temperature
   *
   * [reg] = [temp] * a + b => [temp] = ([reg] - b) / a
   *
   * The constants a and b are calculated using two triplets of int values PTAT
   * and THCODE. PTAT and THCODE can either be read from hardware or use hard
   * coded values from driver. The formula to calculate a and b are taken from
   * BSP and sparsely documented and understood.
   *
   * Examining the linear formula and the formula used to calculate constants a
   * and b while knowing that the span for PTAT and THCODE values are between
   * 0x000 and 0xfff the largest integer possible is 0xfff * 0xfff == 0xffe001.
   * Integer also needs to be signed so that leaves 7 bits for binary
   * fixed point scaling.
   */
  
  #define FIXPT_SHIFT 7
  #define FIXPT_INT(_x) ((_x) << FIXPT_SHIFT)
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
120
  #define INT_FIXPT(_x) ((_x) >> FIXPT_SHIFT)
564e73d28   Wolfram Sang   thermal: rcar_gen...
121
122
123
124
125
126
  #define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b))
  #define FIXPT_TO_MCELSIUS(_x) ((_x) * 1000 >> FIXPT_SHIFT)
  
  #define RCAR3_THERMAL_GRAN 500 /* mili Celsius */
  
  /* no idea where these constants come from */
564e73d28   Wolfram Sang   thermal: rcar_gen...
127
  #define TJ_3 -41
bdc4480a6   Yoshihiro Kaneko   thermal: rcar_gen...
128
  static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc,
6a310f8f9   Yoshihiro Kaneko   thermal: rcar_gen...
129
  					 int *ptat, const int *thcode,
4eb39f79e   Yoshihiro Kaneko   thermal: rcar_gen...
130
  					 int ths_tj_1)
564e73d28   Wolfram Sang   thermal: rcar_gen...
131
  {
564e73d28   Wolfram Sang   thermal: rcar_gen...
132
133
134
135
136
137
  	/* TODO: Find documentation and document constant calculation formula */
  
  	/*
  	 * Division is not scaled in BSP and if scaled it might overflow
  	 * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled
  	 */
bdc4480a6   Yoshihiro Kaneko   thermal: rcar_gen...
138
139
  	tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * 157)
  		     / (ptat[0] - ptat[2])) + FIXPT_INT(TJ_3);
564e73d28   Wolfram Sang   thermal: rcar_gen...
140

bdc4480a6   Yoshihiro Kaneko   thermal: rcar_gen...
141
142
143
  	tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]),
  				 tsc->tj_t - FIXPT_INT(TJ_3));
  	tsc->coef.b1 = FIXPT_INT(thcode[2]) - tsc->coef.a1 * TJ_3;
564e73d28   Wolfram Sang   thermal: rcar_gen...
144

bdc4480a6   Yoshihiro Kaneko   thermal: rcar_gen...
145
146
147
  	tsc->coef.a2 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[0]),
  				 tsc->tj_t - FIXPT_INT(ths_tj_1));
  	tsc->coef.b2 = FIXPT_INT(thcode[0]) - tsc->coef.a2 * ths_tj_1;
564e73d28   Wolfram Sang   thermal: rcar_gen...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  }
  
  static int rcar_gen3_thermal_round(int temp)
  {
  	int result, round_offs;
  
  	round_offs = temp >= 0 ? RCAR3_THERMAL_GRAN / 2 :
  		-RCAR3_THERMAL_GRAN / 2;
  	result = (temp + round_offs) / RCAR3_THERMAL_GRAN;
  	return result * RCAR3_THERMAL_GRAN;
  }
  
  static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
  {
  	struct rcar_gen3_thermal_tsc *tsc = devdata;
6a310f8f9   Yoshihiro Kaneko   thermal: rcar_gen...
163
  	int mcelsius, val;
5f8f06425   Dien Pham   thermal/drivers/r...
164
  	int reg;
564e73d28   Wolfram Sang   thermal: rcar_gen...
165
166
  
  	/* Read register and convert to mili Celsius */
564e73d28   Wolfram Sang   thermal: rcar_gen...
167
  	reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
679d10df7   Niklas Söderlund   thermal: rcar_gen...
168
  	if (reg <= thcodes[tsc->id][1])
6a310f8f9   Yoshihiro Kaneko   thermal: rcar_gen...
169
170
171
172
173
174
  		val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1,
  				tsc->coef.a1);
  	else
  		val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2,
  				tsc->coef.a2);
  	mcelsius = FIXPT_TO_MCELSIUS(val);
564e73d28   Wolfram Sang   thermal: rcar_gen...
175

0f510a245   Niklas Söderlund   thermal: rcar_gen...
176
  	/* Guaranteed operating range is -40C to 125C. */
564e73d28   Wolfram Sang   thermal: rcar_gen...
177
178
179
180
181
182
  
  	/* Round value to device granularity setting */
  	*temp = rcar_gen3_thermal_round(mcelsius);
  
  	return 0;
  }
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
183
184
185
  static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,
  					      int mcelsius)
  {
bdc4480a6   Yoshihiro Kaneko   thermal: rcar_gen...
186
  	int celsius, val;
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
187
188
  
  	celsius = DIV_ROUND_CLOSEST(mcelsius, 1000);
bdc4480a6   Yoshihiro Kaneko   thermal: rcar_gen...
189
190
191
192
  	if (celsius <= INT_FIXPT(tsc->tj_t))
  		val = celsius * tsc->coef.a1 + tsc->coef.b1;
  	else
  		val = celsius * tsc->coef.a2 + tsc->coef.b2;
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
193

bdc4480a6   Yoshihiro Kaneko   thermal: rcar_gen...
194
  	return INT_FIXPT(val);
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
195
  }
267c4d8d1   Niklas Söderlund   thermal: rcar_gen...
196
  static int rcar_gen3_thermal_update_range(struct rcar_gen3_thermal_tsc *tsc)
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
197
  {
267c4d8d1   Niklas Söderlund   thermal: rcar_gen...
198
199
200
  	int temperature, low, high;
  
  	rcar_gen3_thermal_get_temp(tsc, &temperature);
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
201

267c4d8d1   Niklas Söderlund   thermal: rcar_gen...
202
203
  	low = temperature - MCELSIUS(1);
  	high = temperature + MCELSIUS(1);
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
204
205
206
207
208
209
210
211
212
  
  	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1,
  				rcar_gen3_thermal_mcelsius_to_temp(tsc, low));
  
  	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2,
  				rcar_gen3_thermal_mcelsius_to_temp(tsc, high));
  
  	return 0;
  }
a0def10b6   Julia Lawall   thermal: rcar_gen...
213
  static const struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
564e73d28   Wolfram Sang   thermal: rcar_gen...
214
215
  	.get_temp	= rcar_gen3_thermal_get_temp,
  };
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
216
217
218
219
220
221
222
223
224
225
226
227
228
  static void rcar_thermal_irq_set(struct rcar_gen3_thermal_priv *priv, bool on)
  {
  	unsigned int i;
  	u32 val = on ? IRQ_TEMPD1 | IRQ_TEMP2 : 0;
  
  	for (i = 0; i < priv->num_tscs; i++)
  		rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQMSK, val);
  }
  
  static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
  {
  	struct rcar_gen3_thermal_priv *priv = data;
  	u32 status;
2c0928c9e   Jiada Wang   thermal: rcar_gen...
229
  	int i;
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
230

7d4b26977   Niklas Söderlund   thermal: rcar_gen...
231
232
233
  	for (i = 0; i < priv->num_tscs; i++) {
  		status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR);
  		rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0);
267c4d8d1   Niklas Söderlund   thermal: rcar_gen...
234
235
  		if (status) {
  			rcar_gen3_thermal_update_range(priv->tscs[i]);
2c0928c9e   Jiada Wang   thermal: rcar_gen...
236
237
  			thermal_zone_device_update(priv->tscs[i]->zone,
  						   THERMAL_EVENT_UNSPECIFIED);
267c4d8d1   Niklas Söderlund   thermal: rcar_gen...
238
  		}
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
239
  	}
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
240
241
  	return IRQ_HANDLED;
  }
d668c807a   Niklas Söderlund   thermal: rcar_gen...
242
243
244
245
246
247
  static const struct soc_device_attribute r8a7795es1[] = {
  	{ .soc_id = "r8a7795", .revision = "ES1.*" },
  	{ /* sentinel */ }
  };
  
  static void rcar_gen3_thermal_init_r8a7795es1(struct rcar_gen3_thermal_tsc *tsc)
564e73d28   Wolfram Sang   thermal: rcar_gen...
248
249
250
251
252
253
254
  {
  	rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,  CTSR_THBGR);
  	rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,  0x0);
  
  	usleep_range(1000, 2000);
  
  	rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_PONM);
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
255

564e73d28   Wolfram Sang   thermal: rcar_gen...
256
  	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
257
258
  	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
  	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2);
564e73d28   Wolfram Sang   thermal: rcar_gen...
259
260
261
262
263
264
265
266
267
268
269
  	rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
  				CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN);
  
  	usleep_range(100, 200);
  
  	rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
  				CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN |
  				CTSR_VMST | CTSR_THSST);
  
  	usleep_range(1000, 2000);
  }
d668c807a   Niklas Söderlund   thermal: rcar_gen...
270
  static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
564e73d28   Wolfram Sang   thermal: rcar_gen...
271
272
273
274
275
276
277
278
  {
  	u32 reg_val;
  
  	reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
  	reg_val &= ~THCTR_PONM;
  	rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
  
  	usleep_range(1000, 2000);
ed1b1ac14   Hoan Nguyen An   thermal: rcar_gen...
279
  	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0);
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
280
281
  	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
  	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2);
564e73d28   Wolfram Sang   thermal: rcar_gen...
282
283
284
  	reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
  	reg_val |= THCTR_THSST;
  	rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
78aefd2d5   Niklas Söderlund   thermal: rcar_gen...
285
286
  
  	usleep_range(1000, 2000);
564e73d28   Wolfram Sang   thermal: rcar_gen...
287
  }
4eb39f79e   Yoshihiro Kaneko   thermal: rcar_gen...
288
289
  static const int rcar_gen3_ths_tj_1 = 126;
  static const int rcar_gen3_ths_tj_1_m3_w = 116;
564e73d28   Wolfram Sang   thermal: rcar_gen...
290
  static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
4eb39f79e   Yoshihiro Kaneko   thermal: rcar_gen...
291
292
293
294
295
  	{
  		.compatible = "renesas,r8a774a1-thermal",
  		.data = &rcar_gen3_ths_tj_1_m3_w,
  	},
  	{
1a0059124   Biju Das   thermal: rcar_gen...
296
297
298
299
  		.compatible = "renesas,r8a774b1-thermal",
  		.data = &rcar_gen3_ths_tj_1,
  	},
  	{
947d85f00   Marian-Cristian Rotariu   thermal: rcar_gen...
300
301
302
303
  		.compatible = "renesas,r8a774e1-thermal",
  		.data = &rcar_gen3_ths_tj_1,
  	},
  	{
4eb39f79e   Yoshihiro Kaneko   thermal: rcar_gen...
304
305
306
307
308
309
310
311
  		.compatible = "renesas,r8a7795-thermal",
  		.data = &rcar_gen3_ths_tj_1,
  	},
  	{
  		.compatible = "renesas,r8a7796-thermal",
  		.data = &rcar_gen3_ths_tj_1_m3_w,
  	},
  	{
8d74bf79d   Geert Uytterhoeven   thermal: rcar_gen...
312
313
314
315
  		.compatible = "renesas,r8a77961-thermal",
  		.data = &rcar_gen3_ths_tj_1_m3_w,
  	},
  	{
4eb39f79e   Yoshihiro Kaneko   thermal: rcar_gen...
316
317
318
319
320
321
322
  		.compatible = "renesas,r8a77965-thermal",
  		.data = &rcar_gen3_ths_tj_1,
  	},
  	{
  		.compatible = "renesas,r8a77980-thermal",
  		.data = &rcar_gen3_ths_tj_1,
  	},
564e73d28   Wolfram Sang   thermal: rcar_gen...
323
324
325
326
327
328
329
  	{},
  };
  MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
  
  static int rcar_gen3_thermal_remove(struct platform_device *pdev)
  {
  	struct device *dev = &pdev->dev;
63f55fcea   Jiada Wang   thermal: rcar_gen...
330
331
332
  	struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
  
  	rcar_thermal_irq_set(priv, false);
564e73d28   Wolfram Sang   thermal: rcar_gen...
333
334
335
336
337
338
  
  	pm_runtime_put(dev);
  	pm_runtime_disable(dev);
  
  	return 0;
  }
6269e9f79   Marek Vasut   thermal: rcar_gen...
339
340
341
342
343
344
  static void rcar_gen3_hwmon_action(void *data)
  {
  	struct thermal_zone_device *zone = data;
  
  	thermal_remove_hwmon_sysfs(zone);
  }
564e73d28   Wolfram Sang   thermal: rcar_gen...
345
346
347
348
  static int rcar_gen3_thermal_probe(struct platform_device *pdev)
  {
  	struct rcar_gen3_thermal_priv *priv;
  	struct device *dev = &pdev->dev;
4eb39f79e   Yoshihiro Kaneko   thermal: rcar_gen...
349
  	const int *rcar_gen3_ths_tj_1 = of_device_get_match_data(dev);
564e73d28   Wolfram Sang   thermal: rcar_gen...
350
351
  	struct resource *res;
  	struct thermal_zone_device *zone;
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
352
353
  	int ret, irq, i;
  	char *irqname;
564e73d28   Wolfram Sang   thermal: rcar_gen...
354
355
356
  
  	/* default values if FUSEs are missing */
  	/* TODO: Read values from hardware on supported platforms */
fc66ddff3   Hien Dang   thermal: rcar_gen...
357
  	int ptat[3] = { 2631, 1509, 435 };
564e73d28   Wolfram Sang   thermal: rcar_gen...
358
359
360
361
  
  	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  	if (!priv)
  		return -ENOMEM;
d668c807a   Niklas Söderlund   thermal: rcar_gen...
362
363
364
  	priv->thermal_init = rcar_gen3_thermal_init;
  	if (soc_device_match(r8a7795es1))
  		priv->thermal_init = rcar_gen3_thermal_init_r8a7795es1;
cc4d072b6   Niklas Söderlund   thermal: rcar_gen...
365

564e73d28   Wolfram Sang   thermal: rcar_gen...
366
  	platform_set_drvdata(pdev, priv);
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
367
368
369
370
371
372
373
374
375
376
377
378
379
380
  	/*
  	 * Request 2 (of the 3 possible) IRQs, the driver only needs to
  	 * to trigger on the low and high trip points of the current
  	 * temp window at this point.
  	 */
  	for (i = 0; i < 2; i++) {
  		irq = platform_get_irq(pdev, i);
  		if (irq < 0)
  			return irq;
  
  		irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:ch%d",
  					 dev_name(dev), i);
  		if (!irqname)
  			return -ENOMEM;
2c0928c9e   Jiada Wang   thermal: rcar_gen...
381
382
383
  		ret = devm_request_threaded_irq(dev, irq, NULL,
  						rcar_gen3_thermal_irq,
  						IRQF_ONESHOT, irqname, priv);
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
384
385
386
  		if (ret)
  			return ret;
  	}
564e73d28   Wolfram Sang   thermal: rcar_gen...
387
388
389
390
391
  	pm_runtime_enable(dev);
  	pm_runtime_get_sync(dev);
  
  	for (i = 0; i < TSC_MAX_NUM; i++) {
  		struct rcar_gen3_thermal_tsc *tsc;
d51546c0d   Niklas Söderlund   thermal: rcar_gen...
392
393
394
  		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
  		if (!res)
  			break;
564e73d28   Wolfram Sang   thermal: rcar_gen...
395
396
397
398
399
  		tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL);
  		if (!tsc) {
  			ret = -ENOMEM;
  			goto error_unregister;
  		}
564e73d28   Wolfram Sang   thermal: rcar_gen...
400
401
402
403
404
  		tsc->base = devm_ioremap_resource(dev, res);
  		if (IS_ERR(tsc->base)) {
  			ret = PTR_ERR(tsc->base);
  			goto error_unregister;
  		}
6a310f8f9   Yoshihiro Kaneko   thermal: rcar_gen...
405
  		tsc->id = i;
564e73d28   Wolfram Sang   thermal: rcar_gen...
406
407
  
  		priv->tscs[i] = tsc;
564e73d28   Wolfram Sang   thermal: rcar_gen...
408

d668c807a   Niklas Söderlund   thermal: rcar_gen...
409
  		priv->thermal_init(tsc);
679d10df7   Niklas Söderlund   thermal: rcar_gen...
410
  		rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i],
4eb39f79e   Yoshihiro Kaneko   thermal: rcar_gen...
411
  					     *rcar_gen3_ths_tj_1);
564e73d28   Wolfram Sang   thermal: rcar_gen...
412
413
414
415
416
417
418
419
420
421
  
  		zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
  							    &rcar_gen3_tz_of_ops);
  		if (IS_ERR(zone)) {
  			dev_err(dev, "Can't register thermal zone
  ");
  			ret = PTR_ERR(zone);
  			goto error_unregister;
  		}
  		tsc->zone = zone;
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
422

6269e9f79   Marek Vasut   thermal: rcar_gen...
423
424
425
426
  		tsc->zone->tzp->no_hwmon = false;
  		ret = thermal_add_hwmon_sysfs(tsc->zone);
  		if (ret)
  			goto error_unregister;
b9cd1663f   Fuqian Huang   thermal: rcar_gen...
427
  		ret = devm_add_action_or_reset(dev, rcar_gen3_hwmon_action, zone);
d543c8424   Niklas Söderlund   thermal: rcar_gen...
428
  		if (ret)
6269e9f79   Marek Vasut   thermal: rcar_gen...
429
  			goto error_unregister;
6269e9f79   Marek Vasut   thermal: rcar_gen...
430

e380ea811   Jiada Wang   thermal: rcar_gen...
431
432
433
  		ret = of_thermal_get_ntrips(tsc->zone);
  		if (ret < 0)
  			goto error_unregister;
267c4d8d1   Niklas Söderlund   thermal: rcar_gen...
434
  		rcar_gen3_thermal_update_range(tsc);
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
435
436
  		dev_info(dev, "TSC%d: Loaded %d trip points
  ", i, ret);
564e73d28   Wolfram Sang   thermal: rcar_gen...
437
  	}
97dad1f1d   Niklas Söderlund   thermal: rcar_gen...
438
439
440
441
442
443
  	priv->num_tscs = i;
  
  	if (!priv->num_tscs) {
  		ret = -ENODEV;
  		goto error_unregister;
  	}
7d4b26977   Niklas Söderlund   thermal: rcar_gen...
444
  	rcar_thermal_irq_set(priv, true);
564e73d28   Wolfram Sang   thermal: rcar_gen...
445
446
447
448
449
450
451
  	return 0;
  
  error_unregister:
  	rcar_gen3_thermal_remove(pdev);
  
  	return ret;
  }
75f78d6d9   Niklas Söderlund   thermal: rcar_gen...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
  static int __maybe_unused rcar_gen3_thermal_suspend(struct device *dev)
  {
  	struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
  
  	rcar_thermal_irq_set(priv, false);
  
  	return 0;
  }
  
  static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)
  {
  	struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
  	unsigned int i;
  
  	for (i = 0; i < priv->num_tscs; i++) {
  		struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
d668c807a   Niklas Söderlund   thermal: rcar_gen...
468
  		priv->thermal_init(tsc);
267c4d8d1   Niklas Söderlund   thermal: rcar_gen...
469
  		rcar_gen3_thermal_update_range(tsc);
75f78d6d9   Niklas Söderlund   thermal: rcar_gen...
470
471
472
473
474
475
476
477
478
  	}
  
  	rcar_thermal_irq_set(priv, true);
  
  	return 0;
  }
  
  static SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops, rcar_gen3_thermal_suspend,
  			 rcar_gen3_thermal_resume);
564e73d28   Wolfram Sang   thermal: rcar_gen...
479
480
481
  static struct platform_driver rcar_gen3_thermal_driver = {
  	.driver	= {
  		.name	= "rcar_gen3_thermal",
75f78d6d9   Niklas Söderlund   thermal: rcar_gen...
482
  		.pm = &rcar_gen3_thermal_pm_ops,
564e73d28   Wolfram Sang   thermal: rcar_gen...
483
484
485
486
487
488
489
490
491
492
  		.of_match_table = rcar_gen3_thermal_dt_ids,
  	},
  	.probe		= rcar_gen3_thermal_probe,
  	.remove		= rcar_gen3_thermal_remove,
  };
  module_platform_driver(rcar_gen3_thermal_driver);
  
  MODULE_LICENSE("GPL v2");
  MODULE_DESCRIPTION("R-Car Gen3 THS thermal sensor driver");
  MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>");