Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux

Pull thermal managament updates from Zhang Rui:
"Specifics:

- Abstract the code and introduce helper functions for all int340x
thermal drivers. From: Srinivas Pandruvada.

- Reorganize the ACPI LPAT table support code so that it can be
shared for both ACPI PMIC driver and int340x thermal driver.

- Add support for Braswell in intel_soc_dts thermal driver.

- a couple of small fixes/cleanups for step_wise governor and int340x
thermal driver"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux:
Thermal/int340x_thermal: remove unused uuids.
thermal: step_wise: spelling fixes
thermal: int340x: fix sparse warning
Thermal/int340x: LPAT conversion for temperature
ACPI / PMIC: Use common LPAT table handling functions
ACPI / LPAT: Common table processing functions
thermal: Intel SoC DTS: Add Braswell support
Thermal/int340x/int3402: Provide notification support
Thermal/int340x/processor_thermal: Add thermal zone support
Thermal/int340x/int3403: Use int340x thermal API
Thermal/int340x/int3402: Use int340x thermal API
Thermal/int340x: Add common thermal zone handler

+758 -505
+1
drivers/acpi/Makefile
··· 55 55 ifdef CONFIG_ACPI_VIDEO 56 56 acpi-y += video_detect.o 57 57 endif 58 + acpi-y += acpi_lpat.o 58 59 59 60 # These are (potentially) separate modules 60 61
+161
drivers/acpi/acpi_lpat.c
··· 1 + /* 2 + * acpi_lpat.c - LPAT table processing functions 3 + * 4 + * Copyright (C) 2015 Intel Corporation. All rights reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License version 8 + * 2 as published by the Free Software Foundation. 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/module.h> 17 + #include <linux/acpi.h> 18 + #include <acpi/acpi_lpat.h> 19 + 20 + /** 21 + * acpi_lpat_raw_to_temp(): Return temperature from raw value through 22 + * LPAT conversion table 23 + * 24 + * @lpat_table: the temperature_raw mapping table structure 25 + * @raw: the raw value, used as a key to get the temerature from the 26 + * above mapping table 27 + * 28 + * A positive converted temperarure value will be returned on success, 29 + * a negative errno will be returned in error cases. 30 + */ 31 + int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table, 32 + int raw) 33 + { 34 + int i, delta_temp, delta_raw, temp; 35 + struct acpi_lpat *lpat = lpat_table->lpat; 36 + 37 + for (i = 0; i < lpat_table->lpat_count - 1; i++) { 38 + if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) || 39 + (raw <= lpat[i].raw && raw >= lpat[i+1].raw)) 40 + break; 41 + } 42 + 43 + if (i == lpat_table->lpat_count - 1) 44 + return -ENOENT; 45 + 46 + delta_temp = lpat[i+1].temp - lpat[i].temp; 47 + delta_raw = lpat[i+1].raw - lpat[i].raw; 48 + temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw; 49 + 50 + return temp; 51 + } 52 + EXPORT_SYMBOL_GPL(acpi_lpat_raw_to_temp); 53 + 54 + /** 55 + * acpi_lpat_temp_to_raw(): Return raw value from temperature through 56 + * LPAT conversion table 57 + * 58 + * @lpat: the temperature_raw mapping table 59 + * @temp: the temperature, used as a key to get the raw value from the 60 + * above mapping table 61 + * 62 + * A positive converted temperature value will be returned on success, 63 + * a negative errno will be returned in error cases. 64 + */ 65 + int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table, 66 + int temp) 67 + { 68 + int i, delta_temp, delta_raw, raw; 69 + struct acpi_lpat *lpat = lpat_table->lpat; 70 + 71 + for (i = 0; i < lpat_table->lpat_count - 1; i++) { 72 + if (temp >= lpat[i].temp && temp <= lpat[i+1].temp) 73 + break; 74 + } 75 + 76 + if (i == lpat_table->lpat_count - 1) 77 + return -ENOENT; 78 + 79 + delta_temp = lpat[i+1].temp - lpat[i].temp; 80 + delta_raw = lpat[i+1].raw - lpat[i].raw; 81 + raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp; 82 + 83 + return raw; 84 + } 85 + EXPORT_SYMBOL_GPL(acpi_lpat_temp_to_raw); 86 + 87 + /** 88 + * acpi_lpat_get_conversion_table(): Parse ACPI LPAT table if present. 89 + * 90 + * @handle: Handle to acpi device 91 + * 92 + * Parse LPAT table to a struct of type acpi_lpat_table. On success 93 + * it returns a pointer to newly allocated table. This table must 94 + * be freed by the caller when finished processing, using a call to 95 + * acpi_lpat_free_conversion_table. 96 + */ 97 + struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle 98 + handle) 99 + { 100 + struct acpi_lpat_conversion_table *lpat_table = NULL; 101 + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 102 + union acpi_object *obj_p, *obj_e; 103 + int *lpat, i; 104 + acpi_status status; 105 + 106 + status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer); 107 + if (ACPI_FAILURE(status)) 108 + return NULL; 109 + 110 + obj_p = (union acpi_object *)buffer.pointer; 111 + if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) || 112 + (obj_p->package.count % 2) || (obj_p->package.count < 4)) 113 + goto out; 114 + 115 + lpat = kcalloc(obj_p->package.count, sizeof(int), GFP_KERNEL); 116 + if (!lpat) 117 + goto out; 118 + 119 + for (i = 0; i < obj_p->package.count; i++) { 120 + obj_e = &obj_p->package.elements[i]; 121 + if (obj_e->type != ACPI_TYPE_INTEGER) { 122 + kfree(lpat); 123 + goto out; 124 + } 125 + lpat[i] = (s64)obj_e->integer.value; 126 + } 127 + 128 + lpat_table = kzalloc(sizeof(*lpat_table), GFP_KERNEL); 129 + if (!lpat_table) { 130 + kfree(lpat); 131 + goto out; 132 + } 133 + 134 + lpat_table->lpat = (struct acpi_lpat *)lpat; 135 + lpat_table->lpat_count = obj_p->package.count / 2; 136 + 137 + out: 138 + kfree(buffer.pointer); 139 + return lpat_table; 140 + } 141 + EXPORT_SYMBOL_GPL(acpi_lpat_get_conversion_table); 142 + 143 + /** 144 + * acpi_lpat_free_conversion_table(): Free LPAT table. 145 + * 146 + * @lpat_table: the temperature_raw mapping table structure 147 + * 148 + * Frees the LPAT table previously allocated by a call to 149 + * acpi_lpat_get_conversion_table. 150 + */ 151 + void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table 152 + *lpat_table) 153 + { 154 + if (lpat_table) { 155 + kfree(lpat_table->lpat); 156 + kfree(lpat_table); 157 + } 158 + } 159 + EXPORT_SYMBOL_GPL(acpi_lpat_free_conversion_table); 160 + 161 + MODULE_LICENSE("GPL");
+18 -115
drivers/acpi/pmic/intel_pmic.c
··· 16 16 #include <linux/module.h> 17 17 #include <linux/acpi.h> 18 18 #include <linux/regmap.h> 19 + #include <acpi/acpi_lpat.h> 19 20 #include "intel_pmic.h" 20 21 21 22 #define PMIC_POWER_OPREGION_ID 0x8d 22 23 #define PMIC_THERMAL_OPREGION_ID 0x8c 23 24 24 - struct acpi_lpat { 25 - int temp; 26 - int raw; 27 - }; 28 - 29 25 struct intel_pmic_opregion { 30 26 struct mutex lock; 31 - struct acpi_lpat *lpat; 32 - int lpat_count; 27 + struct acpi_lpat_conversion_table *lpat_table; 33 28 struct regmap *regmap; 34 29 struct intel_pmic_opregion_data *data; 35 30 }; ··· 43 48 } 44 49 } 45 50 return -ENOENT; 46 - } 47 - 48 - /** 49 - * raw_to_temp(): Return temperature from raw value through LPAT table 50 - * 51 - * @lpat: the temperature_raw mapping table 52 - * @count: the count of the above mapping table 53 - * @raw: the raw value, used as a key to get the temerature from the 54 - * above mapping table 55 - * 56 - * A positive value will be returned on success, a negative errno will 57 - * be returned in error cases. 58 - */ 59 - static int raw_to_temp(struct acpi_lpat *lpat, int count, int raw) 60 - { 61 - int i, delta_temp, delta_raw, temp; 62 - 63 - for (i = 0; i < count - 1; i++) { 64 - if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) || 65 - (raw <= lpat[i].raw && raw >= lpat[i+1].raw)) 66 - break; 67 - } 68 - 69 - if (i == count - 1) 70 - return -ENOENT; 71 - 72 - delta_temp = lpat[i+1].temp - lpat[i].temp; 73 - delta_raw = lpat[i+1].raw - lpat[i].raw; 74 - temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw; 75 - 76 - return temp; 77 - } 78 - 79 - /** 80 - * temp_to_raw(): Return raw value from temperature through LPAT table 81 - * 82 - * @lpat: the temperature_raw mapping table 83 - * @count: the count of the above mapping table 84 - * @temp: the temperature, used as a key to get the raw value from the 85 - * above mapping table 86 - * 87 - * A positive value will be returned on success, a negative errno will 88 - * be returned in error cases. 89 - */ 90 - static int temp_to_raw(struct acpi_lpat *lpat, int count, int temp) 91 - { 92 - int i, delta_temp, delta_raw, raw; 93 - 94 - for (i = 0; i < count - 1; i++) { 95 - if (temp >= lpat[i].temp && temp <= lpat[i+1].temp) 96 - break; 97 - } 98 - 99 - if (i == count - 1) 100 - return -ENOENT; 101 - 102 - delta_temp = lpat[i+1].temp - lpat[i].temp; 103 - delta_raw = lpat[i+1].raw - lpat[i].raw; 104 - raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp; 105 - 106 - return raw; 107 - } 108 - 109 - static void pmic_thermal_lpat(struct intel_pmic_opregion *opregion, 110 - acpi_handle handle, struct device *dev) 111 - { 112 - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 113 - union acpi_object *obj_p, *obj_e; 114 - int *lpat, i; 115 - acpi_status status; 116 - 117 - status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer); 118 - if (ACPI_FAILURE(status)) 119 - return; 120 - 121 - obj_p = (union acpi_object *)buffer.pointer; 122 - if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) || 123 - (obj_p->package.count % 2) || (obj_p->package.count < 4)) 124 - goto out; 125 - 126 - lpat = devm_kmalloc(dev, sizeof(int) * obj_p->package.count, 127 - GFP_KERNEL); 128 - if (!lpat) 129 - goto out; 130 - 131 - for (i = 0; i < obj_p->package.count; i++) { 132 - obj_e = &obj_p->package.elements[i]; 133 - if (obj_e->type != ACPI_TYPE_INTEGER) { 134 - devm_kfree(dev, lpat); 135 - goto out; 136 - } 137 - lpat[i] = (s64)obj_e->integer.value; 138 - } 139 - 140 - opregion->lpat = (struct acpi_lpat *)lpat; 141 - opregion->lpat_count = obj_p->package.count / 2; 142 - 143 - out: 144 - kfree(buffer.pointer); 145 51 } 146 52 147 53 static acpi_status intel_pmic_power_handler(u32 function, ··· 88 192 if (raw_temp < 0) 89 193 return raw_temp; 90 194 91 - if (!opregion->lpat) { 195 + if (!opregion->lpat_table) { 92 196 *value = raw_temp; 93 197 return 0; 94 198 } 95 199 96 - temp = raw_to_temp(opregion->lpat, opregion->lpat_count, raw_temp); 200 + temp = acpi_lpat_raw_to_temp(opregion->lpat_table, raw_temp); 97 201 if (temp < 0) 98 202 return temp; 99 203 ··· 119 223 if (!opregion->data->update_aux) 120 224 return -ENXIO; 121 225 122 - if (opregion->lpat) { 123 - raw_temp = temp_to_raw(opregion->lpat, opregion->lpat_count, 124 - *value); 226 + if (opregion->lpat_table) { 227 + raw_temp = acpi_lpat_temp_to_raw(opregion->lpat_table, *value); 125 228 if (raw_temp < 0) 126 229 return raw_temp; 127 230 } else { ··· 209 314 { 210 315 acpi_status status; 211 316 struct intel_pmic_opregion *opregion; 317 + int ret; 212 318 213 319 if (!dev || !regmap || !d) 214 320 return -EINVAL; ··· 223 327 224 328 mutex_init(&opregion->lock); 225 329 opregion->regmap = regmap; 226 - pmic_thermal_lpat(opregion, handle, dev); 330 + opregion->lpat_table = acpi_lpat_get_conversion_table(handle); 227 331 228 332 status = acpi_install_address_space_handler(handle, 229 333 PMIC_POWER_OPREGION_ID, 230 334 intel_pmic_power_handler, 231 335 NULL, opregion); 232 - if (ACPI_FAILURE(status)) 233 - return -ENODEV; 336 + if (ACPI_FAILURE(status)) { 337 + ret = -ENODEV; 338 + goto out_error; 339 + } 234 340 235 341 status = acpi_install_address_space_handler(handle, 236 342 PMIC_THERMAL_OPREGION_ID, ··· 241 343 if (ACPI_FAILURE(status)) { 242 344 acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, 243 345 intel_pmic_power_handler); 244 - return -ENODEV; 346 + ret = -ENODEV; 347 + goto out_error; 245 348 } 246 349 247 350 opregion->data = d; 248 351 return 0; 352 + 353 + out_error: 354 + acpi_lpat_free_conversion_table(opregion->lpat_table); 355 + return ret; 249 356 } 250 357 EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); 251 358
+1
drivers/thermal/int340x_thermal/Makefile
··· 1 1 obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o 2 + obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o 2 3 obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o 3 4 obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o 4 5 obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o
-4
drivers/thermal/int340x_thermal/int3400_thermal.c
··· 18 18 19 19 enum int3400_thermal_uuid { 20 20 INT3400_THERMAL_PASSIVE_1, 21 - INT3400_THERMAL_PASSIVE_2, 22 21 INT3400_THERMAL_ACTIVE, 23 22 INT3400_THERMAL_CRITICAL, 24 - INT3400_THERMAL_COOLING_MODE, 25 23 INT3400_THERMAL_MAXIMUM_UUID, 26 24 }; 27 25 28 26 static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = { 29 27 "42A441D6-AE6A-462b-A84B-4A8CE79027D3", 30 - "9E04115A-AE87-4D1C-9500-0F3E340BFE75", 31 28 "3A95C389-E4B8-4629-A526-C52C88626BAE", 32 29 "97C68AE7-15FA-499c-B8C9-5DA81D606E0A", 33 - "16CAF1B7-DD38-40ed-B1C1-1B8A1913D531", 34 30 }; 35 31 36 32 struct int3400_thermal_priv {
+35 -169
drivers/thermal/int340x_thermal/int3402_thermal.c
··· 14 14 #include <linux/platform_device.h> 15 15 #include <linux/acpi.h> 16 16 #include <linux/thermal.h> 17 + #include "int340x_thermal_zone.h" 17 18 18 - #define ACPI_ACTIVE_COOLING_MAX_NR 10 19 - 20 - struct active_trip { 21 - unsigned long temp; 22 - int id; 23 - bool valid; 24 - }; 19 + #define INT3402_PERF_CHANGED_EVENT 0x80 20 + #define INT3402_THERMAL_EVENT 0x90 25 21 26 22 struct int3402_thermal_data { 27 - unsigned long *aux_trips; 28 - int aux_trip_nr; 29 - unsigned long psv_temp; 30 - int psv_trip_id; 31 - unsigned long crt_temp; 32 - int crt_trip_id; 33 - unsigned long hot_temp; 34 - int hot_trip_id; 35 - struct active_trip act_trips[ACPI_ACTIVE_COOLING_MAX_NR]; 36 23 acpi_handle *handle; 24 + struct int34x_thermal_zone *int340x_zone; 37 25 }; 38 26 39 - static int int3402_thermal_get_zone_temp(struct thermal_zone_device *zone, 40 - unsigned long *temp) 27 + static void int3402_notify(acpi_handle handle, u32 event, void *data) 41 28 { 42 - struct int3402_thermal_data *d = zone->devdata; 43 - unsigned long long tmp; 44 - acpi_status status; 29 + struct int3402_thermal_data *priv = data; 45 30 46 - status = acpi_evaluate_integer(d->handle, "_TMP", NULL, &tmp); 47 - if (ACPI_FAILURE(status)) 48 - return -ENODEV; 31 + if (!priv) 32 + return; 49 33 50 - /* _TMP returns the temperature in tenths of degrees Kelvin */ 51 - *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp); 52 - 53 - return 0; 54 - } 55 - 56 - static int int3402_thermal_get_trip_temp(struct thermal_zone_device *zone, 57 - int trip, unsigned long *temp) 58 - { 59 - struct int3402_thermal_data *d = zone->devdata; 60 - int i; 61 - 62 - if (trip < d->aux_trip_nr) 63 - *temp = d->aux_trips[trip]; 64 - else if (trip == d->crt_trip_id) 65 - *temp = d->crt_temp; 66 - else if (trip == d->psv_trip_id) 67 - *temp = d->psv_temp; 68 - else if (trip == d->hot_trip_id) 69 - *temp = d->hot_temp; 70 - else { 71 - for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { 72 - if (d->act_trips[i].valid && 73 - d->act_trips[i].id == trip) { 74 - *temp = d->act_trips[i].temp; 75 - break; 76 - } 77 - } 78 - if (i == ACPI_ACTIVE_COOLING_MAX_NR) 79 - return -EINVAL; 34 + switch (event) { 35 + case INT3402_PERF_CHANGED_EVENT: 36 + break; 37 + case INT3402_THERMAL_EVENT: 38 + int340x_thermal_zone_device_update(priv->int340x_zone); 39 + break; 40 + default: 41 + break; 80 42 } 81 - return 0; 82 - } 83 - 84 - static int int3402_thermal_get_trip_type(struct thermal_zone_device *zone, 85 - int trip, enum thermal_trip_type *type) 86 - { 87 - struct int3402_thermal_data *d = zone->devdata; 88 - int i; 89 - 90 - if (trip < d->aux_trip_nr) 91 - *type = THERMAL_TRIP_PASSIVE; 92 - else if (trip == d->crt_trip_id) 93 - *type = THERMAL_TRIP_CRITICAL; 94 - else if (trip == d->hot_trip_id) 95 - *type = THERMAL_TRIP_HOT; 96 - else if (trip == d->psv_trip_id) 97 - *type = THERMAL_TRIP_PASSIVE; 98 - else { 99 - for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { 100 - if (d->act_trips[i].valid && 101 - d->act_trips[i].id == trip) { 102 - *type = THERMAL_TRIP_ACTIVE; 103 - break; 104 - } 105 - } 106 - if (i == ACPI_ACTIVE_COOLING_MAX_NR) 107 - return -EINVAL; 108 - } 109 - return 0; 110 - } 111 - 112 - static int int3402_thermal_set_trip_temp(struct thermal_zone_device *zone, int trip, 113 - unsigned long temp) 114 - { 115 - struct int3402_thermal_data *d = zone->devdata; 116 - acpi_status status; 117 - char name[10]; 118 - 119 - snprintf(name, sizeof(name), "PAT%d", trip); 120 - status = acpi_execute_simple_method(d->handle, name, 121 - MILLICELSIUS_TO_DECI_KELVIN(temp)); 122 - if (ACPI_FAILURE(status)) 123 - return -EIO; 124 - 125 - d->aux_trips[trip] = temp; 126 - return 0; 127 - } 128 - 129 - static struct thermal_zone_device_ops int3402_thermal_zone_ops = { 130 - .get_temp = int3402_thermal_get_zone_temp, 131 - .get_trip_temp = int3402_thermal_get_trip_temp, 132 - .get_trip_type = int3402_thermal_get_trip_type, 133 - .set_trip_temp = int3402_thermal_set_trip_temp, 134 - }; 135 - 136 - static struct thermal_zone_params int3402_thermal_params = { 137 - .governor_name = "user_space", 138 - .no_hwmon = true, 139 - }; 140 - 141 - static int int3402_thermal_get_temp(acpi_handle handle, char *name, 142 - unsigned long *temp) 143 - { 144 - unsigned long long r; 145 - acpi_status status; 146 - 147 - status = acpi_evaluate_integer(handle, name, NULL, &r); 148 - if (ACPI_FAILURE(status)) 149 - return -EIO; 150 - 151 - *temp = DECI_KELVIN_TO_MILLICELSIUS(r); 152 - return 0; 153 43 } 154 44 155 45 static int int3402_thermal_probe(struct platform_device *pdev) 156 46 { 157 47 struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); 158 48 struct int3402_thermal_data *d; 159 - struct thermal_zone_device *zone; 160 - acpi_status status; 161 - unsigned long long trip_cnt; 162 - int trip_mask = 0, i; 49 + int ret; 163 50 164 51 if (!acpi_has_method(adev->handle, "_TMP")) 165 52 return -ENODEV; ··· 55 168 if (!d) 56 169 return -ENOMEM; 57 170 58 - status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt); 59 - if (ACPI_FAILURE(status)) 60 - trip_cnt = 0; 61 - else { 62 - d->aux_trips = devm_kzalloc(&pdev->dev, 63 - sizeof(*d->aux_trips) * trip_cnt, GFP_KERNEL); 64 - if (!d->aux_trips) 65 - return -ENOMEM; 66 - trip_mask = trip_cnt - 1; 67 - d->handle = adev->handle; 68 - d->aux_trip_nr = trip_cnt; 171 + d->int340x_zone = int340x_thermal_zone_add(adev, NULL); 172 + if (IS_ERR(d->int340x_zone)) 173 + return PTR_ERR(d->int340x_zone); 174 + 175 + ret = acpi_install_notify_handler(adev->handle, 176 + ACPI_DEVICE_NOTIFY, 177 + int3402_notify, 178 + d); 179 + if (ret) { 180 + int340x_thermal_zone_remove(d->int340x_zone); 181 + return ret; 69 182 } 70 183 71 - d->crt_trip_id = -1; 72 - if (!int3402_thermal_get_temp(adev->handle, "_CRT", &d->crt_temp)) 73 - d->crt_trip_id = trip_cnt++; 74 - d->hot_trip_id = -1; 75 - if (!int3402_thermal_get_temp(adev->handle, "_HOT", &d->hot_temp)) 76 - d->hot_trip_id = trip_cnt++; 77 - d->psv_trip_id = -1; 78 - if (!int3402_thermal_get_temp(adev->handle, "_PSV", &d->psv_temp)) 79 - d->psv_trip_id = trip_cnt++; 80 - for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { 81 - char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; 82 - if (int3402_thermal_get_temp(adev->handle, name, 83 - &d->act_trips[i].temp)) 84 - break; 85 - d->act_trips[i].id = trip_cnt++; 86 - d->act_trips[i].valid = true; 87 - } 88 - 89 - zone = thermal_zone_device_register(acpi_device_bid(adev), trip_cnt, 90 - trip_mask, d, 91 - &int3402_thermal_zone_ops, 92 - &int3402_thermal_params, 93 - 0, 0); 94 - if (IS_ERR(zone)) 95 - return PTR_ERR(zone); 96 - platform_set_drvdata(pdev, zone); 184 + d->handle = adev->handle; 185 + platform_set_drvdata(pdev, d); 97 186 98 187 return 0; 99 188 } 100 189 101 190 static int int3402_thermal_remove(struct platform_device *pdev) 102 191 { 103 - struct thermal_zone_device *zone = platform_get_drvdata(pdev); 192 + struct int3402_thermal_data *d = platform_get_drvdata(pdev); 104 193 105 - thermal_zone_device_unregister(zone); 194 + acpi_remove_notify_handler(d->handle, 195 + ACPI_DEVICE_NOTIFY, int3402_notify); 196 + int340x_thermal_zone_remove(d->int340x_zone); 197 + 106 198 return 0; 107 199 } 108 200
+10 -198
drivers/thermal/int340x_thermal/int3403_thermal.c
··· 19 19 #include <linux/acpi.h> 20 20 #include <linux/thermal.h> 21 21 #include <linux/platform_device.h> 22 + #include "int340x_thermal_zone.h" 22 23 23 24 #define INT3403_TYPE_SENSOR 0x03 24 25 #define INT3403_TYPE_CHARGER 0x0B ··· 27 26 #define INT3403_PERF_CHANGED_EVENT 0x80 28 27 #define INT3403_THERMAL_EVENT 0x90 29 28 30 - #define DECI_KELVIN_TO_MILLI_CELSIUS(t, off) (((t) - (off)) * 100) 31 - #define KELVIN_OFFSET 2732 32 - #define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off)) 33 - 29 + /* Preserved structure for future expandbility */ 34 30 struct int3403_sensor { 35 - struct thermal_zone_device *tzone; 36 - unsigned long *thresholds; 37 - unsigned long crit_temp; 38 - int crit_trip_id; 39 - unsigned long psv_temp; 40 - int psv_trip_id; 41 - 31 + struct int34x_thermal_zone *int340x_zone; 42 32 }; 43 33 44 34 struct int3403_performance_state { ··· 55 63 void *priv; 56 64 }; 57 65 58 - static int sys_get_curr_temp(struct thermal_zone_device *tzone, 59 - unsigned long *temp) 60 - { 61 - struct int3403_priv *priv = tzone->devdata; 62 - struct acpi_device *device = priv->adev; 63 - unsigned long long tmp; 64 - acpi_status status; 65 - 66 - status = acpi_evaluate_integer(device->handle, "_TMP", NULL, &tmp); 67 - if (ACPI_FAILURE(status)) 68 - return -EIO; 69 - 70 - *temp = DECI_KELVIN_TO_MILLI_CELSIUS(tmp, KELVIN_OFFSET); 71 - 72 - return 0; 73 - } 74 - 75 - static int sys_get_trip_hyst(struct thermal_zone_device *tzone, 76 - int trip, unsigned long *temp) 77 - { 78 - struct int3403_priv *priv = tzone->devdata; 79 - struct acpi_device *device = priv->adev; 80 - unsigned long long hyst; 81 - acpi_status status; 82 - 83 - status = acpi_evaluate_integer(device->handle, "GTSH", NULL, &hyst); 84 - if (ACPI_FAILURE(status)) 85 - return -EIO; 86 - 87 - /* 88 - * Thermal hysteresis represents a temperature difference. 89 - * Kelvin and Celsius have same degree size. So the 90 - * conversion here between tenths of degree Kelvin unit 91 - * and Milli-Celsius unit is just to multiply 100. 92 - */ 93 - *temp = hyst * 100; 94 - 95 - return 0; 96 - } 97 - 98 - static int sys_get_trip_temp(struct thermal_zone_device *tzone, 99 - int trip, unsigned long *temp) 100 - { 101 - struct int3403_priv *priv = tzone->devdata; 102 - struct int3403_sensor *obj = priv->priv; 103 - 104 - if (priv->type != INT3403_TYPE_SENSOR || !obj) 105 - return -EINVAL; 106 - 107 - if (trip == obj->crit_trip_id) 108 - *temp = obj->crit_temp; 109 - else if (trip == obj->psv_trip_id) 110 - *temp = obj->psv_temp; 111 - else { 112 - /* 113 - * get_trip_temp is a mandatory callback but 114 - * PATx method doesn't return any value, so return 115 - * cached value, which was last set from user space 116 - */ 117 - *temp = obj->thresholds[trip]; 118 - } 119 - 120 - return 0; 121 - } 122 - 123 - static int sys_get_trip_type(struct thermal_zone_device *thermal, 124 - int trip, enum thermal_trip_type *type) 125 - { 126 - struct int3403_priv *priv = thermal->devdata; 127 - struct int3403_sensor *obj = priv->priv; 128 - 129 - /* Mandatory callback, may not mean much here */ 130 - if (trip == obj->crit_trip_id) 131 - *type = THERMAL_TRIP_CRITICAL; 132 - else 133 - *type = THERMAL_TRIP_PASSIVE; 134 - 135 - return 0; 136 - } 137 - 138 - int sys_set_trip_temp(struct thermal_zone_device *tzone, int trip, 139 - unsigned long temp) 140 - { 141 - struct int3403_priv *priv = tzone->devdata; 142 - struct acpi_device *device = priv->adev; 143 - struct int3403_sensor *obj = priv->priv; 144 - acpi_status status; 145 - char name[10]; 146 - int ret = 0; 147 - 148 - snprintf(name, sizeof(name), "PAT%d", trip); 149 - if (acpi_has_method(device->handle, name)) { 150 - status = acpi_execute_simple_method(device->handle, name, 151 - MILLI_CELSIUS_TO_DECI_KELVIN(temp, 152 - KELVIN_OFFSET)); 153 - if (ACPI_FAILURE(status)) 154 - ret = -EIO; 155 - else 156 - obj->thresholds[trip] = temp; 157 - } else { 158 - ret = -EIO; 159 - dev_err(&device->dev, "sys_set_trip_temp: method not found\n"); 160 - } 161 - 162 - return ret; 163 - } 164 - 165 - static struct thermal_zone_device_ops tzone_ops = { 166 - .get_temp = sys_get_curr_temp, 167 - .get_trip_temp = sys_get_trip_temp, 168 - .get_trip_type = sys_get_trip_type, 169 - .set_trip_temp = sys_set_trip_temp, 170 - .get_trip_hyst = sys_get_trip_hyst, 171 - }; 172 - 173 - static struct thermal_zone_params int3403_thermal_params = { 174 - .governor_name = "user_space", 175 - .no_hwmon = true, 176 - }; 177 - 178 66 static void int3403_notify(acpi_handle handle, 179 67 u32 event, void *data) 180 68 { ··· 72 200 case INT3403_PERF_CHANGED_EVENT: 73 201 break; 74 202 case INT3403_THERMAL_EVENT: 75 - thermal_zone_device_update(obj->tzone); 203 + int340x_thermal_zone_device_update(obj->int340x_zone); 76 204 break; 77 205 default: 78 206 dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event); ··· 80 208 } 81 209 } 82 210 83 - static int sys_get_trip_crt(struct acpi_device *device, unsigned long *temp) 84 - { 85 - unsigned long long crt; 86 - acpi_status status; 87 - 88 - status = acpi_evaluate_integer(device->handle, "_CRT", NULL, &crt); 89 - if (ACPI_FAILURE(status)) 90 - return -EIO; 91 - 92 - *temp = DECI_KELVIN_TO_MILLI_CELSIUS(crt, KELVIN_OFFSET); 93 - 94 - return 0; 95 - } 96 - 97 - static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp) 98 - { 99 - unsigned long long psv; 100 - acpi_status status; 101 - 102 - status = acpi_evaluate_integer(device->handle, "_PSV", NULL, &psv); 103 - if (ACPI_FAILURE(status)) 104 - return -EIO; 105 - 106 - *temp = DECI_KELVIN_TO_MILLI_CELSIUS(psv, KELVIN_OFFSET); 107 - 108 - return 0; 109 - } 110 - 111 211 static int int3403_sensor_add(struct int3403_priv *priv) 112 212 { 113 213 int result = 0; 114 - acpi_status status; 115 214 struct int3403_sensor *obj; 116 - unsigned long long trip_cnt; 117 - int trip_mask = 0; 118 215 119 216 obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL); 120 217 if (!obj) ··· 91 250 92 251 priv->priv = obj; 93 252 94 - status = acpi_evaluate_integer(priv->adev->handle, "PATC", NULL, 95 - &trip_cnt); 96 - if (ACPI_FAILURE(status)) 97 - trip_cnt = 0; 98 - 99 - if (trip_cnt) { 100 - /* We have to cache, thresholds can't be readback */ 101 - obj->thresholds = devm_kzalloc(&priv->pdev->dev, 102 - sizeof(*obj->thresholds) * trip_cnt, 103 - GFP_KERNEL); 104 - if (!obj->thresholds) { 105 - result = -ENOMEM; 106 - goto err_free_obj; 107 - } 108 - trip_mask = BIT(trip_cnt) - 1; 109 - } 110 - 111 - obj->psv_trip_id = -1; 112 - if (!sys_get_trip_psv(priv->adev, &obj->psv_temp)) 113 - obj->psv_trip_id = trip_cnt++; 114 - 115 - obj->crit_trip_id = -1; 116 - if (!sys_get_trip_crt(priv->adev, &obj->crit_temp)) 117 - obj->crit_trip_id = trip_cnt++; 118 - 119 - obj->tzone = thermal_zone_device_register(acpi_device_bid(priv->adev), 120 - trip_cnt, trip_mask, priv, &tzone_ops, 121 - &int3403_thermal_params, 0, 0); 122 - if (IS_ERR(obj->tzone)) { 123 - result = PTR_ERR(obj->tzone); 124 - obj->tzone = NULL; 125 - goto err_free_obj; 126 - } 253 + obj->int340x_zone = int340x_thermal_zone_add(priv->adev, NULL); 254 + if (IS_ERR(obj->int340x_zone)) 255 + return PTR_ERR(obj->int340x_zone); 127 256 128 257 result = acpi_install_notify_handler(priv->adev->handle, 129 258 ACPI_DEVICE_NOTIFY, int3403_notify, ··· 104 293 return 0; 105 294 106 295 err_free_obj: 107 - thermal_zone_device_unregister(obj->tzone); 296 + int340x_thermal_zone_remove(obj->int340x_zone); 108 297 return result; 109 298 } 110 299 ··· 114 303 115 304 acpi_remove_notify_handler(priv->adev->handle, 116 305 ACPI_DEVICE_NOTIFY, int3403_notify); 117 - thermal_zone_device_unregister(obj->tzone); 306 + int340x_thermal_zone_remove(obj->int340x_zone); 307 + 118 308 return 0; 119 309 } 120 310
+276
drivers/thermal/int340x_thermal/int340x_thermal_zone.c
··· 1 + /* 2 + * int340x_thermal_zone.c 3 + * Copyright (c) 2015, Intel Corporation. 4 + * 5 + * This program is free software; you can redistribute it and/or modify it 6 + * under the terms and conditions of the GNU General Public License, 7 + * version 2, as published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope it will be useful, but WITHOUT 10 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 + * more details. 13 + * 14 + */ 15 + #include <linux/kernel.h> 16 + #include <linux/module.h> 17 + #include <linux/init.h> 18 + #include <linux/acpi.h> 19 + #include <linux/thermal.h> 20 + #include "int340x_thermal_zone.h" 21 + 22 + static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone, 23 + unsigned long *temp) 24 + { 25 + struct int34x_thermal_zone *d = zone->devdata; 26 + unsigned long long tmp; 27 + acpi_status status; 28 + 29 + if (d->override_ops && d->override_ops->get_temp) 30 + return d->override_ops->get_temp(zone, temp); 31 + 32 + status = acpi_evaluate_integer(d->adev->handle, "_TMP", NULL, &tmp); 33 + if (ACPI_FAILURE(status)) 34 + return -EIO; 35 + 36 + if (d->lpat_table) { 37 + int conv_temp; 38 + 39 + conv_temp = acpi_lpat_raw_to_temp(d->lpat_table, (int)tmp); 40 + if (conv_temp < 0) 41 + return conv_temp; 42 + 43 + *temp = (unsigned long)conv_temp * 10; 44 + } else 45 + /* _TMP returns the temperature in tenths of degrees Kelvin */ 46 + *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp); 47 + 48 + return 0; 49 + } 50 + 51 + static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone, 52 + int trip, unsigned long *temp) 53 + { 54 + struct int34x_thermal_zone *d = zone->devdata; 55 + int i; 56 + 57 + if (d->override_ops && d->override_ops->get_trip_temp) 58 + return d->override_ops->get_trip_temp(zone, trip, temp); 59 + 60 + if (trip < d->aux_trip_nr) 61 + *temp = d->aux_trips[trip]; 62 + else if (trip == d->crt_trip_id) 63 + *temp = d->crt_temp; 64 + else if (trip == d->psv_trip_id) 65 + *temp = d->psv_temp; 66 + else if (trip == d->hot_trip_id) 67 + *temp = d->hot_temp; 68 + else { 69 + for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { 70 + if (d->act_trips[i].valid && 71 + d->act_trips[i].id == trip) { 72 + *temp = d->act_trips[i].temp; 73 + break; 74 + } 75 + } 76 + if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) 77 + return -EINVAL; 78 + } 79 + 80 + return 0; 81 + } 82 + 83 + static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, 84 + int trip, 85 + enum thermal_trip_type *type) 86 + { 87 + struct int34x_thermal_zone *d = zone->devdata; 88 + int i; 89 + 90 + if (d->override_ops && d->override_ops->get_trip_type) 91 + return d->override_ops->get_trip_type(zone, trip, type); 92 + 93 + if (trip < d->aux_trip_nr) 94 + *type = THERMAL_TRIP_PASSIVE; 95 + else if (trip == d->crt_trip_id) 96 + *type = THERMAL_TRIP_CRITICAL; 97 + else if (trip == d->hot_trip_id) 98 + *type = THERMAL_TRIP_HOT; 99 + else if (trip == d->psv_trip_id) 100 + *type = THERMAL_TRIP_PASSIVE; 101 + else { 102 + for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { 103 + if (d->act_trips[i].valid && 104 + d->act_trips[i].id == trip) { 105 + *type = THERMAL_TRIP_ACTIVE; 106 + break; 107 + } 108 + } 109 + if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) 110 + return -EINVAL; 111 + } 112 + 113 + return 0; 114 + } 115 + 116 + static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone, 117 + int trip, unsigned long temp) 118 + { 119 + struct int34x_thermal_zone *d = zone->devdata; 120 + acpi_status status; 121 + char name[10]; 122 + 123 + if (d->override_ops && d->override_ops->set_trip_temp) 124 + return d->override_ops->set_trip_temp(zone, trip, temp); 125 + 126 + snprintf(name, sizeof(name), "PAT%d", trip); 127 + status = acpi_execute_simple_method(d->adev->handle, name, 128 + MILLICELSIUS_TO_DECI_KELVIN(temp)); 129 + if (ACPI_FAILURE(status)) 130 + return -EIO; 131 + 132 + d->aux_trips[trip] = temp; 133 + 134 + return 0; 135 + } 136 + 137 + 138 + static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone, 139 + int trip, unsigned long *temp) 140 + { 141 + struct int34x_thermal_zone *d = zone->devdata; 142 + acpi_status status; 143 + unsigned long long hyst; 144 + 145 + if (d->override_ops && d->override_ops->get_trip_hyst) 146 + return d->override_ops->get_trip_hyst(zone, trip, temp); 147 + 148 + status = acpi_evaluate_integer(d->adev->handle, "GTSH", NULL, &hyst); 149 + if (ACPI_FAILURE(status)) 150 + return -EIO; 151 + 152 + *temp = hyst * 100; 153 + 154 + return 0; 155 + } 156 + 157 + static struct thermal_zone_device_ops int340x_thermal_zone_ops = { 158 + .get_temp = int340x_thermal_get_zone_temp, 159 + .get_trip_temp = int340x_thermal_get_trip_temp, 160 + .get_trip_type = int340x_thermal_get_trip_type, 161 + .set_trip_temp = int340x_thermal_set_trip_temp, 162 + .get_trip_hyst = int340x_thermal_get_trip_hyst, 163 + }; 164 + 165 + static int int340x_thermal_get_trip_config(acpi_handle handle, char *name, 166 + unsigned long *temp) 167 + { 168 + unsigned long long r; 169 + acpi_status status; 170 + 171 + status = acpi_evaluate_integer(handle, name, NULL, &r); 172 + if (ACPI_FAILURE(status)) 173 + return -EIO; 174 + 175 + *temp = DECI_KELVIN_TO_MILLICELSIUS(r); 176 + 177 + return 0; 178 + } 179 + 180 + static struct thermal_zone_params int340x_thermal_params = { 181 + .governor_name = "user_space", 182 + .no_hwmon = true, 183 + }; 184 + 185 + struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, 186 + struct thermal_zone_device_ops *override_ops) 187 + { 188 + struct int34x_thermal_zone *int34x_thermal_zone; 189 + acpi_status status; 190 + unsigned long long trip_cnt; 191 + int trip_mask = 0, i; 192 + int ret; 193 + 194 + int34x_thermal_zone = kzalloc(sizeof(*int34x_thermal_zone), 195 + GFP_KERNEL); 196 + if (!int34x_thermal_zone) 197 + return ERR_PTR(-ENOMEM); 198 + 199 + int34x_thermal_zone->adev = adev; 200 + int34x_thermal_zone->override_ops = override_ops; 201 + 202 + status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt); 203 + if (ACPI_FAILURE(status)) 204 + trip_cnt = 0; 205 + else { 206 + int34x_thermal_zone->aux_trips = kzalloc( 207 + sizeof(*int34x_thermal_zone->aux_trips) * 208 + trip_cnt, GFP_KERNEL); 209 + if (!int34x_thermal_zone->aux_trips) { 210 + ret = -ENOMEM; 211 + goto free_mem; 212 + } 213 + trip_mask = BIT(trip_cnt) - 1; 214 + int34x_thermal_zone->aux_trip_nr = trip_cnt; 215 + } 216 + 217 + int34x_thermal_zone->crt_trip_id = -1; 218 + if (!int340x_thermal_get_trip_config(adev->handle, "_CRT", 219 + &int34x_thermal_zone->crt_temp)) 220 + int34x_thermal_zone->crt_trip_id = trip_cnt++; 221 + int34x_thermal_zone->hot_trip_id = -1; 222 + if (!int340x_thermal_get_trip_config(adev->handle, "_HOT", 223 + &int34x_thermal_zone->hot_temp)) 224 + int34x_thermal_zone->hot_trip_id = trip_cnt++; 225 + int34x_thermal_zone->psv_trip_id = -1; 226 + if (!int340x_thermal_get_trip_config(adev->handle, "_PSV", 227 + &int34x_thermal_zone->psv_temp)) 228 + int34x_thermal_zone->psv_trip_id = trip_cnt++; 229 + for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { 230 + char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; 231 + 232 + if (int340x_thermal_get_trip_config(adev->handle, name, 233 + &int34x_thermal_zone->act_trips[i].temp)) 234 + break; 235 + 236 + int34x_thermal_zone->act_trips[i].id = trip_cnt++; 237 + int34x_thermal_zone->act_trips[i].valid = true; 238 + } 239 + int34x_thermal_zone->lpat_table = acpi_lpat_get_conversion_table( 240 + adev->handle); 241 + 242 + int34x_thermal_zone->zone = thermal_zone_device_register( 243 + acpi_device_bid(adev), 244 + trip_cnt, 245 + trip_mask, int34x_thermal_zone, 246 + &int340x_thermal_zone_ops, 247 + &int340x_thermal_params, 248 + 0, 0); 249 + if (IS_ERR(int34x_thermal_zone->zone)) { 250 + ret = PTR_ERR(int34x_thermal_zone->zone); 251 + goto free_lpat; 252 + } 253 + 254 + return int34x_thermal_zone; 255 + 256 + free_lpat: 257 + acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); 258 + free_mem: 259 + kfree(int34x_thermal_zone); 260 + return ERR_PTR(ret); 261 + } 262 + EXPORT_SYMBOL_GPL(int340x_thermal_zone_add); 263 + 264 + void int340x_thermal_zone_remove(struct int34x_thermal_zone 265 + *int34x_thermal_zone) 266 + { 267 + thermal_zone_device_unregister(int34x_thermal_zone->zone); 268 + acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); 269 + kfree(int34x_thermal_zone); 270 + } 271 + EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove); 272 + 273 + MODULE_AUTHOR("Aaron Lu <aaron.lu@intel.com>"); 274 + MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); 275 + MODULE_DESCRIPTION("Intel INT340x common thermal zone handler"); 276 + MODULE_LICENSE("GPL v2");
+68
drivers/thermal/int340x_thermal/int340x_thermal_zone.h
··· 1 + /* 2 + * int340x_thermal_zone.h 3 + * Copyright (c) 2015, Intel Corporation. 4 + * 5 + * This program is free software; you can redistribute it and/or modify it 6 + * under the terms and conditions of the GNU General Public License, 7 + * version 2, as published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope it will be useful, but WITHOUT 10 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 + * more details. 13 + * 14 + */ 15 + 16 + #ifndef __INT340X_THERMAL_ZONE_H__ 17 + #define __INT340X_THERMAL_ZONE_H__ 18 + 19 + #include <acpi/acpi_lpat.h> 20 + 21 + #define INT340X_THERMAL_MAX_ACT_TRIP_COUNT 10 22 + 23 + struct active_trip { 24 + unsigned long temp; 25 + int id; 26 + bool valid; 27 + }; 28 + 29 + struct int34x_thermal_zone { 30 + struct acpi_device *adev; 31 + struct active_trip act_trips[INT340X_THERMAL_MAX_ACT_TRIP_COUNT]; 32 + unsigned long *aux_trips; 33 + int aux_trip_nr; 34 + unsigned long psv_temp; 35 + int psv_trip_id; 36 + unsigned long crt_temp; 37 + int crt_trip_id; 38 + unsigned long hot_temp; 39 + int hot_trip_id; 40 + struct thermal_zone_device *zone; 41 + struct thermal_zone_device_ops *override_ops; 42 + void *priv_data; 43 + struct acpi_lpat_conversion_table *lpat_table; 44 + }; 45 + 46 + struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *, 47 + struct thermal_zone_device_ops *override_ops); 48 + void int340x_thermal_zone_remove(struct int34x_thermal_zone *); 49 + 50 + static inline void int340x_thermal_zone_set_priv_data( 51 + struct int34x_thermal_zone *tzone, void *priv_data) 52 + { 53 + tzone->priv_data = priv_data; 54 + } 55 + 56 + static inline void *int340x_thermal_zone_get_priv_data( 57 + struct int34x_thermal_zone *tzone) 58 + { 59 + return tzone->priv_data; 60 + } 61 + 62 + static inline void int340x_thermal_zone_device_update( 63 + struct int34x_thermal_zone *tzone) 64 + { 65 + thermal_zone_device_update(tzone->zone); 66 + } 67 + 68 + #endif
+91 -1
drivers/thermal/int340x_thermal/processor_thermal_device.c
··· 18 18 #include <linux/pci.h> 19 19 #include <linux/platform_device.h> 20 20 #include <linux/acpi.h> 21 + #include <linux/thermal.h> 22 + #include "int340x_thermal_zone.h" 21 23 22 24 /* Broadwell-U/HSB thermal reporting device */ 23 25 #define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 ··· 41 39 struct device *dev; 42 40 struct acpi_device *adev; 43 41 struct power_config power_limits[2]; 42 + struct int34x_thermal_zone *int340x_zone; 44 43 }; 45 44 46 45 enum proc_thermal_emum_mode_type { ··· 120 117 .name = "power_limits" 121 118 }; 122 119 120 + static int stored_tjmax; /* since it is fixed, we can have local storage */ 121 + 122 + static int get_tjmax(void) 123 + { 124 + u32 eax, edx; 125 + u32 val; 126 + int err; 127 + 128 + err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); 129 + if (err) 130 + return err; 131 + 132 + val = (eax >> 16) & 0xff; 133 + if (val) 134 + return val; 135 + 136 + return -EINVAL; 137 + } 138 + 139 + static int read_temp_msr(unsigned long *temp) 140 + { 141 + int cpu; 142 + u32 eax, edx; 143 + int err; 144 + unsigned long curr_temp_off = 0; 145 + 146 + *temp = 0; 147 + 148 + for_each_online_cpu(cpu) { 149 + err = rdmsr_safe_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax, 150 + &edx); 151 + if (err) 152 + goto err_ret; 153 + else { 154 + if (eax & 0x80000000) { 155 + curr_temp_off = (eax >> 16) & 0x7f; 156 + if (!*temp || curr_temp_off < *temp) 157 + *temp = curr_temp_off; 158 + } else { 159 + err = -EINVAL; 160 + goto err_ret; 161 + } 162 + } 163 + } 164 + 165 + return 0; 166 + err_ret: 167 + return err; 168 + } 169 + 170 + static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone, 171 + unsigned long *temp) 172 + { 173 + int ret; 174 + 175 + ret = read_temp_msr(temp); 176 + if (!ret) 177 + *temp = (stored_tjmax - *temp) * 1000; 178 + 179 + return ret; 180 + } 181 + 182 + static struct thermal_zone_device_ops proc_thermal_local_ops = { 183 + .get_temp = proc_thermal_get_zone_temp, 184 + }; 185 + 123 186 static int proc_thermal_add(struct device *dev, 124 187 struct proc_thermal_device **priv) 125 188 { ··· 195 126 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; 196 127 union acpi_object *elements, *ppcc; 197 128 union acpi_object *p; 129 + unsigned long long tmp; 130 + struct thermal_zone_device_ops *ops = NULL; 198 131 int i; 199 132 int ret; 200 133 ··· 249 178 250 179 ret = sysfs_create_group(&dev->kobj, 251 180 &power_limit_attribute_group); 181 + if (ret) 182 + goto free_buffer; 183 + 184 + status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp); 185 + if (ACPI_FAILURE(status)) { 186 + /* there is no _TMP method, add local method */ 187 + stored_tjmax = get_tjmax(); 188 + if (stored_tjmax > 0) 189 + ops = &proc_thermal_local_ops; 190 + } 191 + 192 + proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops); 193 + if (IS_ERR(proc_priv->int340x_zone)) { 194 + sysfs_remove_group(&proc_priv->dev->kobj, 195 + &power_limit_attribute_group); 196 + ret = PTR_ERR(proc_priv->int340x_zone); 197 + } else 198 + ret = 0; 252 199 253 200 free_buffer: 254 201 kfree(buf.pointer); ··· 274 185 return ret; 275 186 } 276 187 277 - void proc_thermal_remove(struct proc_thermal_device *proc_priv) 188 + static void proc_thermal_remove(struct proc_thermal_device *proc_priv) 278 189 { 190 + int340x_thermal_zone_remove(proc_priv->int340x_zone); 279 191 sysfs_remove_group(&proc_priv->dev->kobj, 280 192 &power_limit_attribute_group); 281 193 }
+30 -16
drivers/thermal/intel_soc_dts_thermal.c
··· 309 309 return ret; 310 310 } 311 311 312 - static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max) 312 + static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max, 313 + bool notification_support) 313 314 { 314 315 struct soc_sensor_entry *aux_entry; 315 316 char name[10]; 317 + int trip_count = 0; 318 + int trip_mask = 0; 316 319 int err; 317 320 318 321 aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL); ··· 335 332 aux_entry->tj_max = tj_max; 336 333 aux_entry->temp_mask = 0x00FF << (id * 8); 337 334 aux_entry->temp_shift = id * 8; 335 + if (notification_support) { 336 + trip_count = SOC_MAX_DTS_TRIPS; 337 + trip_mask = 0x02; 338 + } 338 339 snprintf(name, sizeof(name), "soc_dts%d", id); 339 340 aux_entry->tzone = thermal_zone_device_register(name, 340 - SOC_MAX_DTS_TRIPS, 341 - 0x02, 342 - aux_entry, &tzone_ops, NULL, 0, 0); 341 + trip_count, 342 + trip_mask, 343 + aux_entry, &tzone_ops, 344 + NULL, 0, 0); 343 345 if (IS_ERR(aux_entry->tzone)) { 344 346 err = PTR_ERR(aux_entry->tzone); 345 347 goto err_ret; ··· 410 402 411 403 static const struct x86_cpu_id soc_thermal_ids[] = { 412 404 { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x37, 0, BYT_SOC_DTS_APIC_IRQ}, 405 + { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x4c, 0, 0}, 413 406 {} 414 407 }; 415 408 MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids); ··· 429 420 if (get_tj_max(&tj_max)) 430 421 return -EINVAL; 431 422 423 + soc_dts_thres_irq = (int)match_cpu->driver_data; 424 + 432 425 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 433 - soc_dts[i] = alloc_soc_dts(i, tj_max); 426 + soc_dts[i] = alloc_soc_dts(i, tj_max, 427 + soc_dts_thres_irq ? true : false); 434 428 if (IS_ERR(soc_dts[i])) { 435 429 err = PTR_ERR(soc_dts[i]); 436 430 goto err_free; ··· 442 430 443 431 spin_lock_init(&intr_notify_lock); 444 432 445 - soc_dts_thres_irq = (int)match_cpu->driver_data; 446 - 447 - err = request_threaded_irq(soc_dts_thres_irq, NULL, 448 - soc_irq_thread_fn, 449 - IRQF_TRIGGER_RISING | IRQF_ONESHOT, 450 - "soc_dts", soc_dts); 451 - if (err) { 452 - pr_err("request_threaded_irq ret %d\n", err); 453 - goto err_free; 433 + if (soc_dts_thres_irq) { 434 + err = request_threaded_irq(soc_dts_thres_irq, NULL, 435 + soc_irq_thread_fn, 436 + IRQF_TRIGGER_RISING | IRQF_ONESHOT, 437 + "soc_dts", soc_dts); 438 + if (err) { 439 + pr_err("request_threaded_irq ret %d\n", err); 440 + goto err_free; 441 + } 454 442 } 455 443 456 444 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { ··· 463 451 464 452 err_trip_temp: 465 453 i = SOC_MAX_DTS_SENSORS; 466 - free_irq(soc_dts_thres_irq, soc_dts); 454 + if (soc_dts_thres_irq) 455 + free_irq(soc_dts_thres_irq, soc_dts); 467 456 err_free: 468 457 while (--i >= 0) 469 458 free_soc_dts(soc_dts[i]); ··· 479 466 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) 480 467 update_trip_temp(soc_dts[i], 0, 0); 481 468 482 - free_irq(soc_dts_thres_irq, soc_dts); 469 + if (soc_dts_thres_irq) 470 + free_irq(soc_dts_thres_irq, soc_dts); 483 471 484 472 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) 485 473 free_soc_dts(soc_dts[i]);
+2 -2
drivers/thermal/step_wise.c
··· 45 45 * c. if the trend is THERMAL_TREND_RAISE_FULL, do nothing 46 46 * d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit, 47 47 * if the cooling state already equals lower limit, 48 - * deactive the thermal instance 48 + * deactivate the thermal instance 49 49 */ 50 50 static unsigned long get_target_state(struct thermal_instance *instance, 51 51 enum thermal_trend trend, bool throttle) ··· 169 169 } 170 170 171 171 /** 172 - * step_wise_throttle - throttles devices asscciated with the given zone 172 + * step_wise_throttle - throttles devices associated with the given zone 173 173 * @tz - thermal_zone_device 174 174 * @trip - the trip point 175 175 * @trip_type - type of the trip point
+65
include/acpi/acpi_lpat.h
··· 1 + /* 2 + * acpi_lpat.h - LPAT table processing functions 3 + * 4 + * Copyright (C) 2015 Intel Corporation. All rights reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License version 8 + * 2 as published by the Free Software Foundation. 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 + #ifndef ACPI_LPAT_H 17 + #define ACPI_LPAT_H 18 + 19 + struct acpi_lpat { 20 + int temp; 21 + int raw; 22 + }; 23 + 24 + struct acpi_lpat_conversion_table { 25 + struct acpi_lpat *lpat; 26 + int lpat_count; 27 + }; 28 + 29 + #ifdef CONFIG_ACPI 30 + 31 + int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table, 32 + int raw); 33 + int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table, 34 + int temp); 35 + struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle 36 + handle); 37 + void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table 38 + *lpat_table); 39 + 40 + #else 41 + static int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table, 42 + int raw) 43 + { 44 + return 0; 45 + } 46 + 47 + static int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table, 48 + int temp) 49 + { 50 + return 0; 51 + } 52 + 53 + static struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table( 54 + acpi_handle handle) 55 + { 56 + return NULL; 57 + } 58 + 59 + static void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table 60 + *lpat_table) 61 + { 62 + } 63 + 64 + #endif 65 + #endif