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