root/drivers/thermal/tango_thermal.c

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

DEFINITIONS

This source file includes following definitions.
  1. temp_above_thresh
  2. tango_get_temp
  3. tango_thermal_init
  4. tango_thermal_probe
  5. tango_thermal_resume

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 #include <linux/io.h>
   3 #include <linux/delay.h>
   4 #include <linux/module.h>
   5 #include <linux/thermal.h>
   6 #include <linux/platform_device.h>
   7 
   8 /*
   9  * According to a data sheet draft, "this temperature sensor uses a bandgap
  10  * type of circuit to compare a voltage which has a negative temperature
  11  * coefficient with a voltage that is proportional to absolute temperature.
  12  * A resistor bank allows 41 different temperature thresholds to be selected
  13  * and the logic output will then indicate whether the actual die temperature
  14  * lies above or below the selected threshold."
  15  */
  16 
  17 #define TEMPSI_CMD      0
  18 #define TEMPSI_RES      4
  19 #define TEMPSI_CFG      8
  20 
  21 #define CMD_OFF         0
  22 #define CMD_ON          1
  23 #define CMD_READ        2
  24 
  25 #define IDX_MIN         15
  26 #define IDX_MAX         40
  27 
  28 struct tango_thermal_priv {
  29         void __iomem *base;
  30         int thresh_idx;
  31 };
  32 
  33 static bool temp_above_thresh(void __iomem *base, int thresh_idx)
  34 {
  35         writel(CMD_READ | thresh_idx << 8, base + TEMPSI_CMD);
  36         usleep_range(10, 20);
  37         writel(CMD_READ | thresh_idx << 8, base + TEMPSI_CMD);
  38 
  39         return readl(base + TEMPSI_RES);
  40 }
  41 
  42 static int tango_get_temp(void *arg, int *res)
  43 {
  44         struct tango_thermal_priv *priv = arg;
  45         int idx = priv->thresh_idx;
  46 
  47         if (temp_above_thresh(priv->base, idx)) {
  48                 /* Search upward by incrementing thresh_idx */
  49                 while (idx < IDX_MAX && temp_above_thresh(priv->base, ++idx))
  50                         cpu_relax();
  51                 idx = idx - 1; /* always return lower bound */
  52         } else {
  53                 /* Search downward by decrementing thresh_idx */
  54                 while (idx > IDX_MIN && !temp_above_thresh(priv->base, --idx))
  55                         cpu_relax();
  56         }
  57 
  58         *res = (idx * 9 / 2 - 38) * 1000; /* millidegrees Celsius */
  59         priv->thresh_idx = idx;
  60 
  61         return 0;
  62 }
  63 
  64 static const struct thermal_zone_of_device_ops ops = {
  65         .get_temp       = tango_get_temp,
  66 };
  67 
  68 static void tango_thermal_init(struct tango_thermal_priv *priv)
  69 {
  70         writel(0, priv->base + TEMPSI_CFG);
  71         writel(CMD_ON, priv->base + TEMPSI_CMD);
  72 }
  73 
  74 static int tango_thermal_probe(struct platform_device *pdev)
  75 {
  76         struct resource *res;
  77         struct tango_thermal_priv *priv;
  78         struct thermal_zone_device *tzdev;
  79 
  80         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  81         if (!priv)
  82                 return -ENOMEM;
  83 
  84         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  85         priv->base = devm_ioremap_resource(&pdev->dev, res);
  86         if (IS_ERR(priv->base))
  87                 return PTR_ERR(priv->base);
  88 
  89         platform_set_drvdata(pdev, priv);
  90         priv->thresh_idx = IDX_MIN;
  91         tango_thermal_init(priv);
  92 
  93         tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &ops);
  94         return PTR_ERR_OR_ZERO(tzdev);
  95 }
  96 
  97 static int __maybe_unused tango_thermal_resume(struct device *dev)
  98 {
  99         tango_thermal_init(dev_get_drvdata(dev));
 100         return 0;
 101 }
 102 
 103 static SIMPLE_DEV_PM_OPS(tango_thermal_pm, NULL, tango_thermal_resume);
 104 
 105 static const struct of_device_id tango_sensor_ids[] = {
 106         {
 107                 .compatible = "sigma,smp8758-thermal",
 108         },
 109         { /* sentinel */ }
 110 };
 111 MODULE_DEVICE_TABLE(of, tango_sensor_ids);
 112 
 113 static struct platform_driver tango_thermal_driver = {
 114         .probe  = tango_thermal_probe,
 115         .driver = {
 116                 .name           = "tango-thermal",
 117                 .of_match_table = tango_sensor_ids,
 118                 .pm             = &tango_thermal_pm,
 119         },
 120 };
 121 
 122 module_platform_driver(tango_thermal_driver);
 123 
 124 MODULE_LICENSE("GPL");
 125 MODULE_AUTHOR("Sigma Designs");
 126 MODULE_DESCRIPTION("Tango temperature sensor");

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