root/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c

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

DEFINITIONS

This source file includes following definitions.
  1. int340x_thermal_get_zone_temp
  2. int340x_thermal_get_trip_temp
  3. int340x_thermal_get_trip_type
  4. int340x_thermal_set_trip_temp
  5. int340x_thermal_get_trip_hyst
  6. int340x_thermal_get_trip_config
  7. int340x_thermal_read_trips
  8. int340x_thermal_zone_add
  9. int340x_thermal_zone_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * int340x_thermal_zone.c
   4  * Copyright (c) 2015, Intel Corporation.
   5  */
   6 #include <linux/kernel.h>
   7 #include <linux/module.h>
   8 #include <linux/init.h>
   9 #include <linux/acpi.h>
  10 #include <linux/thermal.h>
  11 #include "int340x_thermal_zone.h"
  12 
  13 static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,
  14                                          int *temp)
  15 {
  16         struct int34x_thermal_zone *d = zone->devdata;
  17         unsigned long long tmp;
  18         acpi_status status;
  19 
  20         if (d->override_ops && d->override_ops->get_temp)
  21                 return d->override_ops->get_temp(zone, temp);
  22 
  23         status = acpi_evaluate_integer(d->adev->handle, "_TMP", NULL, &tmp);
  24         if (ACPI_FAILURE(status))
  25                 return -EIO;
  26 
  27         if (d->lpat_table) {
  28                 int conv_temp;
  29 
  30                 conv_temp = acpi_lpat_raw_to_temp(d->lpat_table, (int)tmp);
  31                 if (conv_temp < 0)
  32                         return conv_temp;
  33 
  34                 *temp = (unsigned long)conv_temp * 10;
  35         } else
  36                 /* _TMP returns the temperature in tenths of degrees Kelvin */
  37                 *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp);
  38 
  39         return 0;
  40 }
  41 
  42 static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone,
  43                                          int trip, int *temp)
  44 {
  45         struct int34x_thermal_zone *d = zone->devdata;
  46         int i;
  47 
  48         if (d->override_ops && d->override_ops->get_trip_temp)
  49                 return d->override_ops->get_trip_temp(zone, trip, temp);
  50 
  51         if (trip < d->aux_trip_nr)
  52                 *temp = d->aux_trips[trip];
  53         else if (trip == d->crt_trip_id)
  54                 *temp = d->crt_temp;
  55         else if (trip == d->psv_trip_id)
  56                 *temp = d->psv_temp;
  57         else if (trip == d->hot_trip_id)
  58                 *temp = d->hot_temp;
  59         else {
  60                 for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
  61                         if (d->act_trips[i].valid &&
  62                             d->act_trips[i].id == trip) {
  63                                 *temp = d->act_trips[i].temp;
  64                                 break;
  65                         }
  66                 }
  67                 if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT)
  68                         return -EINVAL;
  69         }
  70 
  71         return 0;
  72 }
  73 
  74 static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone,
  75                                          int trip,
  76                                          enum thermal_trip_type *type)
  77 {
  78         struct int34x_thermal_zone *d = zone->devdata;
  79         int i;
  80 
  81         if (d->override_ops && d->override_ops->get_trip_type)
  82                 return d->override_ops->get_trip_type(zone, trip, type);
  83 
  84         if (trip < d->aux_trip_nr)
  85                 *type = THERMAL_TRIP_PASSIVE;
  86         else if (trip == d->crt_trip_id)
  87                 *type = THERMAL_TRIP_CRITICAL;
  88         else if (trip == d->hot_trip_id)
  89                 *type = THERMAL_TRIP_HOT;
  90         else if (trip == d->psv_trip_id)
  91                 *type = THERMAL_TRIP_PASSIVE;
  92         else {
  93                 for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
  94                         if (d->act_trips[i].valid &&
  95                             d->act_trips[i].id == trip) {
  96                                 *type = THERMAL_TRIP_ACTIVE;
  97                                 break;
  98                         }
  99                 }
 100                 if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT)
 101                         return -EINVAL;
 102         }
 103 
 104         return 0;
 105 }
 106 
 107 static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,
 108                                       int trip, int temp)
 109 {
 110         struct int34x_thermal_zone *d = zone->devdata;
 111         acpi_status status;
 112         char name[10];
 113 
 114         if (d->override_ops && d->override_ops->set_trip_temp)
 115                 return d->override_ops->set_trip_temp(zone, trip, temp);
 116 
 117         snprintf(name, sizeof(name), "PAT%d", trip);
 118         status = acpi_execute_simple_method(d->adev->handle, name,
 119                         MILLICELSIUS_TO_DECI_KELVIN(temp));
 120         if (ACPI_FAILURE(status))
 121                 return -EIO;
 122 
 123         d->aux_trips[trip] = temp;
 124 
 125         return 0;
 126 }
 127 
 128 
 129 static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone,
 130                 int trip, int *temp)
 131 {
 132         struct int34x_thermal_zone *d = zone->devdata;
 133         acpi_status status;
 134         unsigned long long hyst;
 135 
 136         if (d->override_ops && d->override_ops->get_trip_hyst)
 137                 return d->override_ops->get_trip_hyst(zone, trip, temp);
 138 
 139         status = acpi_evaluate_integer(d->adev->handle, "GTSH", NULL, &hyst);
 140         if (ACPI_FAILURE(status))
 141                 *temp = 0;
 142         else
 143                 *temp = hyst * 100;
 144 
 145         return 0;
 146 }
 147 
 148 static struct thermal_zone_device_ops int340x_thermal_zone_ops = {
 149         .get_temp       = int340x_thermal_get_zone_temp,
 150         .get_trip_temp  = int340x_thermal_get_trip_temp,
 151         .get_trip_type  = int340x_thermal_get_trip_type,
 152         .set_trip_temp  = int340x_thermal_set_trip_temp,
 153         .get_trip_hyst =  int340x_thermal_get_trip_hyst,
 154 };
 155 
 156 static int int340x_thermal_get_trip_config(acpi_handle handle, char *name,
 157                                       int *temp)
 158 {
 159         unsigned long long r;
 160         acpi_status status;
 161 
 162         status = acpi_evaluate_integer(handle, name, NULL, &r);
 163         if (ACPI_FAILURE(status))
 164                 return -EIO;
 165 
 166         *temp = DECI_KELVIN_TO_MILLICELSIUS(r);
 167 
 168         return 0;
 169 }
 170 
 171 int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone)
 172 {
 173         int trip_cnt = int34x_zone->aux_trip_nr;
 174         int i;
 175 
 176         int34x_zone->crt_trip_id = -1;
 177         if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_CRT",
 178                                              &int34x_zone->crt_temp))
 179                 int34x_zone->crt_trip_id = trip_cnt++;
 180 
 181         int34x_zone->hot_trip_id = -1;
 182         if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_HOT",
 183                                              &int34x_zone->hot_temp))
 184                 int34x_zone->hot_trip_id = trip_cnt++;
 185 
 186         int34x_zone->psv_trip_id = -1;
 187         if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_PSV",
 188                                              &int34x_zone->psv_temp))
 189                 int34x_zone->psv_trip_id = trip_cnt++;
 190 
 191         for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
 192                 char name[5] = { '_', 'A', 'C', '0' + i, '\0' };
 193 
 194                 if (int340x_thermal_get_trip_config(int34x_zone->adev->handle,
 195                                         name,
 196                                         &int34x_zone->act_trips[i].temp))
 197                         break;
 198 
 199                 int34x_zone->act_trips[i].id = trip_cnt++;
 200                 int34x_zone->act_trips[i].valid = true;
 201         }
 202 
 203         return trip_cnt;
 204 }
 205 EXPORT_SYMBOL_GPL(int340x_thermal_read_trips);
 206 
 207 static struct thermal_zone_params int340x_thermal_params = {
 208         .governor_name = "user_space",
 209         .no_hwmon = true,
 210 };
 211 
 212 struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
 213                                 struct thermal_zone_device_ops *override_ops)
 214 {
 215         struct int34x_thermal_zone *int34x_thermal_zone;
 216         acpi_status status;
 217         unsigned long long trip_cnt;
 218         int trip_mask = 0;
 219         int ret;
 220 
 221         int34x_thermal_zone = kzalloc(sizeof(*int34x_thermal_zone),
 222                                       GFP_KERNEL);
 223         if (!int34x_thermal_zone)
 224                 return ERR_PTR(-ENOMEM);
 225 
 226         int34x_thermal_zone->adev = adev;
 227         int34x_thermal_zone->override_ops = override_ops;
 228 
 229         status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt);
 230         if (ACPI_FAILURE(status))
 231                 trip_cnt = 0;
 232         else {
 233                 int34x_thermal_zone->aux_trips =
 234                         kcalloc(trip_cnt,
 235                                 sizeof(*int34x_thermal_zone->aux_trips),
 236                                 GFP_KERNEL);
 237                 if (!int34x_thermal_zone->aux_trips) {
 238                         ret = -ENOMEM;
 239                         goto err_trip_alloc;
 240                 }
 241                 trip_mask = BIT(trip_cnt) - 1;
 242                 int34x_thermal_zone->aux_trip_nr = trip_cnt;
 243         }
 244 
 245         trip_cnt = int340x_thermal_read_trips(int34x_thermal_zone);
 246 
 247         int34x_thermal_zone->lpat_table = acpi_lpat_get_conversion_table(
 248                                                                 adev->handle);
 249 
 250         int34x_thermal_zone->zone = thermal_zone_device_register(
 251                                                 acpi_device_bid(adev),
 252                                                 trip_cnt,
 253                                                 trip_mask, int34x_thermal_zone,
 254                                                 &int340x_thermal_zone_ops,
 255                                                 &int340x_thermal_params,
 256                                                 0, 0);
 257         if (IS_ERR(int34x_thermal_zone->zone)) {
 258                 ret = PTR_ERR(int34x_thermal_zone->zone);
 259                 goto err_thermal_zone;
 260         }
 261 
 262         return int34x_thermal_zone;
 263 
 264 err_thermal_zone:
 265         acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
 266         kfree(int34x_thermal_zone->aux_trips);
 267 err_trip_alloc:
 268         kfree(int34x_thermal_zone);
 269         return ERR_PTR(ret);
 270 }
 271 EXPORT_SYMBOL_GPL(int340x_thermal_zone_add);
 272 
 273 void int340x_thermal_zone_remove(struct int34x_thermal_zone
 274                                  *int34x_thermal_zone)
 275 {
 276         thermal_zone_device_unregister(int34x_thermal_zone->zone);
 277         acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
 278         kfree(int34x_thermal_zone->aux_trips);
 279         kfree(int34x_thermal_zone);
 280 }
 281 EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
 282 
 283 MODULE_AUTHOR("Aaron Lu <aaron.lu@intel.com>");
 284 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
 285 MODULE_DESCRIPTION("Intel INT340x common thermal zone handler");
 286 MODULE_LICENSE("GPL v2");

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