linux/drivers/thermal/rcar_gen3_thermal.c
<<
>>
Prefs
   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_device.h>
  15#include <linux/platform_device.h>
  16#include <linux/pm_runtime.h>
  17#include <linux/sys_soc.h>
  18#include <linux/thermal.h>
  19
  20#include "thermal_core.h"
  21#include "thermal_hwmon.h"
  22
  23/* Register offsets */
  24#define REG_GEN3_IRQSTR         0x04
  25#define REG_GEN3_IRQMSK         0x08
  26#define REG_GEN3_IRQCTL         0x0C
  27#define REG_GEN3_IRQEN          0x10
  28#define REG_GEN3_IRQTEMP1       0x14
  29#define REG_GEN3_IRQTEMP2       0x18
  30#define REG_GEN3_IRQTEMP3       0x1C
  31#define REG_GEN3_CTSR           0x20
  32#define REG_GEN3_THCTR          0x20
  33#define REG_GEN3_TEMP           0x28
  34#define REG_GEN3_THCODE1        0x50
  35#define REG_GEN3_THCODE2        0x54
  36#define REG_GEN3_THCODE3        0x58
  37
  38/* IRQ{STR,MSK,EN} bits */
  39#define IRQ_TEMP1               BIT(0)
  40#define IRQ_TEMP2               BIT(1)
  41#define IRQ_TEMP3               BIT(2)
  42#define IRQ_TEMPD1              BIT(3)
  43#define IRQ_TEMPD2              BIT(4)
  44#define IRQ_TEMPD3              BIT(5)
  45
  46/* CTSR bits */
  47#define CTSR_PONM       BIT(8)
  48#define CTSR_AOUT       BIT(7)
  49#define CTSR_THBGR      BIT(5)
  50#define CTSR_VMEN       BIT(4)
  51#define CTSR_VMST       BIT(1)
  52#define CTSR_THSST      BIT(0)
  53
  54/* THCTR bits */
  55#define THCTR_PONM      BIT(6)
  56#define THCTR_THSST     BIT(0)
  57
  58#define CTEMP_MASK      0xFFF
  59
  60#define MCELSIUS(temp)  ((temp) * 1000)
  61#define GEN3_FUSE_MASK  0xFFF
  62
  63#define TSC_MAX_NUM     5
  64
  65/* default THCODE values if FUSEs are missing */
  66static const int thcodes[TSC_MAX_NUM][3] = {
  67        { 3397, 2800, 2221 },
  68        { 3393, 2795, 2216 },
  69        { 3389, 2805, 2237 },
  70        { 3415, 2694, 2195 },
  71        { 3356, 2724, 2244 },
  72};
  73
  74/* Structure for thermal temperature calculation */
  75struct equation_coefs {
  76        int a1;
  77        int b1;
  78        int a2;
  79        int b2;
  80};
  81
  82struct rcar_gen3_thermal_tsc {
  83        void __iomem *base;
  84        struct thermal_zone_device *zone;
  85        struct equation_coefs coef;
  86        int tj_t;
  87        unsigned int id; /* thermal channel id */
  88};
  89
  90struct rcar_gen3_thermal_priv {
  91        struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
  92        unsigned int num_tscs;
  93        void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc);
  94};
  95
  96static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc,
  97                                         u32 reg)
  98{
  99        return ioread32(tsc->base + reg);
 100}
 101
 102static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
 103                                           u32 reg, u32 data)
 104{
 105        iowrite32(data, tsc->base + reg);
 106}
 107
 108/*
 109 * Linear approximation for temperature
 110 *
 111 * [reg] = [temp] * a + b => [temp] = ([reg] - b) / a
 112 *
 113 * The constants a and b are calculated using two triplets of int values PTAT
 114 * and THCODE. PTAT and THCODE can either be read from hardware or use hard
 115 * coded values from driver. The formula to calculate a and b are taken from
 116 * BSP and sparsely documented and understood.
 117 *
 118 * Examining the linear formula and the formula used to calculate constants a
 119 * and b while knowing that the span for PTAT and THCODE values are between
 120 * 0x000 and 0xfff the largest integer possible is 0xfff * 0xfff == 0xffe001.
 121 * Integer also needs to be signed so that leaves 7 bits for binary
 122 * fixed point scaling.
 123 */
 124
 125#define FIXPT_SHIFT 7
 126#define FIXPT_INT(_x) ((_x) << FIXPT_SHIFT)
 127#define INT_FIXPT(_x) ((_x) >> FIXPT_SHIFT)
 128#define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b))
 129#define FIXPT_TO_MCELSIUS(_x) ((_x) * 1000 >> FIXPT_SHIFT)
 130
 131#define RCAR3_THERMAL_GRAN 500 /* mili Celsius */
 132
 133/* no idea where these constants come from */
 134#define TJ_3 -41
 135
 136static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc,
 137                                         int *ptat, const int *thcode,
 138                                         int ths_tj_1)
 139{
 140        /* TODO: Find documentation and document constant calculation formula */
 141
 142        /*
 143         * Division is not scaled in BSP and if scaled it might overflow
 144         * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled
 145         */
 146        tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * (ths_tj_1 - TJ_3))
 147                     / (ptat[0] - ptat[2])) + FIXPT_INT(TJ_3);
 148
 149        tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]),
 150                                 tsc->tj_t - FIXPT_INT(TJ_3));
 151        tsc->coef.b1 = FIXPT_INT(thcode[2]) - tsc->coef.a1 * TJ_3;
 152
 153        tsc->coef.a2 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[0]),
 154                                 tsc->tj_t - FIXPT_INT(ths_tj_1));
 155        tsc->coef.b2 = FIXPT_INT(thcode[0]) - tsc->coef.a2 * ths_tj_1;
 156}
 157
 158static int rcar_gen3_thermal_round(int temp)
 159{
 160        int result, round_offs;
 161
 162        round_offs = temp >= 0 ? RCAR3_THERMAL_GRAN / 2 :
 163                -RCAR3_THERMAL_GRAN / 2;
 164        result = (temp + round_offs) / RCAR3_THERMAL_GRAN;
 165        return result * RCAR3_THERMAL_GRAN;
 166}
 167
 168static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
 169{
 170        struct rcar_gen3_thermal_tsc *tsc = devdata;
 171        int mcelsius, val;
 172        int reg;
 173
 174        /* Read register and convert to mili Celsius */
 175        reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
 176
 177        if (reg <= thcodes[tsc->id][1])
 178                val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1,
 179                                tsc->coef.a1);
 180        else
 181                val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2,
 182                                tsc->coef.a2);
 183        mcelsius = FIXPT_TO_MCELSIUS(val);
 184
 185        /* Guaranteed operating range is -40C to 125C. */
 186
 187        /* Round value to device granularity setting */
 188        *temp = rcar_gen3_thermal_round(mcelsius);
 189
 190        return 0;
 191}
 192
 193static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,
 194                                              int mcelsius)
 195{
 196        int celsius, val;
 197
 198        celsius = DIV_ROUND_CLOSEST(mcelsius, 1000);
 199        if (celsius <= INT_FIXPT(tsc->tj_t))
 200                val = celsius * tsc->coef.a1 + tsc->coef.b1;
 201        else
 202                val = celsius * tsc->coef.a2 + tsc->coef.b2;
 203
 204        return INT_FIXPT(val);
 205}
 206
 207static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high)
 208{
 209        struct rcar_gen3_thermal_tsc *tsc = devdata;
 210        u32 irqmsk = 0;
 211
 212        if (low != -INT_MAX) {
 213                irqmsk |= IRQ_TEMPD1;
 214                rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1,
 215                                        rcar_gen3_thermal_mcelsius_to_temp(tsc, low));
 216        }
 217
 218        if (high != INT_MAX) {
 219                irqmsk |= IRQ_TEMP2;
 220                rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2,
 221                                        rcar_gen3_thermal_mcelsius_to_temp(tsc, high));
 222        }
 223
 224        rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, irqmsk);
 225
 226        return 0;
 227}
 228
 229static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
 230        .get_temp       = rcar_gen3_thermal_get_temp,
 231        .set_trips      = rcar_gen3_thermal_set_trips,
 232};
 233
 234static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
 235{
 236        struct rcar_gen3_thermal_priv *priv = data;
 237        unsigned int i;
 238        u32 status;
 239
 240        for (i = 0; i < priv->num_tscs; i++) {
 241                status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR);
 242                rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0);
 243                if (status)
 244                        thermal_zone_device_update(priv->tscs[i]->zone,
 245                                                   THERMAL_EVENT_UNSPECIFIED);
 246        }
 247
 248        return IRQ_HANDLED;
 249}
 250
 251static const struct soc_device_attribute r8a7795es1[] = {
 252        { .soc_id = "r8a7795", .revision = "ES1.*" },
 253        { /* sentinel */ }
 254};
 255
 256static void rcar_gen3_thermal_init_r8a7795es1(struct rcar_gen3_thermal_tsc *tsc)
 257{
 258        rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,  CTSR_THBGR);
 259        rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,  0x0);
 260
 261        usleep_range(1000, 2000);
 262
 263        rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_PONM);
 264
 265        rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
 266        rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
 267        if (tsc->zone->ops->set_trips)
 268                rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN,
 269                                        IRQ_TEMPD1 | IRQ_TEMP2);
 270
 271        rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
 272                                CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN);
 273
 274        usleep_range(100, 200);
 275
 276        rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
 277                                CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN |
 278                                CTSR_VMST | CTSR_THSST);
 279
 280        usleep_range(1000, 2000);
 281}
 282
 283static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
 284{
 285        u32 reg_val;
 286
 287        reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
 288        reg_val &= ~THCTR_PONM;
 289        rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
 290
 291        usleep_range(1000, 2000);
 292
 293        rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0);
 294        rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
 295        if (tsc->zone->ops->set_trips)
 296                rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN,
 297                                        IRQ_TEMPD1 | IRQ_TEMP2);
 298
 299        reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
 300        reg_val |= THCTR_THSST;
 301        rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
 302
 303        usleep_range(1000, 2000);
 304}
 305
 306static const int rcar_gen3_ths_tj_1 = 126;
 307static const int rcar_gen3_ths_tj_1_m3_w = 116;
 308static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
 309        {
 310                .compatible = "renesas,r8a774a1-thermal",
 311                .data = &rcar_gen3_ths_tj_1_m3_w,
 312        },
 313        {
 314                .compatible = "renesas,r8a774b1-thermal",
 315                .data = &rcar_gen3_ths_tj_1,
 316        },
 317        {
 318                .compatible = "renesas,r8a774e1-thermal",
 319                .data = &rcar_gen3_ths_tj_1,
 320        },
 321        {
 322                .compatible = "renesas,r8a7795-thermal",
 323                .data = &rcar_gen3_ths_tj_1,
 324        },
 325        {
 326                .compatible = "renesas,r8a7796-thermal",
 327                .data = &rcar_gen3_ths_tj_1_m3_w,
 328        },
 329        {
 330                .compatible = "renesas,r8a77961-thermal",
 331                .data = &rcar_gen3_ths_tj_1_m3_w,
 332        },
 333        {
 334                .compatible = "renesas,r8a77965-thermal",
 335                .data = &rcar_gen3_ths_tj_1,
 336        },
 337        {
 338                .compatible = "renesas,r8a77980-thermal",
 339                .data = &rcar_gen3_ths_tj_1,
 340        },
 341        {
 342                .compatible = "renesas,r8a779a0-thermal",
 343                .data = &rcar_gen3_ths_tj_1,
 344        },
 345        {},
 346};
 347MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
 348
 349static int rcar_gen3_thermal_remove(struct platform_device *pdev)
 350{
 351        struct device *dev = &pdev->dev;
 352
 353        pm_runtime_put(dev);
 354        pm_runtime_disable(dev);
 355
 356        return 0;
 357}
 358
 359static void rcar_gen3_hwmon_action(void *data)
 360{
 361        struct thermal_zone_device *zone = data;
 362
 363        thermal_remove_hwmon_sysfs(zone);
 364}
 365
 366static int rcar_gen3_thermal_request_irqs(struct rcar_gen3_thermal_priv *priv,
 367                                          struct platform_device *pdev)
 368{
 369        struct device *dev = &pdev->dev;
 370        unsigned int i;
 371        char *irqname;
 372        int ret, irq;
 373
 374        for (i = 0; i < 2; i++) {
 375                irq = platform_get_irq_optional(pdev, i);
 376                if (irq < 0)
 377                        return irq;
 378
 379                irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:ch%d",
 380                                         dev_name(dev), i);
 381                if (!irqname)
 382                        return -ENOMEM;
 383
 384                ret = devm_request_threaded_irq(dev, irq, NULL,
 385                                                rcar_gen3_thermal_irq,
 386                                                IRQF_ONESHOT, irqname, priv);
 387                if (ret)
 388                        return ret;
 389        }
 390
 391        return 0;
 392}
 393
 394static int rcar_gen3_thermal_probe(struct platform_device *pdev)
 395{
 396        struct rcar_gen3_thermal_priv *priv;
 397        struct device *dev = &pdev->dev;
 398        const int *ths_tj_1 = of_device_get_match_data(dev);
 399        struct resource *res;
 400        struct thermal_zone_device *zone;
 401        unsigned int i;
 402        int ret;
 403
 404        /* default values if FUSEs are missing */
 405        /* TODO: Read values from hardware on supported platforms */
 406        int ptat[3] = { 2631, 1509, 435 };
 407
 408        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 409        if (!priv)
 410                return -ENOMEM;
 411
 412        priv->thermal_init = rcar_gen3_thermal_init;
 413        if (soc_device_match(r8a7795es1))
 414                priv->thermal_init = rcar_gen3_thermal_init_r8a7795es1;
 415
 416        platform_set_drvdata(pdev, priv);
 417
 418        if (rcar_gen3_thermal_request_irqs(priv, pdev))
 419                rcar_gen3_tz_of_ops.set_trips = NULL;
 420
 421        pm_runtime_enable(dev);
 422        pm_runtime_get_sync(dev);
 423
 424        for (i = 0; i < TSC_MAX_NUM; i++) {
 425                struct rcar_gen3_thermal_tsc *tsc;
 426
 427                res = platform_get_resource(pdev, IORESOURCE_MEM, i);
 428                if (!res)
 429                        break;
 430
 431                tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL);
 432                if (!tsc) {
 433                        ret = -ENOMEM;
 434                        goto error_unregister;
 435                }
 436
 437                tsc->base = devm_ioremap_resource(dev, res);
 438                if (IS_ERR(tsc->base)) {
 439                        ret = PTR_ERR(tsc->base);
 440                        goto error_unregister;
 441                }
 442                tsc->id = i;
 443
 444                priv->tscs[i] = tsc;
 445
 446                zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
 447                                                            &rcar_gen3_tz_of_ops);
 448                if (IS_ERR(zone)) {
 449                        dev_err(dev, "Can't register thermal zone\n");
 450                        ret = PTR_ERR(zone);
 451                        goto error_unregister;
 452                }
 453                tsc->zone = zone;
 454
 455                priv->thermal_init(tsc);
 456                rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1);
 457
 458                tsc->zone->tzp->no_hwmon = false;
 459                ret = thermal_add_hwmon_sysfs(tsc->zone);
 460                if (ret)
 461                        goto error_unregister;
 462
 463                ret = devm_add_action_or_reset(dev, rcar_gen3_hwmon_action, zone);
 464                if (ret)
 465                        goto error_unregister;
 466
 467                ret = of_thermal_get_ntrips(tsc->zone);
 468                if (ret < 0)
 469                        goto error_unregister;
 470
 471                dev_info(dev, "TSC%u: Loaded %d trip points\n", i, ret);
 472        }
 473
 474        priv->num_tscs = i;
 475
 476        if (!priv->num_tscs) {
 477                ret = -ENODEV;
 478                goto error_unregister;
 479        }
 480
 481        return 0;
 482
 483error_unregister:
 484        rcar_gen3_thermal_remove(pdev);
 485
 486        return ret;
 487}
 488
 489static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)
 490{
 491        struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
 492        unsigned int i;
 493
 494        for (i = 0; i < priv->num_tscs; i++) {
 495                struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
 496                struct thermal_zone_device *zone = tsc->zone;
 497
 498                priv->thermal_init(tsc);
 499                if (zone->ops->set_trips)
 500                        rcar_gen3_thermal_set_trips(tsc, zone->prev_low_trip,
 501                                                    zone->prev_high_trip);
 502        }
 503
 504        return 0;
 505}
 506
 507static SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops, NULL,
 508                         rcar_gen3_thermal_resume);
 509
 510static struct platform_driver rcar_gen3_thermal_driver = {
 511        .driver = {
 512                .name   = "rcar_gen3_thermal",
 513                .pm = &rcar_gen3_thermal_pm_ops,
 514                .of_match_table = rcar_gen3_thermal_dt_ids,
 515        },
 516        .probe          = rcar_gen3_thermal_probe,
 517        .remove         = rcar_gen3_thermal_remove,
 518};
 519module_platform_driver(rcar_gen3_thermal_driver);
 520
 521MODULE_LICENSE("GPL v2");
 522MODULE_DESCRIPTION("R-Car Gen3 THS thermal sensor driver");
 523MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>");
 524