xref: /linux/drivers/thermal/renesas/rcar_gen3_thermal.c (revision 68a052239fc4b351e961f698b824f7654a346091)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  R-Car Gen3 THS thermal sensor driver
4  *  Based on rcar_thermal.c and work from Hien Dang and Khiem Nguyen.
5  *
6  * Copyright (C) 2016 Renesas Electronics Corporation.
7  * Copyright (C) 2016 Sang Engineering
8  */
9 #include <linux/delay.h>
10 #include <linux/err.h>
11 #include <linux/interrupt.h>
12 #include <linux/io.h>
13 #include <linux/module.h>
14 #include <linux/of.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/thermal.h>
18 
19 #include "../thermal_hwmon.h"
20 
21 /* Register offsets */
22 #define REG_GEN3_IRQSTR		0x04
23 #define REG_GEN3_IRQMSK		0x08
24 #define REG_GEN3_IRQCTL		0x0c
25 #define REG_GEN3_IRQEN		0x10
26 #define REG_GEN3_IRQTEMP1	0x14
27 #define REG_GEN3_IRQTEMP2	0x18
28 #define REG_GEN3_IRQTEMP3	0x1c
29 #define REG_GEN3_THCTR		0x20
30 #define REG_GEN3_TEMP		0x28
31 #define REG_GEN3_THCODE1	0x50
32 #define REG_GEN3_THCODE2	0x54
33 #define REG_GEN3_THCODE3	0x58
34 #define REG_GEN3_PTAT1		0x5c
35 #define REG_GEN3_PTAT2		0x60
36 #define REG_GEN3_PTAT3		0x64
37 #define REG_GEN3_THSCP		0x68
38 #define REG_GEN4_THSFMON00	0x180
39 #define REG_GEN4_THSFMON01	0x184
40 #define REG_GEN4_THSFMON02	0x188
41 #define REG_GEN4_THSFMON15	0x1bc
42 #define REG_GEN4_THSFMON16	0x1c0
43 #define REG_GEN4_THSFMON17	0x1c4
44 
45 /* IRQ{STR,MSK,EN} bits */
46 #define IRQ_TEMP1		BIT(0)
47 #define IRQ_TEMP2		BIT(1)
48 #define IRQ_TEMP3		BIT(2)
49 #define IRQ_TEMPD1		BIT(3)
50 #define IRQ_TEMPD2		BIT(4)
51 #define IRQ_TEMPD3		BIT(5)
52 
53 /* THCTR bits */
54 #define THCTR_PONM	BIT(6)
55 #define THCTR_THSST	BIT(0)
56 
57 /* THSCP bits */
58 #define THSCP_COR_PARA_VLD	(BIT(15) | BIT(14))
59 
60 #define CTEMP_MASK	0xfff
61 
62 #define MCELSIUS(temp)	((temp) * 1000)
63 #define GEN3_FUSE_MASK	0xfff
64 #define GEN4_FUSE_MASK	0xfff
65 
66 #define TSC_MAX_NUM	5
67 
68 struct rcar_gen3_thermal_priv;
69 
70 struct rcar_gen3_thermal_fuse_info {
71 	u32 ptat[3];
72 	u32 thcode[3];
73 	u32 mask;
74 };
75 
76 struct rcar_gen3_thermal_fuse_default {
77 	u32 ptat[3];
78 	u32 thcodes[TSC_MAX_NUM][3];
79 };
80 
81 struct rcar_thermal_info {
82 	int scale;
83 	int adj_below;
84 	int adj_above;
85 	const struct rcar_gen3_thermal_fuse_info *fuses;
86 	const struct rcar_gen3_thermal_fuse_default *fuse_defaults;
87 };
88 
89 struct equation_set_coef {
90 	int a;
91 	int b;
92 };
93 
94 struct rcar_gen3_thermal_tsc {
95 	struct rcar_gen3_thermal_priv *priv;
96 	void __iomem *base;
97 	struct thermal_zone_device *zone;
98 	/* Different coefficients are used depending on a threshold. */
99 	struct {
100 		struct equation_set_coef below;
101 		struct equation_set_coef above;
102 	} coef;
103 	int thcode[3];
104 };
105 
106 struct rcar_gen3_thermal_priv {
107 	struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
108 	struct thermal_zone_device_ops ops;
109 	unsigned int num_tscs;
110 	int ptat[3];
111 	int tj_t;
112 	const struct rcar_thermal_info *info;
113 };
114 
115 static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc,
116 					 u32 reg)
117 {
118 	return ioread32(tsc->base + reg);
119 }
120 
121 static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
122 					   u32 reg, u32 data)
123 {
124 	iowrite32(data, tsc->base + reg);
125 }
126 
127 /*
128  * Linear approximation for temperature
129  *
130  * [temp] = ((thadj - [reg]) * a) / b + adj
131  * [reg] = thadj - ([temp] - adj) * b / a
132  *
133  * The constants a and b are calculated using two triplets of int values PTAT
134  * and THCODE. PTAT and THCODE can either be read from hardware or use hard
135  * coded values from the driver. The formula to calculate a and b are taken from
136  * the datasheet. Different calculations are needed for a and b depending on
137  * if the input variables ([temp] or [reg]) are above or below a threshold. The
138  * threshold is also calculated from PTAT and THCODE using formulas from the
139  * datasheet.
140  *
141  * The constant thadj is one of the THCODE values, which one to use depends on
142  * the threshold and input value.
143  *
144  * The constants adj is taken verbatim from the datasheet. Two values exists,
145  * which one to use depends on the input value and the calculated threshold.
146  * Furthermore different SoC models supported by the driver have different sets
147  * of values. The values for each model are stored in the device match data.
148  */
149 
150 static void rcar_gen3_thermal_shared_coefs(struct rcar_gen3_thermal_priv *priv)
151 {
152 	priv->tj_t =
153 		DIV_ROUND_CLOSEST((priv->ptat[1] - priv->ptat[2]) * priv->info->scale,
154 				  priv->ptat[0] - priv->ptat[2])
155 		+ priv->info->adj_below;
156 }
157 static void rcar_gen3_thermal_tsc_coefs(struct rcar_gen3_thermal_priv *priv,
158 					struct rcar_gen3_thermal_tsc *tsc)
159 {
160 	tsc->coef.below.a = priv->info->scale * (priv->ptat[2] - priv->ptat[1]);
161 	tsc->coef.above.a = priv->info->scale * (priv->ptat[0] - priv->ptat[1]);
162 
163 	tsc->coef.below.b = (priv->ptat[2] - priv->ptat[0]) * (tsc->thcode[2] - tsc->thcode[1]);
164 	tsc->coef.above.b = (priv->ptat[0] - priv->ptat[2]) * (tsc->thcode[1] - tsc->thcode[0]);
165 }
166 
167 static int rcar_gen3_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
168 {
169 	struct rcar_gen3_thermal_tsc *tsc = thermal_zone_device_priv(tz);
170 	struct rcar_gen3_thermal_priv *priv = tsc->priv;
171 	const struct equation_set_coef *coef;
172 	int adj, decicelsius, reg, thcode;
173 
174 	/* Read register and convert to millidegree Celsius */
175 	reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
176 
177 	if (reg < tsc->thcode[1]) {
178 		adj = priv->info->adj_below;
179 		coef = &tsc->coef.below;
180 		thcode = tsc->thcode[2];
181 	} else {
182 		adj = priv->info->adj_above;
183 		coef = &tsc->coef.above;
184 		thcode = tsc->thcode[0];
185 	}
186 
187 	/*
188 	 * The dividend can't be grown as it might overflow, instead shorten the
189 	 * divisor to convert to decidegree Celsius. If we convert after the
190 	 * division precision is lost as we will scale up from whole degrees
191 	 * Celsius.
192 	 */
193 	decicelsius = DIV_ROUND_CLOSEST(coef->a * (thcode - reg), coef->b / 10);
194 
195 	/* Guaranteed operating range is -40C to 125C. */
196 
197 	/* Reporting is done in millidegree Celsius */
198 	*temp = decicelsius * 100 + adj * 1000;
199 
200 	return 0;
201 }
202 
203 static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,
204 					      int mcelsius)
205 {
206 	struct rcar_gen3_thermal_priv *priv = tsc->priv;
207 	const struct equation_set_coef *coef;
208 	int adj, celsius, thcode;
209 
210 	celsius = DIV_ROUND_CLOSEST(mcelsius, 1000);
211 	if (celsius < priv->tj_t) {
212 		coef = &tsc->coef.below;
213 		adj = priv->info->adj_below;
214 		thcode = tsc->thcode[2];
215 	} else {
216 		coef = &tsc->coef.above;
217 		adj = priv->info->adj_above;
218 		thcode = tsc->thcode[0];
219 	}
220 
221 	return thcode - DIV_ROUND_CLOSEST((celsius - adj) * coef->b, coef->a);
222 }
223 
224 static int rcar_gen3_thermal_set_trips(struct thermal_zone_device *tz, int low, int high)
225 {
226 	struct rcar_gen3_thermal_tsc *tsc = thermal_zone_device_priv(tz);
227 	u32 irqmsk = 0;
228 
229 	if (low != -INT_MAX) {
230 		irqmsk |= IRQ_TEMPD1;
231 		rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1,
232 					rcar_gen3_thermal_mcelsius_to_temp(tsc, low));
233 	}
234 
235 	if (high != INT_MAX) {
236 		irqmsk |= IRQ_TEMP2;
237 		rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2,
238 					rcar_gen3_thermal_mcelsius_to_temp(tsc, high));
239 	}
240 
241 	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, irqmsk);
242 
243 	return 0;
244 }
245 
246 static const struct thermal_zone_device_ops rcar_gen3_tz_of_ops = {
247 	.get_temp	= rcar_gen3_thermal_get_temp,
248 	.set_trips	= rcar_gen3_thermal_set_trips,
249 };
250 
251 static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
252 {
253 	struct rcar_gen3_thermal_priv *priv = data;
254 	unsigned int i;
255 	u32 status;
256 
257 	for (i = 0; i < priv->num_tscs; i++) {
258 		status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR);
259 		rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0);
260 		if (status && priv->tscs[i]->zone)
261 			thermal_zone_device_update(priv->tscs[i]->zone,
262 						   THERMAL_EVENT_UNSPECIFIED);
263 	}
264 
265 	return IRQ_HANDLED;
266 }
267 
268 static void rcar_gen3_thermal_fetch_fuses(struct rcar_gen3_thermal_priv *priv)
269 {
270 	const struct rcar_gen3_thermal_fuse_info *fuses = priv->info->fuses;
271 
272 	/*
273 	 * Set the pseudo calibration points with fused values.
274 	 * PTAT is shared between all TSCs but only fused for the first
275 	 * TSC while THCODEs are fused for each TSC.
276 	 */
277 	priv->ptat[0] = rcar_gen3_thermal_read(priv->tscs[0], fuses->ptat[0])
278 		& fuses->mask;
279 	priv->ptat[1] = rcar_gen3_thermal_read(priv->tscs[0], fuses->ptat[1])
280 		& fuses->mask;
281 	priv->ptat[2] = rcar_gen3_thermal_read(priv->tscs[0], fuses->ptat[2])
282 		& fuses->mask;
283 
284 	for (unsigned int i = 0; i < priv->num_tscs; i++) {
285 		struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
286 
287 		tsc->thcode[0] = rcar_gen3_thermal_read(tsc, fuses->thcode[0])
288 			& fuses->mask;
289 		tsc->thcode[1] = rcar_gen3_thermal_read(tsc, fuses->thcode[1])
290 			& fuses->mask;
291 		tsc->thcode[2] = rcar_gen3_thermal_read(tsc, fuses->thcode[2])
292 			& fuses->mask;
293 	}
294 }
295 
296 static bool rcar_gen3_thermal_read_fuses(struct rcar_gen3_thermal_priv *priv)
297 {
298 	const struct rcar_gen3_thermal_fuse_default *fuse_defaults = priv->info->fuse_defaults;
299 	unsigned int i;
300 	u32 thscp;
301 
302 	/* If fuses are not set, fallback to pseudo values. */
303 	thscp = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_THSCP);
304 	if (!priv->info->fuses ||
305 	    (thscp & THSCP_COR_PARA_VLD) != THSCP_COR_PARA_VLD) {
306 		/* Default THCODE values in case FUSEs are not set. */
307 		priv->ptat[0] = fuse_defaults->ptat[0];
308 		priv->ptat[1] = fuse_defaults->ptat[1];
309 		priv->ptat[2] = fuse_defaults->ptat[2];
310 
311 		for (i = 0; i < priv->num_tscs; i++) {
312 			struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
313 
314 			tsc->thcode[0] = fuse_defaults->thcodes[i][0];
315 			tsc->thcode[1] = fuse_defaults->thcodes[i][1];
316 			tsc->thcode[2] = fuse_defaults->thcodes[i][2];
317 		}
318 
319 		return false;
320 	}
321 
322 	rcar_gen3_thermal_fetch_fuses(priv);
323 
324 	return true;
325 }
326 
327 static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_priv *priv,
328 				   struct rcar_gen3_thermal_tsc *tsc)
329 {
330 	u32 reg_val;
331 
332 	reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
333 	reg_val &= ~THCTR_PONM;
334 	rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
335 
336 	usleep_range(1000, 2000);
337 
338 	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0);
339 	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
340 	if (priv->ops.set_trips)
341 		rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN,
342 					IRQ_TEMPD1 | IRQ_TEMP2);
343 
344 	reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
345 	reg_val |= THCTR_THSST;
346 	rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
347 
348 	usleep_range(1000, 2000);
349 }
350 
351 static const struct rcar_gen3_thermal_fuse_info rcar_gen3_thermal_fuse_info_gen3 = {
352 	.ptat = { REG_GEN3_PTAT1, REG_GEN3_PTAT2, REG_GEN3_PTAT3 },
353 	.thcode = { REG_GEN3_THCODE1, REG_GEN3_THCODE2, REG_GEN3_THCODE3 },
354 	.mask = GEN3_FUSE_MASK,
355 };
356 
357 static const struct rcar_gen3_thermal_fuse_info rcar_gen3_thermal_fuse_info_gen4 = {
358 	.ptat = { REG_GEN4_THSFMON16, REG_GEN4_THSFMON17, REG_GEN4_THSFMON15 },
359 	.thcode = { REG_GEN4_THSFMON01, REG_GEN4_THSFMON02, REG_GEN4_THSFMON00 },
360 	.mask = GEN4_FUSE_MASK,
361 };
362 
363 static const struct rcar_gen3_thermal_fuse_default rcar_gen3_thermal_fuse_default_info_gen3 = {
364 	.ptat = { 2631, 1509, 435 },
365 	.thcodes = {
366 		{ 3397, 2800, 2221 },
367 		{ 3393, 2795, 2216 },
368 		{ 3389, 2805, 2237 },
369 		{ 3415, 2694, 2195 },
370 		{ 3356, 2724, 2244 },
371 	},
372 };
373 
374 static const struct rcar_gen3_thermal_fuse_default rcar_gen3_thermal_fuse_default_info_gen4 = {
375 	.ptat = { 3274, 2164, 985 },
376 	.thcodes = { /* All four THS units share the same trimming */
377 		{ 3218, 2617, 1980 },
378 		{ 3218, 2617, 1980 },
379 		{ 3218, 2617, 1980 },
380 		{ 3218, 2617, 1980 },
381 	}
382 };
383 
384 static const struct rcar_thermal_info rcar_m3w_thermal_info = {
385 	.scale = 157,
386 	.adj_below = -41,
387 	.adj_above = 116,
388 	.fuses = &rcar_gen3_thermal_fuse_info_gen3,
389 	.fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3,
390 };
391 
392 static const struct rcar_thermal_info rcar_gen3_thermal_info = {
393 	.scale = 167,
394 	.adj_below = -41,
395 	.adj_above = 126,
396 	.fuses = &rcar_gen3_thermal_fuse_info_gen3,
397 	.fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3,
398 };
399 
400 static const struct rcar_thermal_info rcar_s4_thermal_info = {
401 	.scale = 167,
402 	.adj_below = -41,
403 	.adj_above = 126,
404 	.fuses = &rcar_gen3_thermal_fuse_info_gen4,
405 	.fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3,
406 };
407 
408 static const struct rcar_thermal_info rcar_gen4_thermal_info = {
409 	.scale = 167,
410 	.adj_below = -41,
411 	.adj_above = 126,
412 	.fuses = &rcar_gen3_thermal_fuse_info_gen4,
413 	.fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen4,
414 };
415 
416 static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
417 	{
418 		.compatible = "renesas,r8a774a1-thermal",
419 		.data = &rcar_m3w_thermal_info,
420 	},
421 	{
422 		.compatible = "renesas,r8a774b1-thermal",
423 		.data = &rcar_gen3_thermal_info,
424 	},
425 	{
426 		.compatible = "renesas,r8a774e1-thermal",
427 		.data = &rcar_gen3_thermal_info,
428 	},
429 	{
430 		.compatible = "renesas,r8a7795-thermal",
431 		.data = &rcar_gen3_thermal_info,
432 	},
433 	{
434 		.compatible = "renesas,r8a7796-thermal",
435 		.data = &rcar_m3w_thermal_info,
436 	},
437 	{
438 		.compatible = "renesas,r8a77961-thermal",
439 		.data = &rcar_m3w_thermal_info,
440 	},
441 	{
442 		.compatible = "renesas,r8a77965-thermal",
443 		.data = &rcar_gen3_thermal_info,
444 	},
445 	{
446 		.compatible = "renesas,r8a77980-thermal",
447 		.data = &rcar_gen3_thermal_info,
448 	},
449 	{
450 		.compatible = "renesas,r8a779a0-thermal",
451 		.data = &rcar_gen3_thermal_info,
452 	},
453 	{
454 		.compatible = "renesas,r8a779f0-thermal",
455 		.data = &rcar_s4_thermal_info,
456 	},
457 	{
458 		.compatible = "renesas,r8a779g0-thermal",
459 		.data = &rcar_gen4_thermal_info,
460 	},
461 	{
462 		.compatible = "renesas,r8a779h0-thermal",
463 		.data = &rcar_gen4_thermal_info,
464 	},
465 	{},
466 };
467 MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
468 
469 static void rcar_gen3_thermal_remove(struct platform_device *pdev)
470 {
471 	struct device *dev = &pdev->dev;
472 
473 	pm_runtime_put(dev);
474 	pm_runtime_disable(dev);
475 }
476 
477 static void rcar_gen3_hwmon_action(void *data)
478 {
479 	struct thermal_zone_device *zone = data;
480 
481 	thermal_remove_hwmon_sysfs(zone);
482 }
483 
484 static int rcar_gen3_thermal_request_irqs(struct rcar_gen3_thermal_priv *priv,
485 					  struct platform_device *pdev)
486 {
487 	struct device *dev = &pdev->dev;
488 	unsigned int i;
489 	char *irqname;
490 	int ret, irq;
491 
492 	for (i = 0; i < 2; i++) {
493 		irq = platform_get_irq_optional(pdev, i);
494 		if (irq < 0)
495 			return irq;
496 
497 		irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:ch%d",
498 					 dev_name(dev), i);
499 		if (!irqname)
500 			return -ENOMEM;
501 
502 		ret = devm_request_threaded_irq(dev, irq, NULL,
503 						rcar_gen3_thermal_irq,
504 						IRQF_ONESHOT, irqname, priv);
505 		if (ret)
506 			return ret;
507 	}
508 
509 	return 0;
510 }
511 
512 static int rcar_gen3_thermal_probe(struct platform_device *pdev)
513 {
514 	struct rcar_gen3_thermal_priv *priv;
515 	struct device *dev = &pdev->dev;
516 	struct resource *res;
517 	struct thermal_zone_device *zone;
518 	unsigned int i;
519 	int ret;
520 
521 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
522 	if (!priv)
523 		return -ENOMEM;
524 
525 	priv->ops = rcar_gen3_tz_of_ops;
526 
527 	priv->info = of_device_get_match_data(dev);
528 	platform_set_drvdata(pdev, priv);
529 
530 	if (rcar_gen3_thermal_request_irqs(priv, pdev))
531 		priv->ops.set_trips = NULL;
532 
533 	pm_runtime_enable(dev);
534 	pm_runtime_get_sync(dev);
535 
536 	for (i = 0; i < TSC_MAX_NUM; i++) {
537 		struct rcar_gen3_thermal_tsc *tsc;
538 
539 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
540 		if (!res)
541 			break;
542 
543 		tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL);
544 		if (!tsc) {
545 			ret = -ENOMEM;
546 			goto error_unregister;
547 		}
548 
549 		tsc->priv = priv;
550 		tsc->base = devm_ioremap_resource(dev, res);
551 		if (IS_ERR(tsc->base)) {
552 			ret = PTR_ERR(tsc->base);
553 			goto error_unregister;
554 		}
555 
556 		priv->tscs[i] = tsc;
557 	}
558 
559 	priv->num_tscs = i;
560 
561 	if (!rcar_gen3_thermal_read_fuses(priv))
562 		dev_info(dev, "No calibration values fused, fallback to driver values\n");
563 
564 	rcar_gen3_thermal_shared_coefs(priv);
565 
566 	for (i = 0; i < priv->num_tscs; i++) {
567 		struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
568 
569 		rcar_gen3_thermal_init(priv, tsc);
570 		rcar_gen3_thermal_tsc_coefs(priv, tsc);
571 
572 		zone = devm_thermal_of_zone_register(dev, i, tsc, &priv->ops);
573 		if (IS_ERR(zone)) {
574 			dev_err(dev, "Sensor %u: Can't register thermal zone\n", i);
575 			ret = PTR_ERR(zone);
576 			goto error_unregister;
577 		}
578 		tsc->zone = zone;
579 
580 		ret = thermal_add_hwmon_sysfs(tsc->zone);
581 		if (ret)
582 			goto error_unregister;
583 
584 		ret = devm_add_action_or_reset(dev, rcar_gen3_hwmon_action, zone);
585 		if (ret)
586 			goto error_unregister;
587 
588 		dev_info(dev, "Sensor %u: Loaded\n", i);
589 	}
590 
591 	if (!priv->num_tscs) {
592 		ret = -ENODEV;
593 		goto error_unregister;
594 	}
595 
596 	return 0;
597 
598 error_unregister:
599 	rcar_gen3_thermal_remove(pdev);
600 
601 	return ret;
602 }
603 
604 static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)
605 {
606 	struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
607 	unsigned int i;
608 
609 	for (i = 0; i < priv->num_tscs; i++) {
610 		struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
611 
612 		rcar_gen3_thermal_init(priv, tsc);
613 	}
614 
615 	return 0;
616 }
617 
618 static SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops, NULL,
619 			 rcar_gen3_thermal_resume);
620 
621 static struct platform_driver rcar_gen3_thermal_driver = {
622 	.driver	= {
623 		.name	= "rcar_gen3_thermal",
624 		.pm = &rcar_gen3_thermal_pm_ops,
625 		.of_match_table = rcar_gen3_thermal_dt_ids,
626 	},
627 	.probe		= rcar_gen3_thermal_probe,
628 	.remove		= rcar_gen3_thermal_remove,
629 };
630 module_platform_driver(rcar_gen3_thermal_driver);
631 
632 MODULE_LICENSE("GPL v2");
633 MODULE_DESCRIPTION("R-Car Gen3 THS thermal sensor driver");
634 MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>");
635