root/drivers/thermal/zx2967_thermal.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zx2967_thermal_get_temp
  2. zx2967_thermal_probe
  3. zx2967_thermal_exit
  4. zx2967_thermal_suspend
  5. zx2967_thermal_resume

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * ZTE's zx2967 family thermal sensor driver
   4  *
   5  * Copyright (C) 2017 ZTE Ltd.
   6  *
   7  * Author: Baoyou Xie <baoyou.xie@linaro.org>
   8  */
   9 
  10 #include <linux/clk.h>
  11 #include <linux/device.h>
  12 #include <linux/err.h>
  13 #include <linux/iopoll.h>
  14 #include <linux/module.h>
  15 #include <linux/platform_device.h>
  16 #include <linux/thermal.h>
  17 
  18 /* Power Mode: 0->low 1->high */
  19 #define ZX2967_THERMAL_POWER_MODE       0
  20 #define ZX2967_POWER_MODE_LOW           0
  21 #define ZX2967_POWER_MODE_HIGH          1
  22 
  23 /* DCF Control Register */
  24 #define ZX2967_THERMAL_DCF              0x4
  25 #define ZX2967_DCF_EN                   BIT(1)
  26 #define ZX2967_DCF_FREEZE               BIT(0)
  27 
  28 /* Selection Register */
  29 #define ZX2967_THERMAL_SEL              0x8
  30 
  31 /* Control Register */
  32 #define ZX2967_THERMAL_CTRL             0x10
  33 
  34 #define ZX2967_THERMAL_READY            BIT(12)
  35 #define ZX2967_THERMAL_TEMP_MASK        GENMASK(11, 0)
  36 #define ZX2967_THERMAL_ID_MASK          0x18
  37 #define ZX2967_THERMAL_ID               0x10
  38 
  39 #define ZX2967_GET_TEMP_TIMEOUT_US      (100 * 1024)
  40 
  41 /**
  42  * struct zx2967_thermal_priv - zx2967 thermal sensor private structure
  43  * @tzd: struct thermal_zone_device where the sensor is registered
  44  * @lock: prevents read sensor in parallel
  45  * @clk_topcrm: topcrm clk structure
  46  * @clk_apb: apb clk structure
  47  * @regs: pointer to base address of the thermal sensor
  48  */
  49 
  50 struct zx2967_thermal_priv {
  51         struct thermal_zone_device      *tzd;
  52         struct mutex                    lock;
  53         struct clk                      *clk_topcrm;
  54         struct clk                      *clk_apb;
  55         void __iomem                    *regs;
  56         struct device                   *dev;
  57 };
  58 
  59 static int zx2967_thermal_get_temp(void *data, int *temp)
  60 {
  61         void __iomem *regs;
  62         struct zx2967_thermal_priv *priv = data;
  63         u32 val;
  64         int ret;
  65 
  66         if (!priv->tzd)
  67                 return -EAGAIN;
  68 
  69         regs = priv->regs;
  70         mutex_lock(&priv->lock);
  71         writel_relaxed(ZX2967_POWER_MODE_LOW,
  72                        regs + ZX2967_THERMAL_POWER_MODE);
  73         writel_relaxed(ZX2967_DCF_EN, regs + ZX2967_THERMAL_DCF);
  74 
  75         val = readl_relaxed(regs + ZX2967_THERMAL_SEL);
  76         val &= ~ZX2967_THERMAL_ID_MASK;
  77         val |= ZX2967_THERMAL_ID;
  78         writel_relaxed(val, regs + ZX2967_THERMAL_SEL);
  79 
  80         /*
  81          * Must wait for a while, surely it's a bit odd.
  82          * otherwise temperature value we got has a few deviation, even if
  83          * the THERMAL_READY bit is set.
  84          */
  85         usleep_range(100, 300);
  86         ret = readx_poll_timeout(readl, regs + ZX2967_THERMAL_CTRL,
  87                                  val, val & ZX2967_THERMAL_READY, 300,
  88                                  ZX2967_GET_TEMP_TIMEOUT_US);
  89         if (ret) {
  90                 dev_err(priv->dev, "Thermal sensor data timeout\n");
  91                 goto unlock;
  92         }
  93 
  94         writel_relaxed(ZX2967_DCF_FREEZE | ZX2967_DCF_EN,
  95                        regs + ZX2967_THERMAL_DCF);
  96         val = readl_relaxed(regs + ZX2967_THERMAL_CTRL)
  97                          & ZX2967_THERMAL_TEMP_MASK;
  98         writel_relaxed(ZX2967_POWER_MODE_HIGH,
  99                        regs + ZX2967_THERMAL_POWER_MODE);
 100 
 101         /*
 102          * Calculate temperature
 103          * In dts, slope is multiplied by 1000.
 104          */
 105         *temp = DIV_ROUND_CLOSEST(((s32)val + priv->tzd->tzp->offset) * 1000,
 106                                   priv->tzd->tzp->slope);
 107 
 108 unlock:
 109         mutex_unlock(&priv->lock);
 110         return ret;
 111 }
 112 
 113 static const struct thermal_zone_of_device_ops zx2967_of_thermal_ops = {
 114         .get_temp = zx2967_thermal_get_temp,
 115 };
 116 
 117 static int zx2967_thermal_probe(struct platform_device *pdev)
 118 {
 119         struct zx2967_thermal_priv *priv;
 120         struct resource *res;
 121         int ret;
 122 
 123         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 124         if (!priv)
 125                 return -ENOMEM;
 126 
 127         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 128         priv->regs = devm_ioremap_resource(&pdev->dev, res);
 129         if (IS_ERR(priv->regs))
 130                 return PTR_ERR(priv->regs);
 131 
 132         priv->clk_topcrm = devm_clk_get(&pdev->dev, "topcrm");
 133         if (IS_ERR(priv->clk_topcrm)) {
 134                 ret = PTR_ERR(priv->clk_topcrm);
 135                 dev_err(&pdev->dev, "failed to get topcrm clock: %d\n", ret);
 136                 return ret;
 137         }
 138 
 139         ret = clk_prepare_enable(priv->clk_topcrm);
 140         if (ret) {
 141                 dev_err(&pdev->dev, "failed to enable topcrm clock: %d\n",
 142                         ret);
 143                 return ret;
 144         }
 145 
 146         priv->clk_apb = devm_clk_get(&pdev->dev, "apb");
 147         if (IS_ERR(priv->clk_apb)) {
 148                 ret = PTR_ERR(priv->clk_apb);
 149                 dev_err(&pdev->dev, "failed to get apb clock: %d\n", ret);
 150                 goto disable_clk_topcrm;
 151         }
 152 
 153         ret = clk_prepare_enable(priv->clk_apb);
 154         if (ret) {
 155                 dev_err(&pdev->dev, "failed to enable apb clock: %d\n",
 156                         ret);
 157                 goto disable_clk_topcrm;
 158         }
 159 
 160         mutex_init(&priv->lock);
 161         priv->tzd = thermal_zone_of_sensor_register(&pdev->dev,
 162                                         0, priv, &zx2967_of_thermal_ops);
 163 
 164         if (IS_ERR(priv->tzd)) {
 165                 ret = PTR_ERR(priv->tzd);
 166                 dev_err(&pdev->dev, "failed to register sensor: %d\n", ret);
 167                 goto disable_clk_all;
 168         }
 169 
 170         if (priv->tzd->tzp->slope == 0) {
 171                 thermal_zone_of_sensor_unregister(&pdev->dev, priv->tzd);
 172                 dev_err(&pdev->dev, "coefficients of sensor is invalid\n");
 173                 ret = -EINVAL;
 174                 goto disable_clk_all;
 175         }
 176 
 177         priv->dev = &pdev->dev;
 178         platform_set_drvdata(pdev, priv);
 179 
 180         return 0;
 181 
 182 disable_clk_all:
 183         clk_disable_unprepare(priv->clk_apb);
 184 disable_clk_topcrm:
 185         clk_disable_unprepare(priv->clk_topcrm);
 186         return ret;
 187 }
 188 
 189 static int zx2967_thermal_exit(struct platform_device *pdev)
 190 {
 191         struct zx2967_thermal_priv *priv = platform_get_drvdata(pdev);
 192 
 193         thermal_zone_of_sensor_unregister(&pdev->dev, priv->tzd);
 194         clk_disable_unprepare(priv->clk_topcrm);
 195         clk_disable_unprepare(priv->clk_apb);
 196 
 197         return 0;
 198 }
 199 
 200 static const struct of_device_id zx2967_thermal_id_table[] = {
 201         { .compatible = "zte,zx296718-thermal" },
 202         {}
 203 };
 204 MODULE_DEVICE_TABLE(of, zx2967_thermal_id_table);
 205 
 206 #ifdef CONFIG_PM_SLEEP
 207 static int zx2967_thermal_suspend(struct device *dev)
 208 {
 209         struct zx2967_thermal_priv *priv = dev_get_drvdata(dev);
 210 
 211         if (priv && priv->clk_topcrm)
 212                 clk_disable_unprepare(priv->clk_topcrm);
 213 
 214         if (priv && priv->clk_apb)
 215                 clk_disable_unprepare(priv->clk_apb);
 216 
 217         return 0;
 218 }
 219 
 220 static int zx2967_thermal_resume(struct device *dev)
 221 {
 222         struct zx2967_thermal_priv *priv = dev_get_drvdata(dev);
 223         int error;
 224 
 225         error = clk_prepare_enable(priv->clk_topcrm);
 226         if (error)
 227                 return error;
 228 
 229         error = clk_prepare_enable(priv->clk_apb);
 230         if (error) {
 231                 clk_disable_unprepare(priv->clk_topcrm);
 232                 return error;
 233         }
 234 
 235         return 0;
 236 }
 237 #endif
 238 
 239 static SIMPLE_DEV_PM_OPS(zx2967_thermal_pm_ops,
 240                          zx2967_thermal_suspend, zx2967_thermal_resume);
 241 
 242 static struct platform_driver zx2967_thermal_driver = {
 243         .probe = zx2967_thermal_probe,
 244         .remove = zx2967_thermal_exit,
 245         .driver = {
 246                 .name = "zx2967_thermal",
 247                 .of_match_table = zx2967_thermal_id_table,
 248                 .pm = &zx2967_thermal_pm_ops,
 249         },
 250 };
 251 module_platform_driver(zx2967_thermal_driver);
 252 
 253 MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
 254 MODULE_DESCRIPTION("ZTE zx2967 thermal driver");
 255 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */