linux/drivers/thermal/qoriq_thermal.c
<<
>>
Prefs
   1/*
   2 * Copyright 2016 Freescale Semiconductor, Inc.
   3 *
   4 * This program is free software; you can redistribute it and/or modify it
   5 * under the terms and conditions of the GNU General Public License,
   6 * version 2, as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope it will be useful, but WITHOUT
   9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  11 * more details.
  12 *
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/platform_device.h>
  17#include <linux/err.h>
  18#include <linux/io.h>
  19#include <linux/of.h>
  20#include <linux/of_address.h>
  21#include <linux/thermal.h>
  22
  23#include "thermal_core.h"
  24
  25#define SITES_MAX       16
  26
  27/*
  28 * QorIQ TMU Registers
  29 */
  30struct qoriq_tmu_site_regs {
  31        u32 tritsr;             /* Immediate Temperature Site Register */
  32        u32 tratsr;             /* Average Temperature Site Register */
  33        u8 res0[0x8];
  34};
  35
  36struct qoriq_tmu_regs {
  37        u32 tmr;                /* Mode Register */
  38#define TMR_DISABLE     0x0
  39#define TMR_ME          0x80000000
  40#define TMR_ALPF        0x0c000000
  41        u32 tsr;                /* Status Register */
  42        u32 tmtmir;             /* Temperature measurement interval Register */
  43#define TMTMIR_DEFAULT  0x0000000f
  44        u8 res0[0x14];
  45        u32 tier;               /* Interrupt Enable Register */
  46#define TIER_DISABLE    0x0
  47        u32 tidr;               /* Interrupt Detect Register */
  48        u32 tiscr;              /* Interrupt Site Capture Register */
  49        u32 ticscr;             /* Interrupt Critical Site Capture Register */
  50        u8 res1[0x10];
  51        u32 tmhtcrh;            /* High Temperature Capture Register */
  52        u32 tmhtcrl;            /* Low Temperature Capture Register */
  53        u8 res2[0x8];
  54        u32 tmhtitr;            /* High Temperature Immediate Threshold */
  55        u32 tmhtatr;            /* High Temperature Average Threshold */
  56        u32 tmhtactr;   /* High Temperature Average Crit Threshold */
  57        u8 res3[0x24];
  58        u32 ttcfgr;             /* Temperature Configuration Register */
  59        u32 tscfgr;             /* Sensor Configuration Register */
  60        u8 res4[0x78];
  61        struct qoriq_tmu_site_regs site[SITES_MAX];
  62        u8 res5[0x9f8];
  63        u32 ipbrr0;             /* IP Block Revision Register 0 */
  64        u32 ipbrr1;             /* IP Block Revision Register 1 */
  65        u8 res6[0x310];
  66        u32 ttr0cr;             /* Temperature Range 0 Control Register */
  67        u32 ttr1cr;             /* Temperature Range 1 Control Register */
  68        u32 ttr2cr;             /* Temperature Range 2 Control Register */
  69        u32 ttr3cr;             /* Temperature Range 3 Control Register */
  70};
  71
  72/*
  73 * Thermal zone data
  74 */
  75struct qoriq_tmu_data {
  76        struct thermal_zone_device *tz;
  77        struct qoriq_tmu_regs __iomem *regs;
  78        int sensor_id;
  79        bool little_endian;
  80};
  81
  82static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem *addr)
  83{
  84        if (p->little_endian)
  85                iowrite32(val, addr);
  86        else
  87                iowrite32be(val, addr);
  88}
  89
  90static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr)
  91{
  92        if (p->little_endian)
  93                return ioread32(addr);
  94        else
  95                return ioread32be(addr);
  96}
  97
  98static int tmu_get_temp(void *p, int *temp)
  99{
 100        u32 val;
 101        struct qoriq_tmu_data *data = p;
 102
 103        val = tmu_read(data, &data->regs->site[data->sensor_id].tritsr);
 104        *temp = (val & 0xff) * 1000;
 105
 106        return 0;
 107}
 108
 109static int qoriq_tmu_get_sensor_id(void)
 110{
 111        int ret, id;
 112        struct of_phandle_args sensor_specs;
 113        struct device_node *np, *sensor_np;
 114
 115        np = of_find_node_by_name(NULL, "thermal-zones");
 116        if (!np)
 117                return -ENODEV;
 118
 119        sensor_np = of_get_next_child(np, NULL);
 120        ret = of_parse_phandle_with_args(sensor_np, "thermal-sensors",
 121                        "#thermal-sensor-cells",
 122                        0, &sensor_specs);
 123        if (ret) {
 124                of_node_put(np);
 125                of_node_put(sensor_np);
 126                return ret;
 127        }
 128
 129        if (sensor_specs.args_count >= 1) {
 130                id = sensor_specs.args[0];
 131                WARN(sensor_specs.args_count > 1,
 132                                "%s: too many cells in sensor specifier %d\n",
 133                                sensor_specs.np->name, sensor_specs.args_count);
 134        } else {
 135                id = 0;
 136        }
 137
 138        of_node_put(np);
 139        of_node_put(sensor_np);
 140
 141        return id;
 142}
 143
 144static int qoriq_tmu_calibration(struct platform_device *pdev)
 145{
 146        int i, val, len;
 147        u32 range[4];
 148        const u32 *calibration;
 149        struct device_node *np = pdev->dev.of_node;
 150        struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
 151
 152        if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) {
 153                dev_err(&pdev->dev, "missing calibration range.\n");
 154                return -ENODEV;
 155        }
 156
 157        /* Init temperature range registers */
 158        tmu_write(data, range[0], &data->regs->ttr0cr);
 159        tmu_write(data, range[1], &data->regs->ttr1cr);
 160        tmu_write(data, range[2], &data->regs->ttr2cr);
 161        tmu_write(data, range[3], &data->regs->ttr3cr);
 162
 163        calibration = of_get_property(np, "fsl,tmu-calibration", &len);
 164        if (calibration == NULL || len % 8) {
 165                dev_err(&pdev->dev, "invalid calibration data.\n");
 166                return -ENODEV;
 167        }
 168
 169        for (i = 0; i < len; i += 8, calibration += 2) {
 170                val = of_read_number(calibration, 1);
 171                tmu_write(data, val, &data->regs->ttcfgr);
 172                val = of_read_number(calibration + 1, 1);
 173                tmu_write(data, val, &data->regs->tscfgr);
 174        }
 175
 176        return 0;
 177}
 178
 179static void qoriq_tmu_init_device(struct qoriq_tmu_data *data)
 180{
 181        /* Disable interrupt, using polling instead */
 182        tmu_write(data, TIER_DISABLE, &data->regs->tier);
 183
 184        /* Set update_interval */
 185        tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir);
 186
 187        /* Disable monitoring */
 188        tmu_write(data, TMR_DISABLE, &data->regs->tmr);
 189}
 190
 191static const struct thermal_zone_of_device_ops tmu_tz_ops = {
 192        .get_temp = tmu_get_temp,
 193};
 194
 195static int qoriq_tmu_probe(struct platform_device *pdev)
 196{
 197        int ret;
 198        struct qoriq_tmu_data *data;
 199        struct device_node *np = pdev->dev.of_node;
 200        u32 site = 0;
 201
 202        if (!np) {
 203                dev_err(&pdev->dev, "Device OF-Node is NULL");
 204                return -ENODEV;
 205        }
 206
 207        data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data),
 208                            GFP_KERNEL);
 209        if (!data)
 210                return -ENOMEM;
 211
 212        platform_set_drvdata(pdev, data);
 213
 214        data->little_endian = of_property_read_bool(np, "little-endian");
 215
 216        data->sensor_id = qoriq_tmu_get_sensor_id();
 217        if (data->sensor_id < 0) {
 218                dev_err(&pdev->dev, "Failed to get sensor id\n");
 219                ret = -ENODEV;
 220                goto err_iomap;
 221        }
 222
 223        data->regs = of_iomap(np, 0);
 224        if (!data->regs) {
 225                dev_err(&pdev->dev, "Failed to get memory region\n");
 226                ret = -ENODEV;
 227                goto err_iomap;
 228        }
 229
 230        qoriq_tmu_init_device(data);    /* TMU initialization */
 231
 232        ret = qoriq_tmu_calibration(pdev);      /* TMU calibration */
 233        if (ret < 0)
 234                goto err_tmu;
 235
 236        data->tz = thermal_zone_of_sensor_register(&pdev->dev, data->sensor_id,
 237                                data, &tmu_tz_ops);
 238        if (IS_ERR(data->tz)) {
 239                ret = PTR_ERR(data->tz);
 240                dev_err(&pdev->dev,
 241                        "Failed to register thermal zone device %d\n", ret);
 242                goto err_tmu;
 243        }
 244
 245        /* Enable monitoring */
 246        site |= 0x1 << (15 - data->sensor_id);
 247        tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr);
 248
 249        return 0;
 250
 251err_tmu:
 252        iounmap(data->regs);
 253
 254err_iomap:
 255        platform_set_drvdata(pdev, NULL);
 256
 257        return ret;
 258}
 259
 260static int qoriq_tmu_remove(struct platform_device *pdev)
 261{
 262        struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
 263
 264        thermal_zone_of_sensor_unregister(&pdev->dev, data->tz);
 265
 266        /* Disable monitoring */
 267        tmu_write(data, TMR_DISABLE, &data->regs->tmr);
 268
 269        iounmap(data->regs);
 270        platform_set_drvdata(pdev, NULL);
 271
 272        return 0;
 273}
 274
 275#ifdef CONFIG_PM_SLEEP
 276static int qoriq_tmu_suspend(struct device *dev)
 277{
 278        u32 tmr;
 279        struct qoriq_tmu_data *data = dev_get_drvdata(dev);
 280
 281        /* Disable monitoring */
 282        tmr = tmu_read(data, &data->regs->tmr);
 283        tmr &= ~TMR_ME;
 284        tmu_write(data, tmr, &data->regs->tmr);
 285
 286        return 0;
 287}
 288
 289static int qoriq_tmu_resume(struct device *dev)
 290{
 291        u32 tmr;
 292        struct qoriq_tmu_data *data = dev_get_drvdata(dev);
 293
 294        /* Enable monitoring */
 295        tmr = tmu_read(data, &data->regs->tmr);
 296        tmr |= TMR_ME;
 297        tmu_write(data, tmr, &data->regs->tmr);
 298
 299        return 0;
 300}
 301#endif
 302
 303static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
 304                         qoriq_tmu_suspend, qoriq_tmu_resume);
 305
 306static const struct of_device_id qoriq_tmu_match[] = {
 307        { .compatible = "fsl,qoriq-tmu", },
 308        {},
 309};
 310MODULE_DEVICE_TABLE(of, qoriq_tmu_match);
 311
 312static struct platform_driver qoriq_tmu = {
 313        .driver = {
 314                .name           = "qoriq_thermal",
 315                .pm             = &qoriq_tmu_pm_ops,
 316                .of_match_table = qoriq_tmu_match,
 317        },
 318        .probe  = qoriq_tmu_probe,
 319        .remove = qoriq_tmu_remove,
 320};
 321module_platform_driver(qoriq_tmu);
 322
 323MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>");
 324MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver");
 325MODULE_LICENSE("GPL v2");
 326