linux/drivers/thermal/kirkwood_thermal.c
<<
>>
Prefs
   1/*
   2 * Kirkwood thermal sensor driver
   3 *
   4 * Copyright (C) 2012 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
   5 *
   6 * This software is licensed under the terms of the GNU General Public
   7 * License version 2, as published by the Free Software Foundation, and
   8 * may be copied, distributed, and modified under those terms.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13 * GNU General Public License for more details.
  14 *
  15 */
  16#include <linux/device.h>
  17#include <linux/err.h>
  18#include <linux/io.h>
  19#include <linux/kernel.h>
  20#include <linux/of.h>
  21#include <linux/module.h>
  22#include <linux/platform_device.h>
  23#include <linux/thermal.h>
  24
  25#define KIRKWOOD_THERMAL_VALID_OFFSET   9
  26#define KIRKWOOD_THERMAL_VALID_MASK     0x1
  27#define KIRKWOOD_THERMAL_TEMP_OFFSET    10
  28#define KIRKWOOD_THERMAL_TEMP_MASK      0x1FF
  29
  30/* Kirkwood Thermal Sensor Dev Structure */
  31struct kirkwood_thermal_priv {
  32        void __iomem *sensor;
  33};
  34
  35static int kirkwood_get_temp(struct thermal_zone_device *thermal,
  36                          int *temp)
  37{
  38        unsigned long reg;
  39        struct kirkwood_thermal_priv *priv = thermal->devdata;
  40
  41        reg = readl_relaxed(priv->sensor);
  42
  43        /* Valid check */
  44        if (!((reg >> KIRKWOOD_THERMAL_VALID_OFFSET) &
  45            KIRKWOOD_THERMAL_VALID_MASK)) {
  46                dev_err(&thermal->device,
  47                        "Temperature sensor reading not valid\n");
  48                return -EIO;
  49        }
  50
  51        /*
  52         * Calculate temperature. According to Marvell internal
  53         * documentation the formula for this is:
  54         * Celsius = (322-reg)/1.3625
  55         */
  56        reg = (reg >> KIRKWOOD_THERMAL_TEMP_OFFSET) &
  57                KIRKWOOD_THERMAL_TEMP_MASK;
  58        *temp = ((3220000000UL - (10000000UL * reg)) / 13625);
  59
  60        return 0;
  61}
  62
  63static struct thermal_zone_device_ops ops = {
  64        .get_temp = kirkwood_get_temp,
  65};
  66
  67static const struct of_device_id kirkwood_thermal_id_table[] = {
  68        { .compatible = "marvell,kirkwood-thermal" },
  69        {}
  70};
  71
  72static int kirkwood_thermal_probe(struct platform_device *pdev)
  73{
  74        struct thermal_zone_device *thermal = NULL;
  75        struct kirkwood_thermal_priv *priv;
  76        struct resource *res;
  77
  78        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  79        if (!priv)
  80                return -ENOMEM;
  81
  82        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  83        priv->sensor = devm_ioremap_resource(&pdev->dev, res);
  84        if (IS_ERR(priv->sensor))
  85                return PTR_ERR(priv->sensor);
  86
  87        thermal = thermal_zone_device_register("kirkwood_thermal", 0, 0,
  88                                               priv, &ops, NULL, 0, 0);
  89        if (IS_ERR(thermal)) {
  90                dev_err(&pdev->dev,
  91                        "Failed to register thermal zone device\n");
  92                return PTR_ERR(thermal);
  93        }
  94
  95        platform_set_drvdata(pdev, thermal);
  96
  97        return 0;
  98}
  99
 100static int kirkwood_thermal_exit(struct platform_device *pdev)
 101{
 102        struct thermal_zone_device *kirkwood_thermal =
 103                platform_get_drvdata(pdev);
 104
 105        thermal_zone_device_unregister(kirkwood_thermal);
 106
 107        return 0;
 108}
 109
 110MODULE_DEVICE_TABLE(of, kirkwood_thermal_id_table);
 111
 112static struct platform_driver kirkwood_thermal_driver = {
 113        .probe = kirkwood_thermal_probe,
 114        .remove = kirkwood_thermal_exit,
 115        .driver = {
 116                .name = "kirkwood_thermal",
 117                .of_match_table = kirkwood_thermal_id_table,
 118        },
 119};
 120
 121module_platform_driver(kirkwood_thermal_driver);
 122
 123MODULE_AUTHOR("Nobuhiro Iwamatsu <iwamatsu@nigauri.org>");
 124MODULE_DESCRIPTION("kirkwood thermal driver");
 125MODULE_LICENSE("GPL");
 126