linux/drivers/thermal/imx_thermal.c
<<
>>
Prefs
   1/*
   2 * Copyright 2013 Freescale Semiconductor, Inc.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 *
   8 */
   9
  10#include <linux/cpu_cooling.h>
  11#include <linux/cpufreq.h>
  12#include <linux/delay.h>
  13#include <linux/device.h>
  14#include <linux/init.h>
  15#include <linux/interrupt.h>
  16#include <linux/io.h>
  17#include <linux/kernel.h>
  18#include <linux/mfd/syscon.h>
  19#include <linux/module.h>
  20#include <linux/of.h>
  21#include <linux/platform_device.h>
  22#include <linux/regmap.h>
  23#include <linux/slab.h>
  24#include <linux/thermal.h>
  25#include <linux/types.h>
  26
  27#define REG_SET         0x4
  28#define REG_CLR         0x8
  29#define REG_TOG         0xc
  30
  31#define MISC0                           0x0150
  32#define MISC0_REFTOP_SELBIASOFF         (1 << 3)
  33
  34#define TEMPSENSE0                      0x0180
  35#define TEMPSENSE0_ALARM_VALUE_SHIFT    20
  36#define TEMPSENSE0_ALARM_VALUE_MASK     (0xfff << TEMPSENSE0_ALARM_VALUE_SHIFT)
  37#define TEMPSENSE0_TEMP_CNT_SHIFT       8
  38#define TEMPSENSE0_TEMP_CNT_MASK        (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT)
  39#define TEMPSENSE0_FINISHED             (1 << 2)
  40#define TEMPSENSE0_MEASURE_TEMP         (1 << 1)
  41#define TEMPSENSE0_POWER_DOWN           (1 << 0)
  42
  43#define TEMPSENSE1                      0x0190
  44#define TEMPSENSE1_MEASURE_FREQ         0xffff
  45
  46#define OCOTP_ANA1                      0x04e0
  47
  48/* The driver supports 1 passive trip point and 1 critical trip point */
  49enum imx_thermal_trip {
  50        IMX_TRIP_PASSIVE,
  51        IMX_TRIP_CRITICAL,
  52        IMX_TRIP_NUM,
  53};
  54
  55/*
  56 * It defines the temperature in millicelsius for passive trip point
  57 * that will trigger cooling action when crossed.
  58 */
  59#define IMX_TEMP_PASSIVE                85000
  60
  61#define IMX_POLLING_DELAY               2000 /* millisecond */
  62#define IMX_PASSIVE_DELAY               1000
  63
  64struct imx_thermal_data {
  65        struct thermal_zone_device *tz;
  66        struct thermal_cooling_device *cdev;
  67        enum thermal_device_mode mode;
  68        struct regmap *tempmon;
  69        int c1, c2; /* See formula in imx_get_sensor_data() */
  70        unsigned long temp_passive;
  71        unsigned long temp_critical;
  72        unsigned long alarm_temp;
  73        unsigned long last_temp;
  74        bool irq_enabled;
  75        int irq;
  76};
  77
  78static void imx_set_alarm_temp(struct imx_thermal_data *data,
  79                               signed long alarm_temp)
  80{
  81        struct regmap *map = data->tempmon;
  82        int alarm_value;
  83
  84        data->alarm_temp = alarm_temp;
  85        alarm_value = (alarm_temp - data->c2) / data->c1;
  86        regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_ALARM_VALUE_MASK);
  87        regmap_write(map, TEMPSENSE0 + REG_SET, alarm_value <<
  88                        TEMPSENSE0_ALARM_VALUE_SHIFT);
  89}
  90
  91static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
  92{
  93        struct imx_thermal_data *data = tz->devdata;
  94        struct regmap *map = data->tempmon;
  95        unsigned int n_meas;
  96        bool wait;
  97        u32 val;
  98
  99        if (data->mode == THERMAL_DEVICE_ENABLED) {
 100                /* Check if a measurement is currently in progress */
 101                regmap_read(map, TEMPSENSE0, &val);
 102                wait = !(val & TEMPSENSE0_FINISHED);
 103        } else {
 104                /*
 105                 * Every time we measure the temperature, we will power on the
 106                 * temperature sensor, enable measurements, take a reading,
 107                 * disable measurements, power off the temperature sensor.
 108                 */
 109                regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
 110                regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
 111
 112                wait = true;
 113        }
 114
 115        /*
 116         * According to the temp sensor designers, it may require up to ~17us
 117         * to complete a measurement.
 118         */
 119        if (wait)
 120                usleep_range(20, 50);
 121
 122        regmap_read(map, TEMPSENSE0, &val);
 123
 124        if (data->mode != THERMAL_DEVICE_ENABLED) {
 125                regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
 126                regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
 127        }
 128
 129        if ((val & TEMPSENSE0_FINISHED) == 0) {
 130                dev_dbg(&tz->device, "temp measurement never finished\n");
 131                return -EAGAIN;
 132        }
 133
 134        n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT;
 135
 136        /* See imx_get_sensor_data() for formula derivation */
 137        *temp = data->c2 + data->c1 * n_meas;
 138
 139        /* Update alarm value to next higher trip point */
 140        if (data->alarm_temp == data->temp_passive && *temp >= data->temp_passive)
 141                imx_set_alarm_temp(data, data->temp_critical);
 142        if (data->alarm_temp == data->temp_critical && *temp < data->temp_passive) {
 143                imx_set_alarm_temp(data, data->temp_passive);
 144                dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
 145                        data->alarm_temp / 1000);
 146        }
 147
 148        if (*temp != data->last_temp) {
 149                dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
 150                data->last_temp = *temp;
 151        }
 152
 153        /* Reenable alarm IRQ if temperature below alarm temperature */
 154        if (!data->irq_enabled && *temp < data->alarm_temp) {
 155                data->irq_enabled = true;
 156                enable_irq(data->irq);
 157        }
 158
 159        return 0;
 160}
 161
 162static int imx_get_mode(struct thermal_zone_device *tz,
 163                        enum thermal_device_mode *mode)
 164{
 165        struct imx_thermal_data *data = tz->devdata;
 166
 167        *mode = data->mode;
 168
 169        return 0;
 170}
 171
 172static int imx_set_mode(struct thermal_zone_device *tz,
 173                        enum thermal_device_mode mode)
 174{
 175        struct imx_thermal_data *data = tz->devdata;
 176        struct regmap *map = data->tempmon;
 177
 178        if (mode == THERMAL_DEVICE_ENABLED) {
 179                tz->polling_delay = IMX_POLLING_DELAY;
 180                tz->passive_delay = IMX_PASSIVE_DELAY;
 181
 182                regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
 183                regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
 184
 185                if (!data->irq_enabled) {
 186                        data->irq_enabled = true;
 187                        enable_irq(data->irq);
 188                }
 189        } else {
 190                regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
 191                regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
 192
 193                tz->polling_delay = 0;
 194                tz->passive_delay = 0;
 195
 196                if (data->irq_enabled) {
 197                        disable_irq(data->irq);
 198                        data->irq_enabled = false;
 199                }
 200        }
 201
 202        data->mode = mode;
 203        thermal_zone_device_update(tz);
 204
 205        return 0;
 206}
 207
 208static int imx_get_trip_type(struct thermal_zone_device *tz, int trip,
 209                             enum thermal_trip_type *type)
 210{
 211        *type = (trip == IMX_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
 212                                             THERMAL_TRIP_CRITICAL;
 213        return 0;
 214}
 215
 216static int imx_get_crit_temp(struct thermal_zone_device *tz,
 217                             unsigned long *temp)
 218{
 219        struct imx_thermal_data *data = tz->devdata;
 220
 221        *temp = data->temp_critical;
 222        return 0;
 223}
 224
 225static int imx_get_trip_temp(struct thermal_zone_device *tz, int trip,
 226                             unsigned long *temp)
 227{
 228        struct imx_thermal_data *data = tz->devdata;
 229
 230        *temp = (trip == IMX_TRIP_PASSIVE) ? data->temp_passive :
 231                                             data->temp_critical;
 232        return 0;
 233}
 234
 235static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
 236                             unsigned long temp)
 237{
 238        struct imx_thermal_data *data = tz->devdata;
 239
 240        if (trip == IMX_TRIP_CRITICAL)
 241                return -EPERM;
 242
 243        if (temp > IMX_TEMP_PASSIVE)
 244                return -EINVAL;
 245
 246        data->temp_passive = temp;
 247
 248        imx_set_alarm_temp(data, temp);
 249
 250        return 0;
 251}
 252
 253static int imx_bind(struct thermal_zone_device *tz,
 254                    struct thermal_cooling_device *cdev)
 255{
 256        int ret;
 257
 258        ret = thermal_zone_bind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev,
 259                                               THERMAL_NO_LIMIT,
 260                                               THERMAL_NO_LIMIT);
 261        if (ret) {
 262                dev_err(&tz->device,
 263                        "binding zone %s with cdev %s failed:%d\n",
 264                        tz->type, cdev->type, ret);
 265                return ret;
 266        }
 267
 268        return 0;
 269}
 270
 271static int imx_unbind(struct thermal_zone_device *tz,
 272                      struct thermal_cooling_device *cdev)
 273{
 274        int ret;
 275
 276        ret = thermal_zone_unbind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev);
 277        if (ret) {
 278                dev_err(&tz->device,
 279                        "unbinding zone %s with cdev %s failed:%d\n",
 280                        tz->type, cdev->type, ret);
 281                return ret;
 282        }
 283
 284        return 0;
 285}
 286
 287static const struct thermal_zone_device_ops imx_tz_ops = {
 288        .bind = imx_bind,
 289        .unbind = imx_unbind,
 290        .get_temp = imx_get_temp,
 291        .get_mode = imx_get_mode,
 292        .set_mode = imx_set_mode,
 293        .get_trip_type = imx_get_trip_type,
 294        .get_trip_temp = imx_get_trip_temp,
 295        .get_crit_temp = imx_get_crit_temp,
 296        .set_trip_temp = imx_set_trip_temp,
 297};
 298
 299static int imx_get_sensor_data(struct platform_device *pdev)
 300{
 301        struct imx_thermal_data *data = platform_get_drvdata(pdev);
 302        struct regmap *map;
 303        int t1, t2, n1, n2;
 304        int ret;
 305        u32 val;
 306
 307        map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
 308                                              "fsl,tempmon-data");
 309        if (IS_ERR(map)) {
 310                ret = PTR_ERR(map);
 311                dev_err(&pdev->dev, "failed to get sensor regmap: %d\n", ret);
 312                return ret;
 313        }
 314
 315        ret = regmap_read(map, OCOTP_ANA1, &val);
 316        if (ret) {
 317                dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
 318                return ret;
 319        }
 320
 321        if (val == 0 || val == ~0) {
 322                dev_err(&pdev->dev, "invalid sensor calibration data\n");
 323                return -EINVAL;
 324        }
 325
 326        /*
 327         * Sensor data layout:
 328         *   [31:20] - sensor value @ 25C
 329         *    [19:8] - sensor value of hot
 330         *     [7:0] - hot temperature value
 331         */
 332        n1 = val >> 20;
 333        n2 = (val & 0xfff00) >> 8;
 334        t2 = val & 0xff;
 335        t1 = 25; /* t1 always 25C */
 336
 337        /*
 338         * Derived from linear interpolation,
 339         * Tmeas = T2 + (Nmeas - N2) * (T1 - T2) / (N1 - N2)
 340         * We want to reduce this down to the minimum computation necessary
 341         * for each temperature read.  Also, we want Tmeas in millicelsius
 342         * and we don't want to lose precision from integer division. So...
 343         * milli_Tmeas = 1000 * T2 + 1000 * (Nmeas - N2) * (T1 - T2) / (N1 - N2)
 344         * Let constant c1 = 1000 * (T1 - T2) / (N1 - N2)
 345         * milli_Tmeas = (1000 * T2) + c1 * (Nmeas - N2)
 346         * milli_Tmeas = (1000 * T2) + (c1 * Nmeas) - (c1 * N2)
 347         * Let constant c2 = (1000 * T2) - (c1 * N2)
 348         * milli_Tmeas = c2 + (c1 * Nmeas)
 349         */
 350        data->c1 = 1000 * (t1 - t2) / (n1 - n2);
 351        data->c2 = 1000 * t2 - data->c1 * n2;
 352
 353        /*
 354         * Set the default passive cooling trip point to 20 °C below the
 355         * maximum die temperature. Can be changed from userspace.
 356         */
 357        data->temp_passive = 1000 * (t2 - 20);
 358
 359        /*
 360         * The maximum die temperature is t2, let's give 5 °C cushion
 361         * for noise and possible temperature rise between measurements.
 362         */
 363        data->temp_critical = 1000 * (t2 - 5);
 364
 365        return 0;
 366}
 367
 368static irqreturn_t imx_thermal_alarm_irq(int irq, void *dev)
 369{
 370        struct imx_thermal_data *data = dev;
 371
 372        disable_irq_nosync(irq);
 373        data->irq_enabled = false;
 374
 375        return IRQ_WAKE_THREAD;
 376}
 377
 378static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev)
 379{
 380        struct imx_thermal_data *data = dev;
 381
 382        dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
 383                data->alarm_temp / 1000);
 384
 385        thermal_zone_device_update(data->tz);
 386
 387        return IRQ_HANDLED;
 388}
 389
 390static int imx_thermal_probe(struct platform_device *pdev)
 391{
 392        struct imx_thermal_data *data;
 393        struct cpumask clip_cpus;
 394        struct regmap *map;
 395        int measure_freq;
 396        int ret;
 397
 398        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 399        if (!data)
 400                return -ENOMEM;
 401
 402        map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "fsl,tempmon");
 403        if (IS_ERR(map)) {
 404                ret = PTR_ERR(map);
 405                dev_err(&pdev->dev, "failed to get tempmon regmap: %d\n", ret);
 406                return ret;
 407        }
 408        data->tempmon = map;
 409
 410        data->irq = platform_get_irq(pdev, 0);
 411        if (data->irq < 0)
 412                return data->irq;
 413
 414        ret = devm_request_threaded_irq(&pdev->dev, data->irq,
 415                        imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
 416                        0, "imx_thermal", data);
 417        if (ret < 0) {
 418                dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
 419                return ret;
 420        }
 421
 422        platform_set_drvdata(pdev, data);
 423
 424        ret = imx_get_sensor_data(pdev);
 425        if (ret) {
 426                dev_err(&pdev->dev, "failed to get sensor data\n");
 427                return ret;
 428        }
 429
 430        /* Make sure sensor is in known good state for measurements */
 431        regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
 432        regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
 433        regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
 434        regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF);
 435        regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
 436
 437        cpumask_set_cpu(0, &clip_cpus);
 438        data->cdev = cpufreq_cooling_register(&clip_cpus);
 439        if (IS_ERR(data->cdev)) {
 440                ret = PTR_ERR(data->cdev);
 441                dev_err(&pdev->dev,
 442                        "failed to register cpufreq cooling device: %d\n", ret);
 443                return ret;
 444        }
 445
 446        data->tz = thermal_zone_device_register("imx_thermal_zone",
 447                                                IMX_TRIP_NUM,
 448                                                BIT(IMX_TRIP_PASSIVE), data,
 449                                                &imx_tz_ops, NULL,
 450                                                IMX_PASSIVE_DELAY,
 451                                                IMX_POLLING_DELAY);
 452        if (IS_ERR(data->tz)) {
 453                ret = PTR_ERR(data->tz);
 454                dev_err(&pdev->dev,
 455                        "failed to register thermal zone device %d\n", ret);
 456                cpufreq_cooling_unregister(data->cdev);
 457                return ret;
 458        }
 459
 460        /* Enable measurements at ~ 10 Hz */
 461        regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
 462        measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
 463        regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq);
 464        imx_set_alarm_temp(data, data->temp_passive);
 465        regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
 466        regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
 467
 468        data->irq_enabled = true;
 469        data->mode = THERMAL_DEVICE_ENABLED;
 470
 471        return 0;
 472}
 473
 474static int imx_thermal_remove(struct platform_device *pdev)
 475{
 476        struct imx_thermal_data *data = platform_get_drvdata(pdev);
 477        struct regmap *map = data->tempmon;
 478
 479        /* Disable measurements */
 480        regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
 481
 482        thermal_zone_device_unregister(data->tz);
 483        cpufreq_cooling_unregister(data->cdev);
 484
 485        return 0;
 486}
 487
 488#ifdef CONFIG_PM_SLEEP
 489static int imx_thermal_suspend(struct device *dev)
 490{
 491        struct imx_thermal_data *data = dev_get_drvdata(dev);
 492        struct regmap *map = data->tempmon;
 493        u32 val;
 494
 495        regmap_read(map, TEMPSENSE0, &val);
 496        if ((val & TEMPSENSE0_POWER_DOWN) == 0) {
 497                /*
 498                 * If a measurement is taking place, wait for a long enough
 499                 * time for it to finish, and then check again.  If it still
 500                 * does not finish, something must go wrong.
 501                 */
 502                udelay(50);
 503                regmap_read(map, TEMPSENSE0, &val);
 504                if ((val & TEMPSENSE0_POWER_DOWN) == 0)
 505                        return -ETIMEDOUT;
 506        }
 507
 508        return 0;
 509}
 510
 511static int imx_thermal_resume(struct device *dev)
 512{
 513        /* Nothing to do for now */
 514        return 0;
 515}
 516#endif
 517
 518static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops,
 519                         imx_thermal_suspend, imx_thermal_resume);
 520
 521static const struct of_device_id of_imx_thermal_match[] = {
 522        { .compatible = "fsl,imx6q-tempmon", },
 523        { /* end */ }
 524};
 525
 526static struct platform_driver imx_thermal = {
 527        .driver = {
 528                .name   = "imx_thermal",
 529                .owner  = THIS_MODULE,
 530                .pm     = &imx_thermal_pm_ops,
 531                .of_match_table = of_imx_thermal_match,
 532        },
 533        .probe          = imx_thermal_probe,
 534        .remove         = imx_thermal_remove,
 535};
 536module_platform_driver(imx_thermal);
 537
 538MODULE_AUTHOR("Freescale Semiconductor, Inc.");
 539MODULE_DESCRIPTION("Thermal driver for Freescale i.MX SoCs");
 540MODULE_LICENSE("GPL v2");
 541MODULE_ALIAS("platform:imx-thermal");
 542
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.