1 // SPDX-License-Identifier: GPL-2.0
3 * R-Car Gen3 THS thermal sensor driver
4 * Based on rcar_thermal.c and work from Hien Dang and Khiem Nguyen.
6 * Copyright (C) 2016 Renesas Electronics Corporation.
7 * Copyright (C) 2016 Sang Engineering
9 #include <linux/delay.h>
10 #include <linux/err.h>
11 #include <linux/interrupt.h>
13 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/thermal.h>
19 #include "../thermal_hwmon.h"
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
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)
54 #define THCTR_PONM BIT(6)
55 #define THCTR_THSST BIT(0)
58 #define THSCP_COR_PARA_VLD (BIT(15) | BIT(14))
60 #define CTEMP_MASK 0xFFF
62 #define MCELSIUS(temp) ((temp) * 1000)
63 #define GEN3_FUSE_MASK 0xFFF
64 #define GEN4_FUSE_MASK 0xFFF
68 struct rcar_gen3_thermal_priv;
70 struct rcar_thermal_info {
74 void (*read_fuses)(struct rcar_gen3_thermal_priv *priv);
77 struct equation_set_coef {
82 struct rcar_gen3_thermal_tsc {
83 struct rcar_gen3_thermal_priv *priv;
85 struct thermal_zone_device *zone;
86 /* Different coefficients are used depending on a threshold. */
88 struct equation_set_coef below;
89 struct equation_set_coef above;
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;
100 const struct rcar_thermal_info *info;
103 static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc,
106 return ioread32(tsc->base + reg);
109 static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
112 iowrite32(data, tsc->base + reg);
116 * Linear approximation for temperature
118 * [temp] = ((thadj - [reg]) * a) / b + adj
119 * [reg] = thadj - ([temp] - adj) * b / a
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
129 * The constant thadj is one of the THCODE values, which one to use depends on
130 * the threshold and input value.
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.
138 static void rcar_gen3_thermal_shared_coefs(struct rcar_gen3_thermal_priv *priv)
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;
145 static void rcar_gen3_thermal_tsc_coefs(struct rcar_gen3_thermal_priv *priv,
146 struct rcar_gen3_thermal_tsc *tsc)
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]);
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]);
155 static int rcar_gen3_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
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;
162 /* Read register and convert to mili Celsius */
163 reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
165 if (reg < tsc->thcode[1]) {
166 adj = priv->info->adj_below;
167 coef = &tsc->coef.below;
168 thcode = tsc->thcode[2];
170 adj = priv->info->adj_above;
171 coef = &tsc->coef.above;
172 thcode = tsc->thcode[0];
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
181 decicelsius = DIV_ROUND_CLOSEST(coef->a * (thcode - reg), coef->b / 10);
183 /* Guaranteed operating range is -40C to 125C. */
185 /* Reporting is done in millidegree Celsius */
186 *temp = decicelsius * 100 + adj * 1000;
191 static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,
194 struct rcar_gen3_thermal_priv *priv = tsc->priv;
195 const struct equation_set_coef *coef;
196 int adj, celsius, thcode;
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];
204 coef = &tsc->coef.above;
205 adj = priv->info->adj_above;
206 thcode = tsc->thcode[0];
209 return thcode - DIV_ROUND_CLOSEST((celsius - adj) * coef->b, coef->a);
212 static int rcar_gen3_thermal_set_trips(struct thermal_zone_device *tz, int low, int high)
214 struct rcar_gen3_thermal_tsc *tsc = thermal_zone_device_priv(tz);
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));
223 if (high != INT_MAX) {
225 rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2,
226 rcar_gen3_thermal_mcelsius_to_temp(tsc, high));
229 rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, irqmsk);
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,
239 static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
241 struct rcar_gen3_thermal_priv *priv = data;
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);
256 static void rcar_gen3_thermal_read_fuses_gen3(struct rcar_gen3_thermal_priv *priv)
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.
265 priv->ptat[0] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT1) &
267 priv->ptat[1] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT2) &
269 priv->ptat[2] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT3) &
272 for (i = 0; i < priv->num_tscs; i++) {
273 struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
275 tsc->thcode[0] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE1) &
277 tsc->thcode[1] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE2) &
279 tsc->thcode[2] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE3) &
284 static void rcar_gen3_thermal_read_fuses_gen4(struct rcar_gen3_thermal_priv *priv)
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.
293 priv->ptat[0] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN4_THSFMON16) &
295 priv->ptat[1] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN4_THSFMON17) &
297 priv->ptat[2] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN4_THSFMON15) &
300 for (i = 0; i < priv->num_tscs; i++) {
301 struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
303 tsc->thcode[0] = rcar_gen3_thermal_read(tsc, REG_GEN4_THSFMON01) &
305 tsc->thcode[1] = rcar_gen3_thermal_read(tsc, REG_GEN4_THSFMON02) &
307 tsc->thcode[2] = rcar_gen3_thermal_read(tsc, REG_GEN4_THSFMON00) &
312 static bool rcar_gen3_thermal_read_fuses(struct rcar_gen3_thermal_priv *priv)
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 },
330 priv->ptat[0] = 2631;
331 priv->ptat[1] = 1509;
334 for (i = 0; i < priv->num_tscs; i++) {
335 struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
337 tsc->thcode[0] = thcodes[i][0];
338 tsc->thcode[1] = thcodes[i][1];
339 tsc->thcode[2] = thcodes[i][2];
345 priv->info->read_fuses(priv);
349 static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_priv *priv,
350 struct rcar_gen3_thermal_tsc *tsc)
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);
358 usleep_range(1000, 2000);
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);
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);
370 usleep_range(1000, 2000);
373 static const struct rcar_thermal_info rcar_m3w_thermal_info = {
377 .read_fuses = rcar_gen3_thermal_read_fuses_gen3,
380 static const struct rcar_thermal_info rcar_gen3_thermal_info = {
384 .read_fuses = rcar_gen3_thermal_read_fuses_gen3,
387 static const struct rcar_thermal_info rcar_gen4_thermal_info = {
391 .read_fuses = rcar_gen3_thermal_read_fuses_gen4,
394 static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
396 .compatible = "renesas,r8a774a1-thermal",
397 .data = &rcar_m3w_thermal_info,
400 .compatible = "renesas,r8a774b1-thermal",
401 .data = &rcar_gen3_thermal_info,
404 .compatible = "renesas,r8a774e1-thermal",
405 .data = &rcar_gen3_thermal_info,
408 .compatible = "renesas,r8a7795-thermal",
409 .data = &rcar_gen3_thermal_info,
412 .compatible = "renesas,r8a7796-thermal",
413 .data = &rcar_m3w_thermal_info,
416 .compatible = "renesas,r8a77961-thermal",
417 .data = &rcar_m3w_thermal_info,
420 .compatible = "renesas,r8a77965-thermal",
421 .data = &rcar_gen3_thermal_info,
424 .compatible = "renesas,r8a77980-thermal",
425 .data = &rcar_gen3_thermal_info,
428 .compatible = "renesas,r8a779a0-thermal",
429 .data = &rcar_gen3_thermal_info,
432 .compatible = "renesas,r8a779f0-thermal",
433 .data = &rcar_gen4_thermal_info,
436 .compatible = "renesas,r8a779g0-thermal",
437 .data = &rcar_gen4_thermal_info,
440 .compatible = "renesas,r8a779h0-thermal",
441 .data = &rcar_gen4_thermal_info,
445 MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
447 static void rcar_gen3_thermal_remove(struct platform_device *pdev)
449 struct device *dev = &pdev->dev;
452 pm_runtime_disable(dev);
455 static void rcar_gen3_hwmon_action(void *data)
457 struct thermal_zone_device *zone = data;
459 thermal_remove_hwmon_sysfs(zone);
462 static int rcar_gen3_thermal_request_irqs(struct rcar_gen3_thermal_priv *priv,
463 struct platform_device *pdev)
465 struct device *dev = &pdev->dev;
470 for (i = 0; i < 2; i++) {
471 irq = platform_get_irq_optional(pdev, i);
475 irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:ch%d",
480 ret = devm_request_threaded_irq(dev, irq, NULL,
481 rcar_gen3_thermal_irq,
482 IRQF_ONESHOT, irqname, priv);
490 static int rcar_gen3_thermal_probe(struct platform_device *pdev)
492 struct rcar_gen3_thermal_priv *priv;
493 struct device *dev = &pdev->dev;
494 struct resource *res;
495 struct thermal_zone_device *zone;
499 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
503 priv->ops = rcar_gen3_tz_of_ops;
505 priv->info = of_device_get_match_data(dev);
506 platform_set_drvdata(pdev, priv);
508 if (rcar_gen3_thermal_request_irqs(priv, pdev))
509 priv->ops.set_trips = NULL;
511 pm_runtime_enable(dev);
512 pm_runtime_get_sync(dev);
514 for (i = 0; i < TSC_MAX_NUM; i++) {
515 struct rcar_gen3_thermal_tsc *tsc;
517 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
521 tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL);
524 goto error_unregister;
528 tsc->base = devm_ioremap_resource(dev, res);
529 if (IS_ERR(tsc->base)) {
530 ret = PTR_ERR(tsc->base);
531 goto error_unregister;
539 if (!rcar_gen3_thermal_read_fuses(priv))
540 dev_info(dev, "No calibration values fused, fallback to driver values\n");
542 rcar_gen3_thermal_shared_coefs(priv);
544 for (i = 0; i < priv->num_tscs; i++) {
545 struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
547 rcar_gen3_thermal_init(priv, tsc);
548 rcar_gen3_thermal_tsc_coefs(priv, tsc);
550 zone = devm_thermal_of_zone_register(dev, i, tsc, &priv->ops);
552 dev_err(dev, "Sensor %u: Can't register thermal zone\n", i);
554 goto error_unregister;
558 ret = thermal_add_hwmon_sysfs(tsc->zone);
560 goto error_unregister;
562 ret = devm_add_action_or_reset(dev, rcar_gen3_hwmon_action, zone);
564 goto error_unregister;
566 dev_info(dev, "Sensor %u: Loaded\n", i);
569 if (!priv->num_tscs) {
571 goto error_unregister;
577 rcar_gen3_thermal_remove(pdev);
582 static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)
584 struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
587 for (i = 0; i < priv->num_tscs; i++) {
588 struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
590 rcar_gen3_thermal_init(priv, tsc);
596 static SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops, NULL,
597 rcar_gen3_thermal_resume);
599 static struct platform_driver rcar_gen3_thermal_driver = {
601 .name = "rcar_gen3_thermal",
602 .pm = &rcar_gen3_thermal_pm_ops,
603 .of_match_table = rcar_gen3_thermal_dt_ids,
605 .probe = rcar_gen3_thermal_probe,
606 .remove = rcar_gen3_thermal_remove,
608 module_platform_driver(rcar_gen3_thermal_driver);
610 MODULE_LICENSE("GPL v2");
611 MODULE_DESCRIPTION("R-Car Gen3 THS thermal sensor driver");