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