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 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        const struct thermal_trip *trip;
 199        struct qoriq_tmu_data *data;
 200        struct device_node *np = pdev->dev.of_node;
 201        u32 site = 0;
 202
 203        if (!np) {
 204                dev_err(&pdev->dev, "Device OF-Node is NULL");
 205                return -ENODEV;
 206        }
 207
 208        data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data),
 209                            GFP_KERNEL);
 210        if (!data)
 211                return -ENOMEM;
 212
 213        platform_set_drvdata(pdev, data);
 214
 215        data->little_endian = of_property_read_bool(np, "little-endian");
 216
 217        data->sensor_id = qoriq_tmu_get_sensor_id();
 218        if (data->sensor_id < 0) {
 219                dev_err(&pdev->dev, "Failed to get sensor id\n");
 220                ret = -ENODEV;
 221                goto err_iomap;
 222        }
 223
 224        data->regs = of_iomap(np, 0);
 225        if (!data->regs) {
 226                dev_err(&pdev->dev, "Failed to get memory region\n");
 227                ret = -ENODEV;
 228                goto err_iomap;
 229        }
 230
 231        qoriq_tmu_init_device(data);    /* TMU initialization */
 232
 233        ret = qoriq_tmu_calibration(pdev);      /* TMU calibration */
 234        if (ret < 0)
 235                goto err_tmu;
 236
 237        data->tz = thermal_zone_of_sensor_register(&pdev->dev, data->sensor_id,
 238                                data, &tmu_tz_ops);
 239        if (IS_ERR(data->tz)) {
 240                ret = PTR_ERR(data->tz);
 241                dev_err(&pdev->dev,
 242                        "Failed to register thermal zone device %d\n", ret);
 243                goto err_tmu;
 244        }
 245
 246        trip = of_thermal_get_trip_points(data->tz);
 247
 248        /* Enable monitoring */
 249        site |= 0x1 << (15 - data->sensor_id);
 250        tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr);
 251
 252        return 0;
 253
 254err_tmu:
 255        iounmap(data->regs);
 256
 257err_iomap:
 258        platform_set_drvdata(pdev, NULL);
 259
 260        return ret;
 261}
 262
 263static int qoriq_tmu_remove(struct platform_device *pdev)
 264{
 265        struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
 266
 267        thermal_zone_of_sensor_unregister(&pdev->dev, data->tz);
 268
 269        /* Disable monitoring */
 270        tmu_write(data, TMR_DISABLE, &data->regs->tmr);
 271
 272        iounmap(data->regs);
 273        platform_set_drvdata(pdev, NULL);
 274
 275        return 0;
 276}
 277
 278#ifdef CONFIG_PM_SLEEP
 279static int qoriq_tmu_suspend(struct device *dev)
 280{
 281        u32 tmr;
 282        struct qoriq_tmu_data *data = dev_get_drvdata(dev);
 283
 284        /* Disable monitoring */
 285        tmr = tmu_read(data, &data->regs->tmr);
 286        tmr &= ~TMR_ME;
 287        tmu_write(data, tmr, &data->regs->tmr);
 288
 289        return 0;
 290}
 291
 292static int qoriq_tmu_resume(struct device *dev)
 293{
 294        u32 tmr;
 295        struct qoriq_tmu_data *data = dev_get_drvdata(dev);
 296
 297        /* Enable monitoring */
 298        tmr = tmu_read(data, &data->regs->tmr);
 299        tmr |= TMR_ME;
 300        tmu_write(data, tmr, &data->regs->tmr);
 301
 302        return 0;
 303}
 304#endif
 305
 306static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
 307                         qoriq_tmu_suspend, qoriq_tmu_resume);
 308
 309static const struct of_device_id qoriq_tmu_match[] = {
 310        { .compatible = "fsl,qoriq-tmu", },
 311        {},
 312};
 313MODULE_DEVICE_TABLE(of, qoriq_tmu_match);
 314
 315static struct platform_driver qoriq_tmu = {
 316        .driver = {
 317                .name           = "qoriq_thermal",
 318                .pm             = &qoriq_tmu_pm_ops,
 319                .of_match_table = qoriq_tmu_match,
 320        },
 321        .probe  = qoriq_tmu_probe,
 322        .remove = qoriq_tmu_remove,
 323};
 324module_platform_driver(qoriq_tmu);
 325
 326MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>");
 327MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver");
 328MODULE_LICENSE("GPL v2");
 329