root/drivers/thermal/ti-soc-thermal/ti-thermal-common.c

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

DEFINITIONS

This source file includes following definitions.
  1. ti_thermal_work
  2. ti_thermal_hotspot_temperature
  3. __ti_thermal_get_temp
  4. ti_thermal_get_temp
  5. __ti_thermal_get_trend
  6. ti_thermal_build_data
  7. ti_thermal_expose_sensor
  8. ti_thermal_remove_sensor
  9. ti_thermal_report_sensor_temperature
  10. ti_thermal_register_cpu_cooling
  11. ti_thermal_unregister_cpu_cooling

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * OMAP thermal driver interface
   4  *
   5  * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
   6  * Contact:
   7  *   Eduardo Valentin <eduardo.valentin@ti.com>
   8  */
   9 
  10 #include <linux/device.h>
  11 #include <linux/err.h>
  12 #include <linux/mutex.h>
  13 #include <linux/gfp.h>
  14 #include <linux/kernel.h>
  15 #include <linux/workqueue.h>
  16 #include <linux/thermal.h>
  17 #include <linux/cpufreq.h>
  18 #include <linux/cpumask.h>
  19 #include <linux/cpu_cooling.h>
  20 #include <linux/of.h>
  21 
  22 #include "ti-thermal.h"
  23 #include "ti-bandgap.h"
  24 
  25 /* common data structures */
  26 struct ti_thermal_data {
  27         struct cpufreq_policy *policy;
  28         struct thermal_zone_device *ti_thermal;
  29         struct thermal_zone_device *pcb_tz;
  30         struct thermal_cooling_device *cool_dev;
  31         struct ti_bandgap *bgp;
  32         enum thermal_device_mode mode;
  33         struct work_struct thermal_wq;
  34         int sensor_id;
  35         bool our_zone;
  36 };
  37 
  38 static void ti_thermal_work(struct work_struct *work)
  39 {
  40         struct ti_thermal_data *data = container_of(work,
  41                                         struct ti_thermal_data, thermal_wq);
  42 
  43         thermal_zone_device_update(data->ti_thermal, THERMAL_EVENT_UNSPECIFIED);
  44 
  45         dev_dbg(&data->ti_thermal->device, "updated thermal zone %s\n",
  46                 data->ti_thermal->type);
  47 }
  48 
  49 /**
  50  * ti_thermal_hotspot_temperature - returns sensor extrapolated temperature
  51  * @t:  omap sensor temperature
  52  * @s:  omap sensor slope value
  53  * @c:  omap sensor const value
  54  */
  55 static inline int ti_thermal_hotspot_temperature(int t, int s, int c)
  56 {
  57         int delta = t * s / 1000 + c;
  58 
  59         if (delta < 0)
  60                 delta = 0;
  61 
  62         return t + delta;
  63 }
  64 
  65 /* thermal zone ops */
  66 /* Get temperature callback function for thermal zone */
  67 static inline int __ti_thermal_get_temp(void *devdata, int *temp)
  68 {
  69         struct thermal_zone_device *pcb_tz = NULL;
  70         struct ti_thermal_data *data = devdata;
  71         struct ti_bandgap *bgp;
  72         const struct ti_temp_sensor *s;
  73         int ret, tmp, slope, constant;
  74         int pcb_temp;
  75 
  76         if (!data)
  77                 return 0;
  78 
  79         bgp = data->bgp;
  80         s = &bgp->conf->sensors[data->sensor_id];
  81 
  82         ret = ti_bandgap_read_temperature(bgp, data->sensor_id, &tmp);
  83         if (ret)
  84                 return ret;
  85 
  86         /* Default constants */
  87         slope = thermal_zone_get_slope(data->ti_thermal);
  88         constant = thermal_zone_get_offset(data->ti_thermal);
  89 
  90         pcb_tz = data->pcb_tz;
  91         /* In case pcb zone is available, use the extrapolation rule with it */
  92         if (!IS_ERR(pcb_tz)) {
  93                 ret = thermal_zone_get_temp(pcb_tz, &pcb_temp);
  94                 if (!ret) {
  95                         tmp -= pcb_temp; /* got a valid PCB temp */
  96                         slope = s->slope_pcb;
  97                         constant = s->constant_pcb;
  98                 } else {
  99                         dev_err(bgp->dev,
 100                                 "Failed to read PCB state. Using defaults\n");
 101                         ret = 0;
 102                 }
 103         }
 104         *temp = ti_thermal_hotspot_temperature(tmp, slope, constant);
 105 
 106         return ret;
 107 }
 108 
 109 static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
 110                                       int *temp)
 111 {
 112         struct ti_thermal_data *data = thermal->devdata;
 113 
 114         return __ti_thermal_get_temp(data, temp);
 115 }
 116 
 117 static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend)
 118 {
 119         struct ti_thermal_data *data = p;
 120         struct ti_bandgap *bgp;
 121         int id, tr, ret = 0;
 122 
 123         bgp = data->bgp;
 124         id = data->sensor_id;
 125 
 126         ret = ti_bandgap_get_trend(bgp, id, &tr);
 127         if (ret)
 128                 return ret;
 129 
 130         if (tr > 0)
 131                 *trend = THERMAL_TREND_RAISING;
 132         else if (tr < 0)
 133                 *trend = THERMAL_TREND_DROPPING;
 134         else
 135                 *trend = THERMAL_TREND_STABLE;
 136 
 137         return 0;
 138 }
 139 
 140 static const struct thermal_zone_of_device_ops ti_of_thermal_ops = {
 141         .get_temp = __ti_thermal_get_temp,
 142         .get_trend = __ti_thermal_get_trend,
 143 };
 144 
 145 static struct ti_thermal_data
 146 *ti_thermal_build_data(struct ti_bandgap *bgp, int id)
 147 {
 148         struct ti_thermal_data *data;
 149 
 150         data = devm_kzalloc(bgp->dev, sizeof(*data), GFP_KERNEL);
 151         if (!data) {
 152                 dev_err(bgp->dev, "kzalloc fail\n");
 153                 return NULL;
 154         }
 155         data->sensor_id = id;
 156         data->bgp = bgp;
 157         data->mode = THERMAL_DEVICE_ENABLED;
 158         /* pcb_tz will be either valid or PTR_ERR() */
 159         data->pcb_tz = thermal_zone_get_zone_by_name("pcb");
 160         INIT_WORK(&data->thermal_wq, ti_thermal_work);
 161 
 162         return data;
 163 }
 164 
 165 int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
 166                              char *domain)
 167 {
 168         struct ti_thermal_data *data;
 169 
 170         data = ti_bandgap_get_sensor_data(bgp, id);
 171 
 172         if (!data || IS_ERR(data))
 173                 data = ti_thermal_build_data(bgp, id);
 174 
 175         if (!data)
 176                 return -EINVAL;
 177 
 178         /* in case this is specified by DT */
 179         data->ti_thermal = devm_thermal_zone_of_sensor_register(bgp->dev, id,
 180                                         data, &ti_of_thermal_ops);
 181         if (IS_ERR(data->ti_thermal)) {
 182                 dev_err(bgp->dev, "thermal zone device is NULL\n");
 183                 return PTR_ERR(data->ti_thermal);
 184         }
 185 
 186         ti_bandgap_set_sensor_data(bgp, id, data);
 187         ti_bandgap_write_update_interval(bgp, data->sensor_id,
 188                                         data->ti_thermal->polling_delay);
 189 
 190         return 0;
 191 }
 192 
 193 int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id)
 194 {
 195         struct ti_thermal_data *data;
 196 
 197         data = ti_bandgap_get_sensor_data(bgp, id);
 198 
 199         if (data && data->ti_thermal) {
 200                 if (data->our_zone)
 201                         thermal_zone_device_unregister(data->ti_thermal);
 202         }
 203 
 204         return 0;
 205 }
 206 
 207 int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id)
 208 {
 209         struct ti_thermal_data *data;
 210 
 211         data = ti_bandgap_get_sensor_data(bgp, id);
 212 
 213         schedule_work(&data->thermal_wq);
 214 
 215         return 0;
 216 }
 217 
 218 int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
 219 {
 220         struct ti_thermal_data *data;
 221         struct device_node *np = bgp->dev->of_node;
 222 
 223         /*
 224          * We are assuming here that if one deploys the zone
 225          * using DT, then it must be aware that the cooling device
 226          * loading has to happen via cpufreq driver.
 227          */
 228         if (of_find_property(np, "#thermal-sensor-cells", NULL))
 229                 return 0;
 230 
 231         data = ti_bandgap_get_sensor_data(bgp, id);
 232         if (!data || IS_ERR(data))
 233                 data = ti_thermal_build_data(bgp, id);
 234 
 235         if (!data)
 236                 return -EINVAL;
 237 
 238         data->policy = cpufreq_cpu_get(0);
 239         if (!data->policy) {
 240                 pr_debug("%s: CPUFreq policy not found\n", __func__);
 241                 return -EPROBE_DEFER;
 242         }
 243 
 244         /* Register cooling device */
 245         data->cool_dev = cpufreq_cooling_register(data->policy);
 246         if (IS_ERR(data->cool_dev)) {
 247                 int ret = PTR_ERR(data->cool_dev);
 248                 dev_err(bgp->dev, "Failed to register cpu cooling device %d\n",
 249                         ret);
 250                 cpufreq_cpu_put(data->policy);
 251 
 252                 return ret;
 253         }
 254         ti_bandgap_set_sensor_data(bgp, id, data);
 255 
 256         return 0;
 257 }
 258 
 259 int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
 260 {
 261         struct ti_thermal_data *data;
 262 
 263         data = ti_bandgap_get_sensor_data(bgp, id);
 264 
 265         if (data) {
 266                 cpufreq_cooling_unregister(data->cool_dev);
 267                 if (data->policy)
 268                         cpufreq_cpu_put(data->policy);
 269         }
 270 
 271         return 0;
 272 }

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