linux/drivers/thermal/exynos_thermal.c
<<
>>
Prefs
   1/*
   2 * exynos_thermal.c - Samsung EXYNOS TMU (Thermal Management Unit)
   3 *
   4 *  Copyright (C) 2011 Samsung Electronics
   5 *  Donggeun Kim <dg77.kim@samsung.com>
   6 *  Amit Daniel Kachhap <amit.kachhap@linaro.org>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21 *
  22 */
  23
  24#include <linux/module.h>
  25#include <linux/err.h>
  26#include <linux/kernel.h>
  27#include <linux/slab.h>
  28#include <linux/platform_device.h>
  29#include <linux/interrupt.h>
  30#include <linux/clk.h>
  31#include <linux/workqueue.h>
  32#include <linux/sysfs.h>
  33#include <linux/kobject.h>
  34#include <linux/io.h>
  35#include <linux/mutex.h>
  36#include <linux/platform_data/exynos_thermal.h>
  37#include <linux/thermal.h>
  38#include <linux/cpufreq.h>
  39#include <linux/cpu_cooling.h>
  40#include <linux/of.h>
  41
  42#include <plat/cpu.h>
  43
  44/* Exynos generic registers */
  45#define EXYNOS_TMU_REG_TRIMINFO         0x0
  46#define EXYNOS_TMU_REG_CONTROL          0x20
  47#define EXYNOS_TMU_REG_STATUS           0x28
  48#define EXYNOS_TMU_REG_CURRENT_TEMP     0x40
  49#define EXYNOS_TMU_REG_INTEN            0x70
  50#define EXYNOS_TMU_REG_INTSTAT          0x74
  51#define EXYNOS_TMU_REG_INTCLEAR         0x78
  52
  53#define EXYNOS_TMU_TRIM_TEMP_MASK       0xff
  54#define EXYNOS_TMU_GAIN_SHIFT           8
  55#define EXYNOS_TMU_REF_VOLTAGE_SHIFT    24
  56#define EXYNOS_TMU_CORE_ON              3
  57#define EXYNOS_TMU_CORE_OFF             2
  58#define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET      50
  59
  60/* Exynos4210 specific registers */
  61#define EXYNOS4210_TMU_REG_THRESHOLD_TEMP       0x44
  62#define EXYNOS4210_TMU_REG_TRIG_LEVEL0  0x50
  63#define EXYNOS4210_TMU_REG_TRIG_LEVEL1  0x54
  64#define EXYNOS4210_TMU_REG_TRIG_LEVEL2  0x58
  65#define EXYNOS4210_TMU_REG_TRIG_LEVEL3  0x5C
  66#define EXYNOS4210_TMU_REG_PAST_TEMP0   0x60
  67#define EXYNOS4210_TMU_REG_PAST_TEMP1   0x64
  68#define EXYNOS4210_TMU_REG_PAST_TEMP2   0x68
  69#define EXYNOS4210_TMU_REG_PAST_TEMP3   0x6C
  70
  71#define EXYNOS4210_TMU_TRIG_LEVEL0_MASK 0x1
  72#define EXYNOS4210_TMU_TRIG_LEVEL1_MASK 0x10
  73#define EXYNOS4210_TMU_TRIG_LEVEL2_MASK 0x100
  74#define EXYNOS4210_TMU_TRIG_LEVEL3_MASK 0x1000
  75#define EXYNOS4210_TMU_INTCLEAR_VAL     0x1111
  76
  77/* Exynos5250 and Exynos4412 specific registers */
  78#define EXYNOS_TMU_TRIMINFO_CON 0x14
  79#define EXYNOS_THD_TEMP_RISE            0x50
  80#define EXYNOS_THD_TEMP_FALL            0x54
  81#define EXYNOS_EMUL_CON         0x80
  82
  83#define EXYNOS_TRIMINFO_RELOAD          0x1
  84#define EXYNOS_TMU_CLEAR_RISE_INT       0x111
  85#define EXYNOS_TMU_CLEAR_FALL_INT       (0x111 << 16)
  86#define EXYNOS_MUX_ADDR_VALUE           6
  87#define EXYNOS_MUX_ADDR_SHIFT           20
  88#define EXYNOS_TMU_TRIP_MODE_SHIFT      13
  89
  90#define EFUSE_MIN_VALUE 40
  91#define EFUSE_MAX_VALUE 100
  92
  93/* In-kernel thermal framework related macros & definations */
  94#define SENSOR_NAME_LEN 16
  95#define MAX_TRIP_COUNT  8
  96#define MAX_COOLING_DEVICE 4
  97
  98#define ACTIVE_INTERVAL 500
  99#define IDLE_INTERVAL 10000
 100#define MCELSIUS        1000
 101
 102/* CPU Zone information */
 103#define PANIC_ZONE      4
 104#define WARN_ZONE       3
 105#define MONITOR_ZONE    2
 106#define SAFE_ZONE       1
 107
 108#define GET_ZONE(trip) (trip + 2)
 109#define GET_TRIP(zone) (zone - 2)
 110
 111#define EXYNOS_ZONE_COUNT       3
 112
 113struct exynos_tmu_data {
 114        struct exynos_tmu_platform_data *pdata;
 115        struct resource *mem;
 116        void __iomem *base;
 117        int irq;
 118        enum soc_type soc;
 119        struct work_struct irq_work;
 120        struct mutex lock;
 121        struct clk *clk;
 122        u8 temp_error1, temp_error2;
 123};
 124
 125struct  thermal_trip_point_conf {
 126        int trip_val[MAX_TRIP_COUNT];
 127        int trip_count;
 128};
 129
 130struct  thermal_cooling_conf {
 131        struct freq_clip_table freq_data[MAX_TRIP_COUNT];
 132        int freq_clip_count;
 133};
 134
 135struct thermal_sensor_conf {
 136        char name[SENSOR_NAME_LEN];
 137        int (*read_temperature)(void *data);
 138        struct thermal_trip_point_conf trip_data;
 139        struct thermal_cooling_conf cooling_data;
 140        void *private_data;
 141};
 142
 143struct exynos_thermal_zone {
 144        enum thermal_device_mode mode;
 145        struct thermal_zone_device *therm_dev;
 146        struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
 147        unsigned int cool_dev_size;
 148        struct platform_device *exynos4_dev;
 149        struct thermal_sensor_conf *sensor_conf;
 150        bool bind;
 151};
 152
 153static struct exynos_thermal_zone *th_zone;
 154static void exynos_unregister_thermal(void);
 155static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
 156
 157/* Get mode callback functions for thermal zone */
 158static int exynos_get_mode(struct thermal_zone_device *thermal,
 159                        enum thermal_device_mode *mode)
 160{
 161        if (th_zone)
 162                *mode = th_zone->mode;
 163        return 0;
 164}
 165
 166/* Set mode callback functions for thermal zone */
 167static int exynos_set_mode(struct thermal_zone_device *thermal,
 168                        enum thermal_device_mode mode)
 169{
 170        if (!th_zone->therm_dev) {
 171                pr_notice("thermal zone not registered\n");
 172                return 0;
 173        }
 174
 175        mutex_lock(&th_zone->therm_dev->lock);
 176
 177        if (mode == THERMAL_DEVICE_ENABLED)
 178                th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
 179        else
 180                th_zone->therm_dev->polling_delay = 0;
 181
 182        mutex_unlock(&th_zone->therm_dev->lock);
 183
 184        th_zone->mode = mode;
 185        thermal_zone_device_update(th_zone->therm_dev);
 186        pr_info("thermal polling set for duration=%d msec\n",
 187                                th_zone->therm_dev->polling_delay);
 188        return 0;
 189}
 190
 191
 192/* Get trip type callback functions for thermal zone */
 193static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
 194                                 enum thermal_trip_type *type)
 195{
 196        switch (GET_ZONE(trip)) {
 197        case MONITOR_ZONE:
 198        case WARN_ZONE:
 199                *type = THERMAL_TRIP_ACTIVE;
 200                break;
 201        case PANIC_ZONE:
 202                *type = THERMAL_TRIP_CRITICAL;
 203                break;
 204        default:
 205                return -EINVAL;
 206        }
 207        return 0;
 208}
 209
 210/* Get trip temperature callback functions for thermal zone */
 211static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
 212                                unsigned long *temp)
 213{
 214        if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
 215                return -EINVAL;
 216
 217        *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
 218        /* convert the temperature into millicelsius */
 219        *temp = *temp * MCELSIUS;
 220
 221        return 0;
 222}
 223
 224/* Get critical temperature callback functions for thermal zone */
 225static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
 226                                unsigned long *temp)
 227{
 228        int ret;
 229        /* Panic zone */
 230        ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
 231        return ret;
 232}
 233
 234static int exynos_get_frequency_level(unsigned int cpu, unsigned int freq)
 235{
 236        int i = 0, ret = -EINVAL;
 237        struct cpufreq_frequency_table *table = NULL;
 238#ifdef CONFIG_CPU_FREQ
 239        table = cpufreq_frequency_get_table(cpu);
 240#endif
 241        if (!table)
 242                return ret;
 243
 244        while (table[i].frequency != CPUFREQ_TABLE_END) {
 245                if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
 246                        continue;
 247                if (table[i].frequency == freq)
 248                        return i;
 249                i++;
 250        }
 251        return ret;
 252}
 253
 254/* Bind callback functions for thermal zone */
 255static int exynos_bind(struct thermal_zone_device *thermal,
 256                        struct thermal_cooling_device *cdev)
 257{
 258        int ret = 0, i, tab_size, level;
 259        struct freq_clip_table *tab_ptr, *clip_data;
 260        struct thermal_sensor_conf *data = th_zone->sensor_conf;
 261
 262        tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
 263        tab_size = data->cooling_data.freq_clip_count;
 264
 265        if (tab_ptr == NULL || tab_size == 0)
 266                return -EINVAL;
 267
 268        /* find the cooling device registered*/
 269        for (i = 0; i < th_zone->cool_dev_size; i++)
 270                if (cdev == th_zone->cool_dev[i])
 271                        break;
 272
 273        /* No matching cooling device */
 274        if (i == th_zone->cool_dev_size)
 275                return 0;
 276
 277        /* Bind the thermal zone to the cpufreq cooling device */
 278        for (i = 0; i < tab_size; i++) {
 279                clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
 280                level = exynos_get_frequency_level(0, clip_data->freq_clip_max);
 281                if (level < 0)
 282                        return 0;
 283                switch (GET_ZONE(i)) {
 284                case MONITOR_ZONE:
 285                case WARN_ZONE:
 286                        if (thermal_zone_bind_cooling_device(thermal, i, cdev,
 287                                                                level, level)) {
 288                                pr_err("error binding cdev inst %d\n", i);
 289                                ret = -EINVAL;
 290                        }
 291                        th_zone->bind = true;
 292                        break;
 293                default:
 294                        ret = -EINVAL;
 295                }
 296        }
 297
 298        return ret;
 299}
 300
 301/* Unbind callback functions for thermal zone */
 302static int exynos_unbind(struct thermal_zone_device *thermal,
 303                        struct thermal_cooling_device *cdev)
 304{
 305        int ret = 0, i, tab_size;
 306        struct thermal_sensor_conf *data = th_zone->sensor_conf;
 307
 308        if (th_zone->bind == false)
 309                return 0;
 310
 311        tab_size = data->cooling_data.freq_clip_count;
 312
 313        if (tab_size == 0)
 314                return -EINVAL;
 315
 316        /* find the cooling device registered*/
 317        for (i = 0; i < th_zone->cool_dev_size; i++)
 318                if (cdev == th_zone->cool_dev[i])
 319                        break;
 320
 321        /* No matching cooling device */
 322        if (i == th_zone->cool_dev_size)
 323                return 0;
 324
 325        /* Bind the thermal zone to the cpufreq cooling device */
 326        for (i = 0; i < tab_size; i++) {
 327                switch (GET_ZONE(i)) {
 328                case MONITOR_ZONE:
 329                case WARN_ZONE:
 330                        if (thermal_zone_unbind_cooling_device(thermal, i,
 331                                                                cdev)) {
 332                                pr_err("error unbinding cdev inst=%d\n", i);
 333                                ret = -EINVAL;
 334                        }
 335                        th_zone->bind = false;
 336                        break;
 337                default:
 338                        ret = -EINVAL;
 339                }
 340        }
 341        return ret;
 342}
 343
 344/* Get temperature callback functions for thermal zone */
 345static int exynos_get_temp(struct thermal_zone_device *thermal,
 346                        unsigned long *temp)
 347{
 348        void *data;
 349
 350        if (!th_zone->sensor_conf) {
 351                pr_info("Temperature sensor not initialised\n");
 352                return -EINVAL;
 353        }
 354        data = th_zone->sensor_conf->private_data;
 355        *temp = th_zone->sensor_conf->read_temperature(data);
 356        /* convert the temperature into millicelsius */
 357        *temp = *temp * MCELSIUS;
 358        return 0;
 359}
 360
 361/* Get the temperature trend */
 362static int exynos_get_trend(struct thermal_zone_device *thermal,
 363                        int trip, enum thermal_trend *trend)
 364{
 365        if (thermal->temperature >= trip)
 366                *trend = THERMAL_TREND_RAISING;
 367        else
 368                *trend = THERMAL_TREND_DROPPING;
 369
 370        return 0;
 371}
 372/* Operation callback functions for thermal zone */
 373static struct thermal_zone_device_ops const exynos_dev_ops = {
 374        .bind = exynos_bind,
 375        .unbind = exynos_unbind,
 376        .get_temp = exynos_get_temp,
 377        .get_trend = exynos_get_trend,
 378        .get_mode = exynos_get_mode,
 379        .set_mode = exynos_set_mode,
 380        .get_trip_type = exynos_get_trip_type,
 381        .get_trip_temp = exynos_get_trip_temp,
 382        .get_crit_temp = exynos_get_crit_temp,
 383};
 384
 385/*
 386 * This function may be called from interrupt based temperature sensor
 387 * when threshold is changed.
 388 */
 389static void exynos_report_trigger(void)
 390{
 391        unsigned int i;
 392        char data[10];
 393        char *envp[] = { data, NULL };
 394
 395        if (!th_zone || !th_zone->therm_dev)
 396                return;
 397        if (th_zone->bind == false) {
 398                for (i = 0; i < th_zone->cool_dev_size; i++) {
 399                        if (!th_zone->cool_dev[i])
 400                                continue;
 401                        exynos_bind(th_zone->therm_dev,
 402                                        th_zone->cool_dev[i]);
 403                }
 404        }
 405
 406        thermal_zone_device_update(th_zone->therm_dev);
 407
 408        mutex_lock(&th_zone->therm_dev->lock);
 409        /* Find the level for which trip happened */
 410        for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
 411                if (th_zone->therm_dev->last_temperature <
 412                        th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
 413                        break;
 414        }
 415
 416        if (th_zone->mode == THERMAL_DEVICE_ENABLED) {
 417                if (i > 0)
 418                        th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
 419                else
 420                        th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
 421        }
 422
 423        snprintf(data, sizeof(data), "%u", i);
 424        kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
 425        mutex_unlock(&th_zone->therm_dev->lock);
 426}
 427
 428/* Register with the in-kernel thermal management */
 429static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
 430{
 431        int ret;
 432        struct cpumask mask_val;
 433
 434        if (!sensor_conf || !sensor_conf->read_temperature) {
 435                pr_err("Temperature sensor not initialised\n");
 436                return -EINVAL;
 437        }
 438
 439        th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
 440        if (!th_zone)
 441                return -ENOMEM;
 442
 443        th_zone->sensor_conf = sensor_conf;
 444        cpumask_set_cpu(0, &mask_val);
 445        th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
 446        if (IS_ERR(th_zone->cool_dev[0])) {
 447                pr_err("Failed to register cpufreq cooling device\n");
 448                ret = -EINVAL;
 449                goto err_unregister;
 450        }
 451        th_zone->cool_dev_size++;
 452
 453        th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
 454                        EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
 455                        IDLE_INTERVAL);
 456
 457        if (IS_ERR(th_zone->therm_dev)) {
 458                pr_err("Failed to register thermal zone device\n");
 459                ret = -EINVAL;
 460                goto err_unregister;
 461        }
 462        th_zone->mode = THERMAL_DEVICE_ENABLED;
 463
 464        pr_info("Exynos: Kernel Thermal management registered\n");
 465
 466        return 0;
 467
 468err_unregister:
 469        exynos_unregister_thermal();
 470        return ret;
 471}
 472
 473/* Un-Register with the in-kernel thermal management */
 474static void exynos_unregister_thermal(void)
 475{
 476        int i;
 477
 478        if (!th_zone)
 479                return;
 480
 481        if (th_zone->therm_dev)
 482                thermal_zone_device_unregister(th_zone->therm_dev);
 483
 484        for (i = 0; i < th_zone->cool_dev_size; i++) {
 485                if (th_zone->cool_dev[i])
 486                        cpufreq_cooling_unregister(th_zone->cool_dev[i]);
 487        }
 488
 489        kfree(th_zone);
 490        pr_info("Exynos: Kernel Thermal management unregistered\n");
 491}
 492
 493/*
 494 * TMU treats temperature as a mapped temperature code.
 495 * The temperature is converted differently depending on the calibration type.
 496 */
 497static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
 498{
 499        struct exynos_tmu_platform_data *pdata = data->pdata;
 500        int temp_code;
 501
 502        if (data->soc == SOC_ARCH_EXYNOS4210)
 503                /* temp should range between 25 and 125 */
 504                if (temp < 25 || temp > 125) {
 505                        temp_code = -EINVAL;
 506                        goto out;
 507                }
 508
 509        switch (pdata->cal_type) {
 510        case TYPE_TWO_POINT_TRIMMING:
 511                temp_code = (temp - 25) *
 512                    (data->temp_error2 - data->temp_error1) /
 513                    (85 - 25) + data->temp_error1;
 514                break;
 515        case TYPE_ONE_POINT_TRIMMING:
 516                temp_code = temp + data->temp_error1 - 25;
 517                break;
 518        default:
 519                temp_code = temp + EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
 520                break;
 521        }
 522out:
 523        return temp_code;
 524}
 525
 526/*
 527 * Calculate a temperature value from a temperature code.
 528 * The unit of the temperature is degree Celsius.
 529 */
 530static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
 531{
 532        struct exynos_tmu_platform_data *pdata = data->pdata;
 533        int temp;
 534
 535        if (data->soc == SOC_ARCH_EXYNOS4210)
 536                /* temp_code should range between 75 and 175 */
 537                if (temp_code < 75 || temp_code > 175) {
 538                        temp = -ENODATA;
 539                        goto out;
 540                }
 541
 542        switch (pdata->cal_type) {
 543        case TYPE_TWO_POINT_TRIMMING:
 544                temp = (temp_code - data->temp_error1) * (85 - 25) /
 545                    (data->temp_error2 - data->temp_error1) + 25;
 546                break;
 547        case TYPE_ONE_POINT_TRIMMING:
 548                temp = temp_code - data->temp_error1 + 25;
 549                break;
 550        default:
 551                temp = temp_code - EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
 552                break;
 553        }
 554out:
 555        return temp;
 556}
 557
 558static int exynos_tmu_initialize(struct platform_device *pdev)
 559{
 560        struct exynos_tmu_data *data = platform_get_drvdata(pdev);
 561        struct exynos_tmu_platform_data *pdata = data->pdata;
 562        unsigned int status, trim_info, rising_threshold;
 563        int ret = 0, threshold_code;
 564
 565        mutex_lock(&data->lock);
 566        clk_enable(data->clk);
 567
 568        status = readb(data->base + EXYNOS_TMU_REG_STATUS);
 569        if (!status) {
 570                ret = -EBUSY;
 571                goto out;
 572        }
 573
 574        if (data->soc == SOC_ARCH_EXYNOS) {
 575                __raw_writel(EXYNOS_TRIMINFO_RELOAD,
 576                                data->base + EXYNOS_TMU_TRIMINFO_CON);
 577        }
 578        /* Save trimming info in order to perform calibration */
 579        trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
 580        data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
 581        data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);
 582
 583        if ((EFUSE_MIN_VALUE > data->temp_error1) ||
 584                        (data->temp_error1 > EFUSE_MAX_VALUE) ||
 585                        (data->temp_error2 != 0))
 586                data->temp_error1 = pdata->efuse_value;
 587
 588        if (data->soc == SOC_ARCH_EXYNOS4210) {
 589                /* Write temperature code for threshold */
 590                threshold_code = temp_to_code(data, pdata->threshold);
 591                if (threshold_code < 0) {
 592                        ret = threshold_code;
 593                        goto out;
 594                }
 595                writeb(threshold_code,
 596                        data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
 597
 598                writeb(pdata->trigger_levels[0],
 599                        data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0);
 600                writeb(pdata->trigger_levels[1],
 601                        data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL1);
 602                writeb(pdata->trigger_levels[2],
 603                        data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL2);
 604                writeb(pdata->trigger_levels[3],
 605                        data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL3);
 606
 607                writel(EXYNOS4210_TMU_INTCLEAR_VAL,
 608                        data->base + EXYNOS_TMU_REG_INTCLEAR);
 609        } else if (data->soc == SOC_ARCH_EXYNOS) {
 610                /* Write temperature code for threshold */
 611                threshold_code = temp_to_code(data, pdata->trigger_levels[0]);
 612                if (threshold_code < 0) {
 613                        ret = threshold_code;
 614                        goto out;
 615                }
 616                rising_threshold = threshold_code;
 617                threshold_code = temp_to_code(data, pdata->trigger_levels[1]);
 618                if (threshold_code < 0) {
 619                        ret = threshold_code;
 620                        goto out;
 621                }
 622                rising_threshold |= (threshold_code << 8);
 623                threshold_code = temp_to_code(data, pdata->trigger_levels[2]);
 624                if (threshold_code < 0) {
 625                        ret = threshold_code;
 626                        goto out;
 627                }
 628                rising_threshold |= (threshold_code << 16);
 629
 630                writel(rising_threshold,
 631                                data->base + EXYNOS_THD_TEMP_RISE);
 632                writel(0, data->base + EXYNOS_THD_TEMP_FALL);
 633
 634                writel(EXYNOS_TMU_CLEAR_RISE_INT|EXYNOS_TMU_CLEAR_FALL_INT,
 635                                data->base + EXYNOS_TMU_REG_INTCLEAR);
 636        }
 637out:
 638        clk_disable(data->clk);
 639        mutex_unlock(&data->lock);
 640
 641        return ret;
 642}
 643
 644static void exynos_tmu_control(struct platform_device *pdev, bool on)
 645{
 646        struct exynos_tmu_data *data = platform_get_drvdata(pdev);
 647        struct exynos_tmu_platform_data *pdata = data->pdata;
 648        unsigned int con, interrupt_en;
 649
 650        mutex_lock(&data->lock);
 651        clk_enable(data->clk);
 652
 653        con = pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT |
 654                pdata->gain << EXYNOS_TMU_GAIN_SHIFT;
 655
 656        if (data->soc == SOC_ARCH_EXYNOS) {
 657                con |= pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT;
 658                con |= (EXYNOS_MUX_ADDR_VALUE << EXYNOS_MUX_ADDR_SHIFT);
 659        }
 660
 661        if (on) {
 662                con |= EXYNOS_TMU_CORE_ON;
 663                interrupt_en = pdata->trigger_level3_en << 12 |
 664                        pdata->trigger_level2_en << 8 |
 665                        pdata->trigger_level1_en << 4 |
 666                        pdata->trigger_level0_en;
 667        } else {
 668                con |= EXYNOS_TMU_CORE_OFF;
 669                interrupt_en = 0; /* Disable all interrupts */
 670        }
 671        writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN);
 672        writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
 673
 674        clk_disable(data->clk);
 675        mutex_unlock(&data->lock);
 676}
 677
 678static int exynos_tmu_read(struct exynos_tmu_data *data)
 679{
 680        u8 temp_code;
 681        int temp;
 682
 683        mutex_lock(&data->lock);
 684        clk_enable(data->clk);
 685
 686        temp_code = readb(data->base + EXYNOS_TMU_REG_CURRENT_TEMP);
 687        temp = code_to_temp(data, temp_code);
 688
 689        clk_disable(data->clk);
 690        mutex_unlock(&data->lock);
 691
 692        return temp;
 693}
 694
 695static void exynos_tmu_work(struct work_struct *work)
 696{
 697        struct exynos_tmu_data *data = container_of(work,
 698                        struct exynos_tmu_data, irq_work);
 699
 700        mutex_lock(&data->lock);
 701        clk_enable(data->clk);
 702
 703
 704        if (data->soc == SOC_ARCH_EXYNOS)
 705                writel(EXYNOS_TMU_CLEAR_RISE_INT,
 706                                data->base + EXYNOS_TMU_REG_INTCLEAR);
 707        else
 708                writel(EXYNOS4210_TMU_INTCLEAR_VAL,
 709                                data->base + EXYNOS_TMU_REG_INTCLEAR);
 710
 711        clk_disable(data->clk);
 712        mutex_unlock(&data->lock);
 713        exynos_report_trigger();
 714        enable_irq(data->irq);
 715}
 716
 717static irqreturn_t exynos_tmu_irq(int irq, void *id)
 718{
 719        struct exynos_tmu_data *data = id;
 720
 721        disable_irq_nosync(irq);
 722        schedule_work(&data->irq_work);
 723
 724        return IRQ_HANDLED;
 725}
 726static struct thermal_sensor_conf exynos_sensor_conf = {
 727        .name                   = "exynos-therm",
 728        .read_temperature       = (int (*)(void *))exynos_tmu_read,
 729};
 730
 731#if defined(CONFIG_CPU_EXYNOS4210)
 732static struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
 733        .threshold = 80,
 734        .trigger_levels[0] = 5,
 735        .trigger_levels[1] = 20,
 736        .trigger_levels[2] = 30,
 737        .trigger_level0_en = 1,
 738        .trigger_level1_en = 1,
 739        .trigger_level2_en = 1,
 740        .trigger_level3_en = 0,
 741        .gain = 15,
 742        .reference_voltage = 7,
 743        .cal_type = TYPE_ONE_POINT_TRIMMING,
 744        .freq_tab[0] = {
 745                .freq_clip_max = 800 * 1000,
 746                .temp_level = 85,
 747        },
 748        .freq_tab[1] = {
 749                .freq_clip_max = 200 * 1000,
 750                .temp_level = 100,
 751        },
 752        .freq_tab_count = 2,
 753        .type = SOC_ARCH_EXYNOS4210,
 754};
 755#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
 756#else
 757#define EXYNOS4210_TMU_DRV_DATA (NULL)
 758#endif
 759
 760#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
 761static struct exynos_tmu_platform_data const exynos_default_tmu_data = {
 762        .trigger_levels[0] = 85,
 763        .trigger_levels[1] = 103,
 764        .trigger_levels[2] = 110,
 765        .trigger_level0_en = 1,
 766        .trigger_level1_en = 1,
 767        .trigger_level2_en = 1,
 768        .trigger_level3_en = 0,
 769        .gain = 8,
 770        .reference_voltage = 16,
 771        .noise_cancel_mode = 4,
 772        .cal_type = TYPE_ONE_POINT_TRIMMING,
 773        .efuse_value = 55,
 774        .freq_tab[0] = {
 775                .freq_clip_max = 800 * 1000,
 776                .temp_level = 85,
 777        },
 778        .freq_tab[1] = {
 779                .freq_clip_max = 200 * 1000,
 780                .temp_level = 103,
 781        },
 782        .freq_tab_count = 2,
 783        .type = SOC_ARCH_EXYNOS,
 784};
 785#define EXYNOS_TMU_DRV_DATA (&exynos_default_tmu_data)
 786#else
 787#define EXYNOS_TMU_DRV_DATA (NULL)
 788#endif
 789
 790#ifdef CONFIG_OF
 791static const struct of_device_id exynos_tmu_match[] = {
 792        {
 793                .compatible = "samsung,exynos4210-tmu",
 794                .data = (void *)EXYNOS4210_TMU_DRV_DATA,
 795        },
 796        {
 797                .compatible = "samsung,exynos5250-tmu",
 798                .data = (void *)EXYNOS_TMU_DRV_DATA,
 799        },
 800        {},
 801};
 802MODULE_DEVICE_TABLE(of, exynos_tmu_match);
 803#else
 804#define  exynos_tmu_match NULL
 805#endif
 806
 807static struct platform_device_id exynos_tmu_driver_ids[] = {
 808        {
 809                .name           = "exynos4210-tmu",
 810                .driver_data    = (kernel_ulong_t)EXYNOS4210_TMU_DRV_DATA,
 811        },
 812        {
 813                .name           = "exynos5250-tmu",
 814                .driver_data    = (kernel_ulong_t)EXYNOS_TMU_DRV_DATA,
 815        },
 816        { },
 817};
 818MODULE_DEVICE_TABLE(platform, exynos_tmu_driver_ids);
 819
 820static inline struct  exynos_tmu_platform_data *exynos_get_driver_data(
 821                        struct platform_device *pdev)
 822{
 823#ifdef CONFIG_OF
 824        if (pdev->dev.of_node) {
 825                const struct of_device_id *match;
 826                match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
 827                if (!match)
 828                        return NULL;
 829                return (struct exynos_tmu_platform_data *) match->data;
 830        }
 831#endif
 832        return (struct exynos_tmu_platform_data *)
 833                        platform_get_device_id(pdev)->driver_data;
 834}
 835static int exynos_tmu_probe(struct platform_device *pdev)
 836{
 837        struct exynos_tmu_data *data;
 838        struct exynos_tmu_platform_data *pdata = pdev->dev.platform_data;
 839        int ret, i;
 840
 841        if (!pdata)
 842                pdata = exynos_get_driver_data(pdev);
 843
 844        if (!pdata) {
 845                dev_err(&pdev->dev, "No platform init data supplied.\n");
 846                return -ENODEV;
 847        }
 848        data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data),
 849                                        GFP_KERNEL);
 850        if (!data) {
 851                dev_err(&pdev->dev, "Failed to allocate driver structure\n");
 852                return -ENOMEM;
 853        }
 854
 855        data->irq = platform_get_irq(pdev, 0);
 856        if (data->irq < 0) {
 857                dev_err(&pdev->dev, "Failed to get platform irq\n");
 858                return data->irq;
 859        }
 860
 861        INIT_WORK(&data->irq_work, exynos_tmu_work);
 862
 863        data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 864        if (!data->mem) {
 865                dev_err(&pdev->dev, "Failed to get platform resource\n");
 866                return -ENOENT;
 867        }
 868
 869        data->base = devm_request_and_ioremap(&pdev->dev, data->mem);
 870        if (!data->base) {
 871                dev_err(&pdev->dev, "Failed to ioremap memory\n");
 872                return -ENODEV;
 873        }
 874
 875        ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
 876                IRQF_TRIGGER_RISING, "exynos-tmu", data);
 877        if (ret) {
 878                dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
 879                return ret;
 880        }
 881
 882        data->clk = clk_get(NULL, "tmu_apbif");
 883        if (IS_ERR(data->clk)) {
 884                dev_err(&pdev->dev, "Failed to get clock\n");
 885                return  PTR_ERR(data->clk);
 886        }
 887
 888        if (pdata->type == SOC_ARCH_EXYNOS ||
 889                                pdata->type == SOC_ARCH_EXYNOS4210)
 890                data->soc = pdata->type;
 891        else {
 892                ret = -EINVAL;
 893                dev_err(&pdev->dev, "Platform not supported\n");
 894                goto err_clk;
 895        }
 896
 897        data->pdata = pdata;
 898        platform_set_drvdata(pdev, data);
 899        mutex_init(&data->lock);
 900
 901        ret = exynos_tmu_initialize(pdev);
 902        if (ret) {
 903                dev_err(&pdev->dev, "Failed to initialize TMU\n");
 904                goto err_clk;
 905        }
 906
 907        exynos_tmu_control(pdev, true);
 908
 909        /* Register the sensor with thermal management interface */
 910        (&exynos_sensor_conf)->private_data = data;
 911        exynos_sensor_conf.trip_data.trip_count = pdata->trigger_level0_en +
 912                        pdata->trigger_level1_en + pdata->trigger_level2_en +
 913                        pdata->trigger_level3_en;
 914
 915        for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
 916                exynos_sensor_conf.trip_data.trip_val[i] =
 917                        pdata->threshold + pdata->trigger_levels[i];
 918
 919        exynos_sensor_conf.cooling_data.freq_clip_count =
 920                                                pdata->freq_tab_count;
 921        for (i = 0; i < pdata->freq_tab_count; i++) {
 922                exynos_sensor_conf.cooling_data.freq_data[i].freq_clip_max =
 923                                        pdata->freq_tab[i].freq_clip_max;
 924                exynos_sensor_conf.cooling_data.freq_data[i].temp_level =
 925                                        pdata->freq_tab[i].temp_level;
 926        }
 927
 928        ret = exynos_register_thermal(&exynos_sensor_conf);
 929        if (ret) {
 930                dev_err(&pdev->dev, "Failed to register thermal interface\n");
 931                goto err_clk;
 932        }
 933        return 0;
 934err_clk:
 935        platform_set_drvdata(pdev, NULL);
 936        clk_put(data->clk);
 937        return ret;
 938}
 939
 940static int exynos_tmu_remove(struct platform_device *pdev)
 941{
 942        struct exynos_tmu_data *data = platform_get_drvdata(pdev);
 943
 944        exynos_tmu_control(pdev, false);
 945
 946        exynos_unregister_thermal();
 947
 948        clk_put(data->clk);
 949
 950        platform_set_drvdata(pdev, NULL);
 951
 952        return 0;
 953}
 954
 955#ifdef CONFIG_PM_SLEEP
 956static int exynos_tmu_suspend(struct device *dev)
 957{
 958        exynos_tmu_control(to_platform_device(dev), false);
 959
 960        return 0;
 961}
 962
 963static int exynos_tmu_resume(struct device *dev)
 964{
 965        struct platform_device *pdev = to_platform_device(dev);
 966
 967        exynos_tmu_initialize(pdev);
 968        exynos_tmu_control(pdev, true);
 969
 970        return 0;
 971}
 972
 973static SIMPLE_DEV_PM_OPS(exynos_tmu_pm,
 974                         exynos_tmu_suspend, exynos_tmu_resume);
 975#define EXYNOS_TMU_PM   (&exynos_tmu_pm)
 976#else
 977#define EXYNOS_TMU_PM   NULL
 978#endif
 979
 980static struct platform_driver exynos_tmu_driver = {
 981        .driver = {
 982                .name   = "exynos-tmu",
 983                .owner  = THIS_MODULE,
 984                .pm     = EXYNOS_TMU_PM,
 985                .of_match_table = exynos_tmu_match,
 986        },
 987        .probe = exynos_tmu_probe,
 988        .remove = exynos_tmu_remove,
 989        .id_table = exynos_tmu_driver_ids,
 990};
 991
 992module_platform_driver(exynos_tmu_driver);
 993
 994MODULE_DESCRIPTION("EXYNOS TMU Driver");
 995MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
 996MODULE_LICENSE("GPL");
 997MODULE_ALIAS("platform:exynos-tmu");
 998
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.